• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.am;
18 
19 import static android.os.Process.PROC_NEWLINE_TERM;
20 import static android.os.Process.PROC_OUT_LONG;
21 
22 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
23 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
24 
25 import android.os.Handler;
26 import android.os.Process;
27 import android.os.StrictMode;
28 import android.os.SystemClock;
29 import android.os.Trace;
30 import android.os.UserHandle;
31 import android.text.TextUtils;
32 import android.util.EventLog;
33 import android.util.Slog;
34 import android.util.TimeUtils;
35 
36 import com.android.internal.annotations.GuardedBy;
37 
38 import java.io.FileDescriptor;
39 import java.io.IOException;
40 import java.io.PrintWriter;
41 import java.util.function.Consumer;
42 
43 /**
44  * The "phantom" app processes, which are forked by app processes so we are not aware of
45  * them until we walk through the process list in /proc.
46  */
47 public final class PhantomProcessRecord {
48     static final String TAG = TAG_WITH_CLASS_NAME ? "PhantomProcessRecord" : TAG_AM;
49 
50     static final long[] LONG_OUT = new long[1];
51     static final int[] LONG_FORMAT = new int[] {PROC_NEWLINE_TERM | PROC_OUT_LONG};
52 
53     final String mProcessName;   // name of the process
54     final int mUid;              // uid of the process
55     final int mPid;              // The id of the process
56     final int mPpid;             // Ancestor (managed app process) pid of the process
57     final long mKnownSince;      // The timestamp when we're aware of the process
58     final FileDescriptor mPidFd; // The fd to monitor the termination of this process
59 
60     long mLastCputime;           // How long proc has run CPU at last check
61     long mCurrentCputime;        // How long proc has run CPU most recently
62     int mUpdateSeq;              // Seq no, indicating the last check on this process
63     int mAdj;                    // The last known oom adj score
64     boolean mKilled;             // Whether it has been killed by us or not
65     boolean mZombie;             // Whether it was signaled to be killed but timed out
66     String mStringName;          // Caching of the toString() result
67 
68     final ActivityManagerService mService;
69     final Object mLock;
70     final Consumer<PhantomProcessRecord> mOnKillListener;
71     final Handler mKillHandler;
72 
PhantomProcessRecord(final String processName, final int uid, final int pid, final int ppid, final ActivityManagerService service, final Consumer<PhantomProcessRecord> onKillListener)73     PhantomProcessRecord(final String processName, final int uid, final int pid,
74             final int ppid, final ActivityManagerService service,
75             final Consumer<PhantomProcessRecord> onKillListener) throws IllegalStateException {
76         mProcessName = processName;
77         mUid = uid;
78         mPid = pid;
79         mPpid = ppid;
80         mKilled = false;
81         mAdj = ProcessList.NATIVE_ADJ;
82         mKnownSince = SystemClock.elapsedRealtime();
83         mService = service;
84         mLock = service.mPhantomProcessList.mLock;
85         mOnKillListener = onKillListener;
86         mKillHandler = service.mProcessList.sKillHandler;
87         if (Process.supportsPidFd()) {
88             StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
89             try {
90                 mPidFd = Process.openPidFd(pid, 0);
91                 if (mPidFd == null) {
92                     throw new IllegalStateException();
93                 }
94             } catch (IOException e) {
95                 // Maybe a race condition, the process is gone.
96                 Slog.w(TAG, "Unable to open process " + pid + ", it might be gone");
97                 IllegalStateException ex = new IllegalStateException();
98                 ex.initCause(e);
99                 throw ex;
100             } finally {
101                 StrictMode.setThreadPolicy(oldPolicy);
102             }
103         } else {
104             mPidFd = null;
105         }
106     }
107 
108     @GuardedBy("mLock")
killLocked(String reason, boolean noisy)109     void killLocked(String reason, boolean noisy) {
110         if (!mKilled) {
111             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "kill");
112             if (noisy || mUid == mService.mCurOomAdjUid) {
113                 mService.reportUidInfoMessageLocked(TAG,
114                         "Killing " + toString() + ": " + reason, mUid);
115             }
116             if (mPid > 0) {
117                 EventLog.writeEvent(EventLogTags.AM_KILL, UserHandle.getUserId(mUid),
118                         mPid, mProcessName, mAdj, reason);
119                 if (!Process.supportsPidFd()) {
120                     onProcDied(false);
121                 } else {
122                     // We'll notify the listener when we're notified it's dead.
123                     // Meanwhile, we'd also need handle the case of zombie processes.
124                     mKillHandler.postDelayed(mProcKillTimer, this,
125                             ProcessList.PROC_KILL_TIMEOUT);
126                 }
127                 Process.killProcessQuiet(mPid);
128                 ProcessList.killProcessGroup(mUid, mPid);
129             }
130             mKilled = true;
131             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
132         }
133     }
134 
135     private Runnable mProcKillTimer = new Runnable() {
136         @Override
137         public void run() {
138             synchronized (mLock) {
139                 // The process is maybe in either D or Z state.
140                 Slog.w(TAG, "Process " + toString() + " is still alive after "
141                         + ProcessList.PROC_KILL_TIMEOUT + "ms");
142                 // Force a cleanup as we can't keep the fd open forever
143                 mZombie = true;
144                 onProcDied(false);
145                 // But still bookkeep it, so it won't be added as a new one if it's spotted again.
146             }
147         }
148     };
149 
150     @GuardedBy("mLock")
updateAdjLocked()151     void updateAdjLocked() {
152         if (Process.readProcFile("/proc/" + mPid + "/oom_score_adj",
153                 LONG_FORMAT, null, LONG_OUT, null)) {
154             mAdj = (int) LONG_OUT[0];
155         }
156     }
157 
158     @GuardedBy("mLock")
onProcDied(boolean reallyDead)159     void onProcDied(boolean reallyDead) {
160         if (reallyDead) {
161             Slog.i(TAG, "Process " + toString() + " died");
162         }
163         mKillHandler.removeCallbacks(mProcKillTimer, this);
164         if (mOnKillListener != null) {
165             mOnKillListener.accept(this);
166         }
167     }
168 
169     @Override
toString()170     public String toString() {
171         if (mStringName != null) {
172             return mStringName;
173         }
174         StringBuilder sb = new StringBuilder(128);
175         sb.append("PhantomProcessRecord {");
176         sb.append(Integer.toHexString(System.identityHashCode(this)));
177         sb.append(' ');
178         sb.append(mPid);
179         sb.append(':');
180         sb.append(mPpid);
181         sb.append(':');
182         sb.append(mProcessName);
183         sb.append('/');
184         if (mUid < Process.FIRST_APPLICATION_UID) {
185             sb.append(mUid);
186         } else {
187             sb.append('u');
188             sb.append(UserHandle.getUserId(mUid));
189             int appId = UserHandle.getAppId(mUid);
190             if (appId >= Process.FIRST_APPLICATION_UID) {
191                 sb.append('a');
192                 sb.append(appId - Process.FIRST_APPLICATION_UID);
193             } else {
194                 sb.append('s');
195                 sb.append(appId);
196             }
197             if (appId >= Process.FIRST_ISOLATED_UID && appId <= Process.LAST_ISOLATED_UID) {
198                 sb.append('i');
199                 sb.append(appId - Process.FIRST_ISOLATED_UID);
200             }
201         }
202         sb.append('}');
203         return mStringName = sb.toString();
204     }
205 
dump(PrintWriter pw, String prefix)206     void dump(PrintWriter pw, String prefix) {
207         final long now = SystemClock.elapsedRealtime();
208         pw.print(prefix);
209         pw.print("user #");
210         pw.print(UserHandle.getUserId(mUid));
211         pw.print(" uid=");
212         pw.print(mUid);
213         pw.print(" pid=");
214         pw.print(mPid);
215         pw.print(" ppid=");
216         pw.print(mPpid);
217         pw.print(" knownSince=");
218         TimeUtils.formatDuration(mKnownSince, now, pw);
219         pw.print(" killed=");
220         pw.println(mKilled);
221         pw.print(prefix);
222         pw.print("lastCpuTime=");
223         pw.print(mLastCputime);
224         if (mLastCputime > 0) {
225             pw.print(" timeUsed=");
226             TimeUtils.formatDuration(mCurrentCputime - mLastCputime, pw);
227         }
228         pw.print(" oom adj=");
229         pw.print(mAdj);
230         pw.print(" seq=");
231         pw.println(mUpdateSeq);
232     }
233 
equals(final String processName, final int uid, final int pid)234     boolean equals(final String processName, final int uid, final int pid) {
235         return mUid == uid && mPid == pid && TextUtils.equals(mProcessName, processName);
236     }
237 }
238