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