• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.appop;
18 
19 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL;
20 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
21 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
22 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
23 import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
24 import static android.app.ActivityManager.ProcessCapability;
25 import static android.app.AppOpsManager.MIN_PRIORITY_UID_STATE;
26 import static android.app.AppOpsManager.MODE_ALLOWED;
27 import static android.app.AppOpsManager.MODE_FOREGROUND;
28 import static android.app.AppOpsManager.MODE_IGNORED;
29 import static android.app.AppOpsManager.OP_CAMERA;
30 import static android.app.AppOpsManager.OP_CONTROL_AUDIO;
31 import static android.app.AppOpsManager.OP_NONE;
32 import static android.app.AppOpsManager.OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO;
33 import static android.app.AppOpsManager.OP_RECORD_AUDIO;
34 import static android.app.AppOpsManager.UID_STATE_CACHED;
35 import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
36 import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
37 import static android.app.AppOpsManager.UID_STATE_NONEXISTENT;
38 import static android.app.AppOpsManager.UID_STATE_TOP;
39 import static android.permission.flags.Flags.delayUidStateChangesFromCapabilityUpdates;
40 import static android.permission.flags.Flags.finishRunningOpsForKilledPackages;
41 
42 import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState;
43 
44 import android.app.ActivityManager;
45 import android.app.ActivityManagerInternal;
46 import android.app.AppOpsManager;
47 import android.os.Handler;
48 import android.util.ArrayMap;
49 import android.util.SparseArray;
50 import android.util.SparseBooleanArray;
51 import android.util.SparseIntArray;
52 import android.util.SparseLongArray;
53 import android.util.TimeUtils;
54 
55 import com.android.internal.annotations.VisibleForTesting;
56 import com.android.internal.os.Clock;
57 import com.android.internal.util.function.pooled.PooledLambda;
58 
59 import java.io.PrintWriter;
60 import java.util.concurrent.Executor;
61 
62 class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker {
63 
64     private static final String LOG_TAG = AppOpsUidStateTrackerImpl.class.getSimpleName();
65 
66     private final DelayableExecutor mExecutor;
67     private final Clock mClock;
68     private ActivityManagerInternal mActivityManagerInternal;
69     private AppOpsService.Constants mConstants;
70 
71     private SparseIntArray mUidStates = new SparseIntArray();
72     private SparseIntArray mPendingUidStates = new SparseIntArray();
73     private SparseIntArray mCapability = new SparseIntArray();
74     private SparseIntArray mPendingCapability = new SparseIntArray();
75     private SparseBooleanArray mAppWidgetVisible = new SparseBooleanArray();
76     private SparseBooleanArray mPendingAppWidgetVisible = new SparseBooleanArray();
77     private SparseLongArray mPendingCommitTime = new SparseLongArray();
78 
79     private ArrayMap<UidStateChangedCallback, Executor>
80             mUidStateChangedCallbacks = new ArrayMap<>();
81 
82     private final EventLog mEventLog;
83 
84     @VisibleForTesting
85     interface DelayableExecutor extends Executor {
86 
execute(Runnable runnable)87         void execute(Runnable runnable);
88 
executeDelayed(Runnable runnable, long delay)89         void executeDelayed(Runnable runnable, long delay);
90     }
91 
AppOpsUidStateTrackerImpl(ActivityManagerInternal activityManagerInternal, Handler handler, Executor lockingExecutor, Clock clock, AppOpsService.Constants constants)92     AppOpsUidStateTrackerImpl(ActivityManagerInternal activityManagerInternal,
93             Handler handler, Executor lockingExecutor, Clock clock,
94             AppOpsService.Constants constants) {
95 
96         this(activityManagerInternal, new DelayableExecutor() {
97             @Override
98             public void execute(Runnable runnable) {
99                 handler.post(() -> lockingExecutor.execute(runnable));
100             }
101 
102             @Override
103             public void executeDelayed(Runnable runnable, long delay) {
104                 handler.postDelayed(() -> lockingExecutor.execute(runnable), delay);
105             }
106         }, clock, constants, handler.getLooper().getThread());
107     }
108 
109     @VisibleForTesting
AppOpsUidStateTrackerImpl(ActivityManagerInternal activityManagerInternal, DelayableExecutor executor, Clock clock, AppOpsService.Constants constants, Thread executorThread)110     AppOpsUidStateTrackerImpl(ActivityManagerInternal activityManagerInternal,
111             DelayableExecutor executor, Clock clock, AppOpsService.Constants constants,
112             Thread executorThread) {
113         mActivityManagerInternal = activityManagerInternal;
114         mExecutor = executor;
115         mClock = clock;
116         mConstants = constants;
117 
118         mEventLog = new EventLog(executor, executorThread);
119     }
120 
121     @Override
getUidState(int uid)122     public int getUidState(int uid) {
123         return getUidStateLocked(uid);
124     }
125 
getUidStateLocked(int uid)126     private int getUidStateLocked(int uid) {
127         updateUidPendingStateIfNeeded(uid);
128         return mUidStates.get(uid, MIN_PRIORITY_UID_STATE);
129     }
130 
131     @Override
evalMode(int uid, int code, int mode)132     public int evalMode(int uid, int code, int mode) {
133         if (mode != MODE_FOREGROUND) {
134             return mode;
135         }
136 
137         int uidState = getUidState(uid);
138         int uidCapability = getUidCapability(uid);
139         int result = evalModeInternal(uid, code, uidState, uidCapability);
140 
141         mEventLog.logEvalForegroundMode(uid, uidState, uidCapability, code, result);
142         return result;
143     }
144 
evalModeInternal(int uid, int code, int uidState, int uidCapability)145     private int evalModeInternal(int uid, int code, int uidState, int uidCapability) {
146         if (getUidAppWidgetVisible(uid) || mActivityManagerInternal.isPendingTopUid(uid)
147                 || mActivityManagerInternal.isTempAllowlistedForFgsWhileInUse(uid)) {
148             return MODE_ALLOWED;
149         }
150 
151         int opCapability = getOpCapability(code);
152         if (opCapability != PROCESS_CAPABILITY_NONE) {
153             if ((uidCapability & opCapability) == 0) {
154                 return MODE_IGNORED;
155             } else {
156                 return MODE_ALLOWED;
157             }
158         }
159 
160         if (uidState > AppOpsManager.resolveFirstUnrestrictedUidState(code)) {
161             return MODE_IGNORED;
162         }
163 
164         return MODE_ALLOWED;
165     }
166 
getOpCapability(int opCode)167     private int getOpCapability(int opCode) {
168         switch (opCode) {
169             case AppOpsManager.OP_FINE_LOCATION:
170             case AppOpsManager.OP_COARSE_LOCATION:
171             case AppOpsManager.OP_MONITOR_LOCATION:
172             case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION:
173                 return PROCESS_CAPABILITY_FOREGROUND_LOCATION;
174             case OP_CAMERA:
175                 return PROCESS_CAPABILITY_FOREGROUND_CAMERA;
176             case OP_RECORD_AUDIO:
177             case OP_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO:
178                 return PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
179             case OP_CONTROL_AUDIO:
180                 return PROCESS_CAPABILITY_FOREGROUND_AUDIO_CONTROL;
181             default:
182                 return PROCESS_CAPABILITY_NONE;
183         }
184     }
185 
186     @Override
isUidInForeground(int uid)187     public boolean isUidInForeground(int uid) {
188         return evalMode(uid, OP_NONE, MODE_FOREGROUND) == MODE_ALLOWED;
189     }
190 
191     @Override
addUidStateChangedCallback(Executor executor, UidStateChangedCallback callback)192     public void addUidStateChangedCallback(Executor executor, UidStateChangedCallback callback) {
193         if (mUidStateChangedCallbacks.containsKey(callback)) {
194             throw new IllegalStateException("Callback is already registered.");
195         }
196 
197         mUidStateChangedCallbacks.put(callback, executor);
198     }
199 
200     @Override
removeUidStateChangedCallback(UidStateChangedCallback callback)201     public void removeUidStateChangedCallback(UidStateChangedCallback callback) {
202         if (!mUidStateChangedCallbacks.containsKey(callback)) {
203             throw new IllegalStateException("Callback is not registered.");
204         }
205         mUidStateChangedCallbacks.remove(callback);
206     }
207 
208     @Override
updateAppWidgetVisibility(SparseArray<String> uidPackageNames, boolean visible)209     public void updateAppWidgetVisibility(SparseArray<String> uidPackageNames, boolean visible) {
210         int numUids = uidPackageNames.size();
211         for (int i = 0; i < numUids; i++) {
212             int uid = uidPackageNames.keyAt(i);
213             mPendingAppWidgetVisible.put(uid, visible);
214 
215             commitUidPendingState(uid);
216         }
217     }
218 
219     @Override
updateUidProcState(int uid, int procState, int capability)220     public void updateUidProcState(int uid, int procState, int capability) {
221         int uidState = processStateToUidState(procState);
222 
223         int prevUidState = mUidStates.get(uid, AppOpsManager.UID_STATE_NONEXISTENT);
224         int prevCapability = mCapability.get(uid, PROCESS_CAPABILITY_NONE);
225         int pendingUidState = mPendingUidStates.get(uid, UID_STATE_NONEXISTENT);
226         int pendingCapability = mPendingCapability.get(uid, PROCESS_CAPABILITY_NONE);
227         long pendingStateCommitTime = mPendingCommitTime.get(uid, 0);
228 
229         if ((pendingStateCommitTime == 0
230                 && (uidState != prevUidState || capability != prevCapability))
231                 || (pendingStateCommitTime != 0
232                 && (uidState != pendingUidState || capability != pendingCapability))) {
233 
234             // If this process update results in a capability or uid state change, log it. It's
235             // not interesting otherwise.
236             mEventLog.logUpdateUidProcState(uid, procState, capability);
237             mPendingUidStates.put(uid, uidState);
238             mPendingCapability.put(uid, capability);
239 
240             boolean hasLostCapability = (prevCapability & ~capability) != 0;
241 
242             if (uidState == UID_STATE_NONEXISTENT) {
243                 commitUidPendingState(uid);
244             } else if (uidState < prevUidState) {
245                 // We are moving to a more important state, or the new state may be in the
246                 // foreground and the old state is in the background, then always do it
247                 // immediately.
248                 commitUidPendingState(uid);
249             } else if (delayUidStateChangesFromCapabilityUpdates()
250                     && uidState == prevUidState && !hasLostCapability) {
251                 // No change on process state, but process capability hasn't decreased.
252                 commitUidPendingState(uid);
253             } else if (!delayUidStateChangesFromCapabilityUpdates()
254                     && uidState == prevUidState && capability != prevCapability) {
255                 // No change on process state, but process capability has changed.
256                 commitUidPendingState(uid);
257             } else if (uidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
258                     && (!delayUidStateChangesFromCapabilityUpdates() || !hasLostCapability)) {
259                 // We are moving to a less important state, but it doesn't cross the restriction
260                 // threshold.
261                 commitUidPendingState(uid);
262             } else if (pendingStateCommitTime == 0) {
263                 // We are moving to a less important state for the first time,
264                 // delay the application for a bit.
265                 final long settleTime;
266                 if (prevUidState <= UID_STATE_TOP) {
267                     settleTime = mConstants.TOP_STATE_SETTLE_TIME;
268                 } else if (prevUidState <= UID_STATE_FOREGROUND_SERVICE) {
269                     settleTime = mConstants.FG_SERVICE_STATE_SETTLE_TIME;
270                 } else {
271                     settleTime = mConstants.BG_STATE_SETTLE_TIME;
272                 }
273                 final long commitTime = mClock.elapsedRealtime() + settleTime;
274                 mPendingCommitTime.put(uid, commitTime);
275 
276                 mExecutor.executeDelayed(PooledLambda.obtainRunnable(
277                                 AppOpsUidStateTrackerImpl::updateUidPendingStateIfNeeded, this,
278                                 uid), settleTime + 1);
279             }
280         }
281     }
282 
283     @Override
dumpUidState(PrintWriter pw, int uid, long nowElapsed)284     public void dumpUidState(PrintWriter pw, int uid, long nowElapsed) {
285         int state = mUidStates.get(uid, MIN_PRIORITY_UID_STATE);
286         // if no pendingState set to state to suppress output
287         int pendingState = mPendingUidStates.get(uid, state);
288         pw.print("    state=");
289         pw.println(AppOpsManager.getUidStateName(state));
290         if (state != pendingState) {
291             pw.print("    pendingState=");
292             pw.println(AppOpsManager.getUidStateName(pendingState));
293         }
294         int capability = mCapability.get(uid, PROCESS_CAPABILITY_NONE);
295         // if no pendingCapability set to capability to suppress output
296         int pendingCapability = mPendingCapability.get(uid, capability);
297         pw.print("    capability=");
298         ActivityManager.printCapabilitiesFull(pw, capability);
299         pw.println();
300         if (capability != pendingCapability) {
301             pw.print("    pendingCapability=");
302             ActivityManager.printCapabilitiesFull(pw, pendingCapability);
303             pw.println();
304         }
305         boolean appWidgetVisible = mAppWidgetVisible.get(uid, false);
306         // if no pendingAppWidgetVisible set to appWidgetVisible to suppress output
307         boolean pendingAppWidgetVisible = mPendingAppWidgetVisible.get(uid, appWidgetVisible);
308         pw.print("    appWidgetVisible=");
309         pw.println(appWidgetVisible);
310         if (appWidgetVisible != pendingAppWidgetVisible) {
311             pw.print("    pendingAppWidgetVisible=");
312             pw.println(pendingAppWidgetVisible);
313         }
314         long pendingStateCommitTime = mPendingCommitTime.get(uid, 0);
315         if (pendingStateCommitTime != 0) {
316             pw.print("    pendingStateCommitTime=");
317             TimeUtils.formatDuration(pendingStateCommitTime, nowElapsed, pw);
318             pw.println();
319         }
320     }
321 
322     @Override
dumpEvents(PrintWriter pw)323     public void dumpEvents(PrintWriter pw) {
324         mEventLog.dumpEvents(pw);
325     }
326 
updateUidPendingStateIfNeeded(int uid)327     private void updateUidPendingStateIfNeeded(int uid) {
328         updateUidPendingStateIfNeededLocked(uid);
329     }
330 
updateUidPendingStateIfNeededLocked(int uid)331     private void updateUidPendingStateIfNeededLocked(int uid) {
332         long pendingCommitTime = mPendingCommitTime.get(uid, 0);
333         if (pendingCommitTime != 0) {
334             long currentTime = mClock.elapsedRealtime();
335             if (currentTime < mPendingCommitTime.get(uid)) {
336                 return;
337             }
338             commitUidPendingState(uid);
339         }
340     }
341 
commitUidPendingState(int uid)342     private void commitUidPendingState(int uid) {
343 
344         int uidState = mUidStates.get(uid, UID_STATE_NONEXISTENT);
345         int capability = mCapability.get(uid, PROCESS_CAPABILITY_NONE);
346         boolean appWidgetVisible = mAppWidgetVisible.get(uid, false);
347 
348         int pendingUidState = mPendingUidStates.get(uid, uidState);
349         int pendingCapability = mPendingCapability.get(uid, capability);
350         boolean pendingAppWidgetVisible = mPendingAppWidgetVisible.get(uid, appWidgetVisible);
351 
352         // UID_STATE_NONEXISTENT is a state that isn't used outside of this class, nonexistent
353         // processes have always been represented as CACHED
354         int externalUidState = Math.min(uidState, UID_STATE_CACHED);
355         int externalPendingUidState = Math.min(pendingUidState, UID_STATE_CACHED);
356 
357         boolean foregroundChange = externalUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
358                 != externalPendingUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
359                 || capability != pendingCapability
360                 || appWidgetVisible != pendingAppWidgetVisible;
361 
362         if (externalUidState != externalPendingUidState
363                 || capability != pendingCapability
364                 || appWidgetVisible != pendingAppWidgetVisible) {
365 
366             if (foregroundChange) {
367                 // To save on memory usage, log only interesting changes.
368                 mEventLog.logCommitUidState(uid, externalPendingUidState, pendingCapability,
369                         pendingAppWidgetVisible, appWidgetVisible != pendingAppWidgetVisible);
370             }
371 
372             for (int i = 0; i < mUidStateChangedCallbacks.size(); i++) {
373                 UidStateChangedCallback cb = mUidStateChangedCallbacks.keyAt(i);
374                 Executor executor = mUidStateChangedCallbacks.valueAt(i);
375 
376                 executor.execute(PooledLambda.obtainRunnable(
377                         UidStateChangedCallback::onUidStateChanged, cb, uid,
378                         externalPendingUidState, foregroundChange));
379             }
380         }
381 
382         if (pendingUidState == UID_STATE_NONEXISTENT && uidState != pendingUidState) {
383             mUidStates.delete(uid);
384             mCapability.delete(uid);
385             mAppWidgetVisible.delete(uid);
386             if (finishRunningOpsForKilledPackages()) {
387                 for (int i = 0; i < mUidStateChangedCallbacks.size(); i++) {
388                     UidStateChangedCallback cb = mUidStateChangedCallbacks.keyAt(i);
389                     Executor executor = mUidStateChangedCallbacks.valueAt(i);
390 
391                     // If foregroundness changed it should be handled in earlier callback invocation
392                     executor.execute(PooledLambda.obtainRunnable(
393                             UidStateChangedCallback::onUidProcessDeath, cb, uid));
394                 }
395             }
396         } else {
397             mUidStates.put(uid, pendingUidState);
398             mCapability.put(uid, pendingCapability);
399             mAppWidgetVisible.put(uid, pendingAppWidgetVisible);
400         }
401 
402         mPendingUidStates.delete(uid);
403         mPendingCapability.delete(uid);
404         mPendingAppWidgetVisible.delete(uid);
405         mPendingCommitTime.delete(uid);
406     }
407 
getUidCapability(int uid)408     private @ProcessCapability int getUidCapability(int uid) {
409         return mCapability.get(uid, ActivityManager.PROCESS_CAPABILITY_NONE);
410     }
411 
getUidAppWidgetVisible(int uid)412     private boolean getUidAppWidgetVisible(int uid) {
413         return mAppWidgetVisible.get(uid, false);
414     }
415 
416     private static class EventLog {
417 
418         // Memory usage: 16 * size bytes
419         private static final int UPDATE_UID_PROC_STATE_LOG_MAX_SIZE = 200;
420         // Memory usage: 20 * size bytes
421         private static final int COMMIT_UID_STATE_LOG_MAX_SIZE = 200;
422         // Memory usage: 24 * size bytes
423         private static final int EVAL_FOREGROUND_MODE_MAX_SIZE = 200;
424 
425         private static final int APP_WIDGET_VISIBLE = 1 << 0;
426         private static final int APP_WIDGET_VISIBLE_CHANGED = 1 << 1;
427 
428         private final DelayableExecutor mExecutor;
429         private final Thread mExecutorThread;
430 
431         private int[][] mUpdateUidProcStateLog = new int[UPDATE_UID_PROC_STATE_LOG_MAX_SIZE][3];
432         private long[] mUpdateUidProcStateLogTimestamps =
433                 new long[UPDATE_UID_PROC_STATE_LOG_MAX_SIZE];
434         private int mUpdateUidProcStateLogSize = 0;
435         private int mUpdateUidProcStateLogHead = 0;
436 
437         private int[][] mCommitUidStateLog = new int[COMMIT_UID_STATE_LOG_MAX_SIZE][4];
438         private long[] mCommitUidStateLogTimestamps = new long[COMMIT_UID_STATE_LOG_MAX_SIZE];
439         private int mCommitUidStateLogSize = 0;
440         private int mCommitUidStateLogHead = 0;
441 
442         private int[][] mEvalForegroundModeLog = new int[EVAL_FOREGROUND_MODE_MAX_SIZE][5];
443         private long[] mEvalForegroundModeLogTimestamps = new long[EVAL_FOREGROUND_MODE_MAX_SIZE];
444         private int mEvalForegroundModeLogSize = 0;
445         private int mEvalForegroundModeLogHead = 0;
446 
EventLog(DelayableExecutor executor, Thread executorThread)447         EventLog(DelayableExecutor executor, Thread executorThread) {
448             mExecutor = executor;
449             mExecutorThread = executorThread;
450         }
451 
logUpdateUidProcState(int uid, int procState, int capability)452         void logUpdateUidProcState(int uid, int procState, int capability) {
453             if (UPDATE_UID_PROC_STATE_LOG_MAX_SIZE == 0) {
454                 return;
455             }
456             mExecutor.execute(PooledLambda.obtainRunnable(EventLog::logUpdateUidProcStateAsync,
457                     this, System.currentTimeMillis(), uid, procState, capability));
458         }
459 
logUpdateUidProcStateAsync(long timestamp, int uid, int procState, int capability)460         void logUpdateUidProcStateAsync(long timestamp, int uid, int procState, int capability) {
461             int idx = (mUpdateUidProcStateLogHead + mUpdateUidProcStateLogSize)
462                     % UPDATE_UID_PROC_STATE_LOG_MAX_SIZE;
463             if (mUpdateUidProcStateLogSize == UPDATE_UID_PROC_STATE_LOG_MAX_SIZE) {
464                 mUpdateUidProcStateLogHead =
465                         (mUpdateUidProcStateLogHead + 1) % UPDATE_UID_PROC_STATE_LOG_MAX_SIZE;
466             } else {
467                 mUpdateUidProcStateLogSize++;
468             }
469 
470             mUpdateUidProcStateLog[idx][0] = uid;
471             mUpdateUidProcStateLog[idx][1] = procState;
472             mUpdateUidProcStateLog[idx][2] = capability;
473             mUpdateUidProcStateLogTimestamps[idx] = timestamp;
474         }
475 
logCommitUidState(int uid, int uidState, int capability, boolean appWidgetVisible, boolean appWidgetVisibleChanged)476         void logCommitUidState(int uid, int uidState, int capability, boolean appWidgetVisible,
477                 boolean appWidgetVisibleChanged) {
478             if (COMMIT_UID_STATE_LOG_MAX_SIZE == 0) {
479                 return;
480             }
481             mExecutor.execute(PooledLambda.obtainRunnable(EventLog::logCommitUidStateAsync,
482                     this, System.currentTimeMillis(), uid, uidState, capability, appWidgetVisible,
483                     appWidgetVisibleChanged));
484         }
485 
logCommitUidStateAsync(long timestamp, int uid, int uidState, int capability, boolean appWidgetVisible, boolean appWidgetVisibleChanged)486         void logCommitUidStateAsync(long timestamp, int uid, int uidState, int capability,
487                 boolean appWidgetVisible, boolean appWidgetVisibleChanged) {
488             int idx = (mCommitUidStateLogHead + mCommitUidStateLogSize)
489                     % COMMIT_UID_STATE_LOG_MAX_SIZE;
490             if (mCommitUidStateLogSize == COMMIT_UID_STATE_LOG_MAX_SIZE) {
491                 mCommitUidStateLogHead =
492                         (mCommitUidStateLogHead + 1) % COMMIT_UID_STATE_LOG_MAX_SIZE;
493             } else {
494                 mCommitUidStateLogSize++;
495             }
496 
497             mCommitUidStateLog[idx][0] = uid;
498             mCommitUidStateLog[idx][1] = uidState;
499             mCommitUidStateLog[idx][2] = capability;
500             mCommitUidStateLog[idx][3] = 0;
501             if (appWidgetVisible) {
502                 mCommitUidStateLog[idx][3] += APP_WIDGET_VISIBLE;
503             }
504             if (appWidgetVisibleChanged) {
505                 mCommitUidStateLog[idx][3] += APP_WIDGET_VISIBLE_CHANGED;
506             }
507             mCommitUidStateLogTimestamps[idx] = timestamp;
508         }
509 
logEvalForegroundMode(int uid, int uidState, int capability, int code, int result)510         void logEvalForegroundMode(int uid, int uidState, int capability, int code, int result) {
511             if (EVAL_FOREGROUND_MODE_MAX_SIZE == 0) {
512                 return;
513             }
514             mExecutor.execute(PooledLambda.obtainRunnable(EventLog::logEvalForegroundModeAsync,
515                     this, System.currentTimeMillis(), uid, uidState, capability, code, result));
516         }
517 
logEvalForegroundModeAsync(long timestamp, int uid, int uidState, int capability, int code, int result)518         void logEvalForegroundModeAsync(long timestamp, int uid, int uidState, int capability,
519                 int code, int result) {
520             int idx = (mEvalForegroundModeLogHead + mEvalForegroundModeLogSize)
521                     % EVAL_FOREGROUND_MODE_MAX_SIZE;
522             if (mEvalForegroundModeLogSize == EVAL_FOREGROUND_MODE_MAX_SIZE) {
523                 mEvalForegroundModeLogHead =
524                         (mEvalForegroundModeLogHead + 1) % EVAL_FOREGROUND_MODE_MAX_SIZE;
525             } else {
526                 mEvalForegroundModeLogSize++;
527             }
528 
529             mEvalForegroundModeLog[idx][0] = uid;
530             mEvalForegroundModeLog[idx][1] = uidState;
531             mEvalForegroundModeLog[idx][2] = capability;
532             mEvalForegroundModeLog[idx][3] = code;
533             mEvalForegroundModeLog[idx][4] = result;
534             mEvalForegroundModeLogTimestamps[idx] = timestamp;
535         }
536 
dumpEvents(PrintWriter pw)537         void dumpEvents(PrintWriter pw) {
538             int updateIdx = 0;
539             int commitIdx = 0;
540             int evalIdx = 0;
541 
542             while (updateIdx < mUpdateUidProcStateLogSize
543                     || commitIdx < mCommitUidStateLogSize
544                     || evalIdx < mEvalForegroundModeLogSize) {
545                 int updatePtr = 0;
546                 int commitPtr = 0;
547                 int evalPtr = 0;
548                 if (UPDATE_UID_PROC_STATE_LOG_MAX_SIZE != 0) {
549                     updatePtr = (mUpdateUidProcStateLogHead + updateIdx)
550                             % UPDATE_UID_PROC_STATE_LOG_MAX_SIZE;
551                 }
552                 if (COMMIT_UID_STATE_LOG_MAX_SIZE != 0) {
553                     commitPtr = (mCommitUidStateLogHead + commitIdx)
554                             % COMMIT_UID_STATE_LOG_MAX_SIZE;
555                 }
556                 if (EVAL_FOREGROUND_MODE_MAX_SIZE != 0) {
557                     evalPtr = (mEvalForegroundModeLogHead + evalIdx)
558                             % EVAL_FOREGROUND_MODE_MAX_SIZE;
559                 }
560 
561                 long aTimestamp = updateIdx < mUpdateUidProcStateLogSize
562                         ? mUpdateUidProcStateLogTimestamps[updatePtr] : Long.MAX_VALUE;
563                 long bTimestamp = commitIdx < mCommitUidStateLogSize
564                         ? mCommitUidStateLogTimestamps[commitPtr] : Long.MAX_VALUE;
565                 long cTimestamp = evalIdx < mEvalForegroundModeLogSize
566                         ? mEvalForegroundModeLogTimestamps[evalPtr] : Long.MAX_VALUE;
567 
568                 if (aTimestamp <= bTimestamp && aTimestamp <= cTimestamp) {
569                     dumpUpdateUidProcState(pw, updatePtr);
570                     updateIdx++;
571                 } else if (bTimestamp <= cTimestamp) {
572                     dumpCommitUidState(pw, commitPtr);
573                     commitIdx++;
574                 } else {
575                     dumpEvalForegroundMode(pw, evalPtr);
576                     evalIdx++;
577                 }
578             }
579         }
580 
581         void dumpUpdateUidProcState(PrintWriter pw, int idx) {
582             long timestamp = mUpdateUidProcStateLogTimestamps[idx];
583             int uid = mUpdateUidProcStateLog[idx][0];
584             int procState = mUpdateUidProcStateLog[idx][1];
585             int capability = mUpdateUidProcStateLog[idx][2];
586 
587             TimeUtils.dumpTime(pw, timestamp);
588 
589             pw.print(" UPDATE_UID_PROC_STATE");
590 
591             pw.print(" uid=");
592             pw.print(String.format("%-8d", uid));
593 
594             pw.print(" procState=");
595             pw.print(String.format("%-30s", ActivityManager.procStateToString(procState)));
596 
597             pw.print(" capability=");
598             pw.print(ActivityManager.getCapabilitiesSummary(capability) + " ");
599 
600             pw.println();
601         }
602 
603         void dumpCommitUidState(PrintWriter pw, int idx) {
604             long timestamp = mCommitUidStateLogTimestamps[idx];
605             int uid = mCommitUidStateLog[idx][0];
606             int uidState = mCommitUidStateLog[idx][1];
607             int capability = mCommitUidStateLog[idx][2];
608             boolean appWidgetVisible = (mCommitUidStateLog[idx][3] & APP_WIDGET_VISIBLE) != 0;
609             boolean appWidgetVisibleChanged =
610                     (mCommitUidStateLog[idx][3] & APP_WIDGET_VISIBLE_CHANGED) != 0;
611 
612             TimeUtils.dumpTime(pw, timestamp);
613 
614             pw.print(" COMMIT_UID_STATE     ");
615 
616             pw.print(" uid=");
617             pw.print(String.format("%-8d", uid));
618 
619             pw.print(" uidState=");
620             pw.print(String.format("%-30s", AppOpsManager.uidStateToString(uidState)));
621 
622             pw.print(" capability=");
623             pw.print(ActivityManager.getCapabilitiesSummary(capability) + " ");
624 
625             pw.print(" appWidgetVisible=");
626             pw.print(appWidgetVisible);
627 
628             if (appWidgetVisibleChanged) {
629                 pw.print(" (changed)");
630             }
631 
632             pw.println();
633         }
634 
635         void dumpEvalForegroundMode(PrintWriter pw, int idx) {
636             long timestamp = mEvalForegroundModeLogTimestamps[idx];
637             int uid = mEvalForegroundModeLog[idx][0];
638             int uidState = mEvalForegroundModeLog[idx][1];
639             int capability = mEvalForegroundModeLog[idx][2];
640             int code = mEvalForegroundModeLog[idx][3];
641             int result = mEvalForegroundModeLog[idx][4];
642 
643             TimeUtils.dumpTime(pw, timestamp);
644 
645             pw.print(" EVAL_FOREGROUND_MODE ");
646 
647             pw.print(" uid=");
648             pw.print(String.format("%-8d", uid));
649 
650             pw.print(" uidState=");
651             pw.print(String.format("%-30s", AppOpsManager.uidStateToString(uidState)));
652 
653             pw.print(" capability=");
654             pw.print(ActivityManager.getCapabilitiesSummary(capability) + " ");
655 
656             pw.print(" code=");
657             pw.print(String.format("%-20s", AppOpsManager.opToName(code)));
658 
659             pw.print(" result=");
660             pw.print(AppOpsManager.modeToName(result));
661 
662             pw.println();
663         }
664     }
665 }
666