Pass targetSdkVersion to dex2oat

Dex2oat now accepts targetSdkVersion as a parameter to determine
whether ART should treat the app as "legacy" and allow or restrict
access to private APIs.

We bump the otapreopt argument version to v4 due to the new value.

Bug: 64382372
Test: manual
Change-Id: I5de64e96043404df39f09d3d16b575ee39951fcb
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index db1d4a3..b0661c5 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1894,7 +1894,7 @@
         int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
         const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
         const std::unique_ptr<std::string>& classLoaderContext,
-        const std::unique_ptr<std::string>& seInfo, bool downgrade) {
+        const std::unique_ptr<std::string>& seInfo, bool downgrade, int32_t targetSdkVersion) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     if (packageName && *packageName != "*") {
@@ -1912,7 +1912,7 @@
     const char* se_info = seInfo ? seInfo->c_str() : nullptr;
     int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded,
             oat_dir, dexFlags, compiler_filter, volume_uuid, class_loader_context, se_info,
-            downgrade);
+            downgrade, targetSdkVersion);
     return res ? error(res, "Failed to dexopt") : ok();
 }
 
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index e9e5ffc..93b59ed 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -84,7 +84,8 @@
             int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
             const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
             const std::unique_ptr<std::string>& classLoaderContext,
-            const std::unique_ptr<std::string>& seInfo, bool downgrade);
+            const std::unique_ptr<std::string>& seInfo, bool downgrade,
+            int32_t targetSdkVersion);
 
     binder::Status rmdex(const std::string& codePath, const std::string& instructionSet);
 
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index c1a233b..2c9c6bd 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -51,7 +51,7 @@
             @nullable @utf8InCpp String outputPath, int dexFlags,
             @utf8InCpp String compilerFilter, @nullable @utf8InCpp String uuid,
             @nullable @utf8InCpp String sharedLibraries,
-            @nullable @utf8InCpp String seInfo, boolean downgrade);
+            @nullable @utf8InCpp String seInfo, boolean downgrade, int targetSdkVersion);
 
     void rmdex(@utf8InCpp String codePath, @utf8InCpp String instructionSet);
 
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 6c069b2..25b6f64 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -212,7 +212,7 @@
         const char* input_file_name, const char* output_file_name, int swap_fd,
         const char* instruction_set, const char* compiler_filter,
         bool debuggable, bool post_bootcomplete, bool background_job_compile, int profile_fd,
-        const char* class_loader_context) {
+        const char* class_loader_context, int target_sdk_version) {
     static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
 
     if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
@@ -323,6 +323,7 @@
     bool have_dex2oat_image_fd = false;
     char dex2oat_image_fd[arraysize("--app-image-fd=") + MAX_INT_LEN];
     size_t class_loader_context_size = arraysize("--class-loader-context=") + PKG_PATH_MAX;
+    char target_sdk_version_arg[arraysize("-Xtarget-sdk-version:") + MAX_INT_LEN];
     char class_loader_context_arg[class_loader_context_size];
     if (class_loader_context != nullptr) {
         snprintf(class_loader_context_arg, class_loader_context_size, "--class-loader-context=%s",
@@ -353,6 +354,7 @@
     if (have_dex2oat_Xmx_flag) {
         sprintf(dex2oat_Xmx_arg, "-Xmx%s", dex2oat_Xmx_flag);
     }
+    sprintf(target_sdk_version_arg, "-Xtarget-sdk-version:%d", target_sdk_version);
 
     // Compute compiler filter.
 
@@ -435,7 +437,8 @@
                      + (has_base_dir ? 1 : 0)
                      + (have_dex2oat_large_app_threshold ? 1 : 0)
                      + (disable_cdex ? 1 : 0)
-                     + (generate_minidebug_info ? 1 : 0)];
+                     + (generate_minidebug_info ? 1 : 0)
+                     + (target_sdk_version != 0 ? 2 : 0)];
     int i = 0;
     argv[i++] = dex2oat_bin;
     argv[i++] = zip_fd_arg;
@@ -505,6 +508,10 @@
     if (disable_cdex) {
         argv[i++] = kDisableCompactDexFlag;
     }
+    if (target_sdk_version != 0) {
+        argv[i++] = RUNTIME_ARG;
+        argv[i++] = target_sdk_version_arg;
+    }
 
     // Do not add after dex2oat_flags, they should override others for debugging.
     argv[i] = NULL;
@@ -1767,7 +1774,7 @@
 int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set,
         int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
         const char* volume_uuid, const char* class_loader_context, const char* se_info,
-        bool downgrade) {
+        bool downgrade, int target_sdk_version) {
     CHECK(pkgname != nullptr);
     CHECK(pkgname[0] != 0);
     if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
@@ -1884,7 +1891,8 @@
                     boot_complete,
                     background_job_compile,
                     reference_profile_fd.get(),
-                    class_loader_context);
+                    class_loader_context,
+                    target_sdk_version);
         _exit(68);   /* only get here on exec failure */
     } else {
         int res = wait_child(pid);
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 8d81611..4923a43 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -78,7 +78,7 @@
 int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set,
         int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
         const char* volume_uuid, const char* class_loader_context, const char* se_info,
-        bool downgrade);
+        bool downgrade, int target_sdk_version);
 
 bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir,
         const char *apk_path, const char *instruction_set);
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 8a56894..60ad14b 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -178,6 +178,7 @@
         const char* shared_libraries;
         const char* se_info;
         bool downgrade;
+        int target_sdk_version;
     };
 
     bool ReadSystemProperties() {
@@ -358,6 +359,8 @@
                 return ReadArgumentsV2(argc, argv, true);
             case 3:
                 return ReadArgumentsV3(argc, argv);
+            case 4:
+                return ReadArgumentsV4(argc, argv);
 
             default:
                 LOG(ERROR) << "Unsupported version " << version;
@@ -440,6 +443,10 @@
         // filter, which is not the case during ota.
         package_parameters_.downgrade = false;
 
+        // Set target_sdk_version to 0, ie the platform SDK version. This is
+        // conservative and may force some classes to verify at runtime.
+        package_parameters_.target_sdk_version = 0;
+
         if (param_index != 11) {
             LOG(ERROR) << "Not enough parameters";
             return false;
@@ -523,6 +530,97 @@
             }
         }
 
+        // Set target_sdk_version to 0, ie the platform SDK version. This is
+        // conservative and may force some classes to verify at runtime.
+        package_parameters_.target_sdk_version = 0;
+
+        if (param_index != 12) {
+            LOG(ERROR) << "Not enough parameters";
+            return false;
+        }
+
+        return true;
+    }
+
+    bool ReadArgumentsV4(int argc ATTRIBUTE_UNUSED, char** argv) {
+        size_t dexopt_index = 3;
+
+        // Check for "dexopt".
+        if (argv[dexopt_index] == nullptr) {
+            LOG(ERROR) << "Missing parameters";
+            return false;
+        }
+        if (std::string("dexopt").compare(argv[dexopt_index]) != 0) {
+            LOG(ERROR) << "Expected \"dexopt\"";
+            return false;
+        }
+
+        size_t param_index = 0;
+        for (;; ++param_index) {
+            const char* param = argv[dexopt_index + 1 + param_index];
+            if (param == nullptr) {
+                break;
+            }
+
+            switch (param_index) {
+                case 0:
+                    package_parameters_.apk_path = param;
+                    break;
+
+                case 1:
+                    package_parameters_.uid = atoi(param);
+                    break;
+
+                case 2:
+                    package_parameters_.pkgName = param;
+                    break;
+
+                case 3:
+                    package_parameters_.instruction_set = param;
+                    break;
+
+                case 4:
+                    package_parameters_.dexopt_needed = atoi(param);
+                    break;
+
+                case 5:
+                    package_parameters_.oat_dir = param;
+                    break;
+
+                case 6:
+                    package_parameters_.dexopt_flags = atoi(param);
+                    break;
+
+                case 7:
+                    package_parameters_.compiler_filter = param;
+                    break;
+
+                case 8:
+                    package_parameters_.volume_uuid = ParseNull(param);
+                    break;
+
+                case 9:
+                    package_parameters_.shared_libraries = ParseNull(param);
+                    break;
+
+                case 10:
+                    package_parameters_.se_info = ParseNull(param);
+                    break;
+
+                case 11:
+                    package_parameters_.downgrade = ParseBool(param);
+                    break;
+
+                case 12:
+                    package_parameters_.target_sdk_version = atoi(param);
+                    break;
+
+                default:
+                    LOG(ERROR) << "Too many arguments, got " << param;
+                    return false;
+            }
+        }
+
         if (param_index != 12) {
             LOG(ERROR) << "Not enough parameters";
             return false;
@@ -634,6 +732,10 @@
         // filter, which is not the case during ota.
         package_parameters_.downgrade = false;
 
+        // Set target_sdk_version to 0, ie the platform SDK version. This is
+        // conservative and may force some classes to verify at runtime.
+        package_parameters_.target_sdk_version = 0;
+
         return true;
     }
 
@@ -920,7 +1022,8 @@
                       package_parameters_.volume_uuid,
                       package_parameters_.shared_libraries,
                       package_parameters_.se_info,
-                      package_parameters_.downgrade);
+                      package_parameters_.downgrade,
+                      package_parameters_.target_sdk_version);
     }
 
     int RunPreopt() {
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index eaf0aa1..ff29506 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -258,6 +258,7 @@
         std::unique_ptr<std::string> class_loader_context_ptr(new std::string("&"));
         std::unique_ptr<std::string> se_info_ptr(new std::string(se_info_));
         bool downgrade = false;
+        int32_t target_sdk_version = 0;  // default
 
         binder::Status result = service_->dexopt(path,
                                                  uid,
@@ -270,7 +271,8 @@
                                                  volume_uuid_,
                                                  class_loader_context_ptr,
                                                  se_info_ptr,
-                                                 downgrade);
+                                                 downgrade,
+                                                 target_sdk_version);
         ASSERT_EQ(should_binder_call_succeed, result.isOk());
         int expected_access = should_dex_be_compiled ? 0 : -1;
         std::string odex = GetSecondaryDexArtifact(path, "odex");