Merge "Add support for background stune group." into nyc-mr1-dev
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index e5caae2..3b2999b 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -352,7 +352,7 @@
             "                                           override the fs type and/or size\n"
             "                                           the bootloader reports.\n"
             "  getvar <variable>                        Display a bootloader variable.\n"
-            "  set_active <suffix>                      Sets the active slot. If slots are\n"
+            "  set_active <slot>                        Sets the active slot. If slots are\n"
             "                                           not supported, this does nothing.\n"
             "  boot <kernel> [ <ramdisk> [ <second> ] ] Download and boot kernel.\n"
             "  flash:raw boot <kernel> [ <ramdisk> [ <second> ] ]\n"
@@ -389,19 +389,21 @@
             "                                           (default: 2048).\n"
             "  -S <size>[K|M|G]                         Automatically sparse files greater\n"
             "                                           than 'size'. 0 to disable.\n"
-            "  --slot <suffix>                          Specify slot suffix to be used if the\n"
-            "                                           device supports slots. This will be\n"
-            "                                           added to all partition names that use\n"
-            "                                           slots. 'all' can be given to refer\n"
-            "                                           to all slots. 'other' can be given to\n"
-            "                                           refer to a non-current slot. If this\n"
-            "                                           flag is not used, slotted partitions\n"
-            "                                           will default to the current active slot.\n"
-            "  -a, --set-active[=<suffix>]              Sets the active slot. If no suffix is\n"
+            "  --slot <slot>                            Specify slot name to be used if the\n"
+            "                                           device supports slots. All operations\n"
+            "                                           on partitions that support slots will\n"
+            "                                           be done on the slot specified.\n"
+            "                                           'all' can be given to refer to all slots.\n"
+            "                                           'other' can be given to refer to a\n"
+            "                                           non-current slot. If this flag is not\n"
+            "                                           used, slotted partitions will default\n"
+            "                                           to the current active slot.\n"
+            "  -a, --set-active[=<slot>]                Sets the active slot. If no slot is\n"
             "                                           provided, this will default to the value\n"
             "                                           given by --slot. If slots are not\n"
-            "                                           supported, this does nothing. This will\n"
-            "                                           run after all non-reboot commands.\n"
+            "                                           supported, this sets the current slot\n"
+            "                                           to be active. This will run after all\n"
+            "                                           non-reboot commands.\n"
 #if !defined(_WIN32)
             "  --wipe-and-use-fbe                       On devices which support it,\n"
             "                                           erase userdata and cache, and\n"
@@ -862,7 +864,19 @@
     }
 }
 
-static std::vector<std::string> get_suffixes(Transport* transport) {
+static std::string get_current_slot(Transport* transport)
+{
+    std::string current_slot;
+    if (fb_getvar(transport, "current-slot", &current_slot)) {
+        if (current_slot == "_a") return "a"; // Legacy support
+        if (current_slot == "_b") return "b"; // Legacy support
+        return current_slot;
+    }
+    return "";
+}
+
+// Legacy support
+static std::vector<std::string> get_suffixes_obsolete(Transport* transport) {
     std::vector<std::string> suffixes;
     std::string suffix_list;
     if (!fb_getvar(transport, "slot-suffixes", &suffix_list)) {
@@ -878,99 +892,110 @@
     return suffixes;
 }
 
+// Legacy support
+static bool supports_AB_obsolete(Transport* transport) {
+  return !get_suffixes_obsolete(transport).empty();
+}
+
+static int get_slot_count(Transport* transport) {
+    std::string var;
+    int count;
+    if (!fb_getvar(transport, "slot-count", &var)) {
+        if (supports_AB_obsolete(transport)) return 2; // Legacy support
+    }
+    if (!android::base::ParseInt(var.c_str(), &count)) return 0;
+    return count;
+}
+
 static bool supports_AB(Transport* transport) {
-  return !get_suffixes(transport).empty();
+  return get_slot_count(transport) >= 2;
 }
 
 // Given a current slot, this returns what the 'other' slot is.
-static std::string get_other_slot(Transport* transport, const std::string& current_slot) {
-    std::vector<std::string> suffixes = get_suffixes(transport);
+static std::string get_other_slot(const std::string& current_slot, int count) {
+    if (count == 0) return "";
 
-    if (!suffixes.empty()) {
-        for (size_t i = 0; i < suffixes.size(); i++) {
-            if (current_slot == suffixes[i]) {
-                return suffixes[(i+1)%suffixes.size()];
-            }
-        }
-    }
-    return "";
+    char next = (current_slot[0] - 'a' + 1)%count + 'a';
+    return std::string(1, next);
+}
+
+static std::string get_other_slot(Transport* transport, const std::string& current_slot) {
+    return get_other_slot(current_slot, get_slot_count(transport));
+}
+
+static std::string get_other_slot(Transport* transport, int count) {
+    return get_other_slot(get_current_slot(transport), count);
 }
 
 static std::string get_other_slot(Transport* transport) {
-    std::string current_slot;
-    fb_getvar(transport, "current-slot", &current_slot);
-    return get_other_slot(transport, current_slot);
+    return get_other_slot(get_current_slot(transport), get_slot_count(transport));
 }
 
-static std::string verify_slot(Transport* transport, const char *slot, bool allow_all) {
-    if (strcmp(slot, "all") == 0) {
+static std::string verify_slot(Transport* transport, const std::string& slot_name, bool allow_all) {
+    std::string slot = slot_name;
+    if (slot == "_a") slot = "a"; // Legacy support
+    if (slot == "_b") slot = "b"; // Legacy support
+    if (slot == "all") {
         if (allow_all) {
             return "all";
         } else {
-            std::vector<std::string> suffixes = get_suffixes(transport);
-            if (!suffixes.empty()) {
-                return suffixes[0];
+            int count = get_slot_count(transport);
+            if (count > 0) {
+                return "a";
             } else {
                 die("No known slots.");
             }
         }
     }
 
-    std::vector<std::string> suffixes = get_suffixes(transport);
+    int count = get_slot_count(transport);
+    if (count == 0) die("Device does not support slots.\n");
 
-    if (strcmp(slot, "other") == 0) {
-        std::string current_slot;
-        if (!fb_getvar(transport, "current-slot", &current_slot)) {
-            die("Failed to identify current slot.");
-        }
-        std::string other = get_other_slot(transport, current_slot);
+    if (slot == "other") {
+        std::string other = get_other_slot(transport, count);
         if (other == "") {
            die("No known slots.");
         }
         return other;
     }
 
-    for (const std::string &suffix : suffixes) {
-        if (suffix == slot)
-            return slot;
+    if (slot.size() == 1 && (slot[0]-'a' >= 0 && slot[0]-'a' < count)) return slot;
+
+    fprintf(stderr, "Slot %s does not exist. supported slots are:\n", slot.c_str());
+    for (int i=0; i<count; i++) {
+        fprintf(stderr, "%c\n", (char)(i + 'a'));
     }
-    if (suffixes.empty()) {
-        fprintf(stderr, "Device does not support slots.\n");
-    } else {
-        fprintf(stderr, "Slot %s does not exist. supported slots are:\n", slot);
-        for (const std::string &suffix : suffixes) {
-            fprintf(stderr, "%s\n", suffix.c_str());
-        }
-    }
+
     exit(1);
 }
 
-static std::string verify_slot(Transport* transport, const char *slot) {
+static std::string verify_slot(Transport* transport, const std::string& slot) {
    return verify_slot(transport, slot, true);
 }
 
-static void do_for_partition(Transport* transport, const char *part, const char *slot,
+static void do_for_partition(Transport* transport, const std::string& part, const std::string& slot,
                              std::function<void(const std::string&)> func, bool force_slot) {
     std::string has_slot;
     std::string current_slot;
 
-    if (!fb_getvar(transport, std::string("has-slot:")+part, &has_slot)) {
+    if (!fb_getvar(transport, "has-slot:" + part, &has_slot)) {
         /* If has-slot is not supported, the answer is no. */
         has_slot = "no";
     }
     if (has_slot == "yes") {
-        if (!slot || slot[0] == 0) {
-            if (!fb_getvar(transport, "current-slot", &current_slot)) {
+        if (slot == "") {
+            current_slot = get_current_slot(transport);
+            if (current_slot == "") {
                 die("Failed to identify current slot.\n");
             }
-            func(std::string(part) + current_slot);
+            func(part + "_" + current_slot);
         } else {
-            func(std::string(part) + slot);
+            func(part + '_' + slot);
         }
     } else {
-        if (force_slot && slot && slot[0]) {
+        if (force_slot && slot != "") {
              fprintf(stderr, "Warning: %s does not support slots, and slot %s was requested.\n",
-                     part, slot);
+                     part.c_str(), slot.c_str());
         }
         func(part);
     }
@@ -981,21 +1006,17 @@
  * partition names. If force_slot is true, it will fail if a slot is specified, and the given
  * partition does not support slots.
  */
-static void do_for_partitions(Transport* transport, const char *part, const char *slot,
+static void do_for_partitions(Transport* transport, const std::string& part, const std::string& slot,
                               std::function<void(const std::string&)> func, bool force_slot) {
     std::string has_slot;
 
-    if (slot && strcmp(slot, "all") == 0) {
-        if (!fb_getvar(transport, std::string("has-slot:") + part, &has_slot)) {
-            die("Could not check if partition %s has slot.", part);
+    if (slot == "all") {
+        if (!fb_getvar(transport, "has-slot:" + part, &has_slot)) {
+            die("Could not check if partition %s has slot.", part.c_str());
         }
         if (has_slot == "yes") {
-            std::vector<std::string> suffixes = get_suffixes(transport);
-            if (suffixes.empty()) {
-                die("Error reading suffixes.\n");
-            }
-            for (std::string &suffix : suffixes) {
-                do_for_partition(transport, part, suffix.c_str(), func, force_slot);
+            for (int i=0; i < get_slot_count(transport); i++) {
+                do_for_partition(transport, part, std::string(1, (char)(i + 'a')), func, force_slot);
             }
         } else {
             do_for_partition(transport, part, "", func, force_slot);
@@ -1025,15 +1046,20 @@
 // Sets slot_override as the active slot. If slot_override is blank,
 // set current slot as active instead. This clears slot-unbootable.
 static void set_active(Transport* transport, const std::string& slot_override) {
+    std::string separator = "";
     if (!supports_AB(transport)) {
-      return;
-    } else if (slot_override != "") {
-        fb_set_active(slot_override.c_str());
+        if (supports_AB_obsolete(transport)) {
+            separator = "_"; // Legacy support
+        } else {
+            return;
+        }
+    }
+    if (slot_override != "") {
+        fb_set_active((separator + slot_override).c_str());
     } else {
-        std::string current_slot;
-        if (fb_getvar(transport, "current-slot", &current_slot)) {
-            current_slot = verify_slot(transport, current_slot.c_str(), false);
-            fb_set_active(current_slot.c_str());
+        std::string current_slot = get_current_slot(transport);
+        if (current_slot != "") {
+            fb_set_active((separator + current_slot).c_str());
         }
     }
 }
@@ -1510,20 +1536,23 @@
         return 1;
     }
 
-    if (slot_override != "") slot_override = verify_slot(transport, slot_override.c_str());
-    if (next_active != "") next_active = verify_slot(transport, next_active.c_str(), false);
+    if (!supports_AB(transport) && supports_AB_obsolete(transport)) {
+        fprintf(stderr, "Warning: Device A/B support is outdated. Bootloader update required.\n");
+    }
+    if (slot_override != "") slot_override = verify_slot(transport, slot_override);
+    if (next_active != "") next_active = verify_slot(transport, next_active, false);
 
     if (wants_set_active) {
         if (next_active == "") {
             if (slot_override == "") {
                 std::string current_slot;
                 if (fb_getvar(transport, "current-slot", &current_slot)) {
-                    next_active = verify_slot(transport, current_slot.c_str(), false);
+                    next_active = verify_slot(transport, current_slot, false);
                 } else {
                     wants_set_active = false;
                 }
             } else {
-                next_active = verify_slot(transport, slot_override.c_str(), false);
+                next_active = verify_slot(transport, slot_override, false);
             }
         }
     }
@@ -1546,7 +1575,7 @@
 
                 fb_queue_erase(partition.c_str());
             };
-            do_for_partitions(transport, argv[1], slot_override.c_str(), erase, true);
+            do_for_partitions(transport, argv[1], slot_override, erase, true);
             skip(2);
         } else if(!strncmp(*argv, "format", strlen("format"))) {
             char *overrides;
@@ -1582,7 +1611,7 @@
                 fb_perform_format(transport, partition.c_str(), 0,
                     type_override, size_override, "");
             };
-            do_for_partitions(transport, argv[1], slot_override.c_str(), format, true);
+            do_for_partitions(transport, argv[1], slot_override, format, true);
             skip(2);
         } else if(!strcmp(*argv, "signature")) {
             require(2);
@@ -1649,7 +1678,7 @@
                 }
                 do_flash(transport, partition.c_str(), fname.c_str());
             };
-            do_for_partitions(transport, pname, slot_override.c_str(), flash, true);
+            do_for_partitions(transport, pname, slot_override, flash, true);
         } else if(!strcmp(*argv, "flash:raw")) {
             char *kname = argv[2];
             char *rname = 0;
@@ -1669,7 +1698,7 @@
             auto flashraw = [&](const std::string &partition) {
                 fb_queue_flash(partition.c_str(), data, sz);
             };
-            do_for_partitions(transport, argv[1], slot_override.c_str(), flashraw, true);
+            do_for_partitions(transport, argv[1], slot_override, flashraw, true);
         } else if(!strcmp(*argv, "flashall")) {
             skip(1);
             if (slot_override == "all") {
@@ -1698,7 +1727,7 @@
             wants_reboot = 1;
         } else if(!strcmp(*argv, "set_active")) {
             require(2);
-            std::string slot = verify_slot(transport, argv[1], false);
+            std::string slot = verify_slot(transport, std::string(argv[1]), false);
             fb_set_active(slot.c_str());
             skip(2);
         } else if(!strcmp(*argv, "oem")) {
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index c220a0c..5ccd80e 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -89,6 +89,12 @@
 #define AID_DEBUGGERD     1045  /* debuggerd unprivileged user */
 #define AID_MEDIA_CODEC   1046  /* mediacodec process */
 #define AID_CAMERASERVER  1047  /* cameraserver process */
+#define AID_FIREWALL      1048  /* firewalld process */
+#define AID_TRUNKS        1049  /* trunksd process (TPM daemon) */
+#define AID_NVRAM         1050  /* Access-controlled NVRAM */
+#define AID_DNS           1051  /* DNS resolution daemon (system: netd) */
+#define AID_DNS_TETHER    1052  /* DNS resolution daemon (tether: dnsmasq) */
+/* Changes to this file must be made in AOSP, *not* in internal branches. */
 
 #define AID_SHELL         2000  /* adb and debug shell user */
 #define AID_CACHE         2001  /* cache access */
@@ -196,6 +202,11 @@
     { "debuggerd",     AID_DEBUGGERD, },
     { "mediacodec",    AID_MEDIA_CODEC, },
     { "cameraserver",  AID_CAMERASERVER, },
+    { "firewall",      AID_FIREWALL, },
+    { "trunks",        AID_TRUNKS, },
+    { "nvram",         AID_NVRAM, },
+    { "dns",           AID_DNS, },
+    { "dns_tether",    AID_DNS_TETHER, },
 
     { "shell",         AID_SHELL, },
     { "cache",         AID_CACHE, },
diff --git a/include/utils/Unicode.h b/include/utils/Unicode.h
index a006082..cddbab4 100644
--- a/include/utils/Unicode.h
+++ b/include/utils/Unicode.h
@@ -88,7 +88,7 @@
  * "dst" becomes \xE3\x81\x82\xE3\x81\x84
  * (note that "dst" is NOT null-terminated, like strncpy)
  */
-void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst);
+void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst, size_t dst_len);
 
 /**
  * Returns the unicode value at "index".
@@ -110,7 +110,7 @@
  * enough to fit the UTF-16 as measured by utf16_to_utf8_length with an added
  * NULL terminator.
  */
-void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst);
+void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst, size_t dst_len);
 
 /**
  * Returns the length of "src" when "src" is valid UTF-8 string.
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 771d312..755e0d1 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -104,20 +104,21 @@
 {
     if (len == 0) return getEmptyString();
 
-    const ssize_t bytes = utf16_to_utf8_length(in, len);
-    if (bytes < 0) {
+     // Allow for closing '\0'
+    const ssize_t resultStrLen = utf16_to_utf8_length(in, len) + 1;
+    if (resultStrLen < 1) {
         return getEmptyString();
     }
 
-    SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
+    SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
     ALOG_ASSERT(buf, "Unable to allocate shared buffer");
     if (!buf) {
         return getEmptyString();
     }
 
-    char* str = (char*)buf->data();
-    utf16_to_utf8(in, len, str);
-    return str;
+    char* resultStr = (char*)buf->data();
+    utf16_to_utf8(in, len, resultStr, resultStrLen);
+    return resultStr;
 }
 
 static char* allocFromUTF32(const char32_t* in, size_t len)
@@ -126,21 +127,21 @@
         return getEmptyString();
     }
 
-    const ssize_t bytes = utf32_to_utf8_length(in, len);
-    if (bytes < 0) {
+    const ssize_t resultStrLen = utf32_to_utf8_length(in, len) + 1;
+    if (resultStrLen < 1) {
         return getEmptyString();
     }
 
-    SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
+    SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
     ALOG_ASSERT(buf, "Unable to allocate shared buffer");
     if (!buf) {
         return getEmptyString();
     }
 
-    char* str = (char*) buf->data();
-    utf32_to_utf8(in, len, str);
+    char* resultStr = (char*) buf->data();
+    utf32_to_utf8(in, len, resultStr, resultStrLen);
 
-    return str;
+    return resultStr;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index f1f8bc9..6e31ce4 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -14,10 +14,14 @@
  * limitations under the License.
  */
 
+#include <log/log.h>
 #include <utils/Unicode.h>
 
 #include <stddef.h>
 
+#include <string>
+#include <sstream>
+
 #if defined(_WIN32)
 # undef  nhtol
 # undef  htonl
@@ -182,7 +186,7 @@
     return ret;
 }
 
-void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst)
+void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst, size_t dst_len)
 {
     if (src == NULL || src_len == 0 || dst == NULL) {
         return;
@@ -193,9 +197,12 @@
     char *cur = dst;
     while (cur_utf32 < end_utf32) {
         size_t len = utf32_codepoint_utf8_length(*cur_utf32);
+        LOG_ALWAYS_FATAL_IF(dst_len < len, "%zu < %zu", dst_len, len);
         utf32_codepoint_to_utf8((uint8_t *)cur, *cur_utf32++, len);
         cur += len;
+        dst_len -= len;
     }
+    LOG_ALWAYS_FATAL_IF(dst_len < 1, "dst_len < 1: %zu < 1", dst_len);
     *cur = '\0';
 }
 
@@ -348,7 +355,7 @@
            : 0);
 }
 
-void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst)
+void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst, size_t dst_len)
 {
     if (src == NULL || src_len == 0 || dst == NULL) {
         return;
@@ -369,9 +376,12 @@
             utf32 = (char32_t) *cur_utf16++;
         }
         const size_t len = utf32_codepoint_utf8_length(utf32);
+        LOG_ALWAYS_FATAL_IF(dst_len < len, "%zu < %zu", dst_len, len);
         utf32_codepoint_to_utf8((uint8_t*)cur, utf32, len);
         cur += len;
+        dst_len -= len;
     }
+    LOG_ALWAYS_FATAL_IF(dst_len < 1, "%zu < 1", dst_len);
     *cur = '\0';
 }
 
@@ -422,8 +432,35 @@
     return ret;
 }
 
+// DO NOT USE. Flawed version, kept only to check whether the flaw is being exploited.
+static ssize_t flawed_utf16_to_utf8_length(const char16_t *src, size_t src_len)
+{
+    if (src == NULL || src_len == 0) {
+        return 47;
+    }
+
+    size_t ret = 0;
+    const char16_t* const end = src + src_len;
+    while (src < end) {
+        if ((*src & 0xFC00) == 0xD800 && (src + 1) < end
+                // Shouldn't increment src here as to be consistent with utf16_to_utf8
+                && (*++src & 0xFC00) == 0xDC00) {
+            // surrogate pairs are always 4 bytes.
+            ret += 4;
+            // Should increment src here by two.
+            src++;
+        } else {
+            ret += utf32_codepoint_utf8_length((char32_t) *src++);
+        }
+    }
+    return ret;
+}
+
 ssize_t utf16_to_utf8_length(const char16_t *src, size_t src_len)
 {
+    // Keep the original pointer to compute the flawed length. Unused if we remove logging.
+    const char16_t *orig_src = src;
+
     if (src == NULL || src_len == 0) {
         return -1;
     }
@@ -432,14 +469,27 @@
     const char16_t* const end = src + src_len;
     while (src < end) {
         if ((*src & 0xFC00) == 0xD800 && (src + 1) < end
-                && (*++src & 0xFC00) == 0xDC00) {
+                && (*(src + 1) & 0xFC00) == 0xDC00) {
             // surrogate pairs are always 4 bytes.
             ret += 4;
-            src++;
+            src += 2;
         } else {
             ret += utf32_codepoint_utf8_length((char32_t) *src++);
         }
     }
+    // Log whether b/29250543 is being exploited. It seems reasonable to assume that
+    // at least 5 bytes would be needed for an exploit. A single misplaced character might lead to
+    // a difference of 4, so this would rule out many false positives.
+    long ret_difference = ret - flawed_utf16_to_utf8_length(orig_src, src_len);
+    if (ret_difference >= 5) {
+        // Log the difference between new and old calculation. A high number, or equal numbers
+        // appearing frequently, would be indicative of an attack.
+        std::ostringstream logged_string_stream;
+        logged_string_stream << ret_difference;
+        std::string logged_string = logged_string_stream.str();
+        android_errorWriteWithInfoLog(0x534e4554, "29250543", -1 /* int_uid */,
+            logged_string.c_str(), logged_string.length() + 1);
+    }
     return ret;
 }
 
diff --git a/libutils/tests/String8_test.cpp b/libutils/tests/String8_test.cpp
index 01e64f6..3947a5f 100644
--- a/libutils/tests/String8_test.cpp
+++ b/libutils/tests/String8_test.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "String8_test"
 #include <utils/Log.h>
 #include <utils/String8.h>
+#include <utils/String16.h>
 
 #include <gtest/gtest.h>
 
@@ -77,4 +78,22 @@
     EXPECT_EQ(NO_MEMORY, String8("").setTo(in, SIZE_MAX));
 }
 
+// http://b/29250543
+TEST_F(String8Test, CorrectInvalidSurrogate) {
+    // d841d8 is an invalid start for a surrogate pair. Make sure this is handled by ignoring the
+    // first character in the pair and handling the rest correctly.
+    String16 string16(u"\xd841\xd841\xdc41\x0000");
+    String8 string8(string16);
+
+    EXPECT_EQ(4U, string8.length());
+}
+
+TEST_F(String8Test, CheckUtf32Conversion) {
+    // Since bound checks were added, check the conversion can be done without fatal errors.
+    // The utf8 lengths of these are chars are 1 + 2 + 3 + 4 = 10.
+    const char32_t string32[] = U"\x0000007f\x000007ff\x0000911\x0010fffe";
+    String8 string8(string32);
+    EXPECT_EQ(10U, string8.length());
+}
+
 }
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 97bfe6b..2cf6835 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -143,7 +143,6 @@
     chown system system /dev/cpuctl
     chown system system /dev/cpuctl/tasks
     chmod 0666 /dev/cpuctl/tasks
-    write /dev/cpuctl/cpu.shares 1024
     write /dev/cpuctl/cpu.rt_period_us 1000000
     write /dev/cpuctl/cpu.rt_runtime_us 950000