Tracking rebase to jb-mr1-release

Change-Id: Ic2ae1a27682cc4152003a68d59068b2c5c5eb09b
diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc
index 8556cc8..9ed763c 100644
--- a/src/compiler/driver/compiler_driver.cc
+++ b/src/compiler/driver/compiler_driver.cc
@@ -1329,6 +1329,7 @@
   "Landroid/net/Uri$StringUri;", // Requires Uri.
   "Landroid/net/WebAddress;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
   "Landroid/nfc/NdefRecord;", // Calls String.getBytes -> java.nio.charset.Charset.
+  "Landroid/opengl/EGL14;", // Calls android.opengl.EGL14._nativeClassInit.
   "Landroid/opengl/GLES10;", // Calls android.opengl.GLES10._nativeClassInit.
   "Landroid/opengl/GLES10Ext;", // Calls android.opengl.GLES10Ext._nativeClassInit.
   "Landroid/opengl/GLES11;", // Requires GLES10.
@@ -1350,6 +1351,7 @@
   "Landroid/server/BluetoothService;", // Calls android.server.BluetoothService.classInitNative.
   "Landroid/server/BluetoothEventLoop;", // Calls android.server.BluetoothEventLoop.classInitNative.
   "Landroid/telephony/PhoneNumberUtils;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
+  "Landroid/telephony/TelephonyManager;", // Calls OsConstants.initConstants.
   "Landroid/text/AutoText;", // Requires android.util.DisplayMetrics -..-> android.os.SystemProperties.native_get_int.
   "Landroid/text/Layout;", // Calls com.android.internal.util.ArrayUtils.emptyArray -> System.identityHashCode.
   "Landroid/text/BoringLayout;", // Requires Layout.
diff --git a/src/compiler/driver/compiler_driver_test.cc b/src/compiler/driver/compiler_driver_test.cc
index dee448d..cbfc2ae 100644
--- a/src/compiler/driver/compiler_driver_test.cc
+++ b/src/compiler/driver/compiler_driver_test.cc
@@ -44,7 +44,8 @@
       LOCKS_EXCLUDED(Locks::mutator_lock_) {
     CompileAll(class_loader);
     Thread::Current()->TransitionFromSuspendedToRunnable();
-    runtime_->Start();
+    bool started = runtime_->Start();
+    CHECK(started);
     env_ = Thread::Current()->GetJniEnv();
     class_ = env_->FindClass(class_name);
     CHECK(class_ != NULL) << "Class not found: " << class_name;
diff --git a/src/compiler/jni/jni_compiler_test.cc b/src/compiler/jni/jni_compiler_test.cc
index 5176752..77dd51e 100644
--- a/src/compiler/jni/jni_compiler_test.cc
+++ b/src/compiler/jni/jni_compiler_test.cc
@@ -75,7 +75,8 @@
       CompileForTest(class_loader_, direct, method_name, method_sig);
       // Start runtime.
       Thread::Current()->TransitionFromSuspendedToRunnable();
-      runtime_->Start();
+      bool started = runtime_->Start();
+      CHECK(started);
     }
     // JNI operations after runtime start.
     env_ = Thread::Current()->GetJniEnv();
@@ -532,7 +533,8 @@
   }
   // Start runtime to avoid re-initialization in SetupForTest.
   Thread::Current()->TransitionFromSuspendedToRunnable();
-  runtime_->Start();
+  bool started = runtime_->Start();
+  CHECK(started);
 
   gJava_MyClassNatives_foo_calls = 0;
 
diff --git a/src/compiler/llvm/intrinsic_helper.cc b/src/compiler/llvm/intrinsic_helper.cc
index 39c4a58..ac34f70 100644
--- a/src/compiler/llvm/intrinsic_helper.cc
+++ b/src/compiler/llvm/intrinsic_helper.cc
@@ -20,8 +20,8 @@
 
 #include <llvm/DerivedTypes.h>
 #include <llvm/Function.h>
+#include <llvm/IRBuilder.h>
 #include <llvm/Intrinsics.h>
-#include <llvm/Support/IRBuilder.h>
 
 namespace art {
 namespace llvm {
diff --git a/src/compiler/llvm/ir_builder.h b/src/compiler/llvm/ir_builder.h
index 9362a75..32f0bf9 100644
--- a/src/compiler/llvm/ir_builder.h
+++ b/src/compiler/llvm/ir_builder.h
@@ -26,8 +26,8 @@
 
 #include <llvm/Constants.h>
 #include <llvm/DerivedTypes.h>
+#include <llvm/IRBuilder.h>
 #include <llvm/LLVMContext.h>
-#include <llvm/Support/IRBuilder.h>
 #include <llvm/Support/NoFolder.h>
 #include <llvm/Type.h>
 
diff --git a/src/compiler/llvm/llvm_compilation_unit.cc b/src/compiler/llvm/llvm_compilation_unit.cc
index 3783ae9..41c603f 100644
--- a/src/compiler/llvm/llvm_compilation_unit.cc
+++ b/src/compiler/llvm/llvm_compilation_unit.cc
@@ -26,7 +26,6 @@
 #include <llvm/ADT/StringSet.h>
 #include <llvm/ADT/Triple.h>
 #include <llvm/Analysis/CallGraph.h>
-#include <llvm/Analysis/DebugInfo.h>
 #include <llvm/Analysis/Dominators.h>
 #include <llvm/Analysis/LoopInfo.h>
 #include <llvm/Analysis/LoopPass.h>
@@ -39,6 +38,7 @@
 #include <llvm/CodeGen/MachineFrameInfo.h>
 #include <llvm/CodeGen/MachineFunction.h>
 #include <llvm/CodeGen/MachineFunctionPass.h>
+#include <llvm/DebugInfo.h>
 #include <llvm/DerivedTypes.h>
 #include <llvm/LLVMContext.h>
 #include <llvm/Module.h>
diff --git a/src/compiler/llvm/md_builder.cc b/src/compiler/llvm/md_builder.cc
index afb3611..657adc5 100644
--- a/src/compiler/llvm/md_builder.cc
+++ b/src/compiler/llvm/md_builder.cc
@@ -17,7 +17,7 @@
 
 #include "md_builder.h"
 
-#include "llvm/Support/MDBuilder.h"
+#include "llvm/MDBuilder.h"
 
 #include <string>
 
diff --git a/src/compiler/llvm/md_builder.h b/src/compiler/llvm/md_builder.h
index 5231c14..5272ee5 100644
--- a/src/compiler/llvm/md_builder.h
+++ b/src/compiler/llvm/md_builder.h
@@ -19,7 +19,7 @@
 
 #include "backend_types.h"
 
-#include "llvm/Support/MDBuilder.h"
+#include "llvm/MDBuilder.h"
 
 #include <cstring>
 
diff --git a/src/dex_file.cc b/src/dex_file.cc
index e67e767..12c11e8 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -299,7 +299,7 @@
   method_ids_ = reinterpret_cast<const MethodId*>(b + h->method_ids_off_);
   proto_ids_ = reinterpret_cast<const ProtoId*>(b + h->proto_ids_off_);
   class_defs_ = reinterpret_cast<const ClassDef*>(b + h->class_defs_off_);
-  DCHECK_EQ(size_, header_->file_size_);
+  DCHECK_EQ(size_, header_->file_size_) << GetLocation();
 }
 
 bool DexFile::CheckMagicAndVersion() const {
diff --git a/src/exception_test.cc b/src/exception_test.cc
index 1d32f1b..f0bec1b 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -137,7 +137,8 @@
 TEST_F(ExceptionTest, StackTraceElement) {
   Thread* thread = Thread::Current();
   thread->TransitionFromSuspendedToRunnable();
-  runtime_->Start();
+  bool started = runtime_->Start();
+  CHECK(started);
   JNIEnv* env = thread->GetJniEnv();
   ScopedObjectAccess soa(env);
 
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 0ee4c21..726c80b 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -2564,7 +2564,13 @@
     return JNI_ERR;
   }
   Runtime* runtime = Runtime::Current();
-  runtime->Start();
+  bool started = runtime->Start();
+  if (!started) {
+    delete Thread::Current()->GetJniEnv();
+    delete runtime->GetJavaVM();
+    LOG(WARNING) << "CreateJavaVM failed";
+    return JNI_ERR;
+  }
   *p_env = Thread::Current()->GetJniEnv();
   *p_vm = runtime->GetJavaVM();
   return JNI_OK;
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index deff290..4b820f9 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -1179,7 +1179,8 @@
 TEST_F(JniInternalTest, GetPrimitiveField_SetPrimitiveField) {
   Thread::Current()->TransitionFromSuspendedToRunnable();
   LoadDex("AllFields");
-  runtime_->Start();
+  bool started = runtime_->Start();
+  CHECK(started);
 
   jclass c = env_->FindClass("AllFields");
   ASSERT_TRUE(c != NULL);
diff --git a/src/native/dalvik_system_Zygote.cc b/src/native/dalvik_system_Zygote.cc
index d33c67f..9b995f4 100644
--- a/src/native/dalvik_system_Zygote.cc
+++ b/src/native/dalvik_system_Zygote.cc
@@ -14,15 +14,20 @@
  * limitations under the License.
  */
 
+// sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc
+#include <sys/mount.h>
+#include <linux/fs.h>
+
 #include <grp.h>
 #include <paths.h>
 #include <signal.h>
 #include <stdlib.h>
-#include <sys/mount.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include "cutils/fs.h"
+#include "cutils/multiuser.h"
 #include "cutils/sched_policy.h"
 #include "debugger.h"
 #include "jni_internal.h"
@@ -53,6 +58,7 @@
   MOUNT_EXTERNAL_NONE = 0,
   MOUNT_EXTERNAL_SINGLEUSER = 1,
   MOUNT_EXTERNAL_MULTIUSER = 2,
+  MOUNT_EXTERNAL_MULTIUSER_ALL = 3,
 };
 
 // This signal handler is for zygote mode, since the zygote must reap its children
@@ -303,45 +309,91 @@
   }
 }
 
-// Create private mount space for this process and mount SD card
-// into it, based on the active user.
-static void MountExternalStorage(uid_t uid, jint mount_external) {
-  if (mount_external == MOUNT_EXTERNAL_NONE) {
-    return;
+// Create a private mount namespace and bind mount appropriate emulated
+// storage for the given user.
+static bool MountEmulatedStorage(uid_t uid, jint mount_mode) {
+  if (mount_mode == MOUNT_EXTERNAL_NONE) {
+    return true;
   }
 
-#if 0
-  userid_t user_id = multiuser_getUserId(uid);
+  // See storage config details at http://source.android.com/tech/storage/
+  userid_t user_id = multiuser_get_user_id(uid);
 
-  // Create private mount namespace for our process.
+  // Create a second private mount namespace for our process
   if (unshare(CLONE_NEWNS) == -1) {
-    PLOG(FATAL) << "unshare(CLONE_NEWNS) failed";
+      PLOG(WARNING) << "Failed to unshare()";
+      return false;
   }
 
-  // Mark rootfs as being a slave in our process so that changes
-  // from parent namespace flow into our process.
-  if (mount("rootfs", "/", NULL, (MS_SLAVE | MS_REC), NULL) == -1) {
-    PLOG(FATAL) << "mount(\"rootfs\", \"/\", NULL, (MS_SLAVE | MS_REC), NULL) failed";
-  }
-
-  // Create bind mount from specific path.
-  if (mount_external == MOUNT_EXTERNAL_SINGLEUSER) {
-    if (mount(EXTERNAL_STORAGE_SYSTEM, EXTERNAL_STORAGE_APP, "none", MS_BIND, NULL) == -1) {
-      PLOG(FATAL) << "mount(\"" << EXTERNAL_STORAGE_SYSTEM << "\", \"" << EXTERNAL_STORAGE_APP << "\", \"none\", MS_BIND, NULL) failed";
+  // Create bind mounts to expose external storage
+  if (mount_mode == MOUNT_EXTERNAL_MULTIUSER || mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
+    // These paths must already be created by init.rc
+    const char* source = getenv("EMULATED_STORAGE_SOURCE");
+    const char* target = getenv("EMULATED_STORAGE_TARGET");
+    const char* legacy = getenv("EXTERNAL_STORAGE");
+    if (source == NULL || target == NULL || legacy == NULL) {
+      LOG(WARNING) << "Storage environment undefined; unable to provide external storage";
+      return false;
     }
-  } else if (mount_external == MOUNT_EXTERNAL_MULTIUSER) {
-    // Assume path has already been created by installd.
-    std::string source_path(StringPrintf("%s/%d", EXTERNAL_STORAGE_SYSTEM, user_id));
-    if (mount(source_path.c_str(), EXTERNAL_STORAGE_APP, "none", MS_BIND, NULL) == -1) {
-      PLOG(FATAL) << "mount(\"" << source_path.c_str() << "\", \"" << EXTERNAL_STORAGE_APP << "\", \"none\", MS_BIND, NULL) failed";
+
+    // Prepare source paths
+
+    // /mnt/shell/emulated/0
+    std::string source_user(StringPrintf("%s/%d", source, user_id));
+    // /mnt/shell/emulated/obb
+    std::string source_obb(StringPrintf("%s/obb", source));
+    // /storage/emulated/0
+    std::string target_user(StringPrintf("%s/%d", target, user_id));
+
+    if (fs_prepare_dir(source_user.c_str(), 0000, 0, 0) == -1
+        || fs_prepare_dir(source_obb.c_str(), 0000, 0, 0) == -1
+        || fs_prepare_dir(target_user.c_str(), 0000, 0, 0) == -1) {
+      return false;
+    }
+
+    if (mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
+      // Mount entire external storage tree for all users
+      if (mount(source, target, NULL, MS_BIND, NULL) == -1) {
+        PLOG(WARNING) << "Failed to mount " << source << " to " << target;
+        return false;
+      }
+    } else {
+      // Only mount user-specific external storage
+      if (mount(source_user.c_str(), target_user.c_str(), NULL, MS_BIND, NULL) == -1) {
+        PLOG(WARNING) << "Failed to mount " << source_user << " to " << target_user;
+        return false;
+      }
+    }
+
+    // Now that user is mounted, prepare and mount OBB storage
+    // into place for current user
+
+    // /storage/emulated/0/Android
+    std::string target_android(StringPrintf("%s/%d/Android", target, user_id));
+    // /storage/emulated/0/Android/obb
+    std::string target_obb(StringPrintf("%s/%d/Android/obb", target, user_id));
+
+    if (fs_prepare_dir(target_android.c_str(), 0000, 0, 0) == -1
+        || fs_prepare_dir(target_obb.c_str(), 0000, 0, 0) == -1
+        || fs_prepare_dir(legacy, 0000, 0, 0) == -1) {
+        return false;
+    }
+    if (mount(source_obb.c_str(), target_obb.c_str(), NULL, MS_BIND, NULL) == -1) {
+      PLOG(WARNING) << "Failed to mount " << source_obb << " to " << target_obb;
+      return false;
+    }
+
+    // Finally, mount user-specific path into place for legacy users
+    if (mount(target_user.c_str(), legacy, NULL, MS_BIND | MS_REC, NULL) == -1) {
+      PLOG(WARNING) << "Failed to mount " << target_user << " to " << legacy;
+      return false;
     }
   } else {
-    LOG(FATAL) << "Mount mode unsupported: " << mount_external;
+    LOG(WARNING) << "Mount mode " << mount_mode << " unsupported";
+    return false;
   }
-#else
-  UNUSED(uid);
-  UNIMPLEMENTED(FATAL);
-#endif
+
+  return true;
 }
 
 #if defined(__linux__)
@@ -397,7 +449,18 @@
 
     DropCapabilitiesBoundingSet();
 
-    MountExternalStorage(uid, mount_external);
+    if (!MountEmulatedStorage(uid, mount_external)) {
+      PLOG(WARNING) << "Failed to mount emulated storage";
+      if (errno == ENOTCONN || errno == EROFS) {
+        // When device is actively encrypting, we get ENOTCONN here
+        // since FUSE was mounted before the framework restarted.
+        // When encrypted device is booting, we get EROFS since
+        // FUSE hasn't been created yet by init.
+        // In either case, continue without external storage.
+      } else {
+        LOG(FATAL) << "Cannot continue without emulated storage";
+      }
+    }
 
     SetGids(env, javaGids);
 
diff --git a/src/runtime.cc b/src/runtime.cc
index 414bef4..9b2dca7 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -16,6 +16,10 @@
 
 #include "runtime.h"
 
+// sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc
+#include <sys/mount.h>
+#include <linux/fs.h>
+
 #include <signal.h>
 #include <sys/syscall.h>
 
@@ -472,7 +476,7 @@
       double value;
       iss >> value;
       // Ensure that we have a value, there was no cruft after it and it satisfies a sensible range.
-      const bool sane_val = iss.good() && (value >= 0.1) && (value <= 0.9);
+      const bool sane_val = iss.eof() && (value >= 0.1) && (value <= 0.9);
       if (!sane_val) {
         if (ignore_unrecognized) {
           continue;
@@ -640,7 +644,7 @@
   contextClassLoader->SetObject(soa.Self()->GetPeer(), class_loader);
 }
 
-void Runtime::Start() {
+bool Runtime::Start() {
   VLOG(startup) << "Runtime::Start entering";
 
   CHECK(host_prefix_.empty()) << host_prefix_;
@@ -666,7 +670,11 @@
 
   Thread::FinishStartup();
 
-  if (!is_zygote_) {
+  if (is_zygote_) {
+    if (!InitZygote()) {
+      return false;
+    }
+  } else {
     DidForkFromZygote();
   }
 
@@ -679,6 +687,8 @@
   VLOG(startup) << "Runtime::Start exiting";
 
   finished_starting_ = true;
+
+  return true;
 }
 
 void Runtime::EndThreadBirth() EXCLUSIVE_LOCKS_REQUIRED(Locks::runtime_shutdown_lock_) {
@@ -689,6 +699,40 @@
   }
 }
 
+// Do zygote-mode-only initialization.
+bool Runtime::InitZygote() {
+  // zygote goes into its own process group
+  setpgid(0,0);
+
+  // See storage config details at http://source.android.com/tech/storage/
+  // Create private mount namespace shared by all children
+  if (unshare(CLONE_NEWNS) == -1) {
+    PLOG(WARNING) << "Failed to unshare()";
+    return false;
+  }
+
+  // Mark rootfs as being a slave so that changes from default
+  // namespace only flow into our children.
+  if (mount("rootfs", "/", NULL, (MS_SLAVE | MS_REC), NULL) == -1) {
+    PLOG(WARNING) << "Failed to mount() rootfs as MS_SLAVE";
+    return false;
+  }
+
+  // Create a staging tmpfs that is shared by our children; they will
+  // bind mount storage into their respective private namespaces, which
+  // are isolated from each other.
+  const char* target_base = getenv("EMULATED_STORAGE_TARGET");
+  if (target_base != NULL) {
+    if (mount("tmpfs", target_base, "tmpfs", MS_NOSUID | MS_NODEV,
+              "uid=0,gid=1028,mode=0050") == -1) {
+      LOG(WARNING) << "Failed to mount tmpfs to " << target_base;
+      return false;
+    }
+  }
+
+  return true;
+}
+
 void Runtime::DidForkFromZygote() {
   is_zygote_ = false;
 
diff --git a/src/runtime.h b/src/runtime.h
index 696f231..f8788ad 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -126,7 +126,7 @@
   }
 
   // Starts a runtime, which may cause threads to be started and code to run.
-  void Start() UNLOCK_FUNCTION(Locks::mutator_lock_);
+  bool Start() UNLOCK_FUNCTION(Locks::mutator_lock_);
 
   bool IsShuttingDown() const EXCLUSIVE_LOCKS_REQUIRED(Locks::runtime_shutdown_lock_) {
     return shutting_down_;
@@ -346,8 +346,9 @@
 
   void SetStatsEnabled(bool new_state);
 
-  void DidForkFromZygote();
   bool PreZygoteFork();
+  bool InitZygote();
+  void DidForkFromZygote();
 
   void EnableMethodTracing(Trace* trace);
   void DisableMethodTracing();
diff --git a/src/runtime_test.cc b/src/runtime_test.cc
index e147749..d53b4a6 100644
--- a/src/runtime_test.cc
+++ b/src/runtime_test.cc
@@ -46,6 +46,7 @@
   options.push_back(std::make_pair("-Xms2048", null));
   options.push_back(std::make_pair("-Xmx4k", null));
   options.push_back(std::make_pair("-Xss1m", null));
+  options.push_back(std::make_pair("-XX:HeapTargetUtilization=0.75", null));
   options.push_back(std::make_pair("-Dfoo=bar", null));
   options.push_back(std::make_pair("-Dbaz=qux", null));
   options.push_back(std::make_pair("-verbose:gc,class,jni", null));
@@ -63,6 +64,7 @@
   EXPECT_EQ(2048U, parsed->heap_initial_size_);
   EXPECT_EQ(4 * KB, parsed->heap_maximum_size_);
   EXPECT_EQ(1 * MB, parsed->stack_size_);
+  EXPECT_EQ(0.75, parsed->heap_target_utilization_);
   EXPECT_EQ("host_prefix", parsed->host_prefix_);
   EXPECT_TRUE(test_vfprintf == parsed->hook_vfprintf_);
   EXPECT_TRUE(test_exit == parsed->hook_exit_);