OSDN Git Service

build_verity_metadata: Support --signer_args argument.
authorTao Bao <tbao@google.com>
Wed, 26 Oct 2016 22:13:29 +0000 (22:13 +0000)
committerandroid-build-merger <android-build-merger@google.com>
Wed, 26 Oct 2016 22:13:29 +0000 (22:13 +0000)
am: 1522691d1d

Change-Id: I9827575704475f3781a214ab73a3b82b7bd00e38

17 files changed:
cppreopts/Android.mk [new file with mode: 0644]
cppreopts/cppreopts.rc [new file with mode: 0644]
cppreopts/cppreopts.sh [new file with mode: 0644]
ext4_utils/ext4_crypt.cpp
ext4_utils/ext4_crypt.h
ext4_utils/ext4_crypt_init_extensions.cpp
libfec/include/fec/io.h
libpagemap/pm_memusage.c
perfprofd/Android.mk
perfprofd/tests/Android.mk
preopt2cachename/Android.mk [new file with mode: 0644]
preopt2cachename/preopt2cachename.cpp [new file with mode: 0644]
squashfs_utils/mksquashfsimage.sh
tests/binder/benchmarks/binderAddInts.cpp
tests/bootloader/bootctl.py [new file with mode: 0644]
tests/bootloader/haltest.py [new file with mode: 0644]
tests/bootloader/shelltest.py [new file with mode: 0644]

diff --git a/cppreopts/Android.mk b/cppreopts/Android.mk
new file mode 100644 (file)
index 0000000..049f2b4
--- /dev/null
@@ -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 (file)
index 0000000..07a7674
--- /dev/null
@@ -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 (file)
index 0000000..8798206
--- /dev/null
@@ -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
index be77b79..6e7b2d2 100644 (file)
@@ -27,6 +27,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <cutils/properties.h>
 
@@ -48,6 +49,7 @@ struct ext4_encryption_policy {
 
 #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)
@@ -99,7 +101,8 @@ static bool is_dir_empty(const char *dirname, bool *is_empty)
     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;
@@ -112,7 +115,7 @@ static bool e4crypt_policy_set(const char *directory, const char *policy, size_t
 
     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);
@@ -129,7 +132,8 @@ static bool e4crypt_policy_set(const char *directory, const char *policy, size_t
     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;
@@ -151,7 +155,7 @@ static bool e4crypt_policy_get(const char *directory, char *policy, size_t polic
     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;
@@ -162,13 +166,15 @@ static bool e4crypt_policy_get(const char *directory, char *policy, size_t polic
     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);
@@ -185,13 +191,26 @@ static bool e4crypt_policy_check(const char *directory, const char *policy, size
     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;
 }
index ddc09a7..c306ce8 100644 (file)
@@ -22,9 +22,12 @@ __BEGIN_DECLS
 
 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
index c6baea7..70b1750 100644 (file)
@@ -141,8 +141,16 @@ int e4crypt_set_directory_policy(const char* dir)
         KLOG_ERROR(TAG, "Unable to read system policy to set on %s\n", 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) {
         KLOG_ERROR(TAG, "Setting %02x%02x%02x%02x policy on %s failed!\n",
                    policy[0], policy[1], policy[2], policy[3], dir);
index 3b5dac0..670a5d7 100644 (file)
@@ -49,7 +49,7 @@ struct fec_header {
     uint32_t fec_size;
     uint64_t inp_size;
     uint8_t hash[SHA256_DIGEST_LENGTH];
-};
+} __attribute__ ((packed));
 
 struct fec_status {
     int flags;
index 70cfede..71a5783 100644 (file)
@@ -89,15 +89,15 @@ void pm_memusage_pswap_add_offset(pm_memusage_t *mu, unsigned int offset) {
     if (mu->p_swap == NULL)
         return;
 
-    if (offset > mu->p_swap->array_size) {
+    if (offset >= mu->p_swap->array_size) {
         fprintf(stderr, "SWAP offset %d is out of swap bounds.\n", offset);
         return;
+    }
+
+    if (mu->p_swap->offset_array[offset] == USHRT_MAX) {
+        fprintf(stderr, "SWAP offset %d ref. count if overflowing ushort type.\n", offset);
     } else {
-        if (mu->p_swap->offset_array[offset] == USHRT_MAX) {
-            fprintf(stderr, "SWAP offset %d ref. count if overflowing ushort type.\n", offset);
-        } else {
-            mu->p_swap->offset_array[offset]++;
-        }
+        mu->p_swap->offset_array[offset]++;
     }
 
     soff = malloc(sizeof(pm_swap_offset_t));
index 99d6c66..6409f83 100644 (file)
@@ -12,7 +12,7 @@ perfprofd_cppflags := \
 #
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
-LOCAL_CPP_EXTENSION := cc
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_MODULE := libperfprofdcore
 LOCAL_MODULE_CLASS := STATIC_LIBRARIES
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
@@ -41,7 +41,7 @@ include $(BUILD_STATIC_LIBRARY)
 #
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
-LOCAL_CPP_EXTENSION := cc
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_CXX_STL := libc++
 LOCAL_MODULE := libperfprofdutils
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
@@ -55,7 +55,7 @@ include $(BUILD_STATIC_LIBRARY)
 #
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
-LOCAL_CPP_EXTENSION := cc
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_CXX_STL := libc++
 LOCAL_SRC_FILES := perfprofdmain.cc
 LOCAL_STATIC_LIBRARIES := libperfprofdcore libperfprofdutils
index 7d372c4..bdd82e0 100644 (file)
@@ -8,7 +8,7 @@ perfprofd_test_cppflags := -Wall -Wno-sign-compare -Wno-unused-parameter -Werror
 #
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
-LOCAL_CPP_EXTENSION := cc
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_CXX_STL := libc++
 LOCAL_C_INCLUDES += system/extras/perfprofd
 LOCAL_MODULE := libperfprofdmockutils
@@ -32,7 +32,7 @@ include $(BUILD_PREBUILT)
 #
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
-LOCAL_CPP_EXTENSION := cc
+LOCAL_CPP_EXTENSION := .cc
 LOCAL_CXX_STL := libc++
 LOCAL_STATIC_LIBRARIES := libperfprofdcore libperfprofdmockutils libgtest libbase
 LOCAL_SHARED_LIBRARIES := libprotobuf-cpp-lite
diff --git a/preopt2cachename/Android.mk b/preopt2cachename/Android.mk
new file mode 100644 (file)
index 0000000..b5a51d9
--- /dev/null
@@ -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 (file)
index 0000000..dfdc63f
--- /dev/null
@@ -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;
+}
index 5f45a64..6a2ec1c 100755 (executable)
@@ -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] [-]
+${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 @@ if [[ "$1" == "-zo" ]]; then
     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 @@ fi
 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
index d0b2910..7ac5360 100644 (file)
@@ -79,7 +79,7 @@ class AddIntsService : public BBinder
 
 // 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 @@ static bool server(void)
     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 @@ static void BM_client(benchmark::State& state)
         state.ResumeTiming();
     }
 }
-BENCHMARK(BM_client);
+BENCHMARK(BM_addInts);
 
 
 AddIntsService::AddIntsService(int cpu): cpu_(cpu) {
@@ -305,6 +304,30 @@ int main(int argc, char *argv[])
         }
     }
 
-    ::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/bootloader/bootctl.py b/tests/bootloader/bootctl.py
new file mode 100644 (file)
index 0000000..7a69a8c
--- /dev/null
@@ -0,0 +1,61 @@
+# 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.
+
+class Bootctl(object):
+    def __init__(self, device):
+        self.device = device
+        self.base = ["bootctl"]
+
+    def _exec(self, cmd):
+        return self.device.shell_nocheck(self.base + [cmd])
+
+    def get_number_slots(self):
+        """returns number of slots"""
+
+        return int(self._exec("get-number-slots")[1])
+
+    def get_current_slot(self):
+        """returns current slot number"""
+
+        return int(self._exec("get-current-slot")[1])
+
+    def mark_boot_successful(self):
+        """returns true on success, false on failure"""
+
+        return self._exec("mark-boot-successful")[0] == 0
+
+    def set_active_boot_slot(self, slot):
+        """returns true on success, false on failure"""
+
+        return self._exec("set-active-boot-slot " + str(slot))[0] == 0
+
+    def set_slot_as_unbootable_slot(self, slot):
+        """returns true on success, false on failure"""
+
+        return self._exec("set-slot-as-unbootable " + str(slot))[0] == 0
+
+    def is_slot_bootable(self, slot):
+        """Returns true if slot is bootable"""
+
+        return self._exec("is-slot-bootable " + str(slot))[0] == 0
+
+    def is_slot_marked_successful(self, slot):
+        """returns true on success, false on failure"""
+
+        return self._exec("is-slot-marked-successful " + str(slot))[0] == 0
+
+    def get_suffix(self, slot):
+        """returns suffix string for specified slot number"""
+
+        return self._exec("get-suffix " + str(slot))[1].strip()
diff --git a/tests/bootloader/haltest.py b/tests/bootloader/haltest.py
new file mode 100644 (file)
index 0000000..41252c3
--- /dev/null
@@ -0,0 +1,116 @@
+# 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.
+
+import bootctl
+import shelltest
+import sys
+import unittest
+
+# Note: In order to run these tests, the device must be able to boot
+# from all slots on the device.
+class HalTest(shelltest.ShellTest):
+    def __init__(self, *args, **kwargs):
+        super(HalTest, self).__init__(*args, **kwargs)
+        self.bootctl = bootctl.Bootctl(self.device)
+
+    def test_slots(self):
+        """Test that all slots are reported and named uniquely."""
+
+        self.device.root()
+        self.device.wait()
+        num_slots = self.bootctl.get_number_slots()
+        suffixes = dict()
+        for slot in range(num_slots):
+            suffix = self.bootctl.get_suffix(slot)
+            self.assertNotEqual(suffix, "(null)")
+            suffixes[suffix] = slot
+        self.assertEqual(len(suffixes), num_slots)
+
+    def test_mark_successful(self):
+        """Ensure mark successful works, and persists on reboot.
+
+        Ensure that mark_successful will mark the slot as
+        successful, and that the HAL sees this. First resets
+        slot-successful by setting the active slot to the current one."""
+
+        self.device.root()
+        self.device.wait()
+        slot = self.bootctl.get_current_slot()
+        self.assertTrue(self.bootctl.set_active_boot_slot(slot))
+        self.assertFalse(self.bootctl.is_slot_marked_successful(slot))
+        self.assertTrue(self.bootctl.mark_boot_successful())
+        self.assertTrue(self.bootctl.is_slot_marked_successful(slot))
+        self.device.reboot()
+        self.device.wait()
+        self.device.root()
+        self.device.wait()
+        self.assertTrue(self.bootctl.is_slot_marked_successful(slot))
+
+    def test_switch_slots(self):
+        """Test that setActiveBootSlot works and persists
+
+        Ensure switching slots works, and that setting the slot does not
+        change the reported slot until the reboot."""
+
+        # Cycle through all slots once
+        num_slots = self.bootctl.get_number_slots()
+        for i in range(num_slots):
+            self.device.root()
+            self.device.wait()
+            slot = self.bootctl.get_current_slot()
+            new_slot = (slot + 1) % num_slots
+            self.assertTrue(self.bootctl.set_active_boot_slot(new_slot))
+            slot2 = self.bootctl.get_current_slot()
+            self.assertEqual(slot, slot2)
+            self.device.reboot()
+            self.device.wait()
+            self.device.root()
+            self.device.wait()
+            self.assertEqual(new_slot, self.bootctl.get_current_slot())
+
+    def test_unbootable(self):
+        """Test setSlotAsUnbootable
+
+        Test that the device will attempt to roll back to a valid slot if
+        the current slot is unbootable."""
+
+        # Cycle through all slots once
+        num_slots = self.bootctl.get_number_slots()
+        for i in range(num_slots):
+            self.device.root()
+            self.device.wait()
+            slot = self.bootctl.get_current_slot()
+            new_slot = (slot + 1) % num_slots
+            self.device.root()
+            self.device.wait()
+            self.assertTrue(self.bootctl.set_active_boot_slot(new_slot))
+            self.assertTrue(self.bootctl.is_slot_bootable(new_slot))
+            self.assertTrue(self.bootctl.set_slot_as_unbootable_slot(new_slot))
+            self.assertFalse(self.bootctl.is_slot_bootable(new_slot))
+            self.device.reboot()
+            self.device.wait()
+            self.device.root()
+            self.device.wait()
+            self.assertEqual(slot, self.bootctl.get_current_slot())
+            self.assertFalse(self.bootctl.is_slot_bootable(new_slot))
+            self.assertTrue(self.bootctl.set_active_boot_slot(new_slot))
+            self.assertTrue(self.bootctl.is_slot_bootable(new_slot))
+            self.device.reboot()
+            self.device.wait()
+            self.device.root()
+            self.device.wait()
+            self.assertEqual(new_slot, self.bootctl.get_current_slot());
+
+if __name__ == '__main__':
+    unittest.main(verbosity=3)
diff --git a/tests/bootloader/shelltest.py b/tests/bootloader/shelltest.py
new file mode 100644 (file)
index 0000000..d9fbba1
--- /dev/null
@@ -0,0 +1,22 @@
+# 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.
+
+import adb
+import os
+import unittest
+
+class ShellTest(unittest.TestCase):
+    def __init__(self, *args, **kwargs):
+        super(ShellTest, self).__init__(*args, **kwargs)
+        self.device = adb.get_device(os.getenv("BOOTLOADER_TEST_SERIAL"));