Merge changes Ie795897d,I86e1cfed,I840ecbca

* changes:
  Installd: Amend dexopt binder logging
  Installd: Amend dexopt binder logging
  Installd: Amend dexopt binder logging
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 352cf0a..94c3102 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -5,6 +5,10 @@
         "-Wall",
         "-Werror",
         "-Wextra",
+
+        "-Wunreachable-code",
+        "-Wunreachable-code-break",
+        "-Wunreachable-code-return",
     ],
     srcs: [
         "CacheItem.cpp",
@@ -15,6 +19,9 @@
         "utils.cpp",
         ":installd_aidl",
     ],
+    header_libs: [
+        "dex2oat_headers",
+    ],
     shared_libs: [
         "libbase",
         "libbinder",
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 57c64c6..1882771 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -39,6 +39,7 @@
 #include <cutils/fs.h>
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
+#include <dex2oat_return_codes.h>
 #include <log/log.h>               // TODO: Move everything to base/logging.
 #include <openssl/sha.h>
 #include <private/android_filesystem_config.h>
@@ -46,6 +47,7 @@
 #include <system/thread_defs.h>
 
 #include "dexopt.h"
+#include "dexopt_return_codes.h"
 #include "globals.h"
 #include "installd_deps.h"
 #include "otapreopt_utils.h"
@@ -70,6 +72,7 @@
 static constexpr const char* kMinidebugDex2oatFlag = "--generate-mini-debug-info";
 static constexpr const char* kDisableCompactDexFlag = "--compact-dex-level=none";
 
+
 // Deleter using free() for use with std::unique_ptr<>. See also UniqueCPtr<> below.
 struct FreeDelete {
   // NOTE: Deleting a const object is valid but free() takes a non-const pointer.
@@ -221,6 +224,7 @@
     }
 }
 
+[[ noreturn ]]
 static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd,
         const char* input_file_name, const char* output_file_name, int swap_fd,
         const char* instruction_set, const char* compiler_filter,
@@ -230,9 +234,9 @@
     static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
 
     if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
-        ALOGE("Instruction set %s longer than max length of %d",
-              instruction_set, MAX_INSTRUCTION_SET_LEN);
-        return;
+        LOG(ERROR) << "Instruction set '" << instruction_set << "' longer than max length of "
+                   << MAX_INSTRUCTION_SET_LEN;
+        exit(DexoptReturnCodes::kInstructionSetLength);
     }
 
     // Get the relative path to the input file.
@@ -550,7 +554,8 @@
     argv[i] = NULL;
 
     execv(dex2oat_bin, (char * const *)argv);
-    ALOGE("execv(%s) failed: %s\n", dex2oat_bin, strerror(errno));
+    PLOG(ERROR) << "execv(" << dex2oat_bin << ") failed";
+    exit(DexoptReturnCodes::kDex2oatExec);
 }
 
 /*
@@ -602,12 +607,12 @@
 static void SetDex2OatScheduling(bool set_to_bg) {
     if (set_to_bg) {
         if (set_sched_policy(0, SP_BACKGROUND) < 0) {
-            ALOGE("set_sched_policy failed: %s\n", strerror(errno));
-            exit(70);
+            PLOG(ERROR) << "set_sched_policy failed";
+            exit(DexoptReturnCodes::kSetSchedPolicy);
         }
         if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
-            ALOGE("setpriority failed: %s\n", strerror(errno));
-            exit(71);
+            PLOG(ERROR) << "setpriority failed";
+            exit(DexoptReturnCodes::kSetPriority);
         }
     }
 }
@@ -707,12 +712,12 @@
 
 static void drop_capabilities(uid_t uid) {
     if (setgid(uid) != 0) {
-        ALOGE("setgid(%d) failed in installd during dexopt\n", uid);
-        exit(64);
+        PLOG(ERROR) << "setgid(" << uid << ") failed in installd during dexopt";
+        exit(DexoptReturnCodes::kSetGid);
     }
     if (setuid(uid) != 0) {
-        ALOGE("setuid(%d) failed in installd during dexopt\n", uid);
-        exit(65);
+        PLOG(ERROR) << "setuid(" << uid << ") failed in installd during dexopt";
+        exit(DexoptReturnCodes::kSetUid);
     }
     // drop capabilities
     struct __user_cap_header_struct capheader;
@@ -721,8 +726,8 @@
     memset(&capdata, 0, sizeof(capdata));
     capheader.version = _LINUX_CAPABILITY_VERSION_3;
     if (capset(&capheader, &capdata[0]) < 0) {
-        ALOGE("capset failed: %s\n", strerror(errno));
-        exit(66);
+        PLOG(ERROR) << "capset failed";
+        exit(DexoptReturnCodes::kCapSet);
     }
 }
 
@@ -732,6 +737,7 @@
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3;
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4;
 
+[[ noreturn ]]
 static void run_profman(const std::vector<unique_fd>& profile_fds,
                         const unique_fd& reference_profile_fd,
                         const std::vector<unique_fd>* apk_fds,
@@ -775,18 +781,18 @@
     argv[i] = NULL;
 
     execv(profman_bin, (char * const *)argv);
-    ALOGE("execv(%s) failed: %s\n", profman_bin, strerror(errno));
-    exit(68);   /* only get here on exec failure */
+    PLOG(ERROR) << "execv(" << profman_bin << ") failed";
+    exit(DexoptReturnCodes::kProfmanExec);   /* only get here on exec failure */
 }
 
-
+[[ noreturn ]]
 static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
                               const unique_fd& reference_profile_fd,
                               const std::vector<unique_fd>* apk_fds = nullptr) {
     run_profman(profiles_fd, reference_profile_fd, apk_fds, /*copy_and_update*/false);
 }
 
-
+[[ noreturn ]]
 static void run_profman_copy_and_update(unique_fd&& profile_fd,
                                         unique_fd&& reference_profile_fd,
                                         unique_fd&& apk_fd) {
@@ -821,7 +827,6 @@
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
         run_profman_merge(profiles_fd, reference_profile_fd);
-        exit(68);   /* only get here on exec failure */
     }
     /* parent */
     int return_code = wait_child(pid);
@@ -894,6 +899,7 @@
     return analyze_profiles(uid, package_name, profile_name, /*is_secondary_dex*/false);
 }
 
+[[ noreturn ]]
 static void run_profman_dump(const std::vector<unique_fd>& profile_fds,
                              const unique_fd& reference_profile_fd,
                              const std::vector<std::string>& dex_locations,
@@ -925,8 +931,8 @@
     argv[i] = NULL;
 
     execv(PROFMAN_BIN, (char * const *)argv);
-    ALOGE("execv(%s) failed: %s\n", PROFMAN_BIN, strerror(errno));
-    exit(68);   /* only get here on exec failure */
+    PLOG(ERROR) << "execv(" << PROFMAN_BIN << ") failed";
+    exit(DexoptReturnCodes::kProfmanExec);   /* only get here on exec failure */
 }
 
 bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& profile_name,
@@ -971,7 +977,6 @@
         drop_capabilities(uid);
         run_profman_dump(profile_fds, reference_profile_fd, dex_locations,
                          apk_fds, output_fd);
-        exit(68);   /* only get here on exec failure */
     }
     /* parent */
     int return_code = wait_child(pid);
@@ -1642,10 +1647,17 @@
 // secondary dex files. This return codes are returned by the child process created for
 // analyzing secondary dex files in process_secondary_dex_dexopt.
 
-// The dexoptanalyzer was not invoked because of validation or IO errors.
-static int constexpr SECONDARY_DEX_DEXOPTANALYZER_SKIPPED = 200;
-// The dexoptanalyzer was not invoked because the dex file does not exist anymore.
-static int constexpr SECONDARY_DEX_DEXOPTANALYZER_SKIPPED_NO_FILE = 201;
+enum DexoptAnalyzerSkipCodes {
+  // The dexoptanalyzer was not invoked because of validation or IO errors.
+  // Specific errors are encoded in the name.
+  kSecondaryDexDexoptAnalyzerSkippedValidatePath = 200,
+  kSecondaryDexDexoptAnalyzerSkippedOpenZip = 201,
+  kSecondaryDexDexoptAnalyzerSkippedPrepareDir = 202,
+  kSecondaryDexDexoptAnalyzerSkippedOpenOutput = 203,
+  kSecondaryDexDexoptAnalyzerSkippedFailExec = 204,
+  // The dexoptanalyzer was not invoked because the dex file does not exist anymore.
+  kSecondaryDexDexoptAnalyzerSkippedNoFile = 205,
+};
 
 // Verifies the result of analyzing secondary dex files from process_secondary_dex_dexopt.
 // If the result is valid returns true and sets dexopt_needed_out to a valid value.
@@ -1653,7 +1665,7 @@
 // The result is expected to be either one of SECONDARY_DEX_* codes or a valid exit code
 // of dexoptanalyzer.
 static bool process_secondary_dexoptanalyzer_result(const std::string& dex_path, int result,
-            int* dexopt_needed_out) {
+            int* dexopt_needed_out, std::string* error_msg) {
     // The result values are defined in dexoptanalyzer.
     switch (result) {
         case 0:  // dexoptanalyzer: no_dexopt_needed
@@ -1669,21 +1681,42 @@
         case 2:  // dexoptanalyzer: dex2oat_for_bootimage_oat
         case 3:  // dexoptanalyzer: dex2oat_for_filter_oat
         case 4:  // dexoptanalyzer: dex2oat_for_relocation_oat
-            LOG(ERROR) << "Dexoptnalyzer return the status of an oat file."
-                    << " Expected odex file status for secondary dex " << dex_path
-                    << " : dexoptanalyzer result=" << result;
+            *error_msg = StringPrintf("Dexoptanalyzer return the status of an oat file."
+                                      " Expected odex file status for secondary dex %s"
+                                      " : dexoptanalyzer result=%d",
+                                      dex_path.c_str(),
+                                      result);
             return false;
-        case SECONDARY_DEX_DEXOPTANALYZER_SKIPPED_NO_FILE:
+    }
+
+    // Use a second switch for enum switch-case analysis.
+    switch (static_cast<DexoptAnalyzerSkipCodes>(result)) {
+        case kSecondaryDexDexoptAnalyzerSkippedNoFile:
             // If the file does not exist there's no need for dexopt.
             *dexopt_needed_out = NO_DEXOPT_NEEDED;
             return true;
-        case SECONDARY_DEX_DEXOPTANALYZER_SKIPPED:
+
+        case kSecondaryDexDexoptAnalyzerSkippedValidatePath:
+            *error_msg = "Dexoptanalyzer path validation failed";
             return false;
-        default:
-            LOG(ERROR) << "Unexpected result from analyzing secondary dex " << dex_path
-                    << " result=" << result;
+        case kSecondaryDexDexoptAnalyzerSkippedOpenZip:
+            *error_msg = "Dexoptanalyzer open zip failed";
+            return false;
+        case kSecondaryDexDexoptAnalyzerSkippedPrepareDir:
+            *error_msg = "Dexoptanalyzer dir preparation failed";
+            return false;
+        case kSecondaryDexDexoptAnalyzerSkippedOpenOutput:
+            *error_msg = "Dexoptanalyzer open output failed";
+            return false;
+        case kSecondaryDexDexoptAnalyzerSkippedFailExec:
+            *error_msg = "Dexoptanalyzer failed to execute";
             return false;
     }
+
+    *error_msg = StringPrintf("Unexpected result from analyzing secondary dex %s result=%d",
+                              dex_path.c_str(),
+                              result);
+    return false;
 }
 
 enum SecondaryDexAccess {
@@ -1721,10 +1754,10 @@
 // Create the oat file structure for the secondary dex 'dex_path' and assign
 // the individual path component to the 'out_' parameters.
 static bool create_secondary_dex_oat_layout(const std::string& dex_path, const std::string& isa,
-        char* out_oat_dir, char* out_oat_isa_dir, char* out_oat_path) {
+        char* out_oat_dir, char* out_oat_isa_dir, char* out_oat_path, std::string* error_msg) {
     size_t dirIndex = dex_path.rfind('/');
     if (dirIndex == std::string::npos) {
-        LOG(ERROR) << "Unexpected dir structure for dex file " << dex_path;
+        *error_msg = std::string("Unexpected dir structure for dex file ").append(dex_path);
         return false;
     }
     // TODO(calin): we have similar computations in at lest 3 other places
@@ -1736,7 +1769,7 @@
 
     if (!create_oat_out_path(dex_path.c_str(), isa.c_str(), out_oat_dir,
             /*is_secondary_dex*/true, out_oat_path)) {
-        LOG(ERROR) << "Could not create oat path for secondary dex " << dex_path;
+        *error_msg = std::string("Could not create oat path for secondary dex ").append(dex_path);
         return false;
     }
     return true;
@@ -1744,17 +1777,19 @@
 
 // Validate that the dexopt_flags contain a valid storage flag and convert that to an installd
 // recognized storage flags (FLAG_STORAGE_CE or FLAG_STORAGE_DE).
-static bool validate_dexopt_storage_flags(int dexopt_flags, int* out_storage_flag) {
+static bool validate_dexopt_storage_flags(int dexopt_flags,
+                                          int* out_storage_flag,
+                                          std::string* error_msg) {
     if ((dexopt_flags & DEXOPT_STORAGE_CE) != 0) {
         *out_storage_flag = FLAG_STORAGE_CE;
         if ((dexopt_flags & DEXOPT_STORAGE_DE) != 0) {
-            LOG(ERROR) << "Ambiguous secondary dex storage flag. Both, CE and DE, flags are set";
+            *error_msg = "Ambiguous secondary dex storage flag. Both, CE and DE, flags are set";
             return false;
         }
     } else if ((dexopt_flags & DEXOPT_STORAGE_DE) != 0) {
         *out_storage_flag = FLAG_STORAGE_DE;
     } else {
-        LOG(ERROR) << "Secondary dex storage flag must be set";
+        *error_msg = "Secondary dex storage flag must be set";
         return false;
     }
     return true;
@@ -1770,10 +1805,12 @@
 static bool process_secondary_dex_dexopt(const std::string& dex_path, const char* pkgname,
         int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set,
         const char* compiler_filter, bool* is_public_out, int* dexopt_needed_out,
-        std::string* oat_dir_out, bool downgrade, const char* class_loader_context) {
+        std::string* oat_dir_out, bool downgrade, const char* class_loader_context,
+        /* out */ std::string* error_msg) {
     LOG(DEBUG) << "Processing secondary dex path " << dex_path;
     int storage_flag;
-    if (!validate_dexopt_storage_flags(dexopt_flags, &storage_flag)) {
+    if (!validate_dexopt_storage_flags(dexopt_flags, &storage_flag, error_msg)) {
+        LOG(ERROR) << *error_msg;
         return false;
     }
     // Compute the oat dir as it's not easy to extract it from the child computation.
@@ -1781,8 +1818,8 @@
     char oat_dir[PKG_PATH_MAX];
     char oat_isa_dir[PKG_PATH_MAX];
     if (!create_secondary_dex_oat_layout(
-            dex_path, instruction_set, oat_dir, oat_isa_dir, oat_path)) {
-        LOG(ERROR) << "Could not create secondary odex layout: " << dex_path;
+            dex_path, instruction_set, oat_dir, oat_isa_dir, oat_path, error_msg)) {
+        LOG(ERROR) << "Could not create secondary odex layout: " << *error_msg;
         return false;
     }
     oat_dir_out->assign(oat_dir);
@@ -1795,7 +1832,7 @@
         // Validate the path structure.
         if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid, uid, storage_flag)) {
             LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
-            _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
+            _exit(kSecondaryDexDexoptAnalyzerSkippedValidatePath);
         }
 
         // Open the dex file.
@@ -1803,15 +1840,15 @@
         zip_fd.reset(open(dex_path.c_str(), O_RDONLY));
         if (zip_fd.get() < 0) {
             if (errno == ENOENT) {
-                _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED_NO_FILE);
+                _exit(kSecondaryDexDexoptAnalyzerSkippedNoFile);
             } else {
-                _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
+                _exit(kSecondaryDexDexoptAnalyzerSkippedOpenZip);
             }
         }
 
         // Prepare the oat directories.
         if (!prepare_secondary_dex_oat_dir(dex_path, uid, instruction_set)) {
-            _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
+            _exit(kSecondaryDexDexoptAnalyzerSkippedPrepareDir);
         }
 
         // Open the vdex/oat files if any.
@@ -1823,7 +1860,7 @@
                                           true /* is_secondary_dex */,
                                           &oat_file_fd,
                                           &vdex_file_fd)) {
-            _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
+            _exit(kSecondaryDexDexoptAnalyzerSkippedOpenOutput);
         }
 
         // Analyze profiles.
@@ -1840,18 +1877,27 @@
                             downgrade,
                             class_loader_context);
         PLOG(ERROR) << "Failed to exec dexoptanalyzer";
-        _exit(SECONDARY_DEX_DEXOPTANALYZER_SKIPPED);
+        _exit(kSecondaryDexDexoptAnalyzerSkippedFailExec);
     }
 
     /* parent */
     int result = wait_child(pid);
     if (!WIFEXITED(result)) {
-        LOG(ERROR) << "dexoptanalyzer failed for path " << dex_path << ": " << result;
+        *error_msg = StringPrintf("dexoptanalyzer failed for path %s: 0x%04x",
+                                  dex_path.c_str(),
+                                  result);
+        LOG(ERROR) << *error_msg;
         return false;
     }
     result = WEXITSTATUS(result);
     // Check that we successfully executed dexoptanalyzer.
-    bool success = process_secondary_dexoptanalyzer_result(dex_path, result, dexopt_needed_out);
+    bool success = process_secondary_dexoptanalyzer_result(dex_path,
+                                                           result,
+                                                           dexopt_needed_out,
+                                                           error_msg);
+    if (!success) {
+        LOG(ERROR) << *error_msg;
+    }
 
     LOG(DEBUG) << "Processed secondary dex file " << dex_path << " result=" << result;
 
@@ -1859,7 +1905,7 @@
     // Note that dexoptanalyzer is executed even if force compilation is enabled (because it
     // makes the code simpler; force compilation is only needed during tests).
     if (success &&
-        (result != SECONDARY_DEX_DEXOPTANALYZER_SKIPPED_NO_FILE) &&
+        (result != kSecondaryDexDexoptAnalyzerSkippedNoFile) &&
         ((dexopt_flags & DEXOPT_FORCE) != 0)) {
         *dexopt_needed_out = DEX2OAT_FROM_SCRATCH;
     }
@@ -1872,8 +1918,15 @@
     return success;
 }
 
-static std::string format_dexopt_error(int retcode, const char* dex_path) {
-  return StringPrintf("Dex2oat invocation for %s failed with 0x%04x", dex_path, retcode);
+static std::string format_dexopt_error(int status, const char* dex_path) {
+  if (WIFEXITED(status)) {
+    int int_code = WEXITSTATUS(status);
+    const char* code_name = get_return_code_name(static_cast<DexoptReturnCodes>(int_code));
+    if (code_name != nullptr) {
+      return StringPrintf("Dex2oat invocation for %s failed: %s", dex_path, code_name);
+    }
+  }
+  return StringPrintf("Dex2oat invocation for %s failed with 0x%04x", dex_path, status);
 }
 
 int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set,
@@ -1912,13 +1965,15 @@
     if (is_secondary_dex) {
         if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,
                 instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str,
-                downgrade, class_loader_context)) {
+                downgrade, class_loader_context, error_msg)) {
             oat_dir = oat_dir_str.c_str();
             if (dexopt_needed == NO_DEXOPT_NEEDED) {
                 return 0;  // Nothing to do, report success.
             }
         } else {
-            *error_msg = "Failed processing secondary.";
+            if (error_msg->empty()) {  // TODO: Make this a CHECK.
+                *error_msg = "Failed processing secondary.";
+            }
             return -1;  // We had an error, logged in the process method.
         }
     } else {
@@ -1997,7 +2052,7 @@
         SetDex2OatScheduling(boot_complete);
         if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) {
             PLOG(ERROR) << "flock(" << out_oat_path << ") failed";
-            _exit(67);
+            _exit(DexoptReturnCodes::kFlock);
         }
 
         run_dex2oat(input_fd.get(),
@@ -2019,7 +2074,6 @@
                     enable_hidden_api_checks,
                     dex_metadata_fd.get(),
                     compilation_reason);
-        _exit(68);   /* only get here on exec failure */
     } else {
         int res = wait_child(pid);
         if (res == 0) {
@@ -2135,9 +2189,10 @@
         char oat_isa_dir[PKG_PATH_MAX];
         bool result = true;
         for (size_t i = 0; i < isas.size(); i++) {
+            std::string error_msg;
             if (!create_secondary_dex_oat_layout(
-                    dex_path,isas[i], oat_dir, oat_isa_dir, oat_path)) {
-                LOG(ERROR) << "Could not create secondary odex layout: " << dex_path;
+                    dex_path,isas[i], oat_dir, oat_isa_dir, oat_path, &error_msg)) {
+                LOG(ERROR) << error_msg;
                 _exit(kReconcileSecondaryDexValidationError);
             }
 
@@ -2238,7 +2293,7 @@
 
         if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr, uid, storage_flag)) {
             LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
-            _exit(1);
+            _exit(DexoptReturnCodes::kHashValidatePath);
         }
 
         unique_fd fd(TEMP_FAILURE_RETRY(open(dex_path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW)));
@@ -2248,7 +2303,7 @@
                 _exit(0);
             }
             PLOG(ERROR) << "Failed to open secondary dex " << dex_path;
-            _exit(1);
+            _exit(DexoptReturnCodes::kHashOpenPath);
         }
 
         SHA256_CTX ctx;
@@ -2261,7 +2316,7 @@
                 break;
             } else if (bytes_read == -1) {
                 PLOG(ERROR) << "Failed to read secondary dex " << dex_path;
-                _exit(1);
+                _exit(DexoptReturnCodes::kHashReadDex);
             }
 
             SHA256_Update(&ctx, buffer.data(), bytes_read);
@@ -2270,7 +2325,7 @@
         std::array<uint8_t, SHA256_DIGEST_LENGTH> hash;
         SHA256_Final(hash.data(), &ctx);
         if (!WriteFully(pipe_write, hash.data(), hash.size())) {
-            _exit(1);
+            _exit(DexoptReturnCodes::kHashWrite);
         }
 
         _exit(0);
@@ -2588,7 +2643,6 @@
         /* child -- drop privileges before continuing */
         drop_capabilities(app_shared_gid);
         run_profman_merge(profiles_fd, snapshot_fd, &apk_fds);
-        exit(42);   /* only get here on exec failure */
     }
 
     /* parent */
@@ -2666,7 +2720,6 @@
             drop_capabilities(AID_SYSTEM);
 
             run_profman_merge(profiles_fd, snapshot_fd, &apk_fds);
-            exit(42);   /* only get here on exec failure */
         }
 
         /* parent */
@@ -2730,7 +2783,6 @@
         run_profman_copy_and_update(std::move(dex_metadata_fd),
                                     std::move(ref_profile_fd),
                                     std::move(apk_fd));
-        exit(42);   /* only get here on exec failure */
     }
 
     /* parent */
diff --git a/cmds/installd/dexopt_return_codes.h b/cmds/installd/dexopt_return_codes.h
new file mode 100644
index 0000000..bbecfa4
--- /dev/null
+++ b/cmds/installd/dexopt_return_codes.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2018 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 <dex2oat_return_codes.h>
+
+namespace android {
+namespace installd {
+
+// Constants for exit codes that installd code emits. These are failure situations before calling
+// any tools, e.g., in validation, and must not overlap with the exit codes of tools, so they
+// can be distinguished.
+enum DexoptReturnCodes : int {
+    kSetGid = 64,
+    kSetUid = 65,
+    kCapSet = 66,
+    kFlock = 67,
+    kProfmanExec = 68,
+    kSetSchedPolicy = 70,
+    kSetPriority = 71,
+    kDex2oatExec = 72,
+    kInstructionSetLength = 73,
+    kHashValidatePath = 74,
+    kHashOpenPath = 75,
+    kHashReadDex = 76,
+    kHashWrite = 77,
+};
+
+inline const char* get_installd_return_code_name(DexoptReturnCodes code) {
+    switch (code) {
+        case kSetGid:
+            return "setgid";
+        case kSetUid:
+            return "setuid";
+        case kCapSet:
+            return "capset";
+        case kFlock:
+            return "flock";
+        case kProfmanExec:
+            return "exec(profman)";
+        case kSetSchedPolicy:
+            return "setschedpolicy";
+        case kSetPriority:
+            return "setpriority";
+        case kDex2oatExec:
+            return "exec(dex2oat)";
+        case kInstructionSetLength:
+            return "instruction-set-length";
+        case kHashValidatePath:
+            return "hash(validate-path)";
+        case kHashOpenPath:
+            return "hash(open-path)";
+        case kHashReadDex:
+            return "hash(read-dex)";
+        case kHashWrite:
+            return "hash(write)";
+    }
+    return nullptr;
+}
+
+inline const char* get_dex2oat_return_code_name(art::dex2oat::ReturnCode code) {
+    switch (code) {
+        case art::dex2oat::ReturnCode::kNoFailure:
+            return "dex2oat success";
+        case art::dex2oat::ReturnCode::kOther:
+            return "unspecified dex2oat error";
+        case art::dex2oat::ReturnCode::kCreateRuntime:
+            return "dex2oat failed to create a runtime";
+    }
+    return nullptr;
+}
+
+// Get some slightly descriptive string for the return code. Handles both DexoptReturnCodes (local
+// exit codes) as well as art::dex2oat::ReturnCode.
+inline const char* get_return_code_name(int code) {
+    // Try to enforce non-overlap (see comment on DexoptReturnCodes)
+    // TODO: How could switch-case checks be used to enforce completeness?
+    switch (code) {
+        case kSetGid:
+        case kSetUid:
+        case kCapSet:
+        case kFlock:
+        case kProfmanExec:
+        case kSetSchedPolicy:
+        case kSetPriority:
+        case kDex2oatExec:
+        case kInstructionSetLength:
+        case kHashValidatePath:
+        case kHashOpenPath:
+        case kHashReadDex:
+        case kHashWrite:
+            break;
+        case static_cast<int>(art::dex2oat::ReturnCode::kNoFailure):
+        case static_cast<int>(art::dex2oat::ReturnCode::kOther):
+        case static_cast<int>(art::dex2oat::ReturnCode::kCreateRuntime):
+            break;
+    }
+    const char* value = get_installd_return_code_name(static_cast<DexoptReturnCodes>(code));
+    if (value != nullptr) {
+        return value;
+    }
+    value = get_dex2oat_return_code_name(static_cast<art::dex2oat::ReturnCode>(code));
+    return value;
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 7c75713..668e604 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -499,7 +499,8 @@
     binder::Status status;
     CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_DE,
         /*binder_ok*/ false,  /*compile_ok*/ false, &status);
-    EXPECT_STREQ(status.toString8().c_str(), "Status(-8): '-1: Failed processing secondary.'");
+    EXPECT_STREQ(status.toString8().c_str(),
+                 "Status(-8): '-1: Dexoptanalyzer path validation failed'");
 }
 
 TEST_F(DexoptTest, DexoptSecondaryAppOwnershipValidationError) {
@@ -507,7 +508,8 @@
     binder::Status status;
     CompileSecondaryDex("/data/data/random.app/secondary.jar", DEXOPT_STORAGE_CE,
         /*binder_ok*/ false,  /*compile_ok*/ false, &status);
-    EXPECT_STREQ(status.toString8().c_str(), "Status(-8): '-1: Failed processing secondary.'");
+    EXPECT_STREQ(status.toString8().c_str(),
+                 "Status(-8): '-1: Dexoptanalyzer path validation failed'");
 }
 
 TEST_F(DexoptTest, DexoptSecondaryAcessViaDifferentUidError) {
@@ -515,7 +517,7 @@
     binder::Status status;
     CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
         /*binder_ok*/ false,  /*compile_ok*/ false, &status, kSystemUid);
-    EXPECT_STREQ(status.toString8().c_str(), "Status(-8): '-1: Failed processing secondary.'");
+    EXPECT_STREQ(status.toString8().c_str(), "Status(-8): '-1: Dexoptanalyzer open zip failed'");
 }
 
 TEST_F(DexoptTest, DexoptPrimaryPublic) {
@@ -538,7 +540,7 @@
                           &status);
     EXPECT_STREQ(status.toString8().c_str(),
                  "Status(-8): \'256: Dex2oat invocation for "
-                 "/data/app/com.installd.test.dexopt/base.jar failed with 0x0100\'");
+                 "/data/app/com.installd.test.dexopt/base.jar failed: unspecified dex2oat error'");
 }
 
 TEST_F(DexoptTest, DexoptPrimaryProfileNonPublic) {