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;
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) {
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.
// 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.
*/
// 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
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);
}
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
}
}
- @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
if (stopProfiling) {
mProfiler.stopProfiling();
}
+ applyPendingProcessState();
return false;
}
}
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,