Merge "SF: Initialize mSingleBufferMode"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 7560416..237b64a 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -299,7 +299,7 @@
     run_command("UPTIME", 10, "uptime", NULL);
     dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
     dump_file("MEMORY INFO", "/proc/meminfo");
-    run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-t", NULL);
+    run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-H", NULL);
     run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL);
     dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");
     dump_file("VMALLOC INFO", "/proc/vmallocinfo");
@@ -726,7 +726,6 @@
 
     /* redirect output if needed */
     char path[PATH_MAX], tmp_path[PATH_MAX];
-    pid_t gzip_pid = -1;
 
     if (!use_socket && use_outfile) {
         strlcpy(path, use_outfile, sizeof(path));
@@ -757,10 +756,9 @@
         fclose(vibrator);
     }
 
-    /* wait for gzip to finish, otherwise it might get killed when we exit */
-    if (gzip_pid > 0) {
+    /* close output if needed */
+    if (!use_socket && use_outfile) {
         fclose(stdout);
-        waitpid(gzip_pid, NULL, 0);
     }
 
     /* rename the (now complete) .tmp file to its final location */
@@ -770,11 +768,12 @@
 
     /* tell activity manager we're done */
     if (do_broadcast && use_outfile && do_fb) {
-        run_command(NULL, 5, "/system/bin/am", "broadcast", "--user", "0",
+        const char *args[] = { "/system/bin/am", "broadcast", "--user", "0",
                 "-a", "android.intent.action.BUGREPORT_FINISHED",
                 "--es", "android.intent.extra.BUGREPORT", path,
                 "--es", "android.intent.extra.SCREENSHOT", screenshot_path,
-                "--receiver-permission", "android.permission.DUMP", NULL);
+                "--receiver-permission", "android.permission.DUMP", NULL };
+        run_command_always(NULL, 5, args);
     }
 
     ALOGI("done\n");
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index f10ec46..f9f20d2 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -17,6 +17,18 @@
 #ifndef _DUMPSTATE_H_
 #define _DUMPSTATE_H_
 
+/* When defined, skips the real dumps and just print the section headers.
+   Useful when debugging dumpstate itself. */
+//#define _DUMPSTATE_DRY_RUN_
+
+#ifdef _DUMPSTATE_DRY_RUN_
+#define ON_DRY_RUN_RETURN(X) return X
+#endif
+#ifndef _DUMPSTATE_DRY_RUN_
+#define ON_DRY_RUN_RETURN(X)
+#endif
+
+
 #include <time.h>
 #include <unistd.h>
 #include <stdbool.h>
@@ -52,6 +64,11 @@
 /* forks a command and waits for it to finish -- terminate args with NULL */
 int run_command(const char *title, int timeout_seconds, const char *command, ...);
 
+/* forks a command and waits for it to finish
+   first element of args is the command, and last must be NULL.
+   command is always ran, even when _DUMPSTATE_DRY_RUN_ is defined. */
+int run_command_always(const char *title, int timeout_seconds, const char *args[]);
+
 /* prints all the system properties */
 void print_properties();
 
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 12f44ae..e6594ec 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -60,6 +60,7 @@
 }
 
 void for_each_userid(void (*func)(int), const char *header) {
+    ON_DRY_RUN_RETURN();
     DIR *d;
     struct dirent *de;
 
@@ -122,6 +123,7 @@
 }
 
 void for_each_pid(for_each_pid_func func, const char *header) {
+    ON_DRY_RUN_RETURN();
   __for_each_pid(for_each_pid_helper, header, (void *)func);
 }
 
@@ -174,10 +176,12 @@
 }
 
 void for_each_tid(for_each_tid_func func, const char *header) {
+    ON_DRY_RUN_RETURN();
     __for_each_pid(for_each_tid_helper, header, (void *) func);
 }
 
 void show_wchan(int pid, int tid, const char *name) {
+    ON_DRY_RUN_RETURN();
     char path[255];
     char buffer[255];
     int fd;
@@ -208,6 +212,7 @@
 
 void do_dmesg() {
     printf("------ KERNEL LOG (dmesg) ------\n");
+    ON_DRY_RUN_RETURN();
     /* Get size of kernel buffer */
     int size = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
     if (size <= 0) {
@@ -299,10 +304,12 @@
 
 /* prints the contents of a file */
 int dump_file(const char *title, const char *path) {
+    if (title) printf("------ %s (%s) ------\n", title, path);
+    ON_DRY_RUN_RETURN(0);
+
     int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
     if (fd < 0) {
         int err = errno;
-        if (title) printf("------ %s (%s) ------\n", title, path);
         printf("*** %s: %s\n", path, strerror(err));
         if (title) printf("\n");
         return -1;
@@ -328,6 +335,7 @@
     if (title) {
         printf("------ %s (%s) ------\n", title, dir);
     }
+    ON_DRY_RUN_RETURN(0);
 
     if (dir[strlen(dir) - 1] == '/') {
         ++slash;
@@ -384,6 +392,7 @@
  * stuck.
  */
 int dump_file_from_fd(const char *title, const char *path, int fd) {
+    ON_DRY_RUN_RETURN(0);
     int flags = fcntl(fd, F_GETFL);
     if (flags == -1) {
         printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
@@ -442,6 +451,29 @@
 /* forks a command and waits for it to finish */
 int run_command(const char *title, int timeout_seconds, const char *command, ...) {
     fflush(stdout);
+
+    const char *args[1024] = {command};
+    size_t arg;
+    va_list ap;
+    va_start(ap, command);
+    if (title) printf("------ %s (%s", title, command);
+    for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) {
+        args[arg] = va_arg(ap, const char *);
+        if (args[arg] == NULL) break;
+        if (title) printf(" %s", args[arg]);
+    }
+    if (title) printf(") ------\n");
+    fflush(stdout);
+
+    ON_DRY_RUN_RETURN(0);
+
+    return run_command_always(title, timeout_seconds, args);
+}
+
+/* forks a command and waits for it to finish */
+int run_command_always(const char *title, int timeout_seconds, const char *args[]) {
+    const char *command = args[0];
+
     uint64_t start = nanotime();
     pid_t pid = fork();
 
@@ -453,8 +485,6 @@
 
     /* handle child case */
     if (pid == 0) {
-        const char *args[1024] = {command};
-        size_t arg;
 
         /* make sure the child dies when dumpstate dies */
         prctl(PR_SET_PDEATHSIG, SIGKILL);
@@ -465,17 +495,6 @@
         sigact.sa_handler = SIG_IGN;
         sigaction(SIGPIPE, &sigact, NULL);
 
-        va_list ap;
-        va_start(ap, command);
-        if (title) printf("------ %s (%s", title, command);
-        for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) {
-            args[arg] = va_arg(ap, const char *);
-            if (args[arg] == NULL) break;
-            if (title) printf(" %s", args[arg]);
-        }
-        if (title) printf(") ------\n");
-        fflush(stdout);
-
         execvp(command, (char**) args);
         printf("*** exec(%s): %s\n", command, strerror(errno));
         fflush(stdout);
@@ -532,12 +551,13 @@
 
 /* prints all the system properties */
 void print_properties() {
+    printf("------ SYSTEM PROPERTIES ------\n");
+    ON_DRY_RUN_RETURN();
     size_t i;
     num_props = 0;
     property_list(print_prop, NULL);
     qsort(&props, num_props, sizeof(props[0]), compare_prop);
 
-    printf("------ SYSTEM PROPERTIES ------\n");
     for (i = 0; i < num_props; ++i) {
         fputs(props[i], stdout);
         free(props[i]);
@@ -611,6 +631,7 @@
 
 /* dump Dalvik and native stack traces, return the trace file location (NULL if none) */
 const char *dump_traces() {
+    ON_DRY_RUN_RETURN(NULL);
     const char* result = NULL;
 
     char traces_path[PROPERTY_VALUE_MAX] = "";
@@ -764,6 +785,7 @@
 }
 
 void dump_route_tables() {
+    ON_DRY_RUN_RETURN();
     const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
     dump_file("RT_TABLES", RT_TABLES_PATH);
     FILE* fp = fopen(RT_TABLES_PATH, "re");
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index 46d72fd..b48fbc1 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -43,36 +43,40 @@
 
 static const char* kCpPath = "/system/bin/cp";
 
-int install(const char *uuid, const char *pkgname, uid_t uid, gid_t gid, const char *seinfo)
-{
+int install(const char *uuid, const char *pkgname, uid_t uid, gid_t gid, const char *seinfo) {
     if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
         ALOGE("invalid uid/gid: %d %d\n", uid, gid);
         return -1;
     }
 
-    std::string _pkgdir(create_data_user_package_path(uuid, 0, pkgname));
-    const char* pkgdir = _pkgdir.c_str();
+    std::string ce_package_path(create_data_user_package_path(uuid, 0, pkgname));
+    std::string de_package_path(create_data_user_de_package_path(uuid, 0, pkgname));
 
-    if (mkdir(pkgdir, 0751) < 0) {
-        ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
+    const char* c_ce_package_path = ce_package_path.c_str();
+    const char* c_de_package_path = de_package_path.c_str();
+
+    if (fs_prepare_dir(c_ce_package_path, 0751, uid, gid) == -1) {
+        PLOG(ERROR) << "Failed to prepare " << ce_package_path;
+        unlink(c_ce_package_path);
         return -1;
     }
-    if (chmod(pkgdir, 0751) < 0) {
-        ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
-        unlink(pkgdir);
+    if (selinux_android_setfilecon(c_ce_package_path, pkgname, seinfo, uid) < 0) {
+        PLOG(ERROR) << "Failed to setfilecon " << ce_package_path;
+        unlink(c_ce_package_path);
         return -1;
     }
 
-    if (selinux_android_setfilecon(pkgdir, pkgname, seinfo, uid) < 0) {
-        ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
-        unlink(pkgdir);
-        return -errno;
-    }
-
-    if (chown(pkgdir, uid, gid) < 0) {
-        ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
-        unlink(pkgdir);
-        return -1;
+    if (property_get_bool("vold.has_fbe", false)) {
+        if (fs_prepare_dir(c_de_package_path, 0751, uid, gid) == -1) {
+            PLOG(ERROR) << "Failed to prepare " << de_package_path;
+            unlink(c_de_package_path);
+            return -1;
+        }
+        if (selinux_android_setfilecon(c_de_package_path, pkgname, seinfo, uid) < 0) {
+            PLOG(ERROR) << "Failed to setfilecon " << de_package_path;
+            unlink(c_de_package_path);
+            return -1;
+        }
     }
 
     return 0;
@@ -89,23 +93,6 @@
     return delete_dir_contents(pkgdir, 1, NULL);
 }
 
-int renamepkg(const char *oldpkgname, const char *newpkgname)
-{
-    char oldpkgdir[PKG_PATH_MAX];
-    char newpkgdir[PKG_PATH_MAX];
-
-    if (create_pkg_path(oldpkgdir, oldpkgname, PKG_DIR_POSTFIX, 0))
-        return -1;
-    if (create_pkg_path(newpkgdir, newpkgname, PKG_DIR_POSTFIX, 0))
-        return -1;
-
-    if (rename(oldpkgdir, newpkgdir) < 0) {
-        ALOGE("cannot rename dir '%s' to '%s': %s\n", oldpkgdir, newpkgdir, strerror(errno));
-        return -errno;
-    }
-    return 0;
-}
-
 int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid)
 {
     struct stat s;
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 7a16150..52f7b9c 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -72,11 +72,6 @@
     return uninstall(parse_null(arg[0]), arg[1], atoi(arg[2])); /* uuid, pkgname, userid */
 }
 
-static int do_rename(char **arg, char reply[REPLY_MAX] __unused)
-{
-    return renamepkg(arg[0], arg[1]); /* oldpkgname, newpkgname */
-}
-
 static int do_fixuid(char **arg, char reply[REPLY_MAX] __unused)
 {
     return fix_uid(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3])); /* uuid, pkgname, uid, gid */
@@ -198,7 +193,6 @@
     { "movedex",              3, do_move_dex },
     { "rmdex",                2, do_rm_dex },
     { "remove",               3, do_remove },
-    { "rename",               2, do_rename },
     { "fixuid",               4, do_fixuid },
     { "freecache",            2, do_free_cache },
     { "rmcache",              3, do_rm_cache },
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index df13fe4..6a73457 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -171,10 +171,14 @@
 
 std::string create_data_app_package_path(const char* volume_uuid, const char* package_name);
 
+// TODO: finish refactoring to "_ce"
 std::string create_data_user_path(const char* volume_uuid, userid_t userid);
+std::string create_data_user_de_path(const char* volume_uuid, userid_t userid);
 
 std::string create_data_user_package_path(const char* volume_uuid,
         userid_t user, const char* package_name);
+std::string create_data_user_de_package_path(const char* volume_uuid,
+        userid_t user, const char* package_name);
 
 std::string create_data_media_path(const char* volume_uuid, userid_t userid);
 
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index e58391f..e586caa 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -64,6 +64,15 @@
             create_data_user_path(volume_uuid, user).c_str(), package_name);
 }
 
+std::string create_data_user_de_package_path(const char* volume_uuid,
+        userid_t user, const char* package_name) {
+    CHECK(is_valid_filename(package_name));
+    CHECK(is_valid_package_name(package_name) == 0);
+
+    return StringPrintf("%s/%s",
+            create_data_user_de_path(volume_uuid, user).c_str(), package_name);
+}
+
 int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname,
         const char *postfix, userid_t userid) {
     if (is_valid_package_name(pkgname) != 0) {
@@ -115,6 +124,14 @@
 }
 
 /**
+ * Create the path name for device encrypted user data for a certain userid.
+ */
+std::string create_data_user_de_path(const char* volume_uuid, userid_t userid) {
+    std::string data(create_data_path(volume_uuid));
+    return StringPrintf("%s/user_de/%u", data.c_str(), userid);
+}
+
+/**
  * Create the path name for media for a certain userid.
  */
 std::string create_data_media_path(const char* volume_uuid, userid_t userid) {
diff --git a/include/media/openmax/OMX_Core.h b/include/media/openmax/OMX_Core.h
index 521c223..f746a69 100644
--- a/include/media/openmax/OMX_Core.h
+++ b/include/media/openmax/OMX_Core.h
@@ -509,7 +509,7 @@
     OMX_EventKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
     OMX_EventVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
 
-    /** Event when tunneled decoder has rendered an output
+    /** Event when tunneled decoder has rendered an output or reached EOS
      *  nData1 must contain the number of timestamps returned
      *  pEventData must point to an array of the OMX_VIDEO_RENDEREVENTTYPE structs containing the
      *  render-timestamps of each frame. Component may batch rendered timestamps using this event,
@@ -518,6 +518,10 @@
      *
      *  If component is doing frame-rate conversion, it must signal the render time of each
      *  converted frame, and must interpolate media timestamps for in-between frames.
+     *
+     *  When the component reached EOS, it must signal an EOS timestamp using the same mechanism.
+     *  This is in addition to the timestamp of the last rendered frame, and should follow that
+     *  frame.
      */
     OMX_EventOutputRendered = 0x7F000001,
     OMX_EventMax = 0x7FFFFFFF
diff --git a/include/media/openmax/OMX_VideoExt.h b/include/media/openmax/OMX_VideoExt.h
index 34c0405..3971bc5 100644
--- a/include/media/openmax/OMX_VideoExt.h
+++ b/include/media/openmax/OMX_VideoExt.h
@@ -203,10 +203,17 @@
     OMX_BOOL bEnableLoopFilterAcrossSlices;
 } OMX_VIDEO_SLICESEGMENTSTYPE;
 
-/** Structure to return timestamps of rendered output frames for tunneled components */
+/** Structure to return timestamps of rendered output frames as well as EOS
+ *  for tunneled components.
+ */
 typedef struct OMX_VIDEO_RENDEREVENTTYPE {
     OMX_S64 nMediaTimeUs;  // timestamp of rendered video frame
     OMX_S64 nSystemTimeNs; // system monotonic time at the time frame was rendered
+                           // Use INT64_MAX for nMediaTimeUs to signal that the EOS
+                           // has been reached. In this case, nSystemTimeNs MUST be
+                           // the system time when the last frame was rendered.
+                           // This MUST be done in addition to returning (and
+                           // following) the render information for the last frame.
 } OMX_VIDEO_RENDEREVENTTYPE;
 
 #ifdef __cplusplus
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 56cde8a..b8f5436 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -338,6 +338,39 @@
     return BAD_TYPE;
 }
 
+namespace {
+
+template<typename T>
+status_t readTypedVector(std::vector<T>* val, const Parcel* p,
+                         status_t(Parcel::*read_func)(T*) const) {
+    val->clear();
+
+    int32_t size;
+    status_t status = p->readInt32(&size);
+
+    if (status != OK) {
+        return status;
+    }
+
+    if (size < 0) {
+        return UNEXPECTED_NULL;
+    }
+
+    val->resize(size);
+
+    for (auto& v: *val) {
+        status = (p->*read_func)(&v);
+
+        if (status != OK) {
+            return status;
+        }
+    }
+
+    return OK;
+}
+
+}  // namespace
+
 // ---------------------------------------------------------------------------
 
 Parcel::Parcel()
@@ -743,6 +776,46 @@
     return NULL;
 }
 
+namespace {
+
+template<typename T, typename U>
+status_t unsafeWriteTypedVector(const std::vector<T>& val, Parcel* p,
+                                status_t(Parcel::*write_func)(U)) {
+    if (val.size() > std::numeric_limits<int32_t>::max()) {
+        return BAD_VALUE;
+    }
+
+    status_t status = p->writeInt32(val.size());
+
+    if (status != OK) {
+        return status;
+    }
+
+    for (const auto& item : val) {
+        status = (p->*write_func)(item);
+
+        if (status != OK) {
+            return status;
+        }
+    }
+
+    return OK;
+}
+
+template<typename T>
+status_t writeTypedVector(const std::vector<T>& val, Parcel* p,
+                          status_t(Parcel::*write_func)(const T&)) {
+    return unsafeWriteTypedVector(val, p, write_func);
+}
+
+template<typename T>
+status_t writeTypedVector(const std::vector<T>& val, Parcel* p,
+                          status_t(Parcel::*write_func)(T)) {
+    return unsafeWriteTypedVector(val, p, write_func);
+}
+
+}  // namespace
+
 status_t Parcel::writeByteVector(const std::vector<int8_t>& val)
 {
     status_t status;
@@ -768,163 +841,37 @@
 
 status_t Parcel::writeInt32Vector(const std::vector<int32_t>& val)
 {
-    if (val.size() > std::numeric_limits<int32_t>::max()) {
-        return BAD_VALUE;
-    }
-
-    status_t status = writeInt32(val.size());
-
-    if (status != OK) {
-        return status;
-    }
-
-    for (const auto& item : val) {
-        status = writeInt32(item);
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
+    return writeTypedVector(val, this, &Parcel::writeInt32);
 }
 
 status_t Parcel::writeInt64Vector(const std::vector<int64_t>& val)
 {
-    if (val.size() > std::numeric_limits<int32_t>::max()) {
-        return BAD_VALUE;
-    }
-
-    status_t status = writeInt32(val.size());
-
-    if (status != OK) {
-        return status;
-    }
-
-    for (const auto& item : val) {
-        status = writeInt64(item);
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
+    return writeTypedVector(val, this, &Parcel::writeInt64);
 }
 
 status_t Parcel::writeFloatVector(const std::vector<float>& val)
 {
-    if (val.size() > std::numeric_limits<int32_t>::max()) {
-        return BAD_VALUE;
-    }
-
-    status_t status = writeInt32(val.size());
-
-    if (status != OK) {
-        return status;
-    }
-
-    for (const auto& item : val) {
-        status = writeFloat(item);
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
+    return writeTypedVector(val, this, &Parcel::writeFloat);
 }
 
 status_t Parcel::writeDoubleVector(const std::vector<double>& val)
 {
-    if (val.size() > std::numeric_limits<int32_t>::max()) {
-        return BAD_VALUE;
-    }
-
-    status_t status = writeInt32(val.size());
-
-    if (status != OK) {
-        return status;
-    }
-
-    for (const auto& item : val) {
-        status = writeDouble(item);
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
+    return writeTypedVector(val, this, &Parcel::writeDouble);
 }
 
 status_t Parcel::writeBoolVector(const std::vector<bool>& val)
 {
-    if (val.size() > std::numeric_limits<int32_t>::max()) {
-        return BAD_VALUE;
-    }
-
-    status_t status = writeInt32(val.size());
-
-    if (status != OK) {
-        return status;
-    }
-
-    for (const auto& item : val) {
-        status = writeBool(item);
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
+    return writeTypedVector(val, this, &Parcel::writeBool);
 }
 
 status_t Parcel::writeCharVector(const std::vector<char16_t>& val)
 {
-    if (val.size() > std::numeric_limits<int32_t>::max()) {
-        return BAD_VALUE;
-    }
-
-    status_t status = writeInt32(val.size());
-
-    if (status != OK) {
-        return status;
-    }
-
-    for (const auto& item : val) {
-        status = writeChar(item);
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
+    return writeTypedVector(val, this, &Parcel::writeChar);
 }
 
 status_t Parcel::writeString16Vector(const std::vector<String16>& val)
 {
-    if (val.size() > std::numeric_limits<int32_t>::max()) {
-        return BAD_VALUE;
-    }
-
-    status_t status = writeInt32(val.size());
-
-    if (status != OK) {
-        return status;
-    }
-
-    for (const auto& item : val) {
-        status = writeString16(item);
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
+    return writeTypedVector(val, this, &Parcel::writeString16);
 }
 
 status_t Parcel::writeInt32(int32_t val)
@@ -1073,52 +1020,11 @@
 
 status_t Parcel::writeStrongBinderVector(const std::vector<sp<IBinder>>& val)
 {
-    if (val.size() > std::numeric_limits<int32_t>::max()) {
-        return BAD_VALUE;
-    }
-
-    status_t status = writeInt32(val.size());
-
-    if (status != OK) {
-        return status;
-    }
-
-    for (const auto& item : val) {
-        status = writeStrongBinder(item);
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
+    return writeTypedVector(val, this, &Parcel::writeStrongBinder);
 }
 
 status_t Parcel::readStrongBinderVector(std::vector<sp<IBinder>>* val) const {
-    val->clear();
-
-    int32_t size;
-    status_t status = readInt32(&size);
-
-    if (status != OK) {
-        return status;
-    }
-
-    if (size < 0) {
-        return BAD_VALUE;
-    }
-
-    val->resize(size);
-
-    for (auto& v : *val) {
-        status = readStrongBinder(&v);
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
+    return readTypedVector(val, this, &Parcel::readStrongBinder);
 }
 
 status_t Parcel::writeWeakBinder(const wp<IBinder>& val)
@@ -1417,10 +1323,15 @@
         return status;
     }
 
-    if (size < 0 || size_t(size) > dataAvail()) {
+    if (size < 0) {
+        status = UNEXPECTED_NULL;
+        return status;
+    }
+    if (size_t(size) > dataAvail()) {
         status = BAD_VALUE;
         return status;
     }
+
     const void* data = readInplace(size);
     if (!data) {
         status = BAD_VALUE;
@@ -1433,111 +1344,19 @@
 }
 
 status_t Parcel::readInt32Vector(std::vector<int32_t>* val) const {
-    val->clear();
-
-    int32_t size;
-    status_t status = readInt32(&size);
-
-    if (status != OK) {
-        return status;
-    }
-
-    if (size < 0) {
-        return BAD_VALUE;
-    }
-
-    val->resize(size);
-
-    for (auto& v: *val) {
-        status = readInt32(&v);
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
+    return readTypedVector(val, this, &Parcel::readInt32);
 }
 
 status_t Parcel::readInt64Vector(std::vector<int64_t>* val) const {
-    val->clear();
-
-    int32_t size;
-    status_t status = readInt32(&size);
-
-    if (status != OK) {
-        return status;
-    }
-
-    if (size < 0) {
-        return BAD_VALUE;
-    }
-
-    val->resize(size);
-
-    for (auto& v : *val) {
-        status = readInt64(&v);
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
+    return readTypedVector(val, this, &Parcel::readInt64);
 }
 
 status_t Parcel::readFloatVector(std::vector<float>* val) const {
-    val->clear();
-
-    int32_t size;
-    status_t status = readInt32(&size);
-
-    if (status != OK) {
-        return status;
-    }
-
-    if (size < 0) {
-        return BAD_VALUE;
-    }
-
-    val->resize(size);
-
-    for (auto& v : *val) {
-        status = readFloat(&v);
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
+    return readTypedVector(val, this, &Parcel::readFloat);
 }
 
 status_t Parcel::readDoubleVector(std::vector<double>* val) const {
-    val->clear();
-
-    int32_t size;
-    status_t status = readInt32(&size);
-
-    if (status != OK) {
-        return status;
-    }
-
-    if (size < 0) {
-        return BAD_VALUE;
-    }
-
-    val->resize(size);
-
-    for (auto& v : *val) {
-        status = readDouble(&v);
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
+    return readTypedVector(val, this, &Parcel::readDouble);
 }
 
 status_t Parcel::readBoolVector(std::vector<bool>* val) const {
@@ -1551,7 +1370,7 @@
     }
 
     if (size < 0) {
-        return BAD_VALUE;
+        return UNEXPECTED_NULL;
     }
 
     val->resize(size);
@@ -1573,61 +1392,11 @@
 }
 
 status_t Parcel::readCharVector(std::vector<char16_t>* val) const {
-    val->clear();
-
-    int32_t size;
-    status_t status = readInt32(&size);
-
-    if (status != OK) {
-        return status;
-    }
-
-    if (size < 0) {
-        return BAD_VALUE;
-    }
-
-    val->resize(size);
-
-    for (auto& v : *val) {
-        status = readChar(&v);
-
-        if (status != OK) {
-            return status;
-        }
-    }
-
-    return OK;
+    return readTypedVector(val, this, &Parcel::readChar);
 }
 
 status_t Parcel::readString16Vector(std::vector<String16>* val) const {
-    val->clear();
-
-    int32_t size;
-    status_t status = readInt32(&size);
-
-    if (status != OK) {
-        return status;
-    }
-
-    if (size < 0) {
-        return BAD_VALUE;
-    }
-
-    val->reserve(size);
-
-    while (size-- > 0) {
-        const char16_t *data;
-        size_t size;
-        data = readString16Inplace(&size);
-
-        if (data == nullptr) {
-            return UNKNOWN_ERROR;
-        }
-
-        val->emplace_back(data, size);
-    }
-
-    return OK;
+    return readTypedVector(val, this, &Parcel::readString16);
 }
 
 
@@ -1834,7 +1603,7 @@
         return 0;
     } else {
         *pArg = String16();
-        return UNKNOWN_ERROR;
+        return UNEXPECTED_NULL;
     }
 }