Merge "Fix kernel panic when boot up"
am: 857a9f9a57

Change-Id: Iee390ee0b79b852b2f40f0482ab7e537715745a1
diff --git a/ANRdaemon/ANRdaemon.cpp b/ANRdaemon/ANRdaemon.cpp
index 7b77a86..35f2ecb 100644
--- a/ANRdaemon/ANRdaemon.cpp
+++ b/ANRdaemon/ANRdaemon.cpp
@@ -67,6 +67,8 @@
 static const int max_buffer_size = 2048;
 static const char *min_buffer_size_str = "16";
 static const char *max_buffer_size_str = "2048";
+static const int time_buf_size = 20;
+static const int path_buf_size = 60;
 
 typedef struct cpu_stat {
     unsigned long utime, ntime, stime, itime;
@@ -82,6 +84,7 @@
 
 static bool quit = false;
 static bool suspend= false;
+static bool dump_requested = false;
 static bool err = false;
 static char err_msg[100];
 static bool tracing = false;
@@ -244,121 +247,23 @@
 }
 
 /*
- * Start logging when cpu usage is high. Meanwhile, moniter the cpu usage and
- * stop logging when it drops down.
- */
-static void start_tracing(void) {
-    ALOGD("High cpu usage, start logging.");
-
-    if (dfs_enable(true, dfs_control_path) != 0) {
-        ALOGE("Failed to start tracing.");
-        return;
-    }
-    tracing = true;
-
-    /* Stop logging when cpu usage drops or the daemon is suspended.*/
-    do {
-        usleep(tracing_check_period);
-    } while (!suspend && is_heavy_load());
-
-    if (dfs_enable(false, dfs_control_path) != 0) {
-        ALOGE("Failed to stop tracing.");
-    }
-
-    ALOGD("Usage back to low, stop logging.");
-    tracing = false;
-}
-
-/*
- * Set the tracing log buffer size.
- * Note the actual buffer size will be buf_size_kb * number of cores.
- * E.g. for dory, the total buffer size is buf_size_kb * 4.
- */
-static int set_tracing_buffer_size(void) {
-    int fd = open(dfs_buffer_size_path, O_WRONLY);
-    if (fd == -1) {
-        err = true;
-        sprintf(err_msg, "Can't open atrace buffer size file under /d/tracing.");
-        return -1;
-    }
-    ssize_t len = strlen(buf_size_kb);
-    if (write(fd, buf_size_kb, len) != len) {
-        err = true;
-        sprintf(err_msg, "Error in writing to atrace buffer size file.");
-    }
-    close(fd);
-    return (err?-1:0);
-
-}
-
-/*
- * Main loop to moniter the cpu usage and decided whether to start logging.
- */
-static void start(void) {
-    if ((set_tracing_buffer_size()) != 0)
-        return;
-
-    dfs_set_property(tag, apps, true);
-    dfs_poke_binder();
-
-    get_cpu_stat(&old_cpu);
-    sleep(check_period);
-
-    while (!quit && !err) {
-        if (!suspend && is_heavy_load()) {
-            /*
-             * Increase process priority to make sure we can stop logging when
-             * necessary and do not overwrite the buffer
-             */
-            setpriority(PRIO_PROCESS, 0, -20);
-            start_tracing();
-            setpriority(PRIO_PROCESS, 0, 0);
-        }
-        sleep(check_period);
-    }
-    return;
-}
-
-/*
  * Dump the log in a compressed format for systrace to visualize.
+ * Create a dump file "dump_of_anrdaemon.<current_time>" under /data/misc/anrd
  */
 static void dump_trace()
 {
-    int remain_attempts = 5;
-    suspend = true;
-    while (tracing) {
-        ALOGI("Waiting logging to stop.");
-        usleep(tracing_check_period);
-        remain_attempts--;
-        if (remain_attempts == 0) {
-            ALOGE("Can't stop logging after 5 attempts. Dump aborted.");
-            return;
-        }
-    }
-
-    /*
-     * Create /sdcard/ANRdaemon/ if it doesn't exist
-     */
-    struct stat st;
-    if (stat("/sdcard/ANRdaemon", &st) == -1) {
-        ALOGI("Creating /sdcard/ANRdaemon/");
-        int err = mkdir("/sdcard/ANRdaemon", 0700);
-        if (err != 0)
-            ALOGI("Creating /sdcard/ANRdaemon/ failed with %s", strerror(err));
-    }
-
-    /*
-     * Create a dump file "dump_of_anrdaemon.<current_time>" under /sdcard/ANRdaemon/
-     */
     time_t now = time(0);
     struct tm  tstruct;
-    char time_buf[80];
-    char path_buf[200];
+    char time_buf[time_buf_size];
+    char path_buf[path_buf_size];
     const char* header = " done\nTRACE:\n";
     ssize_t header_len = strlen(header);
+
+    ALOGI("Started to dump ANRdaemon trace.");
+
     tstruct = *localtime(&now);
-    strftime(time_buf, sizeof(time_buf), "%Y-%m-%d.%X", &tstruct);
-    sprintf(path_buf, "/sdcard/ANRdaemon/dump_of_anrdaemon.%s", time_buf);
+    strftime(time_buf, time_buf_size, "%Y-%m-%d.%X", &tstruct);
+    snprintf(path_buf, path_buf_size, "/data/misc/anrd/dump_of_anrdaemon.%s", time_buf);
     int output_fd = creat(path_buf, S_IRWXU);
     if (output_fd == -1) {
         ALOGE("Failed to create %s. Dump aborted.", path_buf);
@@ -451,10 +356,107 @@
     close(trace_fd);
     close(output_fd);
 
-    suspend = false;
     ALOGI("Finished dump. Output file stored at: %s", path_buf);
 }
 
+/*
+ * Start logging when cpu usage is high. Meanwhile, moniter the cpu usage and
+ * stop logging when it drops down.
+ */
+static void start_tracing(void) {
+    ALOGD("High cpu usage, start logging.");
+
+    if (dfs_enable(true, dfs_control_path) != 0) {
+        ALOGE("Failed to start tracing.");
+        return;
+    }
+    tracing = true;
+
+    /* Stop logging when cpu usage drops or the daemon is suspended.*/
+    do {
+        usleep(tracing_check_period);
+    } while (!suspend && !dump_requested && is_heavy_load());
+
+    if (dfs_enable(false, dfs_control_path) != 0) {
+        ALOGE("Failed to stop tracing.");
+        err = true;
+        return;
+    }
+    tracing = false;
+
+    if (suspend) {
+        ALOGI("trace stopped due to suspend. Send SIGCONT to resume.");
+    } else if (dump_requested) {
+        ALOGI("trace stopped due to dump request.");
+        dump_trace();
+        dump_requested = false;
+    } else {
+        ALOGD("Usage back to low, stop logging.");
+    }
+}
+
+/*
+ * Set the tracing log buffer size.
+ * Note the actual buffer size will be buf_size_kb * number of cores.
+ */
+static int set_tracing_buffer_size(void) {
+    int fd = open(dfs_buffer_size_path, O_WRONLY);
+    if (fd == -1) {
+        err = true;
+        sprintf(err_msg, "Can't open atrace buffer size file under /d/tracing.");
+        return -1;
+    }
+    ssize_t len = strlen(buf_size_kb);
+    if (write(fd, buf_size_kb, len) != len) {
+        err = true;
+        sprintf(err_msg, "Error in writing to atrace buffer size file.");
+    }
+    close(fd);
+    return (err?-1:0);
+
+}
+
+/*
+ * Main loop to moniter the cpu usage and decided whether to start logging.
+ */
+static void start(void) {
+    if ((set_tracing_buffer_size()) != 0)
+        return;
+
+    dfs_set_property(tag, apps, true);
+    dfs_poke_binder();
+
+    get_cpu_stat(&old_cpu);
+    sleep(check_period);
+
+    while (!quit && !err) {
+        if (!suspend && is_heavy_load()) {
+            /*
+             * Increase process priority to make sure we can stop logging when
+             * necessary and do not overwrite the buffer
+             */
+            setpriority(PRIO_PROCESS, 0, -20);
+            start_tracing();
+            setpriority(PRIO_PROCESS, 0, 0);
+        }
+        sleep(check_period);
+    }
+    return;
+}
+
+/*
+ * If trace is not running, dump trace right away.
+ * If trace is running, request to dump trace.
+ */
+static void request_dump_trace()
+{
+    if (!tracing) {
+        dump_trace();
+    } else if (!dump_requested) {
+        dump_requested = true;
+    }
+}
+
 static void handle_signal(int signo)
 {
     switch (signo) {
@@ -469,7 +471,7 @@
             suspend = false;
             break;
         case SIGUSR1:
-            dump_trace();
+            request_dump_trace();
     }
 }
 
diff --git a/ANRdaemon/ANRdaemon_get_trace.sh b/ANRdaemon/ANRdaemon_get_trace.sh
index be4062c..bae3360 100755
--- a/ANRdaemon/ANRdaemon_get_trace.sh
+++ b/ANRdaemon/ANRdaemon_get_trace.sh
@@ -1,6 +1,7 @@
 #!/bin/bash
 
-TRACE_DIR=/sdcard/ANRdaemon
+TRACE_DIR=/data/misc/anrd
+TRACE_FILE_PATTEN=dump_of_anrdaemon
 
 if [ $# -eq 1 ]; then
     DEVICE=$(echo "-s $1")
@@ -18,14 +19,15 @@
 PID=$(echo "$PID" | awk '{ print $2 }')
 adb $DEVICE shell "kill -s SIGUSR1 $PID"
 
-TRACE_FILE=$(adb $DEVICE shell "ls $TRACE_DIR | tail -n1" | tr -d '\r')
+TRACE_FILE=$(adb $DEVICE shell "ls $TRACE_DIR \
+    | grep $TRACE_FILE_PATTEN | tail -n1" | tr -d '\r')
 
 # Wiat the trace file generation to complete
-adb $DEVICE shell "lsof $PID" | grep $TRACE_FILE > /dev/null
+adb $DEVICE shell "lsof -p $PID" | grep $TRACE_FILE > /dev/null
 while [ $? -eq 0 ];
 do
     sleep 1
-    adb $DEVICE shell "lsof $PID" | grep "$TRACE_FILE" > /dev/null
+    adb $DEVICE shell "lsof -p $PID" | grep "$TRACE_FILE" > /dev/null
 done
 
 if [ -z "$TRACE_FILE" ]; then
diff --git a/cppreopts/Android.mk b/cppreopts/Android.mk
new file mode 100644
index 0000000..049f2b4
--- /dev/null
+++ b/cppreopts/Android.mk
@@ -0,0 +1,27 @@
+# Copyright 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+# Create the cppreopts that does the copy
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= cppreopts.sh
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_INIT_RC := cppreopts.rc
+LOCAL_SRC_FILES := cppreopts.sh
+
+LOCAL_REQUIRED_MODULES := preopt2cachename
+
+include $(BUILD_PREBUILT)
diff --git a/cppreopts/cppreopts.rc b/cppreopts/cppreopts.rc
new file mode 100644
index 0000000..07a7674
--- /dev/null
+++ b/cppreopts/cppreopts.rc
@@ -0,0 +1,29 @@
+# Copyright 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+on property:sys.cppreopt=requested && property:ro.boot.slot_suffix=_a
+    mount ext4 /dev/block/bootdevice/by-name/system_b /postinstall ro nosuid nodev noexec
+    exec - root -- /system/bin/cppreopts.sh /postinstall
+    # Optional script to copy additional preloaded content to data directory
+    exec - system system -- /system/bin/preloads_copy.sh /postinstall
+    umount /postinstall
+    setprop sys.cppreopt finished
+
+on property:sys.cppreopt=requested && property:ro.boot.slot_suffix=_b
+    mount ext4 /dev/block/bootdevice/by-name/system_a /postinstall ro nosuid nodev noexec
+    exec - root -- /system/bin/cppreopts.sh /postinstall
+    # Optional script to copy additional preloaded content to data directory
+    exec - system system -- /system/bin/preloads_copy.sh /postinstall
+    umount /postinstall
+    setprop sys.cppreopt finished
diff --git a/cppreopts/cppreopts.sh b/cppreopts/cppreopts.sh
new file mode 100644
index 0000000..8798206
--- /dev/null
+++ b/cppreopts/cppreopts.sh
@@ -0,0 +1,69 @@
+#!/system/bin/sh
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# create files with 644 (global read) permissions.
+umask 022
+
+# Helper function to copy files
+function do_copy() {
+  odex_file=$1
+  dest_name=$2
+  # Move to a temporary file so we can do a rename and have the preopted file
+  # appear atomically in the filesystem.
+  temp_dest_name=${dest_name}.tmp
+  if ! cp ${odex_file} ${temp_dest_name} ; then
+    log -p w -t cppreopts "Unable to copy odex file ${odex_file} to ${temp_dest_name}!"
+  else
+    log -p i -t cppreopts "Copied odex file from ${odex_file} to ${temp_dest_name}"
+    sync
+    if ! mv ${temp_dest_name} ${dest_name} ; then
+      log -p w -t cppreopts "Unable to rename temporary odex file from ${temp_dest_name} to ${dest_name}"
+    else
+      log -p i -t cppreopts "Renamed temporary odex file from ${temp_dest_name} to ${dest_name}"
+    fi
+  fi
+}
+
+if [ $# -eq 1 ]; then
+  # Where the system_b is mounted that contains the preopt'd files
+  mountpoint=$1
+
+  if ! test -f ${mountpoint}/system-other-odex-marker ; then
+    log -p i -t cppreopts "system_other partition does not appear have been built to contain preopted files."
+    exit 1
+  fi
+
+  log -p i -t cppreopts "cppreopts from ${mountpoint}"
+  # For each odex file do the copy task
+  # NOTE: this implementation will break in any path with spaces to favor
+  # background copy tasks
+  for odex_file in $(find ${mountpoint} -type f -name "*.odex"); do
+    real_odex_name=${odex_file/${mountpoint}/\/system}
+    dest_name=$(preopt2cachename ${real_odex_name})
+    if ! test $? -eq 0 ; then
+      log -p i -t cppreopts "Unable to figure out destination for ${odex_file}"
+      continue
+    fi
+    # Copy files in background to speed things up
+    do_copy ${odex_file} ${dest_name} &
+  done
+  # Wait for jobs to finish
+  wait
+  exit 0
+else
+  log -p e -t cppreopts "Usage: cppreopts <preopts-mount-point>"
+  exit 1
+fi
diff --git a/ext4_utils/ext4_crypt.cpp b/ext4_utils/ext4_crypt.cpp
index 4478904..97f255c 100644
--- a/ext4_utils/ext4_crypt.cpp
+++ b/ext4_utils/ext4_crypt.cpp
@@ -26,6 +26,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <cutils/properties.h>
 
@@ -47,6 +48,7 @@
 
 #define EXT4_ENCRYPTION_MODE_AES_256_XTS    1
 #define EXT4_ENCRYPTION_MODE_AES_256_CTS    4
+#define EXT4_ENCRYPTION_MODE_PRIVATE        127
 
 // ext4enc:TODO Get value from somewhere sensible
 #define EXT4_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct ext4_encryption_policy)
@@ -98,7 +100,8 @@
     return true;
 }
 
-static bool e4crypt_policy_set(const char *directory, const char *policy, size_t policy_length) {
+static bool e4crypt_policy_set(const char *directory, const char *policy,
+                               size_t policy_length, int contents_encryption_mode) {
     if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) {
         LOG(ERROR) << "Policy wrong length: " << policy_length;
         return false;
@@ -111,7 +114,7 @@
 
     ext4_encryption_policy eep;
     eep.version = 0;
-    eep.contents_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
+    eep.contents_encryption_mode = contents_encryption_mode;
     eep.filenames_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_CTS;
     eep.flags = 0;
     memcpy(eep.master_key_descriptor, policy, EXT4_KEY_DESCRIPTOR_SIZE);
@@ -128,7 +131,8 @@
     return true;
 }
 
-static bool e4crypt_policy_get(const char *directory, char *policy, size_t policy_length) {
+static bool e4crypt_policy_get(const char *directory, char *policy,
+                               size_t policy_length, int contents_encryption_mode) {
     if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) {
         LOG(ERROR) << "Policy wrong length: " << policy_length;
         return false;
@@ -150,7 +154,7 @@
     close(fd);
 
     if ((eep.version != 0)
-            || (eep.contents_encryption_mode != EXT4_ENCRYPTION_MODE_AES_256_XTS)
+            || (eep.contents_encryption_mode != contents_encryption_mode)
             || (eep.filenames_encryption_mode != EXT4_ENCRYPTION_MODE_AES_256_CTS)
             || (eep.flags != 0)) {
         LOG(ERROR) << "Failed to find matching encryption policy for " << directory;
@@ -161,13 +165,15 @@
     return true;
 }
 
-static bool e4crypt_policy_check(const char *directory, const char *policy, size_t policy_length) {
+static bool e4crypt_policy_check(const char *directory, const char *policy,
+                                 size_t policy_length, int contents_encryption_mode) {
     if (policy_length != EXT4_KEY_DESCRIPTOR_SIZE) {
         LOG(ERROR) << "Policy wrong length: " << policy_length;
         return false;
     }
     char existing_policy[EXT4_KEY_DESCRIPTOR_SIZE];
-    if (!e4crypt_policy_get(directory, existing_policy, EXT4_KEY_DESCRIPTOR_SIZE)) return false;
+    if (!e4crypt_policy_get(directory, existing_policy, EXT4_KEY_DESCRIPTOR_SIZE,
+                            contents_encryption_mode)) return false;
     char existing_policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
 
     policy_to_hex(existing_policy, existing_policy_hex);
@@ -184,13 +190,26 @@
     return true;
 }
 
-int e4crypt_policy_ensure(const char *directory, const char *policy, size_t policy_length) {
+int e4crypt_policy_ensure(const char *directory, const char *policy,
+                          size_t policy_length, const char* contents_encryption_mode) {
+    int mode = 0;
+    if (!strcmp(contents_encryption_mode, "software")) {
+        mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
+    } else if (!strcmp(contents_encryption_mode, "ice")) {
+        mode = EXT4_ENCRYPTION_MODE_PRIVATE;
+    } else {
+        LOG(ERROR) << "Invalid encryption mode";
+        return -1;
+    }
+
     bool is_empty;
     if (!is_dir_empty(directory, &is_empty)) return -1;
     if (is_empty) {
-        if (!e4crypt_policy_set(directory, policy, policy_length)) return -1;
+        if (!e4crypt_policy_set(directory, policy, policy_length,
+                                mode)) return -1;
     } else {
-        if (!e4crypt_policy_check(directory, policy, policy_length)) return -1;
+        if (!e4crypt_policy_check(directory, policy, policy_length,
+                                  mode)) return -1;
     }
     return 0;
 }
diff --git a/ext4_utils/ext4_crypt_init_extensions.cpp b/ext4_utils/ext4_crypt_init_extensions.cpp
index 3c2bc8e..e98db6e 100644
--- a/ext4_utils/ext4_crypt_init_extensions.cpp
+++ b/ext4_utils/ext4_crypt_init_extensions.cpp
@@ -114,8 +114,16 @@
         LOG(ERROR) << "Unable to read system policy to set on " << dir;
         return -1;
     }
+
+    auto type_filename = std::string("/data") + e4crypt_key_mode;
+    std::string contents_encryption_mode;
+    if (!android::base::ReadFileToString(type_filename, &contents_encryption_mode)) {
+        LOG(ERROR) << "Cannot read mode";
+    }
+
     KLOG_INFO(TAG, "Setting policy on %s\n", dir);
-    int result = e4crypt_policy_ensure(dir, policy.c_str(), policy.size());
+    int result = e4crypt_policy_ensure(dir, policy.c_str(), policy.length(),
+                                       contents_encryption_mode.c_str());
     if (result) {
         LOG(ERROR) << android::base::StringPrintf(
             "Setting %02x%02x%02x%02x policy on %s failed!",
diff --git a/ext4_utils/include/ext4_utils/ext4_crypt.h b/ext4_utils/include/ext4_utils/ext4_crypt.h
index d02ff81..2be0bec 100644
--- a/ext4_utils/include/ext4_utils/ext4_crypt.h
+++ b/ext4_utils/include/ext4_utils/ext4_crypt.h
@@ -25,10 +25,13 @@
 
 bool e4crypt_is_native();
 
-int e4crypt_policy_ensure(const char *directory, const char* policy, size_t policy_length);
+int e4crypt_policy_ensure(const char *directory,
+                          const char* policy, size_t policy_length,
+                          const char* contents_encryption_mode);
 
 static const char* e4crypt_unencrypted_folder = "/unencrypted";
 static const char* e4crypt_key_ref = "/unencrypted/ref";
+static const char* e4crypt_key_mode = "/unencrypted/mode";
 
 __END_DECLS
 
diff --git a/preopt2cachename/Android.mk b/preopt2cachename/Android.mk
new file mode 100644
index 0000000..b5a51d9
--- /dev/null
+++ b/preopt2cachename/Android.mk
@@ -0,0 +1,32 @@
+# Copyright 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= preopt2cachename
+
+LOCAL_SRC_FILES := \
+    preopt2cachename.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libsysutils \
+    liblog \
+    libcutils \
+    libbase
+
+LOCAL_CFLAGS := -Werror -Wall
+
+include $(BUILD_EXECUTABLE)
diff --git a/preopt2cachename/preopt2cachename.cpp b/preopt2cachename/preopt2cachename.cpp
new file mode 100644
index 0000000..dfdc63f
--- /dev/null
+++ b/preopt2cachename/preopt2cachename.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+
+#ifndef LOG_TAG
+#define LOG_TAG "preopt2cachename"
+#endif
+
+static const char* kDalvikCacheDir = "/data/dalvik-cache/";
+static const char* kCacheSuffix = "@classes.dex";
+
+// Returns the ISA extracted from the odex_file_location.
+// odex_file_location is formatted like /system/app/<app_name>/oat/<isa>/<app_name>.odex for all
+// functions. We return an empty string "" in error cases.
+static std::string ExtractISA(const std::string& odex_file_location) {
+  std::vector<std::string> split_file_location = android::base::Split(odex_file_location, "/");
+  if (split_file_location.size() <= 1) {
+    return "";
+  } else if (split_file_location.size() != 7) {
+    LOG(WARNING) << "Unexpected length for odex-file-location. We expected 7 segments but found "
+                 << split_file_location.size();
+  }
+  return split_file_location[split_file_location.size() - 2];
+}
+
+// Returns the apk name extracted from the odex_file_location.
+// odex_file_location is formatted like /system/app/<app_name>/oat/<isa>/<app_name>.odex. We return
+// the final <app_name> with the .odex replaced with .apk.
+static std::string ExtractAPKName(const std::string& odex_file_location) {
+  // Find and copy filename.
+  size_t file_location_start = odex_file_location.rfind('/');
+  if (file_location_start == std::string::npos) {
+    return "";
+  }
+  size_t ext_start = odex_file_location.rfind('.');
+  if (ext_start == std::string::npos || ext_start < file_location_start) {
+    return "";
+  }
+  std::string apk_name = odex_file_location.substr(file_location_start + 1,
+                                                   ext_start - file_location_start);
+
+  // Replace extension with .apk.
+  apk_name += "apk";
+  return apk_name;
+}
+
+// The cache file name is /data/dalvik-cache/<isa>/ prior to this function
+static bool OdexFilenameToCacheFile(const std::string& odex_file_location,
+                                    /*in-out*/std::string& cache_file) {
+  // Skip the first '/' in odex_file_location.
+  size_t initial_position = odex_file_location[0] == '/' ? 1 : 0;
+  size_t apk_position = odex_file_location.find("/oat", initial_position);
+  if (apk_position == std::string::npos) {
+    LOG(ERROR) << "Unable to find oat directory!";
+    return false;
+  }
+
+  size_t cache_file_position = cache_file.size();
+  cache_file += odex_file_location.substr(initial_position, apk_position);
+  // '/' -> '@' up to where the apk would be.
+  cache_file_position = cache_file.find('/', cache_file_position);
+  while (cache_file_position != std::string::npos) {
+    cache_file[cache_file_position] = '@';
+    cache_file_position = cache_file.find('/', cache_file_position);
+  }
+
+  // Add <apk_name>.
+  std::string apk_name = ExtractAPKName(odex_file_location);
+  if (apk_name.empty()) {
+    LOG(ERROR) << "Unable to determine apk name from odex file name '" << odex_file_location << "'";
+    return false;
+  }
+  cache_file += apk_name;
+  cache_file += kCacheSuffix;
+  return true;
+}
+
+// Do the overall transformation from odex_file_location to output_file_location. Prior to this the
+// output_file_location is empty.
+static bool OdexToCacheFile(std::string& odex_file_location,
+                            /*out*/std::string& output_file_location) {
+  std::string isa = ExtractISA(odex_file_location);
+  if (isa.empty()) {
+    LOG(ERROR) << "Unable to determine isa for odex file '" << odex_file_location << "', skipping";
+    return false;
+  }
+  output_file_location += isa;
+  output_file_location += '/';
+  return OdexFilenameToCacheFile(odex_file_location, output_file_location);
+}
+
+// This program is used to determine where in the /data directory the runtime will search for an
+// odex file if it is unable to find one at the given 'preopt-name' location. This is used to allow
+// us to store these preopted files in the unused system_b partition and copy them out on first
+// boot of the device.
+int main(int argc, char *argv[]) {
+  if (argc != 2) {
+    LOG(ERROR) << "usage: preopt2cachename preopt-location";
+    return 2;
+  }
+  std::string odex_file_location(argv[1]);
+  std::string output_file_location(kDalvikCacheDir);
+  if (!OdexToCacheFile(odex_file_location, output_file_location)) {
+    return 1;
+  } else {
+    std::cout << output_file_location;
+  }
+  return 0;
+}
diff --git a/squashfs_utils/mksquashfsimage.sh b/squashfs_utils/mksquashfsimage.sh
index 5f45a64..6a2ec1c 100755
--- a/squashfs_utils/mksquashfsimage.sh
+++ b/squashfs_utils/mksquashfsimage.sh
@@ -5,7 +5,7 @@
 function usage() {
 cat<<EOT
 Usage:
-${0##*/} SRC_DIR OUTPUT_FILE [-s] [-m MOUNT_POINT] [-d PRODUCT_OUT] [-C FS_CONFIG ] [-c FILE_CONTEXTS] [-B BLOCK_MAP_FILE] [-b BLOCK_SIZE] [-z COMPRESSOR] [-zo COMPRESSOR_OPT] [-a ]
+${0##*/} SRC_DIR OUTPUT_FILE [-s] [-m MOUNT_POINT] [-d PRODUCT_OUT] [-C FS_CONFIG ] [-c FILE_CONTEXTS] [-B BLOCK_MAP_FILE] [-b BLOCK_SIZE] [-z COMPRESSOR] [-zo COMPRESSOR_OPT] [-t COMPRESS_THRESHOLD] [-a]
 EOT
 }
 
@@ -79,6 +79,13 @@
     shift; shift
 fi
 
+COMPRESS_THRESHOLD=0
+if [[ "$1" == "-t" ]]; then
+    COMPRESS_THRESHOLD=$2
+    shift; shift
+fi
+
+
 DISABLE_4K_ALIGN=false
 if [[ "$1" == "-a" ]]; then
     DISABLE_4K_ALIGN=true
@@ -104,6 +111,9 @@
 if [ -n "$BLOCK_SIZE" ]; then
   OPT="$OPT -b $BLOCK_SIZE"
 fi
+if [ -n "$COMPRESS_THRESHOLD" ]; then
+  OPT="$OPT -t $COMPRESS_THRESHOLD"
+fi
 if [ "$DISABLE_4K_ALIGN" = true ]; then
   OPT="$OPT -disable-4k-align"
 fi
diff --git a/tests/binder/benchmarks/binderAddInts.cpp b/tests/binder/benchmarks/binderAddInts.cpp
index afa464a..1951331 100644
--- a/tests/binder/benchmarks/binderAddInts.cpp
+++ b/tests/binder/benchmarks/binderAddInts.cpp
@@ -79,7 +79,7 @@
 
 // File scope function prototypes
 static bool server(void);
-static void BM_client(benchmark::State& state);
+static void BM_addInts(benchmark::State& state);
 static void bindCPU(unsigned int cpu);
 static ostream &operator<<(ostream &stream, const String16& str);
 static ostream &operator<<(ostream &stream, const cpu_set_t& set);
@@ -103,9 +103,8 @@
     return true;
 }
 
-static void BM_client(benchmark::State& state)
+static void BM_addInts(benchmark::State& state)
 {
-    server();
     int rv;
     sp<IServiceManager> sm = defaultServiceManager();
 
@@ -162,7 +161,7 @@
         state.ResumeTiming();
     }
 }
-BENCHMARK(BM_client);
+BENCHMARK(BM_addInts);
 
 
 AddIntsService::AddIntsService(int cpu): cpu_(cpu) {
@@ -305,6 +304,30 @@
         }
     }
 
-    ::benchmark::RunSpecifiedBenchmarks();
-}
+    fflush(stdout);
+    switch (pid_t pid = fork()) {
+    case 0: // Child
+        ::benchmark::RunSpecifiedBenchmarks();
+        return 0;
 
+    default: // Parent
+        if (!server()) { break; }
+
+        // Wait for all children to end
+        do {
+            int stat;
+            rv = wait(&stat);
+            if ((rv == -1) && (errno == ECHILD)) { break; }
+            if (rv == -1) {
+                cerr << "wait failed, rv: " << rv << " errno: "
+                    << errno << endl;
+                perror(NULL);
+                exit(8);
+            }
+        } while (1);
+        return 0;
+
+    case -1: // Error
+        exit(9);
+    }
+}
diff --git a/tests/framebuffer/minui.h b/tests/framebuffer/minui.h
index 4efc971..0073033 100644
--- a/tests/framebuffer/minui.h
+++ b/tests/framebuffer/minui.h
@@ -26,9 +26,6 @@
 
 void gr_color(unsigned char r, unsigned char g, unsigned char b);
 void gr_fill(int x, int y, int w, int h);
-int gr_text(int x, int y, const char *s);
-int gr_measure(const char *s);
-
 
 typedef struct event event;