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