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 package com.android.server.am; 17 18 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; 19 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; 20 21 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS; 22 import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS; 23 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.app.ActivityManager; 27 import android.app.ActivityManagerProto; 28 import android.app.IUidObserver; 29 import android.content.pm.PackageManager; 30 import android.os.Binder; 31 import android.os.Handler; 32 import android.os.IBinder; 33 import android.os.Message; 34 import android.os.RemoteCallbackList; 35 import android.os.RemoteException; 36 import android.os.SystemClock; 37 import android.os.UserHandle; 38 import android.util.Slog; 39 import android.util.SparseIntArray; 40 import android.util.proto.ProtoOutputStream; 41 import android.util.proto.ProtoUtils; 42 43 import com.android.internal.annotations.GuardedBy; 44 import com.android.internal.annotations.VisibleForTesting; 45 import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto; 46 47 import java.io.PrintWriter; 48 import java.util.ArrayList; 49 import java.util.Arrays; 50 import java.util.UUID; 51 52 public class UidObserverController { 53 /** If a UID observer takes more than this long, send a WTF. */ 54 private static final int SLOW_UID_OBSERVER_THRESHOLD_MS = 20; 55 56 private final Handler mHandler; 57 58 private final Object mLock = new Object(); 59 60 @GuardedBy("mLock") 61 final RemoteCallbackList<IUidObserver> mUidObservers = new RemoteCallbackList<>(); 62 63 @GuardedBy("mLock") 64 private final ArrayList<ChangeRecord> mPendingUidChanges = new ArrayList<>(); 65 @GuardedBy("mLock") 66 private final ArrayList<ChangeRecord> mAvailUidChanges = new ArrayList<>(); 67 68 private ChangeRecord[] mActiveUidChanges = new ChangeRecord[5]; 69 70 /** Total # of UID change events dispatched, shown in dumpsys. */ 71 @GuardedBy("mLock") 72 private int mUidChangeDispatchCount; 73 74 private final Runnable mDispatchRunnable = this::dispatchUidsChanged; 75 76 /** 77 * This is for verifying the UID report flow. 78 */ 79 private static final boolean VALIDATE_UID_STATES = true; 80 private final ActiveUids mValidateUids; 81 UidObserverController(@onNull Handler handler)82 UidObserverController(@NonNull Handler handler) { 83 mHandler = handler; 84 mValidateUids = new ActiveUids(null /* service */, false /* postChangesToAtm */); 85 } 86 register(@onNull IUidObserver observer, int which, int cutpoint, @NonNull String callingPackage, int callingUid, @Nullable int[] uids)87 IBinder register(@NonNull IUidObserver observer, int which, int cutpoint, 88 @NonNull String callingPackage, int callingUid, @Nullable int[] uids) { 89 IBinder token = new Binder("UidObserver-" + callingPackage + "-" 90 + UUID.randomUUID().toString()); 91 92 synchronized (mLock) { 93 mUidObservers.register(observer, new UidObserverRegistration(callingUid, 94 callingPackage, which, cutpoint, 95 ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL, callingUid) 96 == PackageManager.PERMISSION_GRANTED, uids, token)); 97 } 98 99 return token; 100 } 101 unregister(@onNull IUidObserver observer)102 void unregister(@NonNull IUidObserver observer) { 103 synchronized (mLock) { 104 mUidObservers.unregister(observer); 105 } 106 } 107 addUidToObserver(@onNull IBinder observerToken, int uid)108 final void addUidToObserver(@NonNull IBinder observerToken, int uid) { 109 Message msg = Message.obtain(mHandler, ActivityManagerService.ADD_UID_TO_OBSERVER_MSG, 110 uid, /*arg2*/ 0, observerToken); 111 mHandler.sendMessage(msg); 112 } 113 114 /** 115 * Add a uid to the list of uids an observer is interested in. Must be run on the same thread 116 * as mDispatchRunnable. 117 * 118 * @param observerToken The token identifier for a UidObserver 119 * @param uid The uid to add to the list of watched uids 120 */ addUidToObserverImpl(@onNull IBinder observerToken, int uid)121 public final void addUidToObserverImpl(@NonNull IBinder observerToken, int uid) { 122 int i = mUidObservers.beginBroadcast(); 123 while (i-- > 0) { 124 var reg = (UidObserverRegistration) mUidObservers.getBroadcastCookie(i); 125 if (reg.getToken().equals(observerToken)) { 126 reg.addUid(uid); 127 break; 128 } 129 130 if (i == 0) { 131 Slog.e(TAG_UID_OBSERVERS, "Unable to find UidObserver by token"); 132 } 133 } 134 mUidObservers.finishBroadcast(); 135 } 136 removeUidFromObserver(@onNull IBinder observerToken, int uid)137 final void removeUidFromObserver(@NonNull IBinder observerToken, int uid) { 138 Message msg = Message.obtain(mHandler, ActivityManagerService.REMOVE_UID_FROM_OBSERVER_MSG, 139 uid, /*arg2*/ 0, observerToken); 140 mHandler.sendMessage(msg); 141 } 142 143 /** 144 * Remove a uid from the list of uids an observer is interested in. Must be run on the same 145 * thread as mDispatchRunnable. 146 * 147 * @param observerToken The token identifier for a UidObserver 148 * @param uid The uid to remove from the list of watched uids 149 */ removeUidFromObserverImpl(@onNull IBinder observerToken, int uid)150 public final void removeUidFromObserverImpl(@NonNull IBinder observerToken, int uid) { 151 int i = mUidObservers.beginBroadcast(); 152 while (i-- > 0) { 153 var reg = (UidObserverRegistration) mUidObservers.getBroadcastCookie(i); 154 if (reg.getToken().equals(observerToken)) { 155 reg.removeUid(uid); 156 break; 157 } 158 159 if (i == 0) { 160 Slog.e(TAG_UID_OBSERVERS, "Unable to find UidObserver by token"); 161 } 162 } 163 mUidObservers.finishBroadcast(); 164 } 165 enqueueUidChange(@ullable ChangeRecord currentRecord, int uid, int change, int procState, int procAdj, long procStateSeq, int capability, boolean ephemeral)166 int enqueueUidChange(@Nullable ChangeRecord currentRecord, int uid, int change, int procState, 167 int procAdj, long procStateSeq, int capability, boolean ephemeral) { 168 synchronized (mLock) { 169 if (mPendingUidChanges.size() == 0) { 170 if (DEBUG_UID_OBSERVERS) { 171 Slog.i(TAG_UID_OBSERVERS, "*** Enqueueing dispatch uid changed!"); 172 } 173 mHandler.post(mDispatchRunnable); 174 } 175 176 final ChangeRecord changeRecord = currentRecord != null 177 ? currentRecord : getOrCreateChangeRecordLocked(); 178 if (!changeRecord.isPending) { 179 changeRecord.isPending = true; 180 mPendingUidChanges.add(changeRecord); 181 } else { 182 change = mergeWithPendingChange(change, changeRecord.change); 183 } 184 185 changeRecord.uid = uid; 186 changeRecord.change = change; 187 changeRecord.procState = procState; 188 changeRecord.procAdj = procAdj; 189 changeRecord.procStateSeq = procStateSeq; 190 changeRecord.capability = capability; 191 changeRecord.ephemeral = ephemeral; 192 193 return changeRecord.change; 194 } 195 } 196 getPendingUidChangesForTest()197 ArrayList<ChangeRecord> getPendingUidChangesForTest() { 198 return mPendingUidChanges; 199 } 200 getValidateUidsForTest()201 ActiveUids getValidateUidsForTest() { 202 return mValidateUids; 203 } 204 getDispatchRunnableForTest()205 Runnable getDispatchRunnableForTest() { 206 return mDispatchRunnable; 207 } 208 209 @VisibleForTesting mergeWithPendingChange(int currentChange, int pendingChange)210 static int mergeWithPendingChange(int currentChange, int pendingChange) { 211 // If there is no change in idle or active state, then keep whatever was pending. 212 if ((currentChange & (UidRecord.CHANGE_IDLE | UidRecord.CHANGE_ACTIVE)) == 0) { 213 currentChange |= (pendingChange & (UidRecord.CHANGE_IDLE 214 | UidRecord.CHANGE_ACTIVE)); 215 } 216 // If there is no change in cached or uncached state, then keep whatever was pending. 217 if ((currentChange & (UidRecord.CHANGE_CACHED | UidRecord.CHANGE_UNCACHED)) == 0) { 218 currentChange |= (pendingChange & (UidRecord.CHANGE_CACHED 219 | UidRecord.CHANGE_UNCACHED)); 220 } 221 // If this is a report of the UID being gone, then we shouldn't keep any previous 222 // report of it being active or cached. (That is, a gone uid is never active, 223 // and never cached.) 224 if ((currentChange & UidRecord.CHANGE_GONE) != 0) { 225 currentChange &= ~(UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_CACHED); 226 } 227 if ((pendingChange & UidRecord.CHANGE_CAPABILITY) != 0) { 228 currentChange |= UidRecord.CHANGE_CAPABILITY; 229 } 230 if ((pendingChange & UidRecord.CHANGE_PROCSTATE) != 0) { 231 currentChange |= UidRecord.CHANGE_PROCSTATE; 232 } 233 if ((pendingChange & UidRecord.CHANGE_PROCADJ) != 0) { 234 currentChange |= UidRecord.CHANGE_PROCADJ; 235 } 236 return currentChange; 237 } 238 239 @GuardedBy("mLock") getOrCreateChangeRecordLocked()240 private ChangeRecord getOrCreateChangeRecordLocked() { 241 final ChangeRecord changeRecord; 242 final int size = mAvailUidChanges.size(); 243 if (size > 0) { 244 changeRecord = mAvailUidChanges.remove(size - 1); 245 if (DEBUG_UID_OBSERVERS) { 246 Slog.i(TAG_UID_OBSERVERS, "Retrieving available item: " + changeRecord); 247 } 248 } else { 249 changeRecord = new ChangeRecord(); 250 if (DEBUG_UID_OBSERVERS) { 251 Slog.i(TAG_UID_OBSERVERS, "Allocating new item: " + changeRecord); 252 } 253 } 254 return changeRecord; 255 } 256 257 @VisibleForTesting dispatchUidsChanged()258 void dispatchUidsChanged() { 259 final int numUidChanges; 260 synchronized (mLock) { 261 numUidChanges = mPendingUidChanges.size(); 262 if (mActiveUidChanges.length < numUidChanges) { 263 mActiveUidChanges = new ChangeRecord[numUidChanges]; 264 } 265 for (int i = 0; i < numUidChanges; i++) { 266 final ChangeRecord changeRecord = mPendingUidChanges.get(i); 267 mActiveUidChanges[i] = getOrCreateChangeRecordLocked(); 268 changeRecord.copyTo(mActiveUidChanges[i]); 269 changeRecord.isPending = false; 270 } 271 mPendingUidChanges.clear(); 272 if (DEBUG_UID_OBSERVERS) { 273 Slog.i(TAG_UID_OBSERVERS, "*** Delivering " + numUidChanges + " uid changes"); 274 } 275 mUidChangeDispatchCount += numUidChanges; 276 } 277 278 int i = mUidObservers.beginBroadcast(); 279 while (i-- > 0) { 280 dispatchUidsChangedForObserver(mUidObservers.getBroadcastItem(i), 281 (UidObserverRegistration) mUidObservers.getBroadcastCookie(i), numUidChanges); 282 } 283 mUidObservers.finishBroadcast(); 284 285 if (VALIDATE_UID_STATES && mUidObservers.getRegisteredCallbackCount() > 0) { 286 for (int j = 0; j < numUidChanges; ++j) { 287 final ChangeRecord item = mActiveUidChanges[j]; 288 if ((item.change & UidRecord.CHANGE_GONE) != 0) { 289 mValidateUids.remove(item.uid); 290 } else { 291 UidRecord validateUid = mValidateUids.get(item.uid); 292 if (validateUid == null) { 293 validateUid = new UidRecord(item.uid, null); 294 mValidateUids.put(item.uid, validateUid); 295 } 296 if ((item.change & UidRecord.CHANGE_IDLE) != 0) { 297 validateUid.setIdle(true); 298 } else if ((item.change & UidRecord.CHANGE_ACTIVE) != 0) { 299 validateUid.setIdle(false); 300 } 301 validateUid.setSetProcState(item.procState); 302 validateUid.setCurProcState(item.procState); 303 validateUid.setSetCapability(item.capability); 304 validateUid.setCurCapability(item.capability); 305 } 306 } 307 } 308 309 synchronized (mLock) { 310 for (int j = 0; j < numUidChanges; j++) { 311 final ChangeRecord changeRecord = mActiveUidChanges[j]; 312 changeRecord.isPending = false; 313 mAvailUidChanges.add(changeRecord); 314 } 315 } 316 } 317 dispatchUidsChangedForObserver(@onNull IUidObserver observer, @NonNull UidObserverRegistration reg, int changesSize)318 private void dispatchUidsChangedForObserver(@NonNull IUidObserver observer, 319 @NonNull UidObserverRegistration reg, int changesSize) { 320 if (observer == null) { 321 return; 322 } 323 try { 324 for (int j = 0; j < changesSize; j++) { 325 final ChangeRecord item = mActiveUidChanges[j]; 326 final long start = SystemClock.uptimeMillis(); 327 final int change = item.change; 328 // Is the observer watching this uid? 329 if (!reg.isWatchingUid(item.uid)) { 330 continue; 331 } 332 // Does the user have permission? Don't send a non user UID change otherwise 333 if (UserHandle.getUserId(item.uid) != UserHandle.getUserId(reg.mUid) 334 && !reg.mCanInteractAcrossUsers) { 335 continue; 336 } 337 if (change == UidRecord.CHANGE_PROCSTATE 338 && (reg.mWhich & ActivityManager.UID_OBSERVER_PROCSTATE) == 0) { 339 // No-op common case: no significant change, the observer is not 340 // interested in all proc state changes. 341 continue; 342 } 343 if (change == UidRecord.CHANGE_PROCADJ 344 && (reg.mWhich & ActivityManager.UID_OBSERVER_PROC_OOM_ADJ) == 0) { 345 // No-op common case: no significant change, the observer is not 346 // interested in proc adj changes. 347 continue; 348 } 349 if ((change & UidRecord.CHANGE_IDLE) != 0) { 350 if ((reg.mWhich & ActivityManager.UID_OBSERVER_IDLE) != 0) { 351 if (DEBUG_UID_OBSERVERS) { 352 Slog.i(TAG_UID_OBSERVERS, "UID idle uid=" + item.uid); 353 } 354 observer.onUidIdle(item.uid, item.ephemeral); 355 } 356 } else if ((change & UidRecord.CHANGE_ACTIVE) != 0) { 357 if ((reg.mWhich & ActivityManager.UID_OBSERVER_ACTIVE) != 0) { 358 if (DEBUG_UID_OBSERVERS) { 359 Slog.i(TAG_UID_OBSERVERS, "UID active uid=" + item.uid); 360 } 361 observer.onUidActive(item.uid); 362 } 363 } 364 if ((reg.mWhich & ActivityManager.UID_OBSERVER_CACHED) != 0) { 365 if ((change & UidRecord.CHANGE_CACHED) != 0) { 366 if (DEBUG_UID_OBSERVERS) { 367 Slog.i(TAG_UID_OBSERVERS, "UID cached uid=" + item.uid); 368 } 369 observer.onUidCachedChanged(item.uid, true); 370 } else if ((change & UidRecord.CHANGE_UNCACHED) != 0) { 371 if (DEBUG_UID_OBSERVERS) { 372 Slog.i(TAG_UID_OBSERVERS, "UID active uid=" + item.uid); 373 } 374 observer.onUidCachedChanged(item.uid, false); 375 } 376 } 377 if ((change & UidRecord.CHANGE_GONE) != 0) { 378 if ((reg.mWhich & ActivityManager.UID_OBSERVER_GONE) != 0) { 379 if (DEBUG_UID_OBSERVERS) { 380 Slog.i(TAG_UID_OBSERVERS, "UID gone uid=" + item.uid); 381 } 382 observer.onUidGone(item.uid, item.ephemeral); 383 } 384 if (reg.mLastProcStates != null) { 385 reg.mLastProcStates.delete(item.uid); 386 } 387 } else { 388 boolean doReport = false; 389 if ((reg.mWhich & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) { 390 doReport = true; 391 if (reg.mCutpoint >= ActivityManager.MIN_PROCESS_STATE) { 392 final int lastState = reg.mLastProcStates.get(item.uid, 393 ActivityManager.PROCESS_STATE_UNKNOWN); 394 if (lastState != ActivityManager.PROCESS_STATE_UNKNOWN) { 395 final boolean lastAboveCut = lastState <= reg.mCutpoint; 396 final boolean newAboveCut = item.procState <= reg.mCutpoint; 397 doReport = lastAboveCut != newAboveCut; 398 } else { 399 doReport = item.procState != PROCESS_STATE_NONEXISTENT; 400 } 401 } 402 } 403 if ((reg.mWhich & ActivityManager.UID_OBSERVER_CAPABILITY) != 0) { 404 doReport |= (change & UidRecord.CHANGE_CAPABILITY) != 0; 405 } 406 if (doReport) { 407 if (DEBUG_UID_OBSERVERS) { 408 Slog.i(TAG_UID_OBSERVERS, "UID CHANGED uid=" + item.uid 409 + ": " + item.procState + ": " + item.capability); 410 } 411 if (reg.mLastProcStates != null) { 412 reg.mLastProcStates.put(item.uid, item.procState); 413 } 414 observer.onUidStateChanged(item.uid, item.procState, 415 item.procStateSeq, 416 item.capability); 417 } 418 if ((reg.mWhich & ActivityManager.UID_OBSERVER_PROC_OOM_ADJ) != 0 419 && (change & UidRecord.CHANGE_PROCADJ) != 0) { 420 observer.onUidProcAdjChanged(item.uid, item.procAdj); 421 } 422 } 423 final int duration = (int) (SystemClock.uptimeMillis() - start); 424 if (reg.mMaxDispatchTime < duration) { 425 reg.mMaxDispatchTime = duration; 426 } 427 if (duration >= SLOW_UID_OBSERVER_THRESHOLD_MS) { 428 reg.mSlowDispatchCount++; 429 } 430 } 431 } catch (RemoteException e) { 432 } 433 } 434 getValidateUidRecord(int uid)435 UidRecord getValidateUidRecord(int uid) { 436 return mValidateUids.get(uid); 437 } 438 dump(@onNull PrintWriter pw, @Nullable String dumpPackage)439 void dump(@NonNull PrintWriter pw, @Nullable String dumpPackage) { 440 synchronized (mLock) { 441 final int count = mUidObservers.getRegisteredCallbackCount(); 442 boolean printed = false; 443 for (int i = 0; i < count; i++) { 444 final UidObserverRegistration reg = (UidObserverRegistration) 445 mUidObservers.getRegisteredCallbackCookie(i); 446 if (dumpPackage == null || dumpPackage.equals(reg.mPkg)) { 447 if (!printed) { 448 pw.println(" mUidObservers:"); 449 printed = true; 450 } 451 reg.dump(pw, mUidObservers.getRegisteredCallbackItem(i)); 452 } 453 } 454 455 if (dumpPackage == null) { 456 pw.println(); 457 pw.print(" mUidChangeDispatchCount="); 458 pw.print(mUidChangeDispatchCount); 459 pw.println(); 460 pw.println(" Slow UID dispatches:"); 461 for (int i = 0; i < count; i++) { 462 final UidObserverRegistration reg = (UidObserverRegistration) 463 mUidObservers.getRegisteredCallbackCookie(i); 464 pw.print(" "); 465 pw.print(mUidObservers.getRegisteredCallbackItem(i).getClass().getTypeName()); 466 pw.print(": "); 467 pw.print(reg.mSlowDispatchCount); 468 pw.print(" / Max "); 469 pw.print(reg.mMaxDispatchTime); 470 pw.println("ms"); 471 } 472 } 473 } 474 } 475 dumpDebug(@onNull ProtoOutputStream proto, @Nullable String dumpPackage)476 void dumpDebug(@NonNull ProtoOutputStream proto, @Nullable String dumpPackage) { 477 synchronized (mLock) { 478 final int count = mUidObservers.getRegisteredCallbackCount(); 479 for (int i = 0; i < count; i++) { 480 final UidObserverRegistration reg = (UidObserverRegistration) 481 mUidObservers.getRegisteredCallbackCookie(i); 482 if (dumpPackage == null || dumpPackage.equals(reg.mPkg)) { 483 reg.dumpDebug(proto, ActivityManagerServiceDumpProcessesProto.UID_OBSERVERS); 484 } 485 } 486 } 487 } 488 dumpValidateUids(@onNull PrintWriter pw, @Nullable String dumpPackage, int dumpAppId, @NonNull String header, boolean needSep)489 boolean dumpValidateUids(@NonNull PrintWriter pw, @Nullable String dumpPackage, int dumpAppId, 490 @NonNull String header, boolean needSep) { 491 return mValidateUids.dump(pw, dumpPackage, dumpAppId, header, needSep); 492 } 493 dumpValidateUidsProto(@onNull ProtoOutputStream proto, @Nullable String dumpPackage, int dumpAppId, long fieldId)494 void dumpValidateUidsProto(@NonNull ProtoOutputStream proto, @Nullable String dumpPackage, 495 int dumpAppId, long fieldId) { 496 mValidateUids.dumpProto(proto, dumpPackage, dumpAppId, fieldId); 497 } 498 499 static final class ChangeRecord { 500 public boolean isPending; 501 public int uid; 502 public int change; 503 public int procState; 504 public int procAdj; 505 public int capability; 506 public boolean ephemeral; 507 public long procStateSeq; 508 copyTo(@onNull ChangeRecord changeRecord)509 void copyTo(@NonNull ChangeRecord changeRecord) { 510 changeRecord.isPending = isPending; 511 changeRecord.uid = uid; 512 changeRecord.change = change; 513 changeRecord.procState = procState; 514 changeRecord.procAdj = procAdj; 515 changeRecord.capability = capability; 516 changeRecord.ephemeral = ephemeral; 517 changeRecord.procStateSeq = procStateSeq; 518 } 519 } 520 521 private static final class UidObserverRegistration { 522 private final int mUid; 523 private final String mPkg; 524 private final int mWhich; 525 private final int mCutpoint; 526 private final boolean mCanInteractAcrossUsers; 527 private final IBinder mToken; 528 private int[] mUids; 529 530 /** 531 * Total # of callback calls that took more than {@link #SLOW_UID_OBSERVER_THRESHOLD_MS}. 532 * We show it in dumpsys. 533 */ 534 int mSlowDispatchCount; 535 536 /** Max time it took for each dispatch. */ 537 int mMaxDispatchTime; 538 539 final SparseIntArray mLastProcStates; 540 541 // Please keep the enum lists in sync 542 private static final int[] ORIG_ENUMS = new int[]{ 543 ActivityManager.UID_OBSERVER_IDLE, 544 ActivityManager.UID_OBSERVER_ACTIVE, 545 ActivityManager.UID_OBSERVER_GONE, 546 ActivityManager.UID_OBSERVER_PROCSTATE, 547 ActivityManager.UID_OBSERVER_CAPABILITY, 548 ActivityManager.UID_OBSERVER_PROC_OOM_ADJ, 549 }; 550 private static final int[] PROTO_ENUMS = new int[]{ 551 ActivityManagerProto.UID_OBSERVER_FLAG_IDLE, 552 ActivityManagerProto.UID_OBSERVER_FLAG_ACTIVE, 553 ActivityManagerProto.UID_OBSERVER_FLAG_GONE, 554 ActivityManagerProto.UID_OBSERVER_FLAG_PROCSTATE, 555 ActivityManagerProto.UID_OBSERVER_FLAG_CAPABILITY, 556 ActivityManagerProto.UID_OBSERVER_FLAG_PROC_OOM_ADJ, 557 }; 558 UidObserverRegistration(int uid, @NonNull String pkg, int which, int cutpoint, boolean canInteractAcrossUsers, @Nullable int[] uids, @NonNull IBinder token)559 UidObserverRegistration(int uid, @NonNull String pkg, int which, int cutpoint, 560 boolean canInteractAcrossUsers, @Nullable int[] uids, @NonNull IBinder token) { 561 this.mUid = uid; 562 this.mPkg = pkg; 563 this.mWhich = which; 564 this.mCutpoint = cutpoint; 565 this.mCanInteractAcrossUsers = canInteractAcrossUsers; 566 567 if (uids != null) { 568 this.mUids = uids.clone(); 569 Arrays.sort(this.mUids); 570 } else { 571 this.mUids = null; 572 } 573 574 this.mToken = token; 575 576 mLastProcStates = cutpoint >= ActivityManager.MIN_PROCESS_STATE 577 ? new SparseIntArray() : null; 578 } 579 isWatchingUid(int uid)580 boolean isWatchingUid(int uid) { 581 if (mUids == null) { 582 return true; 583 } 584 585 return Arrays.binarySearch(mUids, uid) >= 0; 586 } 587 addUid(int uid)588 void addUid(int uid) { 589 if (mUids == null) { 590 return; 591 } 592 593 int[] temp = mUids; 594 mUids = new int[temp.length + 1]; 595 boolean inserted = false; 596 for (int i = 0; i < temp.length; i++) { 597 if (!inserted) { 598 if (temp[i] < uid) { 599 mUids[i] = temp[i]; 600 } else if (temp[i] == uid) { 601 // Duplicate uid, no-op and fallback to the previous array 602 mUids = temp; 603 return; 604 } else { 605 mUids[i] = uid; 606 mUids[i + 1] = temp[i]; 607 inserted = true; 608 } 609 } else { 610 mUids[i + 1] = temp[i]; 611 } 612 } 613 614 if (!inserted) { 615 mUids[temp.length] = uid; 616 } 617 } 618 removeUid(int uid)619 void removeUid(int uid) { 620 if (mUids == null || mUids.length == 0) { 621 return; 622 } 623 624 int[] temp = mUids; 625 mUids = new int[temp.length - 1]; 626 boolean removed = false; 627 for (int i = 0; i < temp.length; i++) { 628 if (!removed) { 629 if (temp[i] == uid) { 630 removed = true; 631 } else if (i == temp.length - 1) { 632 // Uid not found, no-op and fallback to the previous array 633 mUids = temp; 634 return; 635 } else { 636 mUids[i] = temp[i]; 637 } 638 } else { 639 mUids[i - 1] = temp[i]; 640 } 641 } 642 } 643 getToken()644 IBinder getToken() { 645 return mToken; 646 } 647 dump(@onNull PrintWriter pw, @NonNull IUidObserver observer)648 void dump(@NonNull PrintWriter pw, @NonNull IUidObserver observer) { 649 pw.print(" "); 650 UserHandle.formatUid(pw, mUid); 651 pw.print(" "); 652 pw.print(mPkg); 653 pw.print(" "); 654 pw.print(observer.getClass().getTypeName()); 655 pw.print(":"); 656 if ((mWhich & ActivityManager.UID_OBSERVER_IDLE) != 0) { 657 pw.print(" IDLE"); 658 } 659 if ((mWhich & ActivityManager.UID_OBSERVER_ACTIVE) != 0) { 660 pw.print(" ACT"); 661 } 662 if ((mWhich & ActivityManager.UID_OBSERVER_GONE) != 0) { 663 pw.print(" GONE"); 664 } 665 if ((mWhich & ActivityManager.UID_OBSERVER_CAPABILITY) != 0) { 666 pw.print(" CAP"); 667 } 668 if ((mWhich & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) { 669 pw.print(" STATE"); 670 pw.print(" (cut="); 671 pw.print(mCutpoint); 672 pw.print(")"); 673 } 674 pw.println(); 675 if (mLastProcStates != null) { 676 final int size = mLastProcStates.size(); 677 for (int j = 0; j < size; j++) { 678 pw.print(" Last "); 679 UserHandle.formatUid(pw, mLastProcStates.keyAt(j)); 680 pw.print(": "); 681 pw.println(mLastProcStates.valueAt(j)); 682 } 683 } 684 } 685 dumpDebug(@onNull ProtoOutputStream proto, long fieldId)686 void dumpDebug(@NonNull ProtoOutputStream proto, long fieldId) { 687 final long token = proto.start(fieldId); 688 proto.write(UidObserverRegistrationProto.UID, mUid); 689 proto.write(UidObserverRegistrationProto.PACKAGE, mPkg); 690 ProtoUtils.writeBitWiseFlagsToProtoEnum(proto, UidObserverRegistrationProto.FLAGS, 691 mWhich, ORIG_ENUMS, PROTO_ENUMS); 692 proto.write(UidObserverRegistrationProto.CUT_POINT, mCutpoint); 693 if (mLastProcStates != null) { 694 final int size = mLastProcStates.size(); 695 for (int i = 0; i < size; i++) { 696 final long pToken = proto.start(UidObserverRegistrationProto.LAST_PROC_STATES); 697 proto.write(UidObserverRegistrationProto.ProcState.UID, 698 mLastProcStates.keyAt(i)); 699 proto.write(UidObserverRegistrationProto.ProcState.STATE, 700 mLastProcStates.valueAt(i)); 701 proto.end(pToken); 702 } 703 } 704 proto.end(token); 705 } 706 } 707 } 708