OSDN Git Service

Defer top process state for VM
authorRiddle Hsu <riddlehsu@google.com>
Fri, 12 Apr 2019 12:42:05 +0000 (20:42 +0800)
committerRiddle Hsu <riddlehsu@google.com>
Mon, 15 Apr 2019 06:05:51 +0000 (14:05 +0800)
The top state will make JIT compilation easier to be triggered.
To reduce the impact of startup time, if there is launching activity,
the top state will be deferred to apply until idle or 1s timeout.
The cold launch time of Contacts, Phone, Calculator are reduced ~15ms.

Test: AppLaunchTest
Bug: 123043091
Change-Id: I8a235e18ea6b508c9aa192445c9ea22d9d12f177

core/java/android/app/ActivityThread.java
core/java/android/app/ClientTransactionHandler.java
core/java/android/app/servertransaction/LaunchActivityItem.java

index 143361f..aa35a6f 100644 (file)
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
 import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE;
 import static android.app.servertransaction.ActivityLifecycleItem.ON_DESTROY;
 import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
@@ -193,6 +194,7 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.TimeZone;
 import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicInteger;
 
 final class RemoteServiceException extends AndroidRuntimeException {
     public RemoteServiceException(String msg) {
@@ -225,6 +227,11 @@ public final class ActivityThread extends ClientTransactionHandler {
     public static final boolean DEBUG_ORDER = false;
     private static final long MIN_TIME_BETWEEN_GCS = 5*1000;
     /**
+     * If the activity doesn't become idle in time, the timeout will ensure to apply the pending top
+     * process state.
+     */
+    private static final long PENDING_TOP_PROCESS_STATE_TIMEOUT = 1000;
+    /**
      * The delay to release the provider when it has no more references. It reduces the number of
      * transactions for acquiring and releasing provider if the client accesses the provider
      * frequently in a short time.
@@ -242,6 +249,11 @@ public final class ActivityThread extends ClientTransactionHandler {
     // Whether to invoke an activity callback after delivering new configuration.
     private static final boolean REPORT_TO_ACTIVITY = true;
 
+    /** Use foreground GC policy (less pause time) and higher JIT weight. */
+    private static final int VM_PROCESS_STATE_JANK_PERCEPTIBLE = 0;
+    /** Use background GC policy and default JIT threshold. */
+    private static final int VM_PROCESS_STATE_JANK_IMPERCEPTIBLE = 1;
+
     /**
      * Denotes an invalid sequence number corresponding to a process state change.
      */
@@ -296,6 +308,11 @@ public final class ActivityThread extends ClientTransactionHandler {
     // Number of activities that are currently visible on-screen.
     @UnsupportedAppUsage
     int mNumVisibleActivities = 0;
+    private final AtomicInteger mNumLaunchingActivities = new AtomicInteger();
+    @GuardedBy("mAppThread")
+    private int mLastProcessState = PROCESS_STATE_UNKNOWN;
+    @GuardedBy("mAppThread")
+    private int mPendingProcessState = PROCESS_STATE_UNKNOWN;
     ArrayList<WeakReference<AssistStructure>> mLastAssistStructures = new ArrayList<>();
     private int mLastSessionId;
     @UnsupportedAppUsage
@@ -873,17 +890,6 @@ public final class ActivityThread extends ClientTransactionHandler {
     private class ApplicationThread extends IApplicationThread.Stub {
         private static final String DB_INFO_FORMAT = "  %8s %8s %14s %14s  %s";
 
-        private int mLastProcessState = -1;
-
-        private void updatePendingConfiguration(Configuration config) {
-            synchronized (mResourcesManager) {
-                if (mPendingConfiguration == null ||
-                        mPendingConfiguration.isOtherSeqNewer(config)) {
-                    mPendingConfiguration = config;
-                }
-            }
-        }
-
         public final void scheduleSleeping(IBinder token, boolean sleeping) {
             sendMessage(H.SLEEPING, token, sleeping ? 1 : 0);
         }
@@ -1560,27 +1566,6 @@ public final class ActivityThread extends ClientTransactionHandler {
             updateProcessState(state, true);
         }
 
-        public void updateProcessState(int processState, boolean fromIpc) {
-            synchronized (this) {
-                if (mLastProcessState != processState) {
-                    mLastProcessState = processState;
-                    // Update Dalvik state based on ActivityManager.PROCESS_STATE_* constants.
-                    final int DALVIK_PROCESS_STATE_JANK_PERCEPTIBLE = 0;
-                    final int DALVIK_PROCESS_STATE_JANK_IMPERCEPTIBLE = 1;
-                    int dalvikProcessState = DALVIK_PROCESS_STATE_JANK_IMPERCEPTIBLE;
-                    // TODO: Tune this since things like gmail sync are important background but not jank perceptible.
-                    if (processState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
-                        dalvikProcessState = DALVIK_PROCESS_STATE_JANK_PERCEPTIBLE;
-                    }
-                    VMRuntime.getRuntime().updateProcessState(dalvikProcessState);
-                    if (false) {
-                        Slog.i(TAG, "******************* PROCESS STATE CHANGED TO: " + processState
-                                + (fromIpc ? " (from ipc": ""));
-                    }
-                }
-            }
-        }
-
         /**
          * Updates {@link #mNetworkBlockSeq}. This is used by ActivityManagerService to inform
          * the main thread that it needs to wait for the network rules to get updated before
@@ -1661,16 +1646,6 @@ public final class ActivityThread extends ClientTransactionHandler {
         }
     }
 
-    @Override
-    public void updatePendingConfiguration(Configuration config) {
-        mAppThread.updatePendingConfiguration(config);
-    }
-
-    @Override
-    public void updateProcessState(int processState, boolean fromIpc) {
-        mAppThread.updateProcessState(processState, fromIpc);
-    }
-
     class H extends Handler {
         public static final int BIND_APPLICATION        = 110;
         @UnsupportedAppUsage
@@ -1995,6 +1970,7 @@ public final class ActivityThread extends ClientTransactionHandler {
             if (stopProfiling) {
                 mProfiler.stopProfiling();
             }
+            applyPendingProcessState();
             return false;
         }
     }
@@ -2939,6 +2915,68 @@ public final class ActivityThread extends ClientTransactionHandler {
         return mActivities.get(token);
     }
 
+    @Override
+    public void updatePendingConfiguration(Configuration config) {
+        synchronized (mResourcesManager) {
+            if (mPendingConfiguration == null || mPendingConfiguration.isOtherSeqNewer(config)) {
+                mPendingConfiguration = config;
+            }
+        }
+    }
+
+    @Override
+    public void updateProcessState(int processState, boolean fromIpc) {
+        synchronized (mAppThread) {
+            if (mLastProcessState == processState) {
+                return;
+            }
+            mLastProcessState = processState;
+            // Defer the top state for VM to avoid aggressive JIT compilation affecting activity
+            // launch time.
+            if (processState == ActivityManager.PROCESS_STATE_TOP
+                    && mNumLaunchingActivities.get() > 0) {
+                mPendingProcessState = processState;
+                mH.postDelayed(this::applyPendingProcessState, PENDING_TOP_PROCESS_STATE_TIMEOUT);
+            } else {
+                mPendingProcessState = PROCESS_STATE_UNKNOWN;
+                updateVmProcessState(processState);
+            }
+            if (localLOGV) {
+                Slog.i(TAG, "******************* PROCESS STATE CHANGED TO: " + processState
+                        + (fromIpc ? " (from ipc" : ""));
+            }
+        }
+    }
+
+    /** Update VM state based on ActivityManager.PROCESS_STATE_* constants. */
+    private void updateVmProcessState(int processState) {
+        // TODO: Tune this since things like gmail sync are important background but not jank
+        // perceptible.
+        final int state = processState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+                ? VM_PROCESS_STATE_JANK_PERCEPTIBLE
+                : VM_PROCESS_STATE_JANK_IMPERCEPTIBLE;
+        VMRuntime.getRuntime().updateProcessState(state);
+    }
+
+    private void applyPendingProcessState() {
+        synchronized (mAppThread) {
+            if (mPendingProcessState == PROCESS_STATE_UNKNOWN) {
+                return;
+            }
+            final int pendingState = mPendingProcessState;
+            mPendingProcessState = PROCESS_STATE_UNKNOWN;
+            // Only apply the pending state if the last state doesn't change.
+            if (pendingState == mLastProcessState) {
+                updateVmProcessState(pendingState);
+            }
+        }
+    }
+
+    @Override
+    public void countLaunchingActivities(int num) {
+        mNumLaunchingActivities.getAndAdd(num);
+    }
+
     @UnsupportedAppUsage
     public final void sendActivityResult(
             IBinder token, String id, int requestCode,
index 9dc8b45..d308adc 100644 (file)
@@ -78,6 +78,8 @@ public abstract class ClientTransactionHandler {
     /** Set current process state. */
     public abstract void updateProcessState(int processState, boolean fromIpc);
 
+    /** Count how many activities are launching. */
+    public abstract void countLaunchingActivities(int num);
 
     // Execute phase related logic and handlers. Methods here execute actual lifecycle transactions
     // and deliver callbacks.
index db22f8d..cdf5d49 100644 (file)
@@ -66,6 +66,7 @@ public class LaunchActivityItem extends ClientTransactionItem {
 
     @Override
     public void preExecute(ClientTransactionHandler client, IBinder token) {
+        client.countLaunchingActivities(1);
         client.updateProcessState(mProcState, false);
         client.updatePendingConfiguration(mCurConfig);
     }
@@ -82,6 +83,12 @@ public class LaunchActivityItem extends ClientTransactionItem {
         Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
 
+    @Override
+    public void postExecute(ClientTransactionHandler client, IBinder token,
+            PendingTransactionActions pendingActions) {
+        client.countLaunchingActivities(-1);
+    }
+
 
     // ObjectPoolItem implementation