summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Riddle Hsu <riddlehsu@google.com> 2019-04-12 20:42:05 +0800
committer Riddle Hsu <riddlehsu@google.com> 2019-04-15 14:05:51 +0800
commit50e34009311c849662f7f9fe571ca1e9d4d541b0 (patch)
tree71eb52ccf7226a873a272a948b96379c22103197
parent4e8e3b0204072a38026ce3955e77428e4dacb646 (diff)
Defer top process state for VM
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
-rw-r--r--core/java/android/app/ActivityThread.java122
-rw-r--r--core/java/android/app/ClientTransactionHandler.java2
-rw-r--r--core/java/android/app/servertransaction/LaunchActivityItem.java7
3 files changed, 89 insertions, 42 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 143361f721d1..aa35a6feb5ff 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -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,
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index 9dc8b45a71dc..d308adc52e15 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -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.
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index db22f8d1de87..cdf5d4912ad5 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -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