diff options
8 files changed, 235 insertions, 36 deletions
diff --git a/core/proto/android/os/processstarttime.proto b/core/proto/android/os/processstarttime.proto new file mode 100644 index 000000000000..d0f8baee7da2 --- /dev/null +++ b/core/proto/android/os/processstarttime.proto @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; +package android.os; + +option java_multiple_files = true; + +// This message is used for statsd logging and should be kept in sync with +// frameworks/proto_logging/stats/atoms.proto +/** + * Logs information about process start time. + * + * Logged from: + * frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java + */ +message ProcessStartTime { + // The uid of the ProcessRecord. + optional int32 uid = 1; + + // The process pid. + optional int32 pid = 2; + + // The process name. + // Usually package name, "system" for system server. + // Provided by ActivityManagerService. + optional string process_name = 3; + + enum StartType { + UNKNOWN = 0; + WARM = 1; + HOT = 2; + COLD = 3; + } + + // The start type. + optional StartType type = 4; + + // The elapsed realtime at the start of the process. + optional int64 process_start_time_millis = 5; + + // Number of milliseconds it takes to reach bind application. + optional int32 bind_application_delay_millis = 6; + + // Number of milliseconds it takes to finish start of the process. + optional int32 process_start_delay_millis = 7; + + // hostingType field in ProcessRecord, the component type such as "activity", + // "service", "content provider", "broadcast" or other strings. + optional string hosting_type = 8; + + // hostingNameStr field in ProcessRecord. The component class name that runs + // in this process. + optional string hosting_name = 9; + + // Broadcast action name. + optional string broadcast_action_name = 10; + + enum HostingTypeId { + HOSTING_TYPE_UNKNOWN = 0; + HOSTING_TYPE_ACTIVITY = 1; + HOSTING_TYPE_ADDED_APPLICATION = 2; + HOSTING_TYPE_BACKUP = 3; + HOSTING_TYPE_BROADCAST = 4; + HOSTING_TYPE_CONTENT_PROVIDER = 5; + HOSTING_TYPE_LINK_FAIL = 6; + HOSTING_TYPE_ON_HOLD = 7; + HOSTING_TYPE_NEXT_ACTIVITY = 8; + HOSTING_TYPE_NEXT_TOP_ACTIVITY = 9; + HOSTING_TYPE_RESTART = 10; + HOSTING_TYPE_SERVICE = 11; + HOSTING_TYPE_SYSTEM = 12; + HOSTING_TYPE_TOP_ACTIVITY = 13; + HOSTING_TYPE_EMPTY = 14; + } + + optional HostingTypeId hosting_type_id = 11; +} + diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 38d0e3051899..5026f318e441 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -4177,7 +4177,8 @@ public final class ActiveServices { final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0; final String procName = r.processName; - HostingRecord hostingRecord = new HostingRecord("service", r.instanceName, + HostingRecord hostingRecord = new HostingRecord( + HostingRecord.HOSTING_TYPE_SERVICE, r.instanceName, r.definingPackageName, r.definingUid, r.serviceInfo.processName); ProcessRecord app; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index e639b29e3535..71682f26e664 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1553,7 +1553,8 @@ public class ActivityManagerService extends IActivityManager.Stub @GuardedBy("mProcLock") private ParcelFileDescriptor[] mLifeMonitorFds; - static final HostingRecord sNullHostingRecord = new HostingRecord(null); + static final HostingRecord sNullHostingRecord = + new HostingRecord(HostingRecord.HOSTING_TYPE_EMPTY); /** * Used to notify activity lifecycle events. */ @@ -1876,7 +1877,7 @@ public class ActivityManagerService extends IActivityManager.Stub false, 0, null, - new HostingRecord("system")); + new HostingRecord(HostingRecord.HOSTING_TYPE_SYSTEM)); app.setPersistent(true); app.setPid(MY_PID); app.mState.setMaxAdj(ProcessList.SYSTEM_ADJ); @@ -4731,7 +4732,7 @@ public class ActivityManagerService extends IActivityManager.Stub } catch (RemoteException e) { app.resetPackageList(mProcessStats); mProcessList.startProcessLocked(app, - new HostingRecord("link fail", processName), + new HostingRecord(HostingRecord.HOSTING_TYPE_LINK_FAIL, processName), ZYGOTE_POLICY_FLAG_EMPTY); return false; } @@ -5000,6 +5001,17 @@ public class ActivityManagerService extends IActivityManager.Stub checkTime(startTime, "attachApplicationLocked: after updateOomAdjLocked"); } + + final HostingRecord hostingRecord = app.getHostingRecord(); + final String action = hostingRecord.getAction(); + String shortAction = action; + if (action != null) { + // only log the last part of the action string to save stats data. + int index = action.lastIndexOf("."); + if (index != -1 && index != action.length() - 1) { + shortAction = action.substring(index + 1); + } + } FrameworkStatsLog.write( FrameworkStatsLog.PROCESS_START_TIME, app.info.uid, @@ -5009,8 +5021,10 @@ public class ActivityManagerService extends IActivityManager.Stub app.getStartElapsedTime(), (int) (bindApplicationTimeMillis - app.getStartUptime()), (int) (SystemClock.uptimeMillis() - app.getStartUptime()), - app.getHostingRecord().getType(), - (app.getHostingRecord().getName() != null ? app.getHostingRecord().getName() : "")); + hostingRecord.getType(), + hostingRecord.getName(), + shortAction, + HostingRecord.getHostingTypeIdStatsd(hostingRecord.getType())); return true; } @@ -5109,7 +5123,7 @@ public class ActivityManagerService extends IActivityManager.Stub Slog.v(TAG_PROCESSES, "Starting process on hold: " + procs.get(ip)); } mProcessList.startProcessLocked(procs.get(ip), - new HostingRecord("on-hold"), + new HostingRecord(HostingRecord.HOSTING_TYPE_ON_HOLD), ZYGOTE_POLICY_FLAG_BATCH_LAUNCH); } } @@ -6700,7 +6714,7 @@ public class ActivityManagerService extends IActivityManager.Stub isSdkSandbox, sdkSandboxUid, sdkSandboxClientAppPackage, - new HostingRecord("added application", + new HostingRecord(HostingRecord.HOSTING_TYPE_ADDED_APPLICATION, customProcess != null ? customProcess : info.processName)); updateLruProcessLocked(app, false, null); updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN); @@ -6729,7 +6743,8 @@ public class ActivityManagerService extends IActivityManager.Stub } if (app.getThread() == null && mPersistentStartingProcesses.indexOf(app) < 0) { mPersistentStartingProcesses.add(app); - mProcessList.startProcessLocked(app, new HostingRecord("added application", + mProcessList.startProcessLocked(app, new HostingRecord( + HostingRecord.HOSTING_TYPE_ADDED_APPLICATION, customProcess != null ? customProcess : app.processName), zygotePolicyFlags, disableHiddenApiChecks, disableTestApiChecks, abiOverride); @@ -12384,7 +12399,8 @@ public class ActivityManagerService extends IActivityManager.Stub mProcessList.addProcessNameLocked(app); app.setPendingStart(false); - mProcessList.startProcessLocked(app, new HostingRecord("restart", app.processName), + mProcessList.startProcessLocked(app, new HostingRecord( + HostingRecord.HOSTING_TYPE_RESTART, app.processName), ZYGOTE_POLICY_FLAG_EMPTY); return true; } else if (pid > 0 && pid != MY_PID) { @@ -12769,7 +12785,7 @@ public class ActivityManagerService extends IActivityManager.Stub // startProcessLocked() returns existing proc's record if it's already running ProcessRecord proc = startProcessLocked(app.processName, app, false, 0, - new HostingRecord("backup", hostingName), + new HostingRecord(HostingRecord.HOSTING_TYPE_BACKUP, hostingName), ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS, false, false); if (proc == null) { Slog.e(TAG, "Unable to start backup agent process " + r); diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index d2e40c56c772..f7aa7c155719 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -1870,8 +1870,9 @@ public final class BroadcastQueue { r.curApp = mService.startProcessLocked(targetProcess, info.activityInfo.applicationInfo, true, r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND, - new HostingRecord("broadcast", r.curComponent), isActivityCapable - ? ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE : ZYGOTE_POLICY_FLAG_EMPTY, + new HostingRecord(HostingRecord.HOSTING_TYPE_BROADCAST, r.curComponent, + r.intent.getAction()), + isActivityCapable ? ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE : ZYGOTE_POLICY_FLAG_EMPTY, (r.intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false); if (r.curApp == null) { // Ah, this recipient is unavailable. Finish it if necessary, diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java index 7289331344c6..728792f608ef 100644 --- a/services/core/java/com/android/server/am/ContentProviderHelper.java +++ b/services/core/java/com/android/server/am/ContentProviderHelper.java @@ -483,7 +483,7 @@ public class ContentProviderHelper { checkTime(startTime, "getContentProviderImpl: before start process"); proc = mService.startProcessLocked( cpi.processName, cpr.appInfo, false, 0, - new HostingRecord("content provider", + new HostingRecord(HostingRecord.HOSTING_TYPE_CONTENT_PROVIDER, new ComponentName( cpi.applicationInfo.packageName, cpi.name)), Process.ZYGOTE_POLICY_FLAG_EMPTY, false, false); diff --git a/services/core/java/com/android/server/am/HostingRecord.java b/services/core/java/com/android/server/am/HostingRecord.java index bbf586123e1c..f88a8ce83d02 100644 --- a/services/core/java/com/android/server/am/HostingRecord.java +++ b/services/core/java/com/android/server/am/HostingRecord.java @@ -16,7 +16,10 @@ package com.android.server.am; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.ComponentName; +import android.os.ProcessStartTime; /** * This class describes various information required to start a process. @@ -43,6 +46,9 @@ import android.content.ComponentName; * * {@code mIsTopApp} will be passed to {@link android.os.Process#start}. So Zygote will initialize * the process with high priority. + * + * {@code mAction} the broadcast's intent action if the process is started for a broadcast + * receiver. */ public final class HostingRecord { @@ -50,51 +56,77 @@ public final class HostingRecord { private static final int WEBVIEW_ZYGOTE = 1; private static final int APP_ZYGOTE = 2; - private final String mHostingType; + public static final String HOSTING_TYPE_ACTIVITY = "activity"; + public static final String HOSTING_TYPE_ADDED_APPLICATION = "added application"; + public static final String HOSTING_TYPE_BACKUP = "backup"; + public static final String HOSTING_TYPE_BROADCAST = "broadcast"; + public static final String HOSTING_TYPE_CONTENT_PROVIDER = "content provider"; + public static final String HOSTING_TYPE_LINK_FAIL = "link fail"; + public static final String HOSTING_TYPE_ON_HOLD = "on-hold"; + public static final String HOSTING_TYPE_NEXT_ACTIVITY = "next-activity"; + public static final String HOSTING_TYPE_NEXT_TOP_ACTIVITY = "next-top-activity"; + public static final String HOSTING_TYPE_RESTART = "restart"; + public static final String HOSTING_TYPE_SERVICE = "service"; + public static final String HOSTING_TYPE_SYSTEM = "system"; + public static final String HOSTING_TYPE_TOP_ACTIVITY = "top-activity"; + public static final String HOSTING_TYPE_EMPTY = ""; + + private @NonNull final String mHostingType; private final String mHostingName; private final int mHostingZygote; private final String mDefiningPackageName; private final int mDefiningUid; private final boolean mIsTopApp; private final String mDefiningProcessName; + @Nullable private final String mAction; - public HostingRecord(String hostingType) { + public HostingRecord(@NonNull String hostingType) { this(hostingType, null /* hostingName */, REGULAR_ZYGOTE, null /* definingPackageName */, - -1 /* mDefiningUid */, false /* isTopApp */, null /* definingProcessName */); + -1 /* mDefiningUid */, false /* isTopApp */, null /* definingProcessName */, + null /* action */); } - public HostingRecord(String hostingType, ComponentName hostingName) { + public HostingRecord(@NonNull String hostingType, ComponentName hostingName) { this(hostingType, hostingName, REGULAR_ZYGOTE); } - public HostingRecord(String hostingType, ComponentName hostingName, String definingPackageName, - int definingUid, String definingProcessName) { + public HostingRecord(@NonNull String hostingType, ComponentName hostingName, + @Nullable String action) { + this(hostingType, hostingName.toShortString(), REGULAR_ZYGOTE, + null /* definingPackageName */, -1 /* mDefiningUid */, false /* isTopApp */, + null /* definingProcessName */, action); + } + + public HostingRecord(@NonNull String hostingType, ComponentName hostingName, + String definingPackageName, int definingUid, String definingProcessName) { this(hostingType, hostingName.toShortString(), REGULAR_ZYGOTE, definingPackageName, - definingUid, false /* isTopApp */, definingProcessName); + definingUid, false /* isTopApp */, definingProcessName, null /* action */); } - public HostingRecord(String hostingType, ComponentName hostingName, boolean isTopApp) { + public HostingRecord(@NonNull String hostingType, ComponentName hostingName, boolean isTopApp) { this(hostingType, hostingName.toShortString(), REGULAR_ZYGOTE, null /* definingPackageName */, -1 /* mDefiningUid */, isTopApp /* isTopApp */, - null /* definingProcessName */); + null /* definingProcessName */, null /* action */); } - public HostingRecord(String hostingType, String hostingName) { + public HostingRecord(@NonNull String hostingType, String hostingName) { this(hostingType, hostingName, REGULAR_ZYGOTE); } - private HostingRecord(String hostingType, ComponentName hostingName, int hostingZygote) { + private HostingRecord(@NonNull String hostingType, ComponentName hostingName, + int hostingZygote) { this(hostingType, hostingName.toShortString(), hostingZygote); } - private HostingRecord(String hostingType, String hostingName, int hostingZygote) { + private HostingRecord(@NonNull String hostingType, String hostingName, int hostingZygote) { this(hostingType, hostingName, hostingZygote, null /* definingPackageName */, - -1 /* mDefiningUid */, false /* isTopApp */, null /* definingProcessName */); + -1 /* mDefiningUid */, false /* isTopApp */, null /* definingProcessName */, + null /* action */); } - private HostingRecord(String hostingType, String hostingName, int hostingZygote, + private HostingRecord(@NonNull String hostingType, String hostingName, int hostingZygote, String definingPackageName, int definingUid, boolean isTopApp, - String definingProcessName) { + String definingProcessName, @Nullable String action) { mHostingType = hostingType; mHostingName = hostingName; mHostingZygote = hostingZygote; @@ -102,9 +134,10 @@ public final class HostingRecord { mDefiningUid = definingUid; mIsTopApp = isTopApp; mDefiningProcessName = definingProcessName; + mAction = action; } - public String getType() { + public @NonNull String getType() { return mHostingType; } @@ -147,14 +180,24 @@ public final class HostingRecord { } /** + * Returns the broadcast's intent action if the process is started for a broadcast receiver. + * + * @return the intent action of the broadcast. + */ + public @Nullable String getAction() { + return mAction; + } + + /** * Creates a HostingRecord for a process that must spawn from the webview zygote * @param hostingName name of the component to be hosted in this process * @return The constructed HostingRecord */ public static HostingRecord byWebviewZygote(ComponentName hostingName, String definingPackageName, int definingUid, String definingProcessName) { - return new HostingRecord("", hostingName.toShortString(), WEBVIEW_ZYGOTE, - definingPackageName, definingUid, false /* isTopApp */, definingProcessName); + return new HostingRecord(HostingRecord.HOSTING_TYPE_EMPTY, hostingName.toShortString(), + WEBVIEW_ZYGOTE, definingPackageName, definingUid, false /* isTopApp */, + definingProcessName, null /* action */); } /** @@ -166,8 +209,9 @@ public final class HostingRecord { */ public static HostingRecord byAppZygote(ComponentName hostingName, String definingPackageName, int definingUid, String definingProcessName) { - return new HostingRecord("", hostingName.toShortString(), APP_ZYGOTE, - definingPackageName, definingUid, false /* isTopApp */, definingProcessName); + return new HostingRecord(HostingRecord.HOSTING_TYPE_EMPTY, hostingName.toShortString(), + APP_ZYGOTE, definingPackageName, definingUid, false /* isTopApp */, + definingProcessName, null /* action */); } /** @@ -183,4 +227,44 @@ public final class HostingRecord { public boolean usesWebviewZygote() { return mHostingZygote == WEBVIEW_ZYGOTE; } + + /** + * Map the string hostingType to enum HostingType defined in ProcessStartTime proto. + * @param hostingType + * @return enum HostingType defined in ProcessStartTime proto + */ + public static int getHostingTypeIdStatsd(@NonNull String hostingType) { + switch(hostingType) { + case HOSTING_TYPE_ACTIVITY: + return ProcessStartTime.HOSTING_TYPE_ACTIVITY; + case HOSTING_TYPE_ADDED_APPLICATION: + return ProcessStartTime.HOSTING_TYPE_ADDED_APPLICATION; + case HOSTING_TYPE_BACKUP: + return ProcessStartTime.HOSTING_TYPE_BACKUP; + case HOSTING_TYPE_BROADCAST: + return ProcessStartTime.HOSTING_TYPE_BROADCAST; + case HOSTING_TYPE_CONTENT_PROVIDER: + return ProcessStartTime.HOSTING_TYPE_CONTENT_PROVIDER; + case HOSTING_TYPE_LINK_FAIL: + return ProcessStartTime.HOSTING_TYPE_LINK_FAIL; + case HOSTING_TYPE_ON_HOLD: + return ProcessStartTime.HOSTING_TYPE_ON_HOLD; + case HOSTING_TYPE_NEXT_ACTIVITY: + return ProcessStartTime.HOSTING_TYPE_NEXT_ACTIVITY; + case HOSTING_TYPE_NEXT_TOP_ACTIVITY: + return ProcessStartTime.HOSTING_TYPE_NEXT_TOP_ACTIVITY; + case HOSTING_TYPE_RESTART: + return ProcessStartTime.HOSTING_TYPE_RESTART; + case HOSTING_TYPE_SERVICE: + return ProcessStartTime.HOSTING_TYPE_SERVICE; + case HOSTING_TYPE_SYSTEM: + return ProcessStartTime.HOSTING_TYPE_SYSTEM; + case HOSTING_TYPE_TOP_ACTIVITY: + return ProcessStartTime.HOSTING_TYPE_TOP_ACTIVITY; + case HOSTING_TYPE_EMPTY: + return ProcessStartTime.HOSTING_TYPE_EMPTY; + default: + return ProcessStartTime.HOSTING_TYPE_UNKNOWN; + } + } } diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 95de040551b1..35f977de8290 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -146,6 +146,7 @@ import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; import com.android.server.am.ActivityManagerService; +import com.android.server.am.HostingRecord; import com.android.server.am.UserState; import com.android.server.utils.Slogf; import com.android.server.wm.ActivityMetricsLogger.LaunchingState; @@ -1056,7 +1057,9 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { r.notifyUnknownVisibilityLaunchedForKeyguardTransition(); final boolean isTop = andResume && r.isTopRunningActivity(); - mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity"); + mService.startProcessAsync(r, knownToBeDead, isTop, + isTop ? HostingRecord.HOSTING_TYPE_TOP_ACTIVITY + : HostingRecord.HOSTING_TYPE_ACTIVITY); } boolean checkStartAnyActivityPermission(Intent intent, ActivityInfo aInfo, String resultWho, diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java index 96811ef09ac4..eca0fd77fcb9 100644 --- a/services/core/java/com/android/server/wm/TaskFragment.java +++ b/services/core/java/com/android/server/wm/TaskFragment.java @@ -96,6 +96,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.function.pooled.PooledLambda; import com.android.internal.util.function.pooled.PooledPredicate; +import com.android.server.am.HostingRecord; import com.android.server.pm.parsing.pkg.AndroidPackage; import java.io.FileDescriptor; @@ -1147,7 +1148,8 @@ class TaskFragment extends WindowContainer<WindowContainer> { // for the current activity to be paused. final boolean isTop = this == taskDisplayArea.getFocusedRootTask(); mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop, - isTop ? "pre-top-activity" : "pre-activity"); + isTop ? HostingRecord.HOSTING_TYPE_NEXT_TOP_ACTIVITY + : HostingRecord.HOSTING_TYPE_NEXT_ACTIVITY); } if (lastResumed != null) { lastResumed.setWillCloseOrEnterPip(true); |