[cros] RlzValueStore made protected by a cross-process lock and not persisted over browser lifetime (like on Mac).

*) Moved RecursiveCrossProcessLock out of .mm file to a common _posix file.
*) Added static method to ImportantFileWriter that does blocking write on the current thread.
*) Dedicated RLZ thread gone, replaced back with shutdown-blocking worker pool.


BUG=157348,62328


Review URL: https://chromiumcodereview.appspot.com/11308196

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@170179 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/base/files/important_file_writer.cc b/base/files/important_file_writer.cc
index 536b0fb..351adc2 100644
--- a/base/files/important_file_writer.cc
+++ b/base/files/important_file_writer.cc
@@ -42,7 +42,11 @@
                  << " : " << message;
 }
 
-void WriteToDiskTask(const FilePath& path, const std::string& data) {
+}  // namespace
+
+// static
+bool ImportantFileWriter::WriteFileAtomically(const FilePath& path,
+                                              const std::string& data) {
   // Write the data to a temp file then rename to avoid data loss if we crash
   // while writing the file. Ensure that the temp file is on the same volume
   // as target file, so it can be moved in one step, and that the temp file
@@ -50,7 +54,7 @@
   FilePath tmp_file_path;
   if (!file_util::CreateTemporaryFileInDir(path.DirName(), &tmp_file_path)) {
     LogFailure(path, FAILED_CREATING, "could not create temporary file");
-    return;
+    return false;
   }
 
   int flags = PLATFORM_FILE_OPEN | PLATFORM_FILE_WRITE;
@@ -58,7 +62,7 @@
       CreatePlatformFile(tmp_file_path, flags, NULL, NULL);
   if (tmp_file == kInvalidPlatformFileValue) {
     LogFailure(path, FAILED_OPENING, "could not open temporary file");
-    return;
+    return false;
   }
 
   // If this happens in the wild something really bad is going on.
@@ -70,24 +74,24 @@
   if (!ClosePlatformFile(tmp_file)) {
     LogFailure(path, FAILED_CLOSING, "failed to close temporary file");
     file_util::Delete(tmp_file_path, false);
-    return;
+    return false;
   }
 
   if (bytes_written < static_cast<int>(data.length())) {
     LogFailure(path, FAILED_WRITING, "error writing, bytes_written=" +
                IntToString(bytes_written));
     file_util::Delete(tmp_file_path, false);
-    return;
+    return false;
   }
 
   if (!file_util::ReplaceFile(tmp_file_path, path)) {
     LogFailure(path, FAILED_RENAMING, "could not rename temporary file");
     file_util::Delete(tmp_file_path, false);
-    return;
+    return false;
   }
-}
 
-}  // namespace
+  return true;
+}
 
 ImportantFileWriter::ImportantFileWriter(
     const FilePath& path, base::SequencedTaskRunner* task_runner)
@@ -122,14 +126,17 @@
   if (HasPendingWrite())
     timer_.Stop();
 
-  if (!task_runner_->PostTask(FROM_HERE,
-          MakeCriticalClosure(Bind(&WriteToDiskTask, path_, data)))) {
+  if (!task_runner_->PostTask(
+          FROM_HERE,
+          MakeCriticalClosure(
+              Bind(IgnoreResult(&ImportantFileWriter::WriteFileAtomically),
+                   path_, data)))) {
     // Posting the task to background message loop is not expected
     // to fail, but if it does, avoid losing data and just hit the disk
     // on the current thread.
     NOTREACHED();
 
-    WriteToDiskTask(path_, data);
+    WriteFileAtomically(path_, data);
   }
 }
 
diff --git a/base/files/important_file_writer.h b/base/files/important_file_writer.h
index ae814d5..9bc8f07 100644
--- a/base/files/important_file_writer.h
+++ b/base/files/important_file_writer.h
@@ -51,6 +51,11 @@
     virtual ~DataSerializer() {}
   };
 
+  // Save |data| to |path| in an atomic manner (see the class comment above).
+  // Blocks and writes data on the current thread.
+  static bool WriteFileAtomically(const FilePath& path,
+                                  const std::string& data);
+
   // Initialize the writer.
   // |path| is the name of file to write.
   // |task_runner| is the SequencedTaskRunner instance where on which we will
diff --git a/chrome/browser/rlz/rlz.cc b/chrome/browser/rlz/rlz.cc
index 7005e32..6032dd99 100644
--- a/chrome/browser/rlz/rlz.cc
+++ b/chrome/browser/rlz/rlz.cc
@@ -26,10 +26,6 @@
 #include "content/public/browser/notification_service.h"
 #include "net/http/http_util.h"
 
-#if defined(OS_CHROMEOS)
-#include "base/threading/sequenced_worker_pool.h"
-#endif
-
 #if defined(OS_WIN)
 #include "chrome/installer/util/google_update_settings.h"
 #else
@@ -56,8 +52,6 @@
 
 namespace {
 
-const char kRlzThreadName[] = "RLZ_thread";
-
 bool IsBrandOrganic(const std::string& brand) {
   return brand.empty() || google_util::IsOrganic(brand);
 }
@@ -177,9 +171,6 @@
       is_google_default_search_(false),
       is_google_homepage_(false),
       is_google_in_startpages_(false),
-      rlz_thread_(kRlzThreadName),
-      blocking_task_runner_(NULL),
-      url_request_context_(NULL),
       already_ran_(false),
       omnibox_used_(false),
       homepage_used_(false) {
@@ -208,9 +199,6 @@
   is_google_homepage_ = is_google_homepage;
   is_google_in_startpages_ = is_google_in_startpages;
 
-  if (!InitWorkers())
-    return false;
-
   // A negative delay means that a financial ping should be sent immediately
   // after a first search is recorded, without waiting for the next restart
   // of chrome. However, we only want this behaviour on first run.
@@ -246,7 +234,7 @@
                    content::NotificationService::AllSources());
   }
 
-  url_request_context_ = g_browser_process->system_request_context();
+  rlz_lib::SetURLRequestContext(g_browser_process->system_request_context());
   ScheduleDelayedInit(delay);
 
   return true;
@@ -255,35 +243,14 @@
 void RLZTracker::ScheduleDelayedInit(int delay) {
   // The RLZTracker is a singleton object that outlives any runnable tasks
   // that will be queued up.
-  blocking_task_runner_->PostDelayedTask(
+  BrowserThread::GetBlockingPool()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&RLZTracker::DelayedInit, base::Unretained(this)),
       base::TimeDelta::FromMilliseconds(delay));
 }
 
-bool RLZTracker::InitWorkers() {
-  base::Thread::Options options;
-  options.message_loop_type = MessageLoop::TYPE_IO;
-  if (!rlz_thread_.StartWithOptions(options))
-    return false;
-  blocking_task_runner_ = rlz_thread_.message_loop_proxy();
-
-#if defined(OS_CHROMEOS)
-  base::SequencedWorkerPool* worker_pool =
-      content::BrowserThread::GetBlockingPool();
-  if (!worker_pool)
-    return false;
-  rlz_lib::SetIOTaskRunner(
-      worker_pool->GetSequencedTaskRunnerWithShutdownBehavior(
-          worker_pool->GetSequenceToken(),
-          base::SequencedWorkerPool::BLOCK_SHUTDOWN));
-#endif
-  return true;
-}
-
 void RLZTracker::DelayedInit() {
-  if (!already_ran_)
-    rlz_lib::SetURLRequestContext(url_request_context_);
+  worker_pool_token_ = BrowserThread::GetBlockingPool()->GetSequenceToken();
 
   bool schedule_ping = false;
 
@@ -316,7 +283,8 @@
 }
 
 void RLZTracker::ScheduleFinancialPing() {
-  blocking_task_runner_->PostTask(
+  BrowserThread::GetBlockingPool()->PostSequencedWorkerTask(
+      worker_pool_token_,
       FROM_HERE,
       base::Bind(&RLZTracker::PingNowImpl, base::Unretained(this)));
 }
@@ -421,12 +389,13 @@
                                             rlz_lib::Event event_id) {
   if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
     return false;
-  if (!blocking_task_runner_) {
+  if (!already_ran_) {
     LOG(ERROR) << "Attempted recording RLZ event before RLZ init.";
     return true;
   }
 
-  blocking_task_runner_->PostTask(
+  BrowserThread::GetBlockingPool()->PostSequencedWorkerTask(
+      worker_pool_token_,
       FROM_HERE,
       base::Bind(base::IgnoreResult(&RLZTracker::RecordProductEvent),
                  product, point, event_id));
@@ -454,7 +423,8 @@
 bool RLZTracker::ScheduleRecordFirstSearch(rlz_lib::AccessPoint point) {
   if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
     return false;
-  blocking_task_runner_->PostTask(
+  BrowserThread::GetBlockingPool()->PostSequencedWorkerTask(
+      worker_pool_token_,
       FROM_HERE,
       base::Bind(&RLZTracker::RecordFirstSearch,
                  base::Unretained(this), point));
@@ -522,7 +492,8 @@
     return false;
 
   string16* not_used = NULL;
-  blocking_task_runner_->PostTask(
+  BrowserThread::GetBlockingPool()->PostSequencedWorkerTask(
+      worker_pool_token_,
       FROM_HERE,
       base::Bind(base::IgnoreResult(&RLZTracker::GetAccessPointRlz), point,
                  not_used));
diff --git a/chrome/browser/rlz/rlz.h b/chrome/browser/rlz/rlz.h
index 6a1d3c2..e41b5a3 100644
--- a/chrome/browser/rlz/rlz.h
+++ b/chrome/browser/rlz/rlz.h
@@ -15,7 +15,7 @@
 #include "base/basictypes.h"
 #include "base/memory/singleton.h"
 #include "base/string16.h"
-#include "base/threading/thread.h"
+#include "base/threading/sequenced_worker_pool.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "rlz/lib/rlz_lib.h"
@@ -113,10 +113,6 @@
             bool google_default_homepage,
             bool is_google_in_startpages);
 
-  // Initializes task runners for tasks that access RlzValueStore and perform
-  // disk I/O.
-  virtual bool InitWorkers();
-
   // Implementation called from RecordProductEvent() static method.
   bool RecordProductEventImpl(rlz_lib::Product product,
                               rlz_lib::AccessPoint point,
@@ -169,12 +165,9 @@
   bool is_google_homepage_;
   bool is_google_in_startpages_;
 
-  // Dedicated RLZ thread for accessing RlzValueStore and doing I/O.
-  base::Thread rlz_thread_;
-
-  // Sequenced task runner used to post blocking tasks that access
-  // RlzValueStore.
-  base::SequencedTaskRunner* blocking_task_runner_;
+  // Unique sequence token so that tasks posted by RLZTracker are executed
+  // sequentially in the blocking pool.
+  base::SequencedWorkerPool::SequenceToken worker_pool_token_;
 
   // URLRequestContextGetter used by RLZ library.
   net::URLRequestContextGetter* url_request_context_;
diff --git a/chrome/browser/rlz/rlz_unittest.cc b/chrome/browser/rlz/rlz_unittest.cc
index b1ccca9..165652f 100644
--- a/chrome/browser/rlz/rlz_unittest.cc
+++ b/chrome/browser/rlz/rlz_unittest.cc
@@ -28,12 +28,9 @@
 #include "base/test/test_reg_util_win.h"
 #include "base/win/registry.h"
 #include "rlz/win/lib/rlz_lib.h"  // InitializeTempHivesForTesting
-#elif defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#elif defined(OS_POSIX)
 #include "rlz/lib/rlz_value_store.h"  // SetRlzStoreDirectory
 #endif
-#if defined(OS_CHROMEOS)
-#include "rlz/chromeos/lib/rlz_value_store_chromeos.h"
-#endif
 
 using content::NavigationEntry;
 using testing::AssertionResult;
@@ -119,10 +116,6 @@
   }
 
  private:
-  virtual bool InitWorkers() OVERRIDE {
-    return true;
-  }
-
   virtual void ScheduleDelayedInit(int delay) OVERRIDE {
     // If the delay is 0, invoke the delayed init now. Otherwise,
     // don't schedule anything, it will be manually called during tests.
@@ -172,10 +165,6 @@
 
 class RlzLibTest : public testing::Test {
  public:
-#if defined(OS_CHROMEOS)
-  RlzLibTest();
-#endif
-
   virtual void SetUp() OVERRIDE;
   virtual void TearDown() OVERRIDE;
 
@@ -197,22 +186,12 @@
   TestRLZTracker tracker_;
 #if defined(OS_WIN)
   RegistryOverrideManager override_manager_;
-#elif defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#elif defined(OS_POSIX)
   base::ScopedTempDir temp_dir_;
   scoped_ptr<google_util::BrandForTesting> brand_override_;
 #endif
-#if defined(OS_CHROMEOS)
-  MessageLoop loop_;
-  base::Thread io_thread_;
-#endif
 };
 
-#if defined(OS_CHROMEOS)
-RlzLibTest::RlzLibTest()
-    : io_thread_("RlzLibTest-io") {
-}
-#endif
-
 void RlzLibTest::SetUp() {
   testing::Test::SetUp();
 
@@ -247,19 +226,11 @@
   // initialization performed above.
   override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE, kRlzTempHklm);
   override_manager_.OverrideRegistry(HKEY_CURRENT_USER, kRlzTempHkcu);
-#elif defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#elif defined(OS_POSIX)
   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
   rlz_lib::testing::SetRlzStoreDirectory(temp_dir_.path());
 #endif
 
-#if defined(OS_CHROMEOS)
-  base::Thread::Options options;
-  options.message_loop_type = MessageLoop::TYPE_IO;
-  ASSERT_TRUE(io_thread_.StartWithOptions(options));
-  rlz_lib::SetIOTaskRunner(io_thread_.message_loop_proxy());
-  rlz_lib::RlzValueStoreChromeOS::ResetForTesting();
-#endif
-
   // Make sure a non-organic brand code is set in the registry or the RLZTracker
   // is pretty much a no-op.
   SetMainBrand("TEST");
@@ -267,19 +238,16 @@
 }
 
 void RlzLibTest::TearDown() {
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#if defined(OS_POSIX)
   rlz_lib::testing::SetRlzStoreDirectory(FilePath());
 #endif
-#if defined(OS_CHROMEOS)
-  io_thread_.Stop();
-#endif  // defined(OS_CHROMEOS)
   testing::Test::TearDown();
 }
 
 void RlzLibTest::SetMainBrand(const char* brand) {
 #if defined(OS_WIN)
   SetRegistryBrandValue(google_update::kRegRLZBrandField, brand);
-#elif defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#elif defined(OS_POSIX)
   brand_override_.reset(new google_util::BrandForTesting(brand));
 #endif
   std::string check_brand;
diff --git a/rlz/chromeos/lib/rlz_value_store_chromeos.cc b/rlz/chromeos/lib/rlz_value_store_chromeos.cc
index ddf73e7..bb9c431 100644
--- a/rlz/chromeos/lib/rlz_value_store_chromeos.cc
+++ b/rlz/chromeos/lib/rlz_value_store_chromeos.cc
@@ -4,16 +4,16 @@
 
 #include "rlz/chromeos/lib/rlz_value_store_chromeos.h"
 
-#include "base/file_path.h"
 #include "base/file_util.h"
+#include "base/files/important_file_writer.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/json/json_string_value_serializer.h"
 #include "base/logging.h"
-#include "base/memory/singleton.h"
-#include "base/prefs/json_pref_store.h"
 #include "base/sequenced_task_runner.h"
 #include "base/string_number_conversions.h"
 #include "base/values.h"
 #include "rlz/lib/lib_values.h"
-#include "rlz/lib/recursive_lock.h"
+#include "rlz/lib/recursive_cross_process_lock_posix.h"
 #include "rlz/lib/rlz_lib.h"
 
 namespace rlz_lib {
@@ -36,6 +36,10 @@
 // RLZ store filename.
 const FilePath::CharType kRLZDataFileName[] = FILE_PATH_LITERAL("RLZ Data");
 
+// RLZ store lock filename
+const FilePath::CharType kRLZLockFileName[] =
+    FILE_PATH_LITERAL("RLZ Data.lock");
+
 // RLZ store path for testing.
 FilePath g_testing_rlz_store_path_;
 
@@ -46,6 +50,13 @@
       g_testing_rlz_store_path_.Append(kRLZDataFileName);
 }
 
+// Returns file path of the RLZ storage lock file.
+FilePath GetRlzStoreLockPath() {
+  return g_testing_rlz_store_path_.empty() ?
+      file_util::GetHomeDir().Append(kRLZLockFileName) :
+      g_testing_rlz_store_path_.Append(kRLZLockFileName);
+}
+
 // Returns the dictionary key for storing access point-related prefs.
 std::string GetKeyName(std::string key, AccessPoint access_point) {
   std::string brand = SupplementaryBranding::GetBrand();
@@ -64,89 +75,58 @@
 
 }  // namespace
 
-// static
-base::SequencedTaskRunner* RlzValueStoreChromeOS::io_task_runner_ = NULL;
-
-// static
-bool RlzValueStoreChromeOS::created_;
-
-// static
-RlzValueStoreChromeOS* RlzValueStoreChromeOS::GetInstance() {
-  return Singleton<RlzValueStoreChromeOS>::get();
-}
-
-// static
-void RlzValueStoreChromeOS::SetIOTaskRunner(
-    base::SequencedTaskRunner* io_task_runner) {
-  io_task_runner_ = io_task_runner;
-  // Make sure |io_task_runner_| lives until constructor is called.
-  io_task_runner_->AddRef();
-}
-
-// static
-void RlzValueStoreChromeOS::ResetForTesting() {
-  // Make sure we don't create an instance if it didn't exist.
-  if (created_)
-    GetInstance()->ReadPrefs();
-}
-
-// static
-void RlzValueStoreChromeOS::Cleanup() {
-  if (created_)
-    GetInstance()->rlz_store_ = NULL;
-}
-
-RlzValueStoreChromeOS::RlzValueStoreChromeOS() {
-  ReadPrefs();
-  created_ = true;
+RlzValueStoreChromeOS::RlzValueStoreChromeOS(const FilePath& store_path)
+    : rlz_store_(new base::DictionaryValue),
+      store_path_(store_path),
+      read_only_(true) {
+  ReadStore();
 }
 
 RlzValueStoreChromeOS::~RlzValueStoreChromeOS() {
+  WriteStore();
 }
 
 bool RlzValueStoreChromeOS::HasAccess(AccessType type) {
-  return type == kReadAccess || !rlz_store_->ReadOnly();
+  DCHECK(CalledOnValidThread());
+  return type == kReadAccess || !read_only_;
 }
 
 bool RlzValueStoreChromeOS::WritePingTime(Product product, int64 time) {
-  std::string value = base::Int64ToString(time);
-  rlz_store_->SetValue(GetKeyName(kPingTimeKey, product),
-                       base::Value::CreateStringValue(value));
+  DCHECK(CalledOnValidThread());
+  rlz_store_->SetString(GetKeyName(kPingTimeKey, product),
+                        base::Int64ToString(time));
   return true;
 }
 
 bool RlzValueStoreChromeOS::ReadPingTime(Product product, int64* time) {
-  const base::Value* value = NULL;
-  rlz_store_->GetValue(GetKeyName(kPingTimeKey, product), &value);
-  std::string s_value;
-  return value && value->GetAsString(&s_value) &&
-      base::StringToInt64(s_value, time);
+  DCHECK(CalledOnValidThread());
+  std::string ping_time;
+  return rlz_store_->GetString(GetKeyName(kPingTimeKey, product), &ping_time) &&
+      base::StringToInt64(ping_time, time);
 }
 
 bool RlzValueStoreChromeOS::ClearPingTime(Product product) {
-  rlz_store_->RemoveValue(GetKeyName(kPingTimeKey, product));
+  DCHECK(CalledOnValidThread());
+  rlz_store_->Remove(GetKeyName(kPingTimeKey, product), NULL);
   return true;
 }
 
 bool RlzValueStoreChromeOS::WriteAccessPointRlz(AccessPoint access_point,
                                                 const char* new_rlz) {
-  rlz_store_->SetValue(
-      GetKeyName(kAccessPointKey, access_point),
-      base::Value::CreateStringValue(new_rlz));
+  DCHECK(CalledOnValidThread());
+  rlz_store_->SetString(
+      GetKeyName(kAccessPointKey, access_point), new_rlz);
   return true;
 }
 
 bool RlzValueStoreChromeOS::ReadAccessPointRlz(AccessPoint access_point,
                                                char* rlz,
                                                size_t rlz_size) {
-  const base::Value* value = NULL;
-  rlz_store_->GetValue(
-      GetKeyName(kAccessPointKey, access_point), &value);
-  std::string s_value;
-  if (value)
-    value->GetAsString(&s_value);
-  if (s_value.size() < rlz_size) {
-    strncpy(rlz, s_value.c_str(), rlz_size);
+  DCHECK(CalledOnValidThread());
+  std::string rlz_value;
+  rlz_store_->GetString(GetKeyName(kAccessPointKey, access_point), &rlz_value);
+  if (rlz_value.size() < rlz_size) {
+    strncpy(rlz, rlz_value.c_str(), rlz_size);
     return true;
   }
   if (rlz_size > 0)
@@ -155,13 +135,14 @@
 }
 
 bool RlzValueStoreChromeOS::ClearAccessPointRlz(AccessPoint access_point) {
-  rlz_store_->RemoveValue(
-      GetKeyName(kAccessPointKey, access_point));
+  DCHECK(CalledOnValidThread());
+  rlz_store_->Remove(GetKeyName(kAccessPointKey, access_point), NULL);
   return true;
 }
 
 bool RlzValueStoreChromeOS::AddProductEvent(Product product,
                                             const char* event_rlz) {
+  DCHECK(CalledOnValidThread());
   return AddValueToList(GetKeyName(kProductEventKey, product),
                         base::Value::CreateStringValue(event_rlz));
 }
@@ -169,8 +150,9 @@
 bool RlzValueStoreChromeOS::ReadProductEvents(
     Product product,
     std::vector<std::string>* events) {
-  base::ListValue* events_list = GetList(GetKeyName(kProductEventKey, product));
-  if (!events_list)
+  DCHECK(CalledOnValidThread());
+  base::ListValue* events_list = NULL; ;
+  if (!rlz_store_->GetList(GetKeyName(kProductEventKey, product), &events_list))
     return false;
   events->clear();
   for (size_t i = 0; i < events_list->GetSize(); ++i) {
@@ -183,99 +165,162 @@
 
 bool RlzValueStoreChromeOS::ClearProductEvent(Product product,
                                               const char* event_rlz) {
+  DCHECK(CalledOnValidThread());
   base::StringValue event_value(event_rlz);
   return RemoveValueFromList(GetKeyName(kProductEventKey, product),
                              event_value);
 }
 
 bool RlzValueStoreChromeOS::ClearAllProductEvents(Product product) {
-  rlz_store_->RemoveValue(GetKeyName(kProductEventKey, product));
+  DCHECK(CalledOnValidThread());
+  rlz_store_->Remove(GetKeyName(kProductEventKey, product), NULL);
   return true;
 }
 
 bool RlzValueStoreChromeOS::AddStatefulEvent(Product product,
                                              const char* event_rlz) {
+  DCHECK(CalledOnValidThread());
   return AddValueToList(GetKeyName(kStatefulEventKey, product),
                         base::Value::CreateStringValue(event_rlz));
 }
 
 bool RlzValueStoreChromeOS::IsStatefulEvent(Product product,
                                             const char* event_rlz) {
-  base::ListValue* events_list =
-      GetList(GetKeyName(kStatefulEventKey, product));
+  DCHECK(CalledOnValidThread());
   base::StringValue event_value(event_rlz);
-  return events_list && events_list->Find(event_value) != events_list->end();
+  base::ListValue* events_list = NULL;
+  return rlz_store_->GetList(GetKeyName(kStatefulEventKey, product),
+                             &events_list) &&
+      events_list->Find(event_value) != events_list->end();
 }
 
 bool RlzValueStoreChromeOS::ClearAllStatefulEvents(Product product) {
-  rlz_store_->RemoveValue(GetKeyName(kStatefulEventKey, product));
+  DCHECK(CalledOnValidThread());
+  rlz_store_->Remove(GetKeyName(kStatefulEventKey, product), NULL);
   return true;
 }
 
 void RlzValueStoreChromeOS::CollectGarbage() {
+  DCHECK(CalledOnValidThread());
   NOTIMPLEMENTED();
 }
 
-void RlzValueStoreChromeOS::ReadPrefs() {
-  DCHECK(io_task_runner_)
-      << "Calling GetInstance or ResetForTesting before SetIOTaskRunner?";
-  rlz_store_ = new JsonPrefStore(GetRlzStorePath(), io_task_runner_);
-  rlz_store_->ReadPrefs();
-  switch (rlz_store_->GetReadError()) {
-    case PersistentPrefStore::PREF_READ_ERROR_NONE:
-    case PersistentPrefStore::PREF_READ_ERROR_NO_FILE:
+void RlzValueStoreChromeOS::ReadStore() {
+  int error_code = 0;
+  std::string error_msg;
+  JSONFileValueSerializer serializer(store_path_);
+  scoped_ptr<base::Value> value(
+      serializer.Deserialize(&error_code, &error_msg));
+  switch (error_code) {
+    case JSONFileValueSerializer::JSON_NO_SUCH_FILE:
+      read_only_ = false;
+      break;
+    case JSONFileValueSerializer::JSON_NO_ERROR:
+      read_only_ = false;
+      rlz_store_.reset(static_cast<base::DictionaryValue*>(value.release()));
       break;
     default:
-      LOG(ERROR) << "Error read RLZ store: " << rlz_store_->GetReadError();
+      LOG(ERROR) << "Error reading RLZ store: " << error_msg;
   }
-  // Restore refcount modified by SetIOTaskRunner().
-  io_task_runner_->Release();
-  io_task_runner_ = NULL;
 }
 
-base::ListValue* RlzValueStoreChromeOS::GetList(std::string list_name) {
-  base::Value* list_value = NULL;
-  rlz_store_->GetMutableValue(list_name, &list_value);
-  base::ListValue* list = NULL;
-  if (!list_value || !list_value->GetAsList(&list))
-    return NULL;
-  return list;
+void RlzValueStoreChromeOS::WriteStore() {
+  std::string json_data;
+  JSONStringValueSerializer serializer(&json_data);
+  serializer.set_pretty_print(true);
+  scoped_ptr<DictionaryValue> copy(rlz_store_->DeepCopyWithoutEmptyChildren());
+  if (!serializer.Serialize(*copy.get())) {
+    LOG(ERROR) << "Failed to serialize RLZ data";
+    NOTREACHED();
+    return;
+  }
+  if (!base::ImportantFileWriter::WriteFileAtomically(store_path_, json_data))
+    LOG(ERROR) << "Error writing RLZ store";
 }
 
 bool RlzValueStoreChromeOS::AddValueToList(std::string list_name,
                                            base::Value* value) {
-  base::ListValue* list = GetList(list_name);
-  if (!list) {
-    list = new base::ListValue;
-    rlz_store_->SetValue(list_name, list);
+  base::ListValue* list_value = NULL;
+  if (!rlz_store_->GetList(list_name, &list_value)) {
+    list_value = new base::ListValue;
+    rlz_store_->Set(list_name, list_value);
   }
-  if (list->AppendIfNotPresent(value))
-    rlz_store_->ReportValueChanged(list_name);
+  list_value->AppendIfNotPresent(value);
   return true;
 }
 
 bool RlzValueStoreChromeOS::RemoveValueFromList(std::string list_name,
                                                 const base::Value& value) {
-  base::ListValue* list = GetList(list_name);
-  if (!list)
+  base::ListValue* list_value = NULL;
+  if (!rlz_store_->GetList(list_name, &list_value))
     return false;
-  rlz_store_->MarkNeedsEmptyValue(list_name);
   size_t index;
-  if (list->Remove(value, &index))
-    rlz_store_->ReportValueChanged(list_name);
+  list_value->Remove(value, &index);
   return true;
 }
 
+namespace {
 
-ScopedRlzValueStoreLock::ScopedRlzValueStoreLock()
-    : store_(RlzValueStoreChromeOS::GetInstance()) {
+// RlzValueStoreChromeOS keeps its data in memory and only writes it to disk
+// when ScopedRlzValueStoreLock goes out of scope. Hence, if several
+// ScopedRlzValueStoreLocks are nested, they all need to use the same store
+// object.
+
+RecursiveCrossProcessLock g_recursive_lock =
+    RECURSIVE_CROSS_PROCESS_LOCK_INITIALIZER;
+
+// This counts the nesting depth of |ScopedRlzValueStoreLock|.
+int g_lock_depth = 0;
+
+// This is the shared store object. Non-|NULL| only when |g_lock_depth > 0|.
+RlzValueStoreChromeOS* g_store = NULL;
+
+}  // namespace
+
+ScopedRlzValueStoreLock::ScopedRlzValueStoreLock() {
+  bool got_cross_process_lock =
+      g_recursive_lock.TryGetCrossProcessLock(GetRlzStoreLockPath());
+  // At this point, we hold the in-process lock, no matter the value of
+  // |got_cross_process_lock|.
+
+  ++g_lock_depth;
+  if (!got_cross_process_lock) {
+    // Acquiring cross-process lock failed, so simply return here.
+    // In-process lock will be released in dtor.
+    DCHECK(!g_store);
+    return;
+  }
+
+  if (g_lock_depth > 1) {
+    // Reuse the already existing store object.
+    DCHECK(g_store);
+    store_.reset(g_store);
+    return;
+  }
+
+  // This is the topmost lock, create a new store object.
+  DCHECK(!g_store);
+  g_store = new RlzValueStoreChromeOS(GetRlzStorePath());
+  store_.reset(g_store);
 }
 
 ScopedRlzValueStoreLock::~ScopedRlzValueStoreLock() {
+  --g_lock_depth;
+  DCHECK(g_lock_depth >= 0);
+
+  if (g_lock_depth > 0) {
+    // Other locks are still using store_, so don't free it yet.
+    ignore_result(store_.release());
+    return;
+  }
+
+  g_store = NULL;
+
+  g_recursive_lock.ReleaseLock();
 }
 
 RlzValueStore* ScopedRlzValueStoreLock::GetStore() {
-  return store_;
+  return store_.get();
 }
 
 namespace testing {
@@ -284,6 +329,10 @@
   g_testing_rlz_store_path_ = directory;
 }
 
+std::string RlzStoreFilenameStr() {
+  return GetRlzStorePath().value();
+}
+
 }  // namespace testing
 
 }  // namespace rlz_lib
diff --git a/rlz/chromeos/lib/rlz_value_store_chromeos.h b/rlz/chromeos/lib/rlz_value_store_chromeos.h
index c9456a8..4760418 100644
--- a/rlz/chromeos/lib/rlz_value_store_chromeos.h
+++ b/rlz/chromeos/lib/rlz_value_store_chromeos.h
@@ -5,8 +5,9 @@
 #ifndef RLZ_CHROMEOS_LIB_RLZ_VALUE_STORE_CHROMEOS_H_
 #define RLZ_CHROMEOS_LIB_RLZ_VALUE_STORE_CHROMEOS_H_
 
-#include "base/prefs/persistent_pref_store.h"
+#include "base/file_path.h"
 #include "base/threading/non_thread_safe.h"
+#include "base/values.h"
 #include "rlz/lib/rlz_value_store.h"
 
 namespace base {
@@ -15,28 +16,19 @@
 class Value;
 }
 
-template <typename T> struct DefaultSingletonTraits;
-
 namespace rlz_lib {
 
-// An implementation of RlzValueStore for ChromeOS. Unlike Mac and Win
-// counterparts, it's non thread-safe and should only be accessed on a single
-// Thread instance that has a MessageLoop.
-class RlzValueStoreChromeOS : public RlzValueStore {
+// An implementation of RlzValueStore for ChromeOS.
+class RlzValueStoreChromeOS : public RlzValueStore,
+                              public base::NonThreadSafe {
  public:
-  static RlzValueStoreChromeOS* GetInstance();
+  // // Sets the task runner that will be used by ImportantFileWriter for write
+  // // operations.
+  // static void SetFileTaskRunner(base::SequencedTaskRunner* file_task_runner);
 
-  // Sets the MessageLoopProxy that underlying PersistentPrefStore will post I/O
-  // tasks to. Must be called before the first GetInstance() call.
-  static void SetIOTaskRunner(base::SequencedTaskRunner* io_task_runner);
-
-  // Must be invoked during shutdown to commit pending I/O.
-  static void Cleanup();
-
-  // Resets the store to its initial state. Should only be used for testing.
-  // Same restrictions as for calling GetInstance() for the first time apply,
-  // i.e. must call SetIOTaskRunner first.
-  static void ResetForTesting();
+  // Creates new instance and synchronously reads data from file.
+  RlzValueStoreChromeOS(const FilePath& store_path);
+  virtual ~RlzValueStoreChromeOS();
 
   // RlzValueStore overrides:
   virtual bool HasAccess(AccessType type) OVERRIDE;
@@ -68,28 +60,23 @@
   virtual void CollectGarbage() OVERRIDE;
 
  private:
-  friend struct DefaultSingletonTraits<RlzValueStoreChromeOS>;
+  // Reads RLZ store from file.
+  void ReadStore();
 
-  // Used by JsonPrefStore for write operations.
-  static base::SequencedTaskRunner* io_task_runner_;
+  // Writes RLZ store back to file.
+  void WriteStore();
 
-  static bool created_;
-
-  RlzValueStoreChromeOS();
-  virtual ~RlzValueStoreChromeOS();
-
-  // Initializes RLZ store.
-  void ReadPrefs();
-
-  // Retrieves list at path |list_name| from JSON store.
-  base::ListValue* GetList(std::string list_name);
   // Adds |value| to list at |list_name| path in JSON store.
   bool AddValueToList(std::string list_name, base::Value* value);
   // Removes |value| from list at |list_name| path in JSON store.
   bool RemoveValueFromList(std::string list_name, const base::Value& value);
 
-  // Store with RLZ data.
-  scoped_refptr<PersistentPrefStore> rlz_store_;
+  // In-memory store with RLZ data.
+  scoped_ptr<base::DictionaryValue> rlz_store_;
+
+  FilePath store_path_;
+
+  bool read_only_;
 
   DISALLOW_COPY_AND_ASSIGN(RlzValueStoreChromeOS);
 };
diff --git a/rlz/lib/recursive_cross_process_lock_posix.cc b/rlz/lib/recursive_cross_process_lock_posix.cc
new file mode 100644
index 0000000..071bf8c
--- /dev/null
+++ b/rlz/lib/recursive_cross_process_lock_posix.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "rlz/lib/recursive_cross_process_lock_posix.h"
+
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+
+namespace rlz_lib {
+
+bool RecursiveCrossProcessLock::TryGetCrossProcessLock(
+    const FilePath& lock_filename) {
+  bool just_got_lock = false;
+
+  // Emulate a recursive mutex with a non-recursive one.
+  if (pthread_mutex_trylock(&recursive_lock_) == EBUSY) {
+    if (pthread_equal(pthread_self(), locking_thread_) == 0) {
+      // Some other thread has the lock, wait for it.
+      pthread_mutex_lock(&recursive_lock_);
+      CHECK(locking_thread_ == 0);
+      just_got_lock = true;
+    }
+  } else {
+    just_got_lock = true;
+  }
+
+  locking_thread_ = pthread_self();
+
+  // Try to acquire file lock.
+  if (just_got_lock) {
+    const int kMaxTimeoutMS = 5000;  // Matches Windows.
+    const int kSleepPerTryMS = 200;
+
+    CHECK(file_lock_ == -1);
+    file_lock_ = open(lock_filename.value().c_str(), O_RDWR | O_CREAT, 0666);
+    if (file_lock_ == -1) {
+      perror("open");
+      return false;
+    }
+
+    int flock_result = -1;
+    int elapsed_ms = 0;
+    while ((flock_result =
+               HANDLE_EINTR(flock(file_lock_, LOCK_EX | LOCK_NB))) == -1 &&
+           errno == EWOULDBLOCK &&
+           elapsed_ms < kMaxTimeoutMS) {
+      usleep(kSleepPerTryMS * 1000);
+      elapsed_ms += kSleepPerTryMS;
+    }
+
+    if (flock_result == -1) {
+      perror("flock");
+      ignore_result(HANDLE_EINTR(close(file_lock_)));
+      file_lock_ = -1;
+      return false;
+    }
+    return true;
+  } else {
+    return file_lock_ != -1;
+  }
+}
+
+void RecursiveCrossProcessLock::ReleaseLock() {
+  if (file_lock_ != -1) {
+    ignore_result(HANDLE_EINTR(flock(file_lock_, LOCK_UN)));
+    ignore_result(HANDLE_EINTR(close(file_lock_)));
+    file_lock_ = -1;
+  }
+
+  locking_thread_ = 0;
+  pthread_mutex_unlock(&recursive_lock_);
+}
+
+}  // namespace rlz_lib
diff --git a/rlz/lib/recursive_cross_process_lock_posix.h b/rlz/lib/recursive_cross_process_lock_posix.h
new file mode 100644
index 0000000..a39d473
--- /dev/null
+++ b/rlz/lib/recursive_cross_process_lock_posix.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef RLZ_LIB_RECURSIVE_CROSS_PROCESS_LOCK_POSIX_H_
+#define RLZ_LIB_RECURSIVE_CROSS_PROCESS_LOCK_POSIX_H_
+
+#include <pthread.h>
+
+class FilePath;
+
+namespace rlz_lib {
+
+// Creating a recursive cross-process mutex on Windows is one line. On POSIX,
+// there's no primitive for that, so this lock is emulated by an in-process
+// mutex to get the recursive part, followed by a cross-process lock for the
+// cross-process part.
+// This is a struct so that it doesn't need a static initializer.
+struct RecursiveCrossProcessLock {
+  // Tries to acquire a recursive cross-process lock. Note that this _always_
+  // acquires the in-process lock (if it wasn't already acquired). The parent
+  // directory of |lock_file| must exist.
+  bool TryGetCrossProcessLock(const FilePath& lock_filename);
+
+  // Releases the lock. Should always be called, even if
+  // TryGetCrossProcessLock() returned |false|.
+  void ReleaseLock();
+
+  pthread_mutex_t recursive_lock_;
+  pthread_t locking_thread_;
+
+  int file_lock_;
+};
+
+// On Mac, PTHREAD_RECURSIVE_MUTEX_INITIALIZER doesn't exist before 10.7 and
+// is buggy on 10.7 (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51906#c34),
+// so emulate recursive locking with a normal non-recursive mutex.
+#define RECURSIVE_CROSS_PROCESS_LOCK_INITIALIZER    \
+  { PTHREAD_MUTEX_INITIALIZER, 0, -1 }
+
+}  // namespace rlz_lib
+
+#endif  // RLZ_LIB_RECURSIVE_CROSS_PROCESS_LOCK_POSIX_H_
diff --git a/rlz/lib/recursive_lock.cc b/rlz/lib/recursive_lock.cc
deleted file mode 100644
index 686cf0e..0000000
--- a/rlz/lib/recursive_lock.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "rlz/lib/recursive_lock.h"
-
-#include "base/logging.h"
-
-namespace rlz_lib {
-
-RecursiveLock::RecursiveLock()
-    : owner_(),
-      recursion_() {
-}
-
-RecursiveLock::~RecursiveLock() {
-}
-
-void RecursiveLock::Acquire() {
-  base::subtle::Atomic32 me = base::PlatformThread::CurrentId();
-  if (me != base::subtle::NoBarrier_Load(&owner_)) {
-    lock_.Acquire();
-    DCHECK(!recursion_);
-    DCHECK(!owner_);
-    base::subtle::NoBarrier_Store(&owner_, me);
-  }
-  ++recursion_;
-}
-
-void RecursiveLock::Release() {
-  DCHECK_EQ(base::subtle::NoBarrier_Load(&owner_),
-            base::PlatformThread::CurrentId());
-  DCHECK_GT(recursion_, 0);
-  if (!--recursion_) {
-    base::subtle::NoBarrier_Store(&owner_, 0);
-    lock_.Release();
-  }
-}
-
-}  // namespace rlz_lib
diff --git a/rlz/lib/recursive_lock.h b/rlz/lib/recursive_lock.h
deleted file mode 100644
index 43c95747..0000000
--- a/rlz/lib/recursive_lock.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef RLZ_CHROMEOS_LIB_RECURSIVE_LOCK_H_
-#define RLZ_CHROMEOS_LIB_RECURSIVE_LOCK_H_
-
-#include "base/atomicops.h"
-#include "base/basictypes.h"
-#include "base/synchronization/lock.h"
-
-namespace rlz_lib {
-
-
-class RecursiveLock {
- public:
-  RecursiveLock();
-  ~RecursiveLock();
-
-  void Acquire();
-  void Release();
-
- private:
-  // Underlying non-recursive lock.
-  base::Lock lock_;
-  // Owner thread ID.
-  base::subtle::Atomic32 owner_;
-  // Recursion lock depth.
-  int recursion_;
-};
-
-}  // namespace rlz_lib
-
-#endif  // RLZ_CHROMEOS_LIB_RECURSIVE_LOCK_H_
diff --git a/rlz/lib/recursive_lock_unittest.cc b/rlz/lib/recursive_lock_unittest.cc
deleted file mode 100644
index 916af7f..0000000
--- a/rlz/lib/recursive_lock_unittest.cc
+++ /dev/null
@@ -1,234 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "rlz/lib/recursive_lock.h"
-
-#include <stdlib.h>
-
-#include "base/compiler_specific.h"
-#include "base/threading/platform_thread.h"
-#include "base/time.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::kNullThreadHandle;
-using base::PlatformThread;
-using base::PlatformThreadHandle;
-using base::TimeDelta;
-
-namespace rlz_lib {
-
-// Basic test to make sure that Acquire()/Release() don't crash.
-class BasicLockTestThread : public PlatformThread::Delegate {
- public:
-  BasicLockTestThread(RecursiveLock* lock) : lock_(lock), acquired_(0) {}
-
-  virtual void ThreadMain() OVERRIDE {
-    for (int i = 0; i < 10; i++) {
-      lock_->Acquire();
-      acquired_++;
-      lock_->Release();
-    }
-    for (int i = 0; i < 10; i++) {
-      lock_->Acquire();
-      acquired_++;
-      PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
-      lock_->Release();
-    }
-  }
-
-  int acquired() const { return acquired_; }
-
- private:
-  RecursiveLock* lock_;
-  int acquired_;
-
-  DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread);
-};
-
-TEST(RecursiveLockTest, Basic) {
-  RecursiveLock lock;
-  BasicLockTestThread thread(&lock);
-  PlatformThreadHandle handle = kNullThreadHandle;
-
-  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
-
-  int acquired = 0;
-  for (int i = 0; i < 5; i++) {
-    lock.Acquire();
-    acquired++;
-    lock.Release();
-  }
-  for (int i = 0; i < 10; i++) {
-    lock.Acquire();
-    acquired++;
-    PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
-    lock.Release();
-  }
-  for (int i = 0; i < 5; i++) {
-    lock.Acquire();
-    acquired++;
-    PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
-    lock.Release();
-  }
-
-  PlatformThread::Join(handle);
-
-  EXPECT_EQ(acquired, 20);
-  EXPECT_EQ(thread.acquired(), 20);
-}
-
-// Tests that locks are actually exclusive.
-class MutexLockTestThread : public PlatformThread::Delegate {
- public:
-  MutexLockTestThread(RecursiveLock* lock, int* value)
-      : lock_(lock),
-        value_(value) {
-  }
-
-  // Static helper which can also be called from the main thread.
-  static void DoStuff(RecursiveLock* lock, int* value) {
-    for (int i = 0; i < 40; i++) {
-      lock->Acquire();
-      int v = *value;
-      PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10));
-      *value = v + 1;
-      lock->Release();
-    }
-  }
-
-  virtual void ThreadMain() OVERRIDE {
-    DoStuff(lock_, value_);
-  }
-
- private:
-  RecursiveLock* lock_;
-  int* value_;
-
-  DISALLOW_COPY_AND_ASSIGN(MutexLockTestThread);
-};
-
-TEST(RecursiveLockTest, MutexTwoThreads) {
-  RecursiveLock lock;
-  int value = 0;
-
-  MutexLockTestThread thread(&lock, &value);
-  PlatformThreadHandle handle = kNullThreadHandle;
-
-  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
-
-  MutexLockTestThread::DoStuff(&lock, &value);
-
-  PlatformThread::Join(handle);
-
-  EXPECT_EQ(2 * 40, value);
-}
-
-TEST(RecursiveLockTest, MutexFourThreads) {
-  RecursiveLock lock;
-  int value = 0;
-
-  MutexLockTestThread thread1(&lock, &value);
-  MutexLockTestThread thread2(&lock, &value);
-  MutexLockTestThread thread3(&lock, &value);
-  PlatformThreadHandle handle1 = kNullThreadHandle;
-  PlatformThreadHandle handle2 = kNullThreadHandle;
-  PlatformThreadHandle handle3 = kNullThreadHandle;
-
-  ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1));
-  ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2));
-  ASSERT_TRUE(PlatformThread::Create(0, &thread3, &handle3));
-
-  MutexLockTestThread::DoStuff(&lock, &value);
-
-  PlatformThread::Join(handle1);
-  PlatformThread::Join(handle2);
-  PlatformThread::Join(handle3);
-
-  EXPECT_EQ(4 * 40, value);
-}
-
-// Tests that locks are recursive.
-class MutexRecursiveLockTestThread : public PlatformThread::Delegate {
- public:
-  MutexRecursiveLockTestThread(RecursiveLock* lock, int* value)
-      : lock_(lock),
-        value_(value) {
-  }
-
-  // Static helper which can also be called from the main thread.
-  static void DoStuff(RecursiveLock* lock, int* value) {
-    for (int i = 0; i < 20; i++) {
-      // First lock.
-      lock->Acquire();
-      int v = *value;
-      PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10));
-      *value = v + 1;
-      {
-        // Recursive lock.
-        lock->Acquire();
-        int v = *value;
-        PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10));
-        *value = v + 1;
-        lock->Release();
-      }
-      v = *value;
-      PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10));
-      *value = v + 1;
-      lock->Release();
-    }
-  }
-
-  virtual void ThreadMain() OVERRIDE {
-    DoStuff(lock_, value_);
-  }
-
- private:
-  RecursiveLock* lock_;
-  int* value_;
-
-  DISALLOW_COPY_AND_ASSIGN(MutexRecursiveLockTestThread);
-};
-
-
-TEST(RecursiveLockTest, MutexTwoThreadsRecursive) {
-  RecursiveLock lock;
-  int value = 0;
-
-  MutexRecursiveLockTestThread thread(&lock, &value);
-  PlatformThreadHandle handle = kNullThreadHandle;
-
-  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
-
-  MutexRecursiveLockTestThread::DoStuff(&lock, &value);
-
-  PlatformThread::Join(handle);
-
-  EXPECT_EQ(2 * 60, value);
-}
-
-TEST(RecursiveLockTest, MutexFourThreadsRecursive) {
-  RecursiveLock lock;
-  int value = 0;
-
-  MutexRecursiveLockTestThread thread1(&lock, &value);
-  MutexRecursiveLockTestThread thread2(&lock, &value);
-  MutexRecursiveLockTestThread thread3(&lock, &value);
-  PlatformThreadHandle handle1 = kNullThreadHandle;
-  PlatformThreadHandle handle2 = kNullThreadHandle;
-  PlatformThreadHandle handle3 = kNullThreadHandle;
-
-  ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1));
-  ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2));
-  ASSERT_TRUE(PlatformThread::Create(0, &thread3, &handle3));
-
-  MutexRecursiveLockTestThread::DoStuff(&lock, &value);
-
-  PlatformThread::Join(handle1);
-  PlatformThread::Join(handle2);
-  PlatformThread::Join(handle3);
-
-  EXPECT_EQ(4 * 60, value);
-}
-
-}  // namespace rlz_lib
diff --git a/rlz/lib/rlz_lib.cc b/rlz/lib/rlz_lib.cc
index a820d27..8a1b729 100644
--- a/rlz/lib/rlz_lib.cc
+++ b/rlz/lib/rlz_lib.cc
@@ -16,10 +16,6 @@
 #include "rlz/lib/rlz_value_store.h"
 #include "rlz/lib/string_utils.h"
 
-#if defined(OS_CHROMEOS)
-#include "rlz/chromeos/lib/rlz_value_store_chromeos.h"
-#endif  // defined(OS_CHROMEOS)
-
 namespace {
 
 // Event information returned from ping response.
@@ -218,16 +214,6 @@
 }
 #endif
 
-#if defined(OS_CHROMEOS)
-void RLZ_LIB_API SetIOTaskRunner(base::SequencedTaskRunner* io_task_runner) {
-  RlzValueStoreChromeOS::SetIOTaskRunner(io_task_runner);
-}
-
-void RLZ_LIB_API CleanupRlz() {
-  RlzValueStoreChromeOS::Cleanup();
-}
-#endif
-
 bool GetProductEventsAsCgi(Product product, char* cgi, size_t cgi_size) {
   if (!cgi || cgi_size <= 0) {
     ASSERT_STRING("GetProductEventsAsCgi: Invalid buffer");
diff --git a/rlz/lib/rlz_lib.h b/rlz/lib/rlz_lib.h
index 956fc9e..1f8be5ca 100644
--- a/rlz/lib/rlz_lib.h
+++ b/rlz/lib/rlz_lib.h
@@ -44,12 +44,6 @@
 #endif
 #endif
 
-#if defined(OS_CHROMEOS)
-namespace base {
-class SequencedTaskRunner;
-}  // namespace base
-#endif
-
 #if defined(RLZ_NETWORK_IMPLEMENTATION_CHROME_NET)
 namespace net {
 class URLRequestContextGetter;
@@ -77,15 +71,6 @@
 bool RLZ_LIB_API SetURLRequestContext(net::URLRequestContextGetter* context);
 #endif
 
-#if defined(OS_CHROMEOS)
-// Set the MessageLoopProxy used by RLZ store to run I/O tasks on. Should be
-// called before any other API calls.
-void RLZ_LIB_API SetIOTaskRunner(base::SequencedTaskRunner* io_task_runner);
-
-// Must be invoked during shutdown to finish any remaining tasks.
-void RLZ_LIB_API CleanupRlz();
-#endif
-
 // RLZ storage functions.
 
 // Get all the events reported by this product as a CGI string to append to
diff --git a/rlz/lib/rlz_lib_test.cc b/rlz/lib/rlz_lib_test.cc
index 338473ba..86e659c 100644
--- a/rlz/lib/rlz_lib_test.cc
+++ b/rlz/lib/rlz_lib_test.cc
@@ -788,7 +788,7 @@
   EXPECT_STREQ("events=I7S", value);
 }
 
-#if defined(OS_MACOSX)
+#if defined(OS_POSIX)
 class ReadonlyRlzDirectoryTest : public RlzLibTestNoMachineState {
  protected:
   virtual void SetUp() OVERRIDE;
@@ -799,7 +799,6 @@
   // Make the rlz directory non-writeable.
   int chmod_result = chmod(temp_dir_.path().value().c_str(), 0500);
   ASSERT_EQ(0, chmod_result);
-
 }
 
 TEST_F(ReadonlyRlzDirectoryTest, WriteFails) {
@@ -873,7 +872,7 @@
       rlz_lib::IE_DEFAULT_SEARCH, rlz_lib::INSTALL));
 }
 
-TEST_F(RlzLibTest, LockAcquistionSucceedsButPlistCannotBeCreated) {
+TEST_F(RlzLibTest, LockAcquistionSucceedsButStoreFileCannotBeCreated) {
   // See the comment at the top of WriteFails.
   if (!rlz_lib::SupplementaryBranding::GetBrand().empty())
     return;
@@ -881,7 +880,7 @@
   // Create a directory where the rlz file is supposed to appear. This way,
   // the lock file can be created successfully, but creation of the rlz file
   // itself will fail.
-  int mkdir_result = mkdir(rlz_lib::testing::RlzPlistFilenameStr().c_str(),
+  int mkdir_result = mkdir(rlz_lib::testing::RlzStoreFilenameStr().c_str(),
                            0500);
   ASSERT_EQ(0, mkdir_result);
 
diff --git a/rlz/lib/rlz_value_store.h b/rlz/lib/rlz_value_store.h
index 807f1000..46e87df 100644
--- a/rlz/lib/rlz_value_store.h
+++ b/rlz/lib/rlz_value_store.h
@@ -95,12 +95,7 @@
   RlzValueStore* GetStore();
 
  private:
-#if defined(OS_WIN) || defined(OS_MACOSX)
-  // On ChromeOS, there is a singleton instance of RlzValueStore.
   scoped_ptr<RlzValueStore> store_;
-#elif defined(OS_CHROMEOS)
-  class RlzValueStoreChromeOS* store_;
-#endif
 #if defined(OS_WIN)
   LibMutex lock_;
 #elif defined(OS_MACOSX)
@@ -108,20 +103,15 @@
 #endif
 };
 
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#if defined(OS_POSIX)
 namespace testing {
 // Prefix |directory| to the path where the RLZ data file lives, for tests.
 void SetRlzStoreDirectory(const FilePath& directory);
-}  // namespace testing
-#endif  // defined(OS_MACOSX) || defined(OS_CHROMEOS)
 
-#if defined(OS_MACOSX)
-namespace testing {
-// Returns the path of the plist file used as data store.
-std::string RlzPlistFilenameStr();
+// Returns the path of the file used as data store.
+std::string RlzStoreFilenameStr();
 }  // namespace testing
-#endif  // defined(OS_MACOSX)
-
+#endif  // defined(OS_POSIX)
 
 }  // namespace rlz_lib
 
diff --git a/rlz/mac/lib/rlz_value_store_mac.mm b/rlz/mac/lib/rlz_value_store_mac.mm
index 6148e54d..6b8e6f4 100644
--- a/rlz/mac/lib/rlz_value_store_mac.mm
+++ b/rlz/mac/lib/rlz_value_store_mac.mm
@@ -7,11 +7,11 @@
 #include "base/mac/foundation_util.h"
 #include "base/file_path.h"
 #include "base/logging.h"
-#include "base/posix/eintr_wrapper.h"
 #include "base/sys_string_conversions.h"
 #include "rlz/lib/assert.h"
 #include "rlz/lib/lib_values.h"
 #include "rlz/lib/rlz_lib.h"
+#include "rlz/lib/recursive_cross_process_lock_posix.h"
 
 #import <Foundation/Foundation.h>
 #include <pthread.h>
@@ -217,97 +217,8 @@
 
 namespace {
 
-// Creating a recursive cross-process mutex on windows is one line. On mac,
-// there's no primitve for that, so this lock is emulated by an in-process
-// mutex to get the recursive part, followed by a cross-process lock for the
-// cross-process part.
-
-// This is a struct so that it doesn't need a static initializer.
-struct RecursiveCrossProcessLock {
-  // Tries to acquire a recursive cross-process lock. Note that this _always_
-  // acquires the in-process lock (if it wasn't already acquired). The parent
-  // directory of |lock_file| must exist.
-  bool TryGetCrossProcessLock(NSString* lock_filename);
-
-  // Releases the lock. Should always be called, even if
-  // TryGetCrossProcessLock() returns false.
-  void ReleaseLock();
-
-  pthread_mutex_t recursive_lock_;
-  pthread_t locking_thread_;
-
-  int file_lock_;
-} g_recursive_lock = {
-  // PTHREAD_RECURSIVE_MUTEX_INITIALIZER doesn't exist before 10.7 and is buggy
-  // on 10.7 (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51906#c34), so emulate
-  // recursive locking with a normal non-recursive mutex.
-  PTHREAD_MUTEX_INITIALIZER,
-  0,
-  -1
-};
-
-bool RecursiveCrossProcessLock::TryGetCrossProcessLock(
-    NSString* lock_filename) {
-  bool just_got_lock = false;
-
-  // Emulate a recursive mutex with a non-recursive one.
-  if (pthread_mutex_trylock(&recursive_lock_) == EBUSY) {
-    if (pthread_equal(pthread_self(), locking_thread_) == 0) {
-      // Some other thread has the lock, wait for it.
-      pthread_mutex_lock(&recursive_lock_);
-      CHECK(locking_thread_ == 0);
-      just_got_lock = true;
-    }
-  } else {
-    just_got_lock = true;
-  }
-
-  locking_thread_ = pthread_self();
-
-  // Try to acquire file lock.
-  if (just_got_lock) {
-    const int kMaxTimeoutMS = 5000;  // Matches windows.
-    const int kSleepPerTryMS = 200;
-
-    CHECK(file_lock_ == -1);
-    file_lock_ = open([lock_filename fileSystemRepresentation],
-                      O_RDWR | O_CREAT,
-                      0666);
-    if (file_lock_ == -1)
-      return false;
-
-    int flock_result = -1;
-    int elapsed_ms = 0;
-    while ((flock_result =
-               HANDLE_EINTR(flock(file_lock_, LOCK_EX | LOCK_NB))) == -1 &&
-           errno == EWOULDBLOCK &&
-           elapsed_ms < kMaxTimeoutMS) {
-      usleep(kSleepPerTryMS * 1000);
-      elapsed_ms += kSleepPerTryMS;
-    }
-
-    if (flock_result == -1) {
-      ignore_result(HANDLE_EINTR(close(file_lock_)));
-      file_lock_ = -1;
-      return false;
-    }
-    return true;
-  } else {
-    return file_lock_ != -1;
-  }
-}
-
-void RecursiveCrossProcessLock::ReleaseLock() {
-  if (file_lock_ != -1) {
-    ignore_result(HANDLE_EINTR(flock(file_lock_, LOCK_UN)));
-    ignore_result(HANDLE_EINTR(close(file_lock_)));
-    file_lock_ = -1;
-  }
-
-  locking_thread_ = 0;
-  pthread_mutex_unlock(&recursive_lock_);
-}
-
+RecursiveCrossProcessLock g_recursive_lock =
+    RECURSIVE_CROSS_PROCESS_LOCK_INITIALIZER;
 
 // This is set during test execution, to write RLZ files into a temporary
 // directory instead of the user's Application Support folder.
@@ -363,8 +274,8 @@
 }  // namespace
 
 ScopedRlzValueStoreLock::ScopedRlzValueStoreLock() {
-  bool got_distributed_lock =
-      g_recursive_lock.TryGetCrossProcessLock(RlzLockFilename());
+  bool got_distributed_lock = g_recursive_lock.TryGetCrossProcessLock(
+      FilePath([RlzLockFilename() fileSystemRepresentation]));
   // At this point, we hold the in-process lock, no matter the value of
   // |got_distributed_lock|.
 
@@ -451,7 +362,7 @@
   }
 }
 
-std::string RlzPlistFilenameStr() {
+std::string RlzStoreFilenameStr() {
   @autoreleasepool {
     return std::string([RlzPlistFilename() fileSystemRepresentation]);
   }
diff --git a/rlz/rlz.gyp b/rlz/rlz.gyp
index 3e046548..0d4b330e2 100644
--- a/rlz/rlz.gyp
+++ b/rlz/rlz.gyp
@@ -45,8 +45,8 @@
         'lib/lib_values.cc',
         'lib/machine_id.cc',
         'lib/machine_id.h',
-        'lib/recursive_lock.cc',
-        'lib/recursive_lock.h',
+        'lib/recursive_cross_process_lock_posix.cc',
+        'lib/recursive_cross_process_lock_posix.h',
         'lib/rlz_enums.h',
         'lib/rlz_lib.cc',
         'lib/rlz_lib.h',
@@ -97,12 +97,6 @@
             ],
           },
         }],
-        ['chromeos==0', {
-          'sources!': [
-            'lib/recursive_lock.cc',
-            'lib/recursive_lock.h',
-          ]
-        }],
       ],
     },
     {
@@ -122,7 +116,6 @@
         'lib/financial_ping_test.cc',
         'lib/lib_values_unittest.cc',
         'lib/machine_id_unittest.cc',
-        'lib/recursive_lock_unittest.cc',
         'lib/rlz_lib_test.cc',
         'lib/string_utils_unittest.cc',
         'test/rlz_test_helpers.cc',
@@ -136,11 +129,6 @@
             '../net/net.gyp:net_test_support',
           ],
         }],
-        ['chromeos==0', {
-          'sources!': [
-            'lib/recursive_lock_unittest.cc',
-          ],
-        }]
       ],
     },
     {
diff --git a/rlz/test/rlz_test_helpers.cc b/rlz/test/rlz_test_helpers.cc
index 4fe12d4..32719e0 100644
--- a/rlz/test/rlz_test_helpers.cc
+++ b/rlz/test/rlz_test_helpers.cc
@@ -13,13 +13,10 @@
 #include <shlwapi.h>
 #include "base/win/registry.h"
 #include "rlz/win/lib/rlz_lib.h"
-#elif defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#elif defined(OS_POSIX)
 #include "base/file_path.h"
 #include "rlz/lib/rlz_value_store.h"
 #endif
-#if defined(OS_CHROMEOS)
-#include "rlz/chromeos/lib/rlz_value_store_chromeos.h"
-#endif
 
 #if defined(OS_WIN)
 namespace {
@@ -62,41 +59,24 @@
 }  // namespace
 #endif  // defined(OS_WIN)
 
-
-#if defined(OS_CHROMEOS)
-RlzLibTestNoMachineState::RlzLibTestNoMachineState()
-    : pref_store_io_thread_("test_rlz_pref_store_io_thread") {
-}
-#endif  // defined(OS_CHROMEOS)
-
 void RlzLibTestNoMachineState::SetUp() {
 #if defined(OS_WIN)
   OverrideRegistryHives();
 #elif defined(OS_MACOSX)
   base::mac::ScopedNSAutoreleasePool pool;
 #endif  // defined(OS_WIN)
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#if defined(OS_POSIX)
   ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
   rlz_lib::testing::SetRlzStoreDirectory(temp_dir_.path());
-#endif  // defined(OS_MACOSX) || defined(OS_CHROMEOS)
-#if defined(OS_CHROMEOS)
-  base::Thread::Options options;
-  options.message_loop_type = MessageLoop::TYPE_IO;
-  ASSERT_TRUE(pref_store_io_thread_.StartWithOptions(options));
-  rlz_lib::SetIOTaskRunner(pref_store_io_thread_.message_loop_proxy());
-  rlz_lib::RlzValueStoreChromeOS::ResetForTesting();
-#endif  // defined(OS_CHROMEOS)
+#endif  // defined(OS_POSIX)
 }
 
 void RlzLibTestNoMachineState::TearDown() {
 #if defined(OS_WIN)
   UndoOverrideRegistryHives();
-#elif defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#elif defined(OS_POSIX)
   rlz_lib::testing::SetRlzStoreDirectory(FilePath());
 #endif  // defined(OS_WIN)
-#if defined(OS_CHROMEOS)
-  pref_store_io_thread_.Stop();
-#endif  // defined(OS_CHROMEOS)
 }
 
 void RlzLibTestBase::SetUp() {
diff --git a/rlz/test/rlz_test_helpers.h b/rlz/test/rlz_test_helpers.h
index 8b0565d..a78764f 100644
--- a/rlz/test/rlz_test_helpers.h
+++ b/rlz/test/rlz_test_helpers.h
@@ -10,30 +10,19 @@
 #include "base/compiler_specific.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#if defined(OS_POSIX)
 #include "base/files/scoped_temp_dir.h"
 #endif
-#if defined(OS_CHROMEOS)
-#include "base/message_loop.h"
-#include "base/threading/thread.h"
-#endif
 
 class RlzLibTestNoMachineState : public ::testing::Test {
  protected:
-#if defined(OS_CHROMEOS)
-  RlzLibTestNoMachineState();
-#endif
   virtual void SetUp() OVERRIDE;
   virtual void TearDown() OVERRIDE;
 
 
-#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
+#if defined(OS_POSIX)
  base::ScopedTempDir temp_dir_;
 #endif
-#if defined(OS_CHROMEOS)
-  base::Thread pref_store_io_thread_;
-  MessageLoop message_loop_;
-#endif
 };
 
 class RlzLibTestBase : public RlzLibTestNoMachineState {