| /* |
| * Copyright (C) 2006 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. |
| */ |
| |
| package com.android.server.am; |
| |
| import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; |
| import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; |
| import static com.android.server.am.ActivityManagerService.MY_PID; |
| |
| import android.annotation.Nullable; |
| import android.app.ActivityManager; |
| import android.app.ApplicationExitInfo; |
| import android.app.ApplicationExitInfo.Reason; |
| import android.app.ApplicationExitInfo.SubReason; |
| import android.app.IApplicationThread; |
| import android.app.RemoteServiceException; |
| import android.content.pm.ApplicationInfo; |
| import android.content.pm.ProcessInfo; |
| import android.content.pm.VersionedPackage; |
| import android.content.res.CompatibilityInfo; |
| import android.os.Binder; |
| import android.os.IBinder; |
| import android.os.Process; |
| import android.os.RemoteException; |
| import android.os.SystemClock; |
| import android.os.Trace; |
| import android.os.UserHandle; |
| import android.server.ServerProtoEnums; |
| import android.util.ArrayMap; |
| import android.util.ArraySet; |
| import android.util.DebugUtils; |
| import android.util.EventLog; |
| import android.util.Slog; |
| import android.util.TimeUtils; |
| import android.util.proto.ProtoOutputStream; |
| |
| import com.android.internal.annotations.CompositeRWLock; |
| import com.android.internal.annotations.GuardedBy; |
| import com.android.internal.annotations.VisibleForTesting; |
| import com.android.internal.app.procstats.ProcessState; |
| import com.android.internal.app.procstats.ProcessStats; |
| import com.android.internal.os.Zygote; |
| import com.android.internal.util.FrameworkStatsLog; |
| import com.android.server.wm.WindowProcessController; |
| import com.android.server.wm.WindowProcessListener; |
| |
| import java.io.PrintWriter; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.Objects; |
| |
| /** |
| * Full information about a particular process that |
| * is currently running. |
| */ |
| class ProcessRecord implements WindowProcessListener { |
| static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessRecord" : TAG_AM; |
| |
| final ActivityManagerService mService; // where we came from |
| private final ActivityManagerGlobalLock mProcLock; |
| |
| // ========================================================= |
| // Basic info of the process, immutable or semi-immutable over |
| // the lifecycle of the process |
| // ========================================================= |
| volatile ApplicationInfo info; // all about the first app in the process |
| final ProcessInfo processInfo; // if non-null, process-specific manifest info |
| final boolean isolated; // true if this is a special isolated process |
| final boolean appZygote; // true if this is forked from the app zygote |
| final int uid; // uid of process; may be different from 'info' if isolated |
| final int userId; // user of process. |
| final String processName; // name of the process |
| |
| /** |
| * Overall state of process's uid. |
| */ |
| @CompositeRWLock({"mService", "mProcLock"}) |
| private UidRecord mUidRecord; |
| |
| /** |
| * List of packages running in the process. |
| */ |
| private final PackageList mPkgList = new PackageList(this); |
| |
| /** |
| * Additional packages we have a dependency on. |
| */ |
| @CompositeRWLock({"mService", "mProcLock"}) |
| private ArraySet<String> mPkgDeps; |
| |
| /** |
| * The process of this application; 0 if none. |
| */ |
| @CompositeRWLock({"mService", "mProcLock"}) |
| int mPid; |
| |
| /** |
| * The process ID which will be set when we're killing this process. |
| */ |
| @GuardedBy("mService") |
| private int mDyingPid; |
| |
| /** |
| * The gids this process was launched with. |
| */ |
| @GuardedBy("mService") |
| private int[] mGids; |
| |
| /** |
| * The ABI this process was launched with. |
| */ |
| @GuardedBy("mService") |
| private String mRequiredAbi; |
| |
| /** |
| * The instruction set this process was launched with. |
| */ |
| @GuardedBy("mService") |
| private String mInstructionSet; |
| |
| /** |
| * The actual proc... may be null only if 'persistent' is true |
| * (in which case we are in the process of launching the app). |
| */ |
| @CompositeRWLock({"mService", "mProcLock"}) |
| private IApplicationThread mThread; |
| |
| /** |
| * Always keep this application running? |
| */ |
| private volatile boolean mPersistent; |
| |
| /** |
| * Caching of toShortString() result. |
| * <p>Note: No lock here, it doesn't matter in case of race condition</p> |
| */ |
| private String mShortStringName; |
| |
| /** |
| * Caching of toString() result. |
| * <p>Note: No lock here, it doesn't matter in case of race condition</p> |
| */ |
| private String mStringName; |
| |
| /** |
| * Process start is pending. |
| */ |
| @GuardedBy("mService") |
| private boolean mPendingStart; |
| |
| /** |
| * Seq no. Indicating the latest process start associated with this process record. |
| */ |
| @GuardedBy("mService") |
| private long mStartSeq; |
| |
| /** |
| * Params used in starting this process. |
| */ |
| private volatile HostingRecord mHostingRecord; |
| |
| /** |
| * Selinux info of this process. |
| */ |
| private volatile String mSeInfo; |
| |
| /** |
| * When the process is started. |
| */ |
| private volatile long mStartTime; |
| |
| /** |
| * This will be same as {@link #uid} usually except for some apps used during factory testing. |
| */ |
| private volatile int mStartUid; |
| |
| /** |
| * Indicates how the external storage was mounted for this process. |
| */ |
| private volatile int mMountMode; |
| |
| /** |
| * True if Android/obb and Android/data need to be bind mount. |
| */ |
| private volatile boolean mBindMountPending; |
| |
| /** |
| * True when proc was started in user unlocked state. |
| */ |
| @GuardedBy("mProcLock") |
| private boolean mUnlocked; |
| |
| /** |
| * TID for RenderThread. |
| */ |
| @GuardedBy("mProcLock") |
| private int mRenderThreadTid; |
| |
| /** |
| * Last used compatibility mode. |
| */ |
| @GuardedBy("mService") |
| private CompatibilityInfo mCompat; |
| |
| /** |
| * Set of disabled compat changes for the process (all others are enabled). |
| */ |
| @GuardedBy("mService") |
| private long[] mDisabledCompatChanges; |
| |
| /** |
| * Who is watching for the death. |
| */ |
| @GuardedBy("mService") |
| private IBinder.DeathRecipient mDeathRecipient; |
| |
| /** |
| * Set to currently active instrumentation running in process. |
| */ |
| @CompositeRWLock({"mService", "mProcLock"}) |
| private ActiveInstrumentation mInstr; |
| |
| /** |
| * True when proc has been killed by activity manager, not for RAM. |
| */ |
| @CompositeRWLock({"mService", "mProcLock"}) |
| private boolean mKilledByAm; |
| |
| /** |
| * True once we know the process has been killed. |
| */ |
| @CompositeRWLock({"mService", "mProcLock"}) |
| private boolean mKilled; |
| |
| /** |
| * The timestamp in uptime when this process was killed. |
| */ |
| @CompositeRWLock({"mService", "mProcLock"}) |
| private long mKillTime; |
| |
| /** |
| * Process is waiting to be killed when in the bg, and reason. |
| */ |
| @GuardedBy("mService") |
| private String mWaitingToKill; |
| |
| /** |
| * Whether this process should be killed and removed from process list. |
| * It is set when the package is force-stopped or the process has crashed too many times. |
| */ |
| private volatile boolean mRemoved; |
| |
| /** |
| * Was app launched for debugging? |
| */ |
| @GuardedBy("mService") |
| private boolean mDebugging; |
| |
| /** |
| * Has process show wait for debugger dialog? |
| */ |
| @GuardedBy("mProcLock") |
| private boolean mWaitedForDebugger; |
| |
| /** |
| * For managing the LRU list. |
| */ |
| @CompositeRWLock({"mService", "mProcLock"}) |
| private long mLastActivityTime; |
| |
| /** |
| * Set to true when process was launched with a wrapper attached. |
| */ |
| @GuardedBy("mService") |
| private boolean mUsingWrapper; |
| |
| /** |
| * Sequence id for identifying LRU update cycles. |
| */ |
| @GuardedBy("mService") |
| private int mLruSeq; |
| |
| /** |
| * Class to run on start if this is a special isolated process. |
| */ |
| @GuardedBy("mService") |
| private String mIsolatedEntryPoint; |
| |
| /** |
| * Arguments to pass to isolatedEntryPoint's main(). |
| */ |
| @GuardedBy("mService") |
| private String[] mIsolatedEntryPointArgs; |
| |
| /** |
| * Process is currently hosting a backup agent for backup or restore. |
| */ |
| @GuardedBy("mService") |
| private boolean mInFullBackup; |
| |
| /** |
| * Controller for driving the process state on the window manager side. |
| */ |
| private final WindowProcessController mWindowProcessController; |
| |
| /** |
| * Profiling info of the process, such as PSS, cpu, etc. |
| */ |
| final ProcessProfileRecord mProfile; |
| |
| /** |
| * All about the services in this process. |
| */ |
| final ProcessServiceRecord mServices; |
| |
| /** |
| * All about the providers in this process. |
| */ |
| final ProcessProviderRecord mProviders; |
| |
| /** |
| * All about the receivers in this process. |
| */ |
| final ProcessReceiverRecord mReceivers; |
| |
| /** |
| * All about the error state(crash, ANR) in this process. |
| */ |
| final ProcessErrorStateRecord mErrorState; |
| |
| /** |
| * All about the process state info (proc state, oom adj score) in this process. |
| */ |
| final ProcessStateRecord mState; |
| |
| /** |
| * All about the state info of the optimizer when the process is cached. |
| */ |
| final ProcessCachedOptimizerRecord mOptRecord; |
| |
| /** |
| * The preceding instance of the process, which would exist when the previous process is killed |
| * but not fully dead yet; in this case, the new instance of the process should be held until |
| * this preceding instance is fully dead. |
| */ |
| volatile ProcessRecord mPredecessor; |
| |
| /** |
| * The succeeding instance of the process, which is going to be started after this process |
| * is killed successfully. |
| */ |
| volatile ProcessRecord mSuccessor; |
| |
| void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo, |
| long startTime) { |
| this.mStartUid = startUid; |
| this.mHostingRecord = hostingRecord; |
| this.mSeInfo = seInfo; |
| this.mStartTime = startTime; |
| } |
| |
| @GuardedBy({"mService", "mProcLock"}) |
| void dump(PrintWriter pw, String prefix) { |
| final long nowUptime = SystemClock.uptimeMillis(); |
| |
| pw.print(prefix); pw.print("user #"); pw.print(userId); |
| pw.print(" uid="); pw.print(info.uid); |
| if (uid != info.uid) { |
| pw.print(" ISOLATED uid="); pw.print(uid); |
| } |
| pw.print(" gids={"); |
| if (mGids != null) { |
| for (int gi = 0; gi < mGids.length; gi++) { |
| if (gi != 0) pw.print(", "); |
| pw.print(mGids[gi]); |
| |
| } |
| } |
| pw.println("}"); |
| if (processInfo != null) { |
| pw.print(prefix); pw.println("processInfo:"); |
| if (processInfo.deniedPermissions != null) { |
| for (int i = 0; i < processInfo.deniedPermissions.size(); i++) { |
| pw.print(prefix); pw.print(" deny: "); |
| pw.println(processInfo.deniedPermissions.valueAt(i)); |
| } |
| } |
| if (processInfo.gwpAsanMode != ApplicationInfo.GWP_ASAN_DEFAULT) { |
| pw.print(prefix); pw.println(" gwpAsanMode=" + processInfo.gwpAsanMode); |
| } |
| if (processInfo.memtagMode != ApplicationInfo.MEMTAG_DEFAULT) { |
| pw.print(prefix); pw.println(" memtagMode=" + processInfo.memtagMode); |
| } |
| } |
| pw.print(prefix); pw.print("mRequiredAbi="); pw.print(mRequiredAbi); |
| pw.print(" instructionSet="); pw.println(mInstructionSet); |
| if (info.className != null) { |
| pw.print(prefix); pw.print("class="); pw.println(info.className); |
| } |
| if (info.manageSpaceActivityName != null) { |
| pw.print(prefix); pw.print("manageSpaceActivityName="); |
| pw.println(info.manageSpaceActivityName); |
| } |
| |
| pw.print(prefix); pw.print("dir="); pw.print(info.sourceDir); |
| pw.print(" publicDir="); pw.print(info.publicSourceDir); |
| pw.print(" data="); pw.println(info.dataDir); |
| mPkgList.dump(pw, prefix); |
| if (mPkgDeps != null) { |
| pw.print(prefix); pw.print("packageDependencies={"); |
| for (int i = 0; i < mPkgDeps.size(); i++) { |
| if (i > 0) pw.print(", "); |
| pw.print(mPkgDeps.valueAt(i)); |
| } |
| pw.println("}"); |
| } |
| pw.print(prefix); pw.print("compat="); pw.println(mCompat); |
| if (mInstr != null) { |
| pw.print(prefix); pw.print("mInstr="); pw.println(mInstr); |
| } |
| pw.print(prefix); pw.print("thread="); pw.println(mThread); |
| pw.print(prefix); pw.print("pid="); pw.println(mPid); |
| pw.print(prefix); pw.print("lastActivityTime="); |
| TimeUtils.formatDuration(mLastActivityTime, nowUptime, pw); |
| pw.println(); |
| if (mPersistent || mRemoved) { |
| pw.print(prefix); pw.print("persistent="); pw.print(mPersistent); |
| pw.print(" removed="); pw.println(mRemoved); |
| } |
| if (mDebugging) { |
| pw.print(prefix); pw.print("mDebugging="); pw.println(mDebugging); |
| } |
| if (mPendingStart) { |
| pw.print(prefix); pw.print("pendingStart="); pw.println(mPendingStart); |
| } |
| pw.print(prefix); pw.print("startSeq="); pw.println(mStartSeq); |
| pw.print(prefix); pw.print("mountMode="); pw.println( |
| DebugUtils.valueToString(Zygote.class, "MOUNT_EXTERNAL_", mMountMode)); |
| if (mKilled || mKilledByAm || mWaitingToKill != null) { |
| pw.print(prefix); pw.print("killed="); pw.print(mKilled); |
| pw.print(" killedByAm="); pw.print(mKilledByAm); |
| pw.print(" waitingToKill="); pw.println(mWaitingToKill); |
| } |
| if (mIsolatedEntryPoint != null || mIsolatedEntryPointArgs != null) { |
| pw.print(prefix); pw.print("isolatedEntryPoint="); pw.println(mIsolatedEntryPoint); |
| pw.print(prefix); pw.print("isolatedEntryPointArgs="); |
| pw.println(Arrays.toString(mIsolatedEntryPointArgs)); |
| } |
| if (mState.getSetProcState() > ActivityManager.PROCESS_STATE_SERVICE) { |
| mProfile.dumpCputime(pw, prefix); |
| } |
| mProfile.dumpPss(pw, prefix, nowUptime); |
| mState.dump(pw, prefix, nowUptime); |
| mErrorState.dump(pw, prefix, nowUptime); |
| mServices.dump(pw, prefix, nowUptime); |
| mProviders.dump(pw, prefix, nowUptime); |
| mReceivers.dump(pw, prefix, nowUptime); |
| mOptRecord.dump(pw, prefix, nowUptime); |
| mWindowProcessController.dump(pw, prefix); |
| } |
| |
| ProcessRecord(ActivityManagerService _service, ApplicationInfo _info, String _processName, |
| int _uid) { |
| mService = _service; |
| mProcLock = _service.mProcLock; |
| info = _info; |
| ProcessInfo procInfo = null; |
| if (_service.mPackageManagerInt != null) { |
| ArrayMap<String, ProcessInfo> processes = |
| _service.mPackageManagerInt.getProcessesForUid(_uid); |
| if (processes != null) { |
| procInfo = processes.get(_processName); |
| if (procInfo != null && procInfo.deniedPermissions == null |
| && procInfo.gwpAsanMode == ApplicationInfo.GWP_ASAN_DEFAULT |
| && procInfo.memtagMode == ApplicationInfo.MEMTAG_DEFAULT |
| && procInfo.nativeHeapZeroInitialized == ApplicationInfo.ZEROINIT_DEFAULT) { |
| // If this process hasn't asked for permissions to be denied, or for a |
| // non-default GwpAsan mode, or any other non-default setting, then we don't |
| // care about it. |
| procInfo = null; |
| } |
| } |
| } |
| processInfo = procInfo; |
| isolated = _info.uid != _uid; |
| appZygote = (UserHandle.getAppId(_uid) >= Process.FIRST_APP_ZYGOTE_ISOLATED_UID |
| && UserHandle.getAppId(_uid) <= Process.LAST_APP_ZYGOTE_ISOLATED_UID); |
| uid = _uid; |
| userId = UserHandle.getUserId(_uid); |
| processName = _processName; |
| mPersistent = false; |
| mRemoved = false; |
| mProfile = new ProcessProfileRecord(this); |
| mServices = new ProcessServiceRecord(this); |
| mProviders = new ProcessProviderRecord(this); |
| mReceivers = new ProcessReceiverRecord(this); |
| mErrorState = new ProcessErrorStateRecord(this); |
| mState = new ProcessStateRecord(this); |
| mOptRecord = new ProcessCachedOptimizerRecord(this); |
| final long now = SystemClock.uptimeMillis(); |
| mProfile.init(now); |
| mOptRecord.init(now); |
| mState.init(now); |
| mWindowProcessController = new WindowProcessController( |
| mService.mActivityTaskManager, info, processName, uid, userId, this, this); |
| mPkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.longVersionCode)); |
| } |
| |
| @GuardedBy(anyOf = {"mService", "mProcLock"}) |
| UidRecord getUidRecord() { |
| return mUidRecord; |
| } |
| |
| @GuardedBy({"mService", "mProcLock"}) |
| void setUidRecord(UidRecord uidRecord) { |
| mUidRecord = uidRecord; |
| } |
| |
| PackageList getPkgList() { |
| return mPkgList; |
| } |
| |
| @GuardedBy(anyOf = {"mService", "mProcLock"}) |
| ArraySet<String> getPkgDeps() { |
| return mPkgDeps; |
| } |
| |
| @GuardedBy({"mService", "mProcLock"}) |
| void setPkgDeps(ArraySet<String> pkgDeps) { |
| mPkgDeps = pkgDeps; |
| } |
| |
| @GuardedBy(anyOf = {"mService", "mProcLock"}) |
| int getPid() { |
| return mPid; |
| } |
| |
| @GuardedBy({"mService", "mProcLock"}) |
| void setPid(int pid) { |
| mPid = pid; |
| mWindowProcessController.setPid(pid); |
| mShortStringName = null; |
| mStringName = null; |
| synchronized (mProfile.mProfilerLock) { |
| mProfile.setPid(pid); |
| } |
| } |
| |
| @GuardedBy(anyOf = {"mService", "mProcLock"}) |
| IApplicationThread getThread() { |
| return mThread; |
| } |
| |
| @GuardedBy({"mService", "mProcLock"}) |
| public void makeActive(IApplicationThread thread, ProcessStatsService tracker) { |
| mProfile.onProcessActive(thread, tracker); |
| mThread = thread; |
| mWindowProcessController.setThread(thread); |
| } |
| |
| @GuardedBy({"mService", "mProcLock"}) |
| public void makeInactive(ProcessStatsService tracker) { |
| mThread = null; |
| mWindowProcessController.setThread(null); |
| mProfile.onProcessInactive(tracker); |
| } |
| |
| @GuardedBy("mService") |
| int getDyingPid() { |
| return mDyingPid; |
| } |
| |
| @GuardedBy("mService") |
| void setDyingPid(int dyingPid) { |
| mDyingPid = dyingPid; |
| } |
| |
| @GuardedBy("mService") |
| int[] getGids() { |
| return mGids; |
| } |
| |
| @GuardedBy("mService") |
| void setGids(int[] gids) { |
| mGids = gids; |
| } |
| |
| @GuardedBy("mService") |
| String getRequiredAbi() { |
| return mRequiredAbi; |
| } |
| |
| @GuardedBy("mService") |
| void setRequiredAbi(String requiredAbi) { |
| mRequiredAbi = requiredAbi; |
| mWindowProcessController.setRequiredAbi(requiredAbi); |
| } |
| |
| @GuardedBy("mService") |
| String getInstructionSet() { |
| return mInstructionSet; |
| } |
| |
| @GuardedBy("mService") |
| void setInstructionSet(String instructionSet) { |
| mInstructionSet = instructionSet; |
| } |
| |
| void setPersistent(boolean persistent) { |
| mPersistent = persistent; |
| mWindowProcessController.setPersistent(persistent); |
| } |
| |
| boolean isPersistent() { |
| return mPersistent; |
| } |
| |
| @GuardedBy("mService") |
| boolean isPendingStart() { |
| return mPendingStart; |
| } |
| |
| @GuardedBy("mService") |
| void setPendingStart(boolean pendingStart) { |
| mPendingStart = pendingStart; |
| } |
| |
| @GuardedBy("mService") |
| long getStartSeq() { |
| return mStartSeq; |
| } |
| |
| @GuardedBy("mService") |
| void setStartSeq(long startSeq) { |
| mStartSeq = startSeq; |
| } |
| |
| HostingRecord getHostingRecord() { |
| return mHostingRecord; |
| } |
| |
| void setHostingRecord(HostingRecord hostingRecord) { |
| mHostingRecord = hostingRecord; |
| } |
| |
| String getSeInfo() { |
| return mSeInfo; |
| } |
| |
| void setSeInfo(String seInfo) { |
| mSeInfo = seInfo; |
| } |
| |
| long getStartTime() { |
| return mStartTime; |
| } |
| |
| void setStartTime(long startTime) { |
| mStartTime = startTime; |
| } |
| |
| int getStartUid() { |
| return mStartUid; |
| } |
| |
| void setStartUid(int startUid) { |
| mStartUid = startUid; |
| } |
| |
| int getMountMode() { |
| return mMountMode; |
| } |
| |
| void setMountMode(int mountMode) { |
| mMountMode = mountMode; |
| } |
| |
| boolean isBindMountPending() { |
| return mBindMountPending; |
| } |
| |
| void setBindMountPending(boolean bindMountPending) { |
| mBindMountPending = bindMountPending; |
| } |
| |
| @GuardedBy("mProcLock") |
| boolean isUnlocked() { |
| return mUnlocked; |
| } |
| |
| @GuardedBy("mProcLock") |
| void setUnlocked(boolean unlocked) { |
| mUnlocked = unlocked; |
| } |
| |
| @GuardedBy("mProcLock") |
| int getRenderThreadTid() { |
| return mRenderThreadTid; |
| } |
| |
| @GuardedBy("mProcLock") |
| void setRenderThreadTid(int renderThreadTid) { |
| mRenderThreadTid = renderThreadTid; |
| } |
| |
| @GuardedBy("mService") |
| CompatibilityInfo getCompat() { |
| return mCompat; |
| } |
| |
| @GuardedBy("mService") |
| void setCompat(CompatibilityInfo compat) { |
| mCompat = compat; |
| } |
| |
| @GuardedBy("mService") |
| long[] getDisabledCompatChanges() { |
| return mDisabledCompatChanges; |
| } |
| |
| @GuardedBy("mService") |
| void setDisabledCompatChanges(long[] disabledCompatChanges) { |
| mDisabledCompatChanges = disabledCompatChanges; |
| } |
| |
| @GuardedBy("mService") |
| void unlinkDeathRecipient() { |
| if (mDeathRecipient != null && mThread != null) { |
| mThread.asBinder().unlinkToDeath(mDeathRecipient, 0); |
| } |
| mDeathRecipient = null; |
| } |
| |
| @GuardedBy("mService") |
| void setDeathRecipient(IBinder.DeathRecipient deathRecipient) { |
| mDeathRecipient = deathRecipient; |
| } |
| |
| @GuardedBy("mService") |
| IBinder.DeathRecipient getDeathRecipient() { |
| return mDeathRecipient; |
| } |
| |
| @GuardedBy({"mService", "mProcLock"}) |
| void setActiveInstrumentation(ActiveInstrumentation instr) { |
| mInstr = instr; |
| boolean isInstrumenting = instr != null; |
| mWindowProcessController.setInstrumenting( |
| isInstrumenting, |
| isInstrumenting ? instr.mSourceUid : -1, |
| isInstrumenting && instr.mHasBackgroundActivityStartsPermission); |
| } |
| |
| @GuardedBy(anyOf = {"mService", "mProcLock"}) |
| ActiveInstrumentation getActiveInstrumentation() { |
| return mInstr; |
| } |
| |
| @GuardedBy(anyOf = {"mService", "mProcLock"}) |
| boolean isKilledByAm() { |
| return mKilledByAm; |
| } |
| |
| @GuardedBy({"mService", "mProcLock"}) |
| void setKilledByAm(boolean killedByAm) { |
| mKilledByAm = killedByAm; |
| } |
| |
| @GuardedBy(anyOf = {"mService", "mProcLock"}) |
| boolean isKilled() { |
| return mKilled; |
| } |
| |
| @GuardedBy({"mService", "mProcLock"}) |
| void setKilled(boolean killed) { |
| mKilled = killed; |
| } |
| |
| @GuardedBy(anyOf = {"mService", "mProcLock"}) |
| long getKillTime() { |
| return mKillTime; |
| } |
| |
| @GuardedBy({"mService", "mProcLock"}) |
| void setKillTime(long killTime) { |
| mKillTime = killTime; |
| } |
| |
| @GuardedBy("mService") |
| String getWaitingToKill() { |
| return mWaitingToKill; |
| } |
| |
| @GuardedBy("mService") |
| void setWaitingToKill(String waitingToKill) { |
| mWaitingToKill = waitingToKill; |
| } |
| |
| @Override |
| public boolean isRemoved() { |
| return mRemoved; |
| } |
| |
| void setRemoved(boolean removed) { |
| mRemoved = removed; |
| } |
| |
| @GuardedBy("mService") |
| boolean isDebugging() { |
| return mDebugging; |
| } |
| |
| @GuardedBy("mService") |
| void setDebugging(boolean debugging) { |
| mDebugging = debugging; |
| mWindowProcessController.setDebugging(debugging); |
| } |
| |
| @GuardedBy("mProcLock") |
| boolean hasWaitedForDebugger() { |
| return mWaitedForDebugger; |
| } |
| |
| @GuardedBy("mProcLock") |
| void setWaitedForDebugger(boolean waitedForDebugger) { |
| mWaitedForDebugger = waitedForDebugger; |
| } |
| |
| @GuardedBy(anyOf = {"mService", "mProcLock"}) |
| long getLastActivityTime() { |
| return mLastActivityTime; |
| } |
| |
| @GuardedBy({"mService", "mProcLock"}) |
| void setLastActivityTime(long lastActivityTime) { |
| mLastActivityTime = lastActivityTime; |
| } |
| |
| @GuardedBy("mService") |
| boolean isUsingWrapper() { |
| return mUsingWrapper; |
| } |
| |
| @GuardedBy("mService") |
| void setUsingWrapper(boolean usingWrapper) { |
| mUsingWrapper = usingWrapper; |
| mWindowProcessController.setUsingWrapper(usingWrapper); |
| } |
| |
| @GuardedBy("mService") |
| int getLruSeq() { |
| return mLruSeq; |
| } |
| |
| @GuardedBy("mService") |
| void setLruSeq(int lruSeq) { |
| mLruSeq = lruSeq; |
| } |
| |
| @GuardedBy("mService") |
| String getIsolatedEntryPoint() { |
| return mIsolatedEntryPoint; |
| } |
| |
| @GuardedBy("mService") |
| void setIsolatedEntryPoint(String isolatedEntryPoint) { |
| mIsolatedEntryPoint = isolatedEntryPoint; |
| } |
| |
| @GuardedBy("mService") |
| String[] getIsolatedEntryPointArgs() { |
| return mIsolatedEntryPointArgs; |
| } |
| |
| @GuardedBy("mService") |
| void setIsolatedEntryPointArgs(String[] isolatedEntryPointArgs) { |
| mIsolatedEntryPointArgs = isolatedEntryPointArgs; |
| } |
| |
| @GuardedBy("mService") |
| boolean isInFullBackup() { |
| return mInFullBackup; |
| } |
| |
| @GuardedBy("mService") |
| void setInFullBackup(boolean inFullBackup) { |
| mInFullBackup = inFullBackup; |
| } |
| |
| @Override |
| public boolean isCached() { |
| return mState.isCached(); |
| } |
| |
| boolean hasActivities() { |
| return mWindowProcessController.hasActivities(); |
| } |
| |
| boolean hasActivitiesOrRecentTasks() { |
| return mWindowProcessController.hasActivitiesOrRecentTasks(); |
| } |
| |
| boolean hasRecentTasks() { |
| return mWindowProcessController.hasRecentTasks(); |
| } |
| |
| @GuardedBy({"mService", "mProcLock"}) |
| boolean onCleanupApplicationRecordLSP(ProcessStatsService processStats, boolean allowRestart, |
| boolean unlinkDeath) { |
| mErrorState.onCleanupApplicationRecordLSP(); |
| |
| resetPackageList(processStats); |
| if (unlinkDeath) { |
| unlinkDeathRecipient(); |
| } |
| makeInactive(processStats); |
| setWaitingToKill(null); |
| |
| mState.onCleanupApplicationRecordLSP(); |
| mServices.onCleanupApplicationRecordLocked(); |
| mReceivers.onCleanupApplicationRecordLocked(); |
| |
| return mProviders.onCleanupApplicationRecordLocked(allowRestart); |
| } |
| |
| /** |
| * This method returns true if any of the activities within the process record are interesting |
| * to the user. See HistoryRecord.isInterestingToUserLocked() |
| */ |
| public boolean isInterestingToUserLocked() { |
| if (mWindowProcessController.isInterestingToUser()) { |
| return true; |
| } |
| |
| return mServices.hasForegroundServices(); |
| } |
| |
| @GuardedBy("mService") |
| void scheduleCrashLocked(String message) { |
| scheduleCrashLocked(message, RemoteServiceException.TYPE_ID); |
| } |
| |
| /** |
| * Let an app process throw an exception on a binder thread, which typically crashes the |
| * process, unless it has an unhandled exception handler. |
| * |
| * See {@link ActivityThread#throwRemoteServiceException}. |
| * |
| * @param message exception message |
| * @param exceptionTypeId ID defined in {@link android.app.RemoteServiceException} or one |
| * of its subclasses. |
| */ |
| @GuardedBy("mService") |
| void scheduleCrashLocked(String message, int exceptionTypeId) { |
| // Checking killedbyAm should keep it from showing the crash dialog if the process |
| // was already dead for a good / normal reason. |
| if (!mKilledByAm) { |
| if (mThread != null) { |
| if (mPid == Process.myPid()) { |
| Slog.w(TAG, "scheduleCrash: trying to crash system process!"); |
| return; |
| } |
| final long ident = Binder.clearCallingIdentity(); |
| try { |
| mThread.scheduleCrash(message, exceptionTypeId); |
| } catch (RemoteException e) { |
| // If it's already dead our work is done. If it's wedged just kill it. |
| // We won't get the crash dialog or the error reporting. |
| killLocked("scheduleCrash for '" + message + "' failed", |
| ApplicationExitInfo.REASON_CRASH, true); |
| } finally { |
| Binder.restoreCallingIdentity(ident); |
| } |
| } |
| } |
| } |
| |
| @GuardedBy("mService") |
| void killLocked(String reason, @Reason int reasonCode, boolean noisy) { |
| killLocked(reason, reasonCode, ApplicationExitInfo.SUBREASON_UNKNOWN, noisy); |
| } |
| |
| @GuardedBy("mService") |
| void killLocked(String reason, @Reason int reasonCode, @SubReason int subReason, |
| boolean noisy) { |
| if (!mKilledByAm) { |
| Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "kill"); |
| if (mService != null && (noisy || info.uid == mService.mCurOomAdjUid)) { |
| mService.reportUidInfoMessageLocked(TAG, |
| "Killing " + toShortString() + " (adj " + mState.getSetAdj() |
| + "): " + reason, info.uid); |
| } |
| if (mPid > 0) { |
| mService.mProcessList.noteAppKill(this, reasonCode, subReason, reason); |
| EventLog.writeEvent(EventLogTags.AM_KILL, |
| userId, mPid, processName, mState.getSetAdj(), reason); |
| Process.killProcessQuiet(mPid); |
| ProcessList.killProcessGroup(uid, mPid); |
| } else { |
| mPendingStart = false; |
| } |
| if (!mPersistent) { |
| synchronized (mProcLock) { |
| mKilled = true; |
| mKilledByAm = true; |
| mKillTime = SystemClock.uptimeMillis(); |
| } |
| } |
| Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); |
| } |
| } |
| |
| @Override |
| public void dumpDebug(ProtoOutputStream proto, long fieldId) { |
| dumpDebug(proto, fieldId, -1); |
| } |
| |
| public void dumpDebug(ProtoOutputStream proto, long fieldId, int lruIndex) { |
| long token = proto.start(fieldId); |
| proto.write(ProcessRecordProto.PID, mPid); |
| proto.write(ProcessRecordProto.PROCESS_NAME, processName); |
| proto.write(ProcessRecordProto.UID, info.uid); |
| if (UserHandle.getAppId(info.uid) >= Process.FIRST_APPLICATION_UID) { |
| proto.write(ProcessRecordProto.USER_ID, userId); |
| proto.write(ProcessRecordProto.APP_ID, UserHandle.getAppId(info.uid)); |
| } |
| if (uid != info.uid) { |
| proto.write(ProcessRecordProto.ISOLATED_APP_ID, UserHandle.getAppId(uid)); |
| } |
| proto.write(ProcessRecordProto.PERSISTENT, mPersistent); |
| if (lruIndex >= 0) { |
| proto.write(ProcessRecordProto.LRU_INDEX, lruIndex); |
| } |
| proto.end(token); |
| } |
| |
| public String toShortString() { |
| final String shortStringName = mShortStringName; |
| if (shortStringName != null) { |
| return shortStringName; |
| } |
| StringBuilder sb = new StringBuilder(128); |
| toShortString(sb); |
| return mShortStringName = sb.toString(); |
| } |
| |
| void toShortString(StringBuilder sb) { |
| sb.append(mPid); |
| sb.append(':'); |
| sb.append(processName); |
| sb.append('/'); |
| if (info.uid < Process.FIRST_APPLICATION_UID) { |
| sb.append(uid); |
| } else { |
| sb.append('u'); |
| sb.append(userId); |
| int appId = UserHandle.getAppId(info.uid); |
| if (appId >= Process.FIRST_APPLICATION_UID) { |
| sb.append('a'); |
| sb.append(appId - Process.FIRST_APPLICATION_UID); |
| } else { |
| sb.append('s'); |
| sb.append(appId); |
| } |
| if (uid != info.uid) { |
| sb.append('i'); |
| sb.append(UserHandle.getAppId(uid) - Process.FIRST_ISOLATED_UID); |
| } |
| } |
| } |
| |
| public String toString() { |
| final String stringName = mStringName; |
| if (stringName != null) { |
| return stringName; |
| } |
| StringBuilder sb = new StringBuilder(128); |
| sb.append("ProcessRecord{"); |
| sb.append(Integer.toHexString(System.identityHashCode(this))); |
| sb.append(' '); |
| toShortString(sb); |
| sb.append('}'); |
| return mStringName = sb.toString(); |
| } |
| |
| /* |
| * Return true if package has been added false if not |
| */ |
| public boolean addPackage(String pkg, long versionCode, ProcessStatsService tracker) { |
| synchronized (tracker.mLock) { |
| synchronized (mPkgList) { |
| if (!mPkgList.containsKey(pkg)) { |
| ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder( |
| versionCode); |
| final ProcessState baseProcessTracker = mProfile.getBaseProcessTracker(); |
| if (baseProcessTracker != null) { |
| tracker.updateProcessStateHolderLocked(holder, pkg, info.uid, versionCode, |
| processName); |
| mPkgList.put(pkg, holder); |
| if (holder.state != baseProcessTracker) { |
| holder.state.makeActive(); |
| } |
| } else { |
| mPkgList.put(pkg, holder); |
| } |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| /* |
| * Delete all packages from list except the package indicated in info |
| */ |
| public void resetPackageList(ProcessStatsService tracker) { |
| synchronized (tracker.mLock) { |
| final ProcessState baseProcessTracker = mProfile.getBaseProcessTracker(); |
| synchronized (mPkgList) { |
| final int numOfPkgs = mPkgList.size(); |
| if (baseProcessTracker != null) { |
| long now = SystemClock.uptimeMillis(); |
| baseProcessTracker.setState(ProcessStats.STATE_NOTHING, |
| tracker.getMemFactorLocked(), now, mPkgList.getPackageListLocked()); |
| mPkgList.forEachPackage((pkgName, holder) -> |
| FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED, |
| uid, processName, pkgName, |
| ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING), |
| holder.appVersion) |
| ); |
| if (numOfPkgs != 1) { |
| mPkgList.forEachPackageProcessStats(holder -> { |
| if (holder.state != null && holder.state != baseProcessTracker) { |
| holder.state.makeInactive(); |
| } |
| }); |
| mPkgList.clear(); |
| ProcessStats.ProcessStateHolder holder = |
| new ProcessStats.ProcessStateHolder(info.longVersionCode); |
| tracker.updateProcessStateHolderLocked(holder, info.packageName, info.uid, |
| info.longVersionCode, processName); |
| mPkgList.put(info.packageName, holder); |
| if (holder.state != baseProcessTracker) { |
| holder.state.makeActive(); |
| } |
| } |
| } else if (numOfPkgs != 1) { |
| mPkgList.clear(); |
| mPkgList.put(info.packageName, |
| new ProcessStats.ProcessStateHolder(info.longVersionCode)); |
| } |
| } |
| } |
| } |
| |
| String[] getPackageList() { |
| return mPkgList.getPackageList(); |
| } |
| |
| List<VersionedPackage> getPackageListWithVersionCode() { |
| return mPkgList.getPackageListWithVersionCode(); |
| } |
| |
| WindowProcessController getWindowProcessController() { |
| return mWindowProcessController; |
| } |
| |
| /** |
| * Allows background activity starts using token {@param entity}. Optionally, you can provide |
| * {@param originatingToken} if you have one such originating token, this is useful for tracing |
| * back the grant in the case of the notification token. |
| */ |
| void addOrUpdateAllowBackgroundActivityStartsToken(Binder entity, |
| @Nullable IBinder originatingToken) { |
| Objects.requireNonNull(entity); |
| mWindowProcessController.addOrUpdateAllowBackgroundActivityStartsToken(entity, |
| originatingToken); |
| } |
| |
| void removeAllowBackgroundActivityStartsToken(Binder entity) { |
| Objects.requireNonNull(entity); |
| mWindowProcessController.removeAllowBackgroundActivityStartsToken(entity); |
| } |
| |
| @Override |
| public void clearProfilerIfNeeded() { |
| synchronized (mService.mAppProfiler.mProfilerLock) { |
| mService.mAppProfiler.clearProfilerLPf(); |
| } |
| } |
| |
| @Override |
| public void updateServiceConnectionActivities() { |
| synchronized (mService) { |
| mService.mServices.updateServiceConnectionActivitiesLocked(mServices); |
| } |
| } |
| |
| @Override |
| public void setPendingUiClean(boolean pendingUiClean) { |
| synchronized (mProcLock) { |
| mProfile.setPendingUiClean(pendingUiClean); |
| } |
| } |
| |
| @Override |
| public void setPendingUiCleanAndForceProcessStateUpTo(int newState) { |
| synchronized (mService) { |
| setPendingUiClean(true); |
| mState.forceProcessStateUpTo(newState); |
| } |
| } |
| |
| @Override |
| public void updateProcessInfo(boolean updateServiceConnectionActivities, boolean activityChange, |
| boolean updateOomAdj) { |
| synchronized (mService) { |
| if (updateServiceConnectionActivities) { |
| mService.mServices.updateServiceConnectionActivitiesLocked(mServices); |
| } |
| if (mThread == null) { |
| // Only update lru and oom-adj if the process is alive. Because it may be called |
| // when cleaning up the last activity from handling process died, the dead process |
| // should not be added to lru list again. |
| return; |
| } |
| mService.updateLruProcessLocked(this, activityChange, null /* client */); |
| if (updateOomAdj) { |
| mService.updateOomAdjLocked(this, OomAdjuster.OOM_ADJ_REASON_ACTIVITY); |
| } |
| } |
| } |
| |
| /** |
| * Returns the total time (in milliseconds) spent executing in both user and system code. |
| * Safe to call without lock held. |
| */ |
| @Override |
| public long getCpuTime() { |
| return mService.mAppProfiler.getCpuTimeForPid(mPid); |
| } |
| |
| @Override |
| public void onStartActivity(int topProcessState, boolean setProfileProc, String packageName, |
| long versionCode) { |
| synchronized (mService) { |
| mWaitingToKill = null; |
| if (setProfileProc) { |
| synchronized (mService.mAppProfiler.mProfilerLock) { |
| mService.mAppProfiler.setProfileProcLPf(this); |
| } |
| } |
| if (packageName != null) { |
| addPackage(packageName, versionCode, mService.mProcessStats); |
| } |
| |
| // Update oom adj first, we don't want the additional states are involved in this round. |
| updateProcessInfo(false /* updateServiceConnectionActivities */, |
| true /* activityChange */, true /* updateOomAdj */); |
| setPendingUiClean(true); |
| mState.setHasShownUi(true); |
| mState.forceProcessStateUpTo(topProcessState); |
| } |
| } |
| |
| @Override |
| public void appDied(String reason) { |
| synchronized (mService) { |
| mService.appDiedLocked(this, reason); |
| } |
| } |
| |
| @Override |
| public void setRunningRemoteAnimation(boolean runningRemoteAnimation) { |
| if (mPid == Process.myPid()) { |
| Slog.wtf(TAG, "system can't run remote animation"); |
| return; |
| } |
| synchronized (mService) { |
| mState.setRunningRemoteAnimation(runningRemoteAnimation); |
| } |
| } |
| |
| public long getInputDispatchingTimeoutMillis() { |
| return mWindowProcessController.getInputDispatchingTimeoutMillis(); |
| } |
| |
| public int getProcessClassEnum() { |
| if (mPid == MY_PID) { |
| return ServerProtoEnums.SYSTEM_SERVER; |
| } |
| if (info == null) { |
| return ServerProtoEnums.ERROR_SOURCE_UNKNOWN; |
| } |
| return (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0 ? ServerProtoEnums.SYSTEM_APP : |
| ServerProtoEnums.DATA_APP; |
| } |
| |
| /** Non-private access is for tests only. */ |
| @VisibleForTesting |
| List<ProcessRecord> getLruProcessList() { |
| return mService.mProcessList.getLruProcessesLOSP(); |
| } |
| } |