Installd: Allow different behavior before bootcomplete

Check dev.bootcomplete in dex2oat(). Use the information for
two changes.

Only switch to the background when we're post bootcomplete.
This will ensure better utilization after upgrades.

Add a second dex2oat-threads property that is used pre
bootcomplete. A separation of these phases allows using less
cores when the device is up, freeing up resources for other
purposes, e.g., avoid jank. The precedence during boot is the
boot property, or the image property if the former doesn't
exist, or the default property as a fallback.

Bug: 23898216
Bug: 24004256
Change-Id: I5063f3fc4b437cbe88c4e94584e01c1c78eccc4d
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index 7090b36..769cd34 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -746,7 +746,7 @@
 
 static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
     const char* output_file_name, int swap_fd, const char *pkgname, const char *instruction_set,
-    bool vm_safe_mode, bool debuggable)
+    bool vm_safe_mode, bool debuggable, bool post_bootcomplete)
 {
     static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
 
@@ -770,8 +770,24 @@
                                                           dex2oat_compiler_filter_flag, NULL) > 0;
 
     char dex2oat_threads_buf[PROPERTY_VALUE_MAX];
-    bool have_dex2oat_threads_flag = property_get("dalvik.vm.dex2oat-threads", dex2oat_threads_buf,
-                                                  NULL) > 0;
+    bool have_dex2oat_threads_flag = false;
+    if (!post_bootcomplete) {
+        have_dex2oat_threads_flag = property_get("dalvik.vm.boot-dex2oat-threads",
+                                                 dex2oat_threads_buf,
+                                                 NULL) > 0;
+        // If there's no boot property, fall back to the image property.
+        if (!have_dex2oat_threads_flag) {
+            have_dex2oat_threads_flag = property_get("dalvik.vm.image-dex2oat-threads",
+                                                     dex2oat_threads_buf,
+                                                     NULL) > 0;
+        }
+        // If there's neither, fall back to the default property.
+    }
+    if (!have_dex2oat_threads_flag) {
+        have_dex2oat_threads_flag = property_get("dalvik.vm.dex2oat-threads",
+                                                 dex2oat_threads_buf,
+                                                 NULL) > 0;
+    }
     char dex2oat_threads_arg[PROPERTY_VALUE_MAX + 2];
     if (have_dex2oat_threads_flag) {
         sprintf(dex2oat_threads_arg, "-j%s", dex2oat_threads_buf);
@@ -1065,6 +1081,27 @@
     return true;
 }
 
+static bool IsPostBootComplete() {
+    char dev_bootcomplete_prop_buf[PROPERTY_VALUE_MAX];
+    if (property_get("dev.bootcomplete", dev_bootcomplete_prop_buf, "0") > 0) {
+        return (strcmp(dev_bootcomplete_prop_buf, "1") == 0);
+    }
+    return false;
+}
+
+static void SetDex2OatAndPatchOatScheduling(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);
+        }
+        if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
+            ALOGE("setpriority failed: %s\n", strerror(errno));
+            exit(71);
+        }
+    }
+}
+
 int dexopt(const char *apk_path, uid_t uid, bool is_public,
            const char *pkgname, const char *instruction_set, int dexopt_needed,
            bool vm_safe_mode, bool debuggable, const char* oat_dir)
@@ -1076,6 +1113,7 @@
     const char *input_file;
     char in_odex_path[PKG_PATH_MAX];
     int res, input_fd=-1, out_fd=-1, swap_fd=-1;
+    bool post_bootcomplete = IsPostBootComplete();
 
     // Early best-effort check whether we can fit the the path into our buffers.
     // Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run
@@ -1198,14 +1236,7 @@
             ALOGE("capset failed: %s\n", strerror(errno));
             exit(66);
         }
-        if (set_sched_policy(0, SP_BACKGROUND) < 0) {
-            ALOGE("set_sched_policy failed: %s\n", strerror(errno));
-            exit(70);
-        }
-        if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
-            ALOGE("setpriority failed: %s\n", strerror(errno));
-            exit(71);
-        }
+        SetDex2OatAndPatchOatScheduling(post_bootcomplete);
         if (flock(out_fd, LOCK_EX | LOCK_NB) != 0) {
             ALOGE("flock(%s) failed: %s\n", out_path, strerror(errno));
             exit(67);
@@ -1222,7 +1253,7 @@
                 input_file_name++;
             }
             run_dex2oat(input_fd, out_fd, input_file_name, out_path, swap_fd, pkgname,
-                        instruction_set, vm_safe_mode, debuggable);
+                        instruction_set, vm_safe_mode, debuggable, post_bootcomplete);
         } else {
             ALOGE("Invalid dexopt needed: %d\n", dexopt_needed);
             exit(73);