diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2020-03-04 23:41:40 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2020-03-04 23:41:40 +0000 |
commit | efbcd6752d9e9f980ae5044b9bbd35fe4b192c52 (patch) | |
tree | 4481739bc76a343fae9027607f34497857d31dcb | |
parent | 35c5908f80f7a09a7d3a74896e3f8d52b3696bdc (diff) | |
parent | 364f2500e536c61a4acb1ac7129a2ef348b684ff (diff) | |
download | base-efbcd6752d9e9f980ae5044b9bbd35fe4b192c52.tar.gz |
Merge "Start process of next activity with top priority in advance"
15 files changed, 171 insertions, 58 deletions
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 1725db046a95..9b59ab453acf 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -29,7 +29,6 @@ import android.content.pm.UserInfo; import android.os.Bundle; import android.os.IBinder; import android.os.TransactionTooLargeException; -import android.view.RemoteAnimationAdapter; import java.util.ArrayList; import java.util.List; @@ -300,7 +299,7 @@ public abstract class ActivityManagerInternal { /** Starts a given process. */ public abstract void startProcess(String processName, ApplicationInfo info, - boolean knownToBeDead, String hostingType, ComponentName hostingName); + boolean knownToBeDead, boolean isTop, String hostingType, ComponentName hostingName); /** Starts up the starting activity process for debugging if needed. * This function needs to be called synchronously from WindowManager context so the caller diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 10b4e5ddcd55..1c0f0f42a5dc 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -525,6 +525,7 @@ public class Process { * @param appDataDir null-ok the data directory of the app. * @param invokeWith null-ok the command to invoke with. * @param packageName null-ok the name of the package this process belongs to. + * @param isTopApp whether the process starts for high priority application. * @param disabledCompatChanges null-ok list of disabled compat changes for the process being * started. * @param zygoteArgs Additional arguments to supply to the zygote process. @@ -545,12 +546,13 @@ public class Process { @Nullable String appDataDir, @Nullable String invokeWith, @Nullable String packageName, + boolean isTopApp, @Nullable long[] disabledCompatChanges, @Nullable String[] zygoteArgs) { return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, packageName, - /*useUsapPool=*/ true, disabledCompatChanges, zygoteArgs); + /*useUsapPool=*/ true, isTopApp, disabledCompatChanges, zygoteArgs); } /** @hide */ @@ -571,7 +573,7 @@ public class Process { return WebViewZygote.getProcess().start(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, packageName, - /*useUsapPool=*/ false, disabledCompatChanges, zygoteArgs); + /*useUsapPool=*/ false, /*isTopApp=*/ false, disabledCompatChanges, zygoteArgs); } /** diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index 016823e1a07d..32df0529a41c 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -309,6 +309,7 @@ public class ZygoteProcess { * @param disabledCompatChanges null-ok list of disabled compat changes for the process being * started. * @param zygoteArgs Additional arguments to supply to the zygote process. + * @param isTopApp Whether the process starts for high priority application. * * @return An object that describes the result of the attempt to start the process. * @throws RuntimeException on fatal start failure @@ -325,6 +326,7 @@ public class ZygoteProcess { @Nullable String invokeWith, @Nullable String packageName, boolean useUsapPool, + boolean isTopApp, @Nullable long[] disabledCompatChanges, @Nullable String[] zygoteArgs) { // TODO (chriswailes): Is there a better place to check this value? @@ -336,7 +338,7 @@ public class ZygoteProcess { return startViaZygote(processClass, niceName, uid, gid, gids, runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false, - packageName, useUsapPool, disabledCompatChanges, zygoteArgs); + packageName, useUsapPool, isTopApp, disabledCompatChanges, zygoteArgs); } catch (ZygoteStartFailedEx ex) { Log.e(LOG_TAG, "Starting VM process through Zygote failed"); @@ -537,6 +539,7 @@ public class ZygoteProcess { * @param startChildZygote Start a sub-zygote. This creates a new zygote process * that has its state cloned from this zygote process. * @param packageName null-ok the name of the package this process belongs to. + * @param isTopApp Whether the process starts for high priority application. * @param disabledCompatChanges a list of disabled compat changes for the process being started. * @param extraArgs Additional arguments to supply to the zygote process. * @return An object that describes the result of the attempt to start the process. @@ -556,6 +559,7 @@ public class ZygoteProcess { boolean startChildZygote, @Nullable String packageName, boolean useUsapPool, + boolean isTopApp, @Nullable long[] disabledCompatChanges, @Nullable String[] extraArgs) throws ZygoteStartFailedEx { @@ -628,6 +632,10 @@ public class ZygoteProcess { argsForZygote.add("--package-name=" + packageName); } + if (isTopApp) { + argsForZygote.add(Zygote.START_AS_TOP_APP_ARG); + } + if (disabledCompatChanges != null && disabledCompatChanges.length > 0) { final StringBuilder sb = new StringBuilder(); sb.append("--disabled-compat-changes="); @@ -1190,7 +1198,7 @@ public class ZygoteProcess { gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo, abi, instructionSet, null /* appDataDir */, null /* invokeWith */, true /* startChildZygote */, null /* packageName */, - false /* useUsapPool */, + false /* useUsapPool */, false /* isTopApp */, null /* disabledCompatChanges */, extraArgs); } catch (ZygoteStartFailedEx ex) { throw new RuntimeException("Starting child-zygote through Zygote failed", ex); diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 5f196a0e4c1c..d047415aacfb 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -164,6 +164,9 @@ public final class Zygote { /** Number of bytes sent to the Zygote over USAP pipes or the pool event FD */ public static final int USAP_MANAGEMENT_MESSAGE_BYTES = 8; + /** Make the new process have top application priority. */ + public static final String START_AS_TOP_APP_ARG = "--is-top-app"; + /** * An extraArg passed when a zygote process is forking a child-zygote, specifying a name * in the abstract socket namespace. This socket name is what the new child zygote @@ -266,18 +269,20 @@ public final class Zygote { * new zygote process. * @param instructionSet null-ok the instruction set to use. * @param appDataDir null-ok the data directory of the app. + * @param isTopApp true if the process is for top (high priority) application. * * @return 0 if this is the child, pid of the child * if this is the parent, or -1 on error. */ public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, - int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir) { + int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, + boolean isTopApp) { ZygoteHooks.preFork(); int pid = nativeForkAndSpecialize( uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, - fdsToIgnore, startChildZygote, instructionSet, appDataDir); + fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp); if (pid == 0) { // Note that this event ends at the end of handleChildProc, Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork"); @@ -293,7 +298,7 @@ public final class Zygote { private static native int nativeForkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, - String appDataDir); + String appDataDir, boolean isTopApp); /** * Specialize an unspecialized app process. The current VM must have been started @@ -315,12 +320,13 @@ public final class Zygote { * new zygote process. * @param instructionSet null-ok The instruction set to use. * @param appDataDir null-ok The data directory of the app. + * @param isTopApp True if the process is for top (high priority) application. */ public static void specializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, - boolean startChildZygote, String instructionSet, String appDataDir) { + boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp) { nativeSpecializeAppProcess(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, - niceName, startChildZygote, instructionSet, appDataDir); + niceName, startChildZygote, instructionSet, appDataDir, isTopApp); // Note that this event ends at the end of handleChildProc. Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork"); @@ -339,7 +345,7 @@ public final class Zygote { private static native void nativeSpecializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, - boolean startChildZygote, String instructionSet, String appDataDir); + boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp); /** * Called to do any initialization before starting an application. @@ -662,7 +668,7 @@ public final class Zygote { specializeAppProcess(args.mUid, args.mGid, args.mGids, args.mRuntimeFlags, rlimits, args.mMountExternal, args.mSeInfo, args.mNiceName, args.mStartChildZygote, - args.mInstructionSet, args.mAppDataDir); + args.mInstructionSet, args.mAppDataDir, args.mIsTopApp); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java index 3915ba273dfa..4442cf0c8208 100644 --- a/core/java/com/android/internal/os/ZygoteArguments.java +++ b/core/java/com/android/internal/os/ZygoteArguments.java @@ -210,6 +210,11 @@ class ZygoteArguments { int mHiddenApiAccessStatslogSampleRate = -1; /** + * @see Zygote#START_AS_TOP_APP_ARG + */ + boolean mIsTopApp; + + /** * A set of disabled app compatibility changes for the running app. From * --disabled-compat-changes. */ @@ -422,6 +427,8 @@ class ZygoteArguments { mUsapPoolStatusSpecified = true; mUsapPoolEnabled = Boolean.parseBoolean(arg.substring(arg.indexOf('=') + 1)); expectRuntimeArgs = false; + } else if (arg.startsWith(Zygote.START_AS_TOP_APP_ARG)) { + mIsTopApp = true; } else if (arg.startsWith("--disabled-compat-changes=")) { if (mDisabledCompatChanges != null) { throw new IllegalArgumentException("Duplicate arg specified"); diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index 24ea59ae6ac0..8f1f4cc1077c 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -257,7 +257,7 @@ class ZygoteConnection { pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids, parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote, - parsedArgs.mInstructionSet, parsedArgs.mAppDataDir); + parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mIsTopApp); try { if (pid == 0) { diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index ea58cbd99179..0ce61de270f8 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -663,11 +663,25 @@ static void SetCapabilities(uint64_t permitted, uint64_t effective, uint64_t inh } } -static void SetSchedulerPolicy(fail_fn_t fail_fn) { - errno = -set_sched_policy(0, SP_DEFAULT); +static void SetSchedulerPolicy(fail_fn_t fail_fn, bool is_top_app) { + SchedPolicy policy = is_top_app ? SP_TOP_APP : SP_DEFAULT; + + if (is_top_app && cpusets_enabled()) { + errno = -set_cpuset_policy(0, policy); + if (errno != 0) { + fail_fn(CREATE_ERROR("set_cpuset_policy(0, %d) failed: %s", policy, strerror(errno))); + } + } + + errno = -set_sched_policy(0, policy); if (errno != 0) { - fail_fn(CREATE_ERROR("set_sched_policy(0, SP_DEFAULT) failed: %s", strerror(errno))); + fail_fn(CREATE_ERROR("set_sched_policy(0, %d) failed: %s", policy, strerror(errno))); } + + // We are going to lose the permission to set scheduler policy during the specialization, so make + // sure that we don't cache the fd of cgroup path that may cause sepolicy violation by writing + // value to the cached fd directly when creating new thread. + DropTaskProfilesResourceCaching(); } static int UnmountTree(const char* path) { @@ -1055,7 +1069,7 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, jint mount_external, jstring managed_se_info, jstring managed_nice_name, bool is_system_server, bool is_child_zygote, jstring managed_instruction_set, - jstring managed_app_data_dir) { + jstring managed_app_data_dir, bool is_top_app) { const char* process_name = is_system_server ? "system_server" : "zygote"; auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1); auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1); @@ -1118,6 +1132,9 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, // privileged syscalls used below still need to be accessible in app process. SetUpSeccompFilter(uid, is_child_zygote); + // Must be called before losing the permission to set scheduler policy. + SetSchedulerPolicy(fail_fn, is_top_app); + if (setresuid(uid, uid, uid) == -1) { fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno))); } @@ -1176,8 +1193,6 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities, fail_fn); - SetSchedulerPolicy(fail_fn); - __android_log_close(); stats_log_close(); @@ -1446,7 +1461,7 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote, - jstring instruction_set, jstring app_data_dir) { + jstring instruction_set, jstring app_data_dir, jboolean is_top_app) { jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote); if (UNLIKELY(managed_fds_to_close == nullptr)) { @@ -1482,7 +1497,8 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities, mount_external, se_info, nice_name, false, - is_child_zygote == JNI_TRUE, instruction_set, app_data_dir); + is_child_zygote == JNI_TRUE, instruction_set, app_data_dir, + is_top_app == JNI_TRUE); } return pid; } @@ -1514,7 +1530,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities, effective_capabilities, MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true, - false, nullptr, nullptr); + false, nullptr, nullptr, /* is_top_app= */ false); } else if (pid > 0) { // The zygote process checks whether the child process has died or not. ALOGI("System server process %d has been created", pid); @@ -1637,18 +1653,20 @@ static void com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter( * @param is_child_zygote If the process is to become a WebViewZygote * @param instruction_set The instruction set expected/requested by the new application * @param app_data_dir Path to the application's data directory + * @param is_top_app If the process is for top (high priority) application */ static void com_android_internal_os_Zygote_nativeSpecializeAppProcess( JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint runtime_flags, jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, - jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir) { + jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app) { jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote); SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities, mount_external, se_info, nice_name, false, - is_child_zygote == JNI_TRUE, instruction_set, app_data_dir); + is_child_zygote == JNI_TRUE, instruction_set, app_data_dir, + is_top_app == JNI_TRUE); } /** @@ -1845,7 +1863,7 @@ static jint com_android_internal_os_Zygote_nativeParseSigChld(JNIEnv* env, jclas static const JNINativeMethod gMethods[] = { { "nativeForkAndSpecialize", - "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I", + "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Z)I", (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize }, { "nativeForkSystemServer", "(II[II[[IJJ)I", (void *) com_android_internal_os_Zygote_nativeForkSystemServer }, @@ -1858,7 +1876,7 @@ static const JNINativeMethod gMethods[] = { { "nativeForkUsap", "(II[IZ)I", (void *) com_android_internal_os_Zygote_nativeForkUsap }, { "nativeSpecializeAppProcess", - "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V", + "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z)V", (void *) com_android_internal_os_Zygote_nativeSpecializeAppProcess }, { "nativeInitNativeState", "(Z)V", (void *) com_android_internal_os_Zygote_nativeInitNativeState }, diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 53d23842ec79..f19dc7a11eaa 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -4875,7 +4875,7 @@ public class ActivityManagerService extends IActivityManager.Stub EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName); app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ; - app.setCurrentSchedulingGroup(app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT); + mOomAdjuster.setAttachingSchedGroupLocked(app); app.forcingToImportant = null; updateProcessForegroundLocked(app, false, 0, false); app.hasShownUi = false; @@ -18473,16 +18473,19 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public void startProcess(String processName, ApplicationInfo info, - boolean knownToBeDead, String hostingType, ComponentName hostingName) { + public void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead, + boolean isTop, String hostingType, ComponentName hostingName) { try { if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "startProcess:" + processName); } synchronized (ActivityManagerService.this) { + // If the process is known as top app, set a hint so when the process is + // started, the top priority can be applied immediately to avoid cpu being + // preempted by other processes before attaching the process of top app. startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */, - new HostingRecord(hostingType, hostingName), + new HostingRecord(hostingType, hostingName, isTop), false /* allowWhileBooting */, false /* isolated */, true /* keepIfLarge */); } diff --git a/services/core/java/com/android/server/am/HostingRecord.java b/services/core/java/com/android/server/am/HostingRecord.java index 784dde1e98df..6bb5def26b9d 100644 --- a/services/core/java/com/android/server/am/HostingRecord.java +++ b/services/core/java/com/android/server/am/HostingRecord.java @@ -41,6 +41,8 @@ import android.content.ComponentName; * {@link android.content.Context#BIND_EXTERNAL_SERVICE} service. In that case, the packageName * and uid in the ApplicationInfo will be set to those of the caller, not of the defining package. * + * {@code mIsTopApp} will be passed to {@link android.os.Process#start}. So Zygote will initialize + * the process with high priority. */ public final class HostingRecord { @@ -53,15 +55,22 @@ public final class HostingRecord { private final int mHostingZygote; private final String mDefiningPackageName; private final int mDefiningUid; + private final boolean mIsTopApp; public HostingRecord(String hostingType) { - this(hostingType, null, REGULAR_ZYGOTE, null, -1); + this(hostingType, null /* hostingName */, REGULAR_ZYGOTE, null /* definingPackageName */, + -1 /* mDefiningUid */, false /* isTopApp */); } public HostingRecord(String hostingType, ComponentName hostingName) { this(hostingType, hostingName, REGULAR_ZYGOTE); } + public HostingRecord(String hostingType, ComponentName hostingName, boolean isTopApp) { + this(hostingType, hostingName.toShortString(), REGULAR_ZYGOTE, + null /* definingPackageName */, -1 /* mDefiningUid */, isTopApp /* isTopApp */); + } + public HostingRecord(String hostingType, String hostingName) { this(hostingType, hostingName, REGULAR_ZYGOTE); } @@ -71,16 +80,18 @@ public final class HostingRecord { } private HostingRecord(String hostingType, String hostingName, int hostingZygote) { - this(hostingType, hostingName, hostingZygote, null, -1); + this(hostingType, hostingName, hostingZygote, null /* definingPackageName */, + -1 /* mDefiningUid */, false /* isTopApp */); } private HostingRecord(String hostingType, String hostingName, int hostingZygote, - String definingPackageName, int definingUid) { + String definingPackageName, int definingUid, boolean isTopApp) { mHostingType = hostingType; mHostingName = hostingName; mHostingZygote = hostingZygote; mDefiningPackageName = definingPackageName; mDefiningUid = definingUid; + mIsTopApp = isTopApp; } public String getType() { @@ -91,6 +102,10 @@ public final class HostingRecord { return mHostingName; } + public boolean isTopApp() { + return mIsTopApp; + } + /** * Returns the UID of the package defining the component we want to start. Only valid * when {@link #usesAppZygote()} returns true. @@ -130,7 +145,7 @@ public final class HostingRecord { public static HostingRecord byAppZygote(ComponentName hostingName, String definingPackageName, int definingUid) { return new HostingRecord("", hostingName.toShortString(), APP_ZYGOTE, - definingPackageName, definingUid); + definingPackageName, definingUid, false /* isTopApp */); } /** diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index dbf8acf74dbd..80e22e529ba9 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -178,9 +178,12 @@ public final class OomAdjuster { adjusterThread.start(); Process.setThreadGroupAndCpuset(adjusterThread.getThreadId(), THREAD_GROUP_TOP_APP); mProcessGroupHandler = new Handler(adjusterThread.getLooper(), msg -> { - Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setProcessGroup"); final int pid = msg.arg1; final int group = msg.arg2; + if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) { + Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setProcessGroup " + + msg.obj + " to " + group); + } try { setProcessGroup(pid, group); } catch (Exception e) { @@ -1758,7 +1761,7 @@ public final class OomAdjuster { break; } mProcessGroupHandler.sendMessage(mProcessGroupHandler.obtainMessage( - 0 /* unused */, app.pid, processGroup)); + 0 /* unused */, app.pid, processGroup, app.processName)); try { if (curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) { // do nothing if we already switched to RT @@ -1949,6 +1952,38 @@ public final class OomAdjuster { return success; } + @GuardedBy("mService") + void setAttachingSchedGroupLocked(ProcessRecord app) { + int initialSchedGroup = ProcessList.SCHED_GROUP_DEFAULT; + // If the process has been marked as foreground via Zygote.START_FLAG_USE_TOP_APP_PRIORITY, + // then verify that the top priority is actually is applied. + if (app.hasForegroundActivities()) { + String fallbackReason = null; + try { + // The priority must be the same as how does {@link #applyOomAdjLocked} set for + // {@link ProcessList.SCHED_GROUP_TOP_APP}. We don't check render thread because it + // is not ready when attaching. + if (Process.getProcessGroup(app.pid) == THREAD_GROUP_TOP_APP) { + app.getWindowProcessController().onTopProcChanged(); + setThreadPriority(app.pid, TOP_APP_PRIORITY_BOOST); + } else { + fallbackReason = "not expected top priority"; + } + } catch (Exception e) { + fallbackReason = e.toString(); + } + if (fallbackReason == null) { + initialSchedGroup = ProcessList.SCHED_GROUP_TOP_APP; + } else { + // The real scheduling group will depend on if there is any component of the process + // did something during attaching. + Slog.w(TAG, "Fallback pre-set sched group to default: " + fallbackReason); + } + } + + app.setCurrentSchedulingGroup(app.setSchedGroup = initialSchedGroup); + } + // ONLY used for unit testing in OomAdjusterTests.java @VisibleForTesting void maybeUpdateUsageStats(ProcessRecord app, long nowElapsed) { diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 8520cb7c30b8..3996ae2172b4 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -51,7 +51,6 @@ import android.app.ActivityThread; import android.app.AppGlobals; import android.app.AppProtoEnums; import android.app.IApplicationThread; -import android.app.IUidObserver; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; import android.content.ComponentName; @@ -1899,6 +1898,14 @@ public final class ProcessList { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " + app.processName); checkSlow(startTime, "startProcess: asking zygote to start proc"); + final boolean isTopApp = hostingRecord.isTopApp(); + if (isTopApp) { + // Use has-foreground-activities as a temporary hint so the current scheduling + // group won't be lost when the process is attaching. The actual state will be + // refreshed when computing oom-adj. + app.setHasForegroundActivities(true); + } + final Process.ProcessStartResult startResult; if (hostingRecord.usesWebviewZygote()) { startResult = startWebView(entryPoint, @@ -1913,13 +1920,13 @@ public final class ProcessList { app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, app.info.dataDir, null, app.info.packageName, - /*useUsapPool=*/ false, app.mDisabledCompatChanges, + /*useUsapPool=*/ false, isTopApp, app.mDisabledCompatChanges, new String[]{PROC_START_SEQ_IDENT + app.startSeq}); } else { startResult = Process.start(entryPoint, app.processName, uid, uid, gids, runtimeFlags, mountExternal, app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet, - app.info.dataDir, invokeWith, app.info.packageName, + app.info.dataDir, invokeWith, app.info.packageName, isTopApp, app.mDisabledCompatChanges, new String[]{PROC_START_SEQ_IDENT + app.startSeq}); } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 1d8f059a7e75..500cc38f8b66 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -3551,7 +3551,7 @@ final class ActivityRecord extends ConfigurationContainer { mStackSupervisor.scheduleRestartTimeout(this); } - private boolean isProcessRunning() { + boolean isProcessRunning() { WindowProcessController proc = app; if (proc == null) { proc = mAtmService.mProcessNames.get(processName, info.applicationInfo.uid); diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 242139cd2da7..848971d3b044 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -2743,7 +2743,7 @@ class ActivityStack extends ConfigurationContainer { final boolean resumeWhilePausing = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0 && !lastResumedCanPip; - boolean pausing = getDisplay().pauseBackStacks(userLeaving, next, false); + boolean pausing = display.pauseBackStacks(userLeaving, next, false); if (mResumedActivity != null) { if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Pausing " + mResumedActivity); @@ -2759,6 +2759,13 @@ class ActivityStack extends ConfigurationContainer { if (next.attachedToProcess()) { next.app.updateProcessInfo(false /* updateServiceConnectionActivities */, true /* activityChange */, false /* updateOomAdj */); + } else if (!next.isProcessRunning()) { + // Since the start-process is asynchronous, if we already know the process of next + // activity isn't running, we can start the process earlier to save the time to wait + // for the current activity to be paused. + final boolean isTop = this == display.getFocusedStack(); + mService.startProcessAsync(next, false /* knownToBeDead */, isTop, + isTop ? "pre-top-activity" : "pre-activity"); } if (lastResumed != null) { lastResumed.setWillCloseOrEnterPip(true); @@ -2827,7 +2834,7 @@ class ActivityStack extends ConfigurationContainer { // that the previous one will be hidden soon. This way it can know // to ignore it when computing the desired screen orientation. boolean anim = true; - final DisplayContent dc = getDisplay().mDisplayContent; + final DisplayContent dc = display.mDisplayContent; if (prev != null) { if (prev.finishing) { if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, @@ -2984,7 +2991,7 @@ class ActivityStack extends ConfigurationContainer { next.clearOptionsLocked(); transaction.setLifecycleStateRequest( ResumeActivityItem.obtain(next.app.getReportedProcState(), - getDisplay().mDisplayContent.isNextTransitionForward())); + dc.isNextTransitionForward())); mService.getLifecycleManager().scheduleTransaction(transaction); if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed " diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 8f573c0e7234..69bd84b1267b 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -995,20 +995,8 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { r.notifyUnknownVisibilityLaunched(); } - try { - if (Trace.isTagEnabled(TRACE_TAG_ACTIVITY_MANAGER)) { - Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "dispatchingStartProcess:" - + r.processName); - } - // Post message to start process to avoid possible deadlock of calling into AMS with the - // ATMS lock held. - final Message msg = PooledLambda.obtainMessage( - ActivityManagerInternal::startProcess, mService.mAmInternal, r.processName, - r.info.applicationInfo, knownToBeDead, "activity", r.intent.getComponent()); - mService.mH.sendMessage(msg); - } finally { - Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); - } + final boolean isTop = andResume && r.isTopRunningActivity(); + mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity"); } boolean checkStartAnyActivityPermission(Intent intent, ActivityInfo aInfo, String resultWho, diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 223205377bb9..c0fd24c39908 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -5653,6 +5653,24 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mH.sendMessage(m); } + void startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop, + String hostingType) { + try { + if (Trace.isTagEnabled(TRACE_TAG_ACTIVITY_MANAGER)) { + Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "dispatchingStartProcess:" + + activity.processName); + } + // Post message to start process to avoid possible deadlock of calling into AMS with the + // ATMS lock held. + final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess, + mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead, + isTop, hostingType, activity.intent.getComponent()); + mH.sendMessage(m); + } finally { + Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); + } + } + void setBooting(boolean booting) { mAmInternal.setBooting(booting); } |