Support ICU on Android

This CL adds an icu_data application that vends ICU data to clients via shared
memory. We use a sha1hash to validate the integrity of the data. Currently,
this icu_data service is used on Android only. Desktop platforms load the ICU
data table from the file system, as they did before. See the mojo-dev
discussion for more background.

R=jamesr@chromium.org

Review URL: https://codereview.chromium.org/826093004
diff --git a/services/icu_data/icu_data_impl.cc b/services/icu_data/icu_data_impl.cc
new file mode 100644
index 0000000..af6d99e
--- /dev/null
+++ b/services/icu_data/icu_data_impl.cc
@@ -0,0 +1,73 @@
+// Copyright 2014 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 "mojo/application/application_runner_chromium.h"
+#include "mojo/common/weak_binding_set.h"
+#include "mojo/public/c/system/main.h"
+#include "mojo/public/cpp/application/application_connection.h"
+#include "mojo/public/cpp/application/application_delegate.h"
+#include "mojo/public/cpp/application/interface_factory.h"
+#include "mojo/public/cpp/bindings/interface_ptr.h"
+#include "services/icu_data/data.h"
+#include "services/icu_data/icu_data.mojom.h"
+
+namespace icu_data {
+
+class ICUDataImpl : public mojo::ApplicationDelegate,
+                    public ICUData,
+                    public mojo::InterfaceFactory<ICUData> {
+ public:
+  ICUDataImpl() {}
+  ~ICUDataImpl() override {}
+
+  // mojo::ApplicationDelegate implementation.
+  bool ConfigureIncomingConnection(
+      mojo::ApplicationConnection* connection) override {
+    connection->AddService(this);
+    return true;
+  }
+
+  // mojo::InterfaceFactory<mojo::ICUData> implementation.
+  void Create(mojo::ApplicationConnection* connection,
+              mojo::InterfaceRequest<ICUData> request) override {
+    bindings_.AddBinding(this, request.Pass());
+  }
+
+  void Map(const mojo::String& sha1hash,
+           const mojo::Callback<void(mojo::ScopedSharedBufferHandle)>& callback)
+      override {
+    if (std::string(sha1hash) != std::string(kICUDataTableHash)) {
+      callback.Run(mojo::ScopedSharedBufferHandle());
+      return;
+    }
+    EnsureBuffer();
+    mojo::ScopedSharedBufferHandle handle;
+    // FIXME: We should create a read-only duplicate of the handle.
+    mojo::DuplicateBuffer(buffer_->handle.get(), nullptr, &handle);
+    callback.Run(handle.Pass());
+  }
+
+ private:
+  void EnsureBuffer() {
+    if (buffer_)
+      return;
+    buffer_.reset(new mojo::SharedBuffer(kICUDataTableSize));
+    void* ptr = nullptr;
+    MojoResult rv = mojo::MapBuffer(buffer_->handle.get(), 0, kICUDataTableSize,
+                                    &ptr, MOJO_MAP_BUFFER_FLAG_NONE);
+    CHECK_EQ(rv, MOJO_RESULT_OK);
+    memcpy(ptr, kICUDataTable, kICUDataTableSize);
+    rv = mojo::UnmapBuffer(ptr);
+    CHECK_EQ(rv, MOJO_RESULT_OK);
+  }
+
+  scoped_ptr<mojo::SharedBuffer> buffer_;
+  mojo::WeakBindingSet<ICUData> bindings_;
+};
+}
+
+MojoResult MojoMain(MojoHandle shell_handle) {
+  mojo::ApplicationRunnerChromium runner(new icu_data::ICUDataImpl);
+  return runner.Run(shell_handle);
+}