1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.am; 18 19 import static android.app.ActivityManager.START_SUCCESS; 20 21 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; 22 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; 23 24 import android.annotation.Nullable; 25 import android.app.ActivityManager; 26 import android.app.ActivityOptions; 27 import android.app.BroadcastOptions; 28 import android.app.PendingIntent; 29 import android.content.IIntentReceiver; 30 import android.content.IIntentSender; 31 import android.content.Intent; 32 import android.os.Binder; 33 import android.os.Bundle; 34 import android.os.IBinder; 35 import android.os.PowerWhitelistManager; 36 import android.os.PowerWhitelistManager.ReasonCode; 37 import android.os.RemoteCallbackList; 38 import android.os.RemoteException; 39 import android.os.TransactionTooLargeException; 40 import android.os.UserHandle; 41 import android.util.ArrayMap; 42 import android.util.ArraySet; 43 import android.util.Slog; 44 import android.util.TimeUtils; 45 46 import com.android.internal.os.IResultReceiver; 47 import com.android.internal.util.function.pooled.PooledLambda; 48 import com.android.server.wm.SafeActivityOptions; 49 50 import java.io.PrintWriter; 51 import java.lang.ref.WeakReference; 52 import java.util.Objects; 53 54 public final class PendingIntentRecord extends IIntentSender.Stub { 55 private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM; 56 57 public static final int FLAG_ACTIVITY_SENDER = 1 << 0; 58 public static final int FLAG_BROADCAST_SENDER = 1 << 1; 59 public static final int FLAG_SERVICE_SENDER = 1 << 2; 60 61 final PendingIntentController controller; 62 final Key key; 63 final int uid; 64 public final WeakReference<PendingIntentRecord> ref; 65 boolean sent = false; 66 boolean canceled = false; 67 /** 68 * Map IBinder to duration specified as Pair<Long, Integer>, Long is allowlist duration in 69 * milliseconds, Integer is allowlist type defined at 70 * {@link android.os.PowerExemptionManager.TempAllowListType} 71 */ 72 private ArrayMap<IBinder, TempAllowListDuration> mAllowlistDuration; 73 private RemoteCallbackList<IResultReceiver> mCancelCallbacks; 74 private ArraySet<IBinder> mAllowBgActivityStartsForActivitySender = new ArraySet<>(); 75 private ArraySet<IBinder> mAllowBgActivityStartsForBroadcastSender = new ArraySet<>(); 76 private ArraySet<IBinder> mAllowBgActivityStartsForServiceSender = new ArraySet<>(); 77 78 String stringName; 79 String lastTagPrefix; 80 String lastTag; 81 82 final static class Key { 83 final int type; 84 final String packageName; 85 final String featureId; 86 final IBinder activity; 87 final String who; 88 final int requestCode; 89 final Intent requestIntent; 90 final String requestResolvedType; 91 final SafeActivityOptions options; 92 Intent[] allIntents; 93 String[] allResolvedTypes; 94 final int flags; 95 final int hashCode; 96 final int userId; 97 98 private static final int ODD_PRIME_NUMBER = 37; 99 Key(int _t, String _p, @Nullable String _featureId, IBinder _a, String _w, int _r, Intent[] _i, String[] _it, int _f, SafeActivityOptions _o, int _userId)100 Key(int _t, String _p, @Nullable String _featureId, IBinder _a, String _w, 101 int _r, Intent[] _i, String[] _it, int _f, SafeActivityOptions _o, int _userId) { 102 type = _t; 103 packageName = _p; 104 featureId = _featureId; 105 activity = _a; 106 who = _w; 107 requestCode = _r; 108 requestIntent = _i != null ? _i[_i.length-1] : null; 109 requestResolvedType = _it != null ? _it[_it.length-1] : null; 110 allIntents = _i; 111 allResolvedTypes = _it; 112 flags = _f; 113 options = _o; 114 userId = _userId; 115 116 int hash = 23; 117 hash = (ODD_PRIME_NUMBER*hash) + _f; 118 hash = (ODD_PRIME_NUMBER*hash) + _r; 119 hash = (ODD_PRIME_NUMBER*hash) + _userId; 120 if (_w != null) { 121 hash = (ODD_PRIME_NUMBER*hash) + _w.hashCode(); 122 } 123 if (_a != null) { 124 hash = (ODD_PRIME_NUMBER*hash) + _a.hashCode(); 125 } 126 if (requestIntent != null) { 127 hash = (ODD_PRIME_NUMBER*hash) + requestIntent.filterHashCode(); 128 } 129 if (requestResolvedType != null) { 130 hash = (ODD_PRIME_NUMBER*hash) + requestResolvedType.hashCode(); 131 } 132 hash = (ODD_PRIME_NUMBER*hash) + (_p != null ? _p.hashCode() : 0); 133 hash = (ODD_PRIME_NUMBER*hash) + _t; 134 hashCode = hash; 135 //Slog.i(ActivityManagerService.TAG, this + " hashCode=0x" 136 // + Integer.toHexString(hashCode)); 137 } 138 139 @Override equals(Object otherObj)140 public boolean equals(Object otherObj) { 141 if (otherObj == null) { 142 return false; 143 } 144 try { 145 Key other = (Key)otherObj; 146 if (type != other.type) { 147 return false; 148 } 149 if (userId != other.userId){ 150 return false; 151 } 152 if (!Objects.equals(packageName, other.packageName)) { 153 return false; 154 } 155 if (!Objects.equals(featureId, other.featureId)) { 156 return false; 157 } 158 if (activity != other.activity) { 159 return false; 160 } 161 if (!Objects.equals(who, other.who)) { 162 return false; 163 } 164 if (requestCode != other.requestCode) { 165 return false; 166 } 167 if (requestIntent != other.requestIntent) { 168 if (requestIntent != null) { 169 if (!requestIntent.filterEquals(other.requestIntent)) { 170 return false; 171 } 172 } else if (other.requestIntent != null) { 173 return false; 174 } 175 } 176 if (!Objects.equals(requestResolvedType, other.requestResolvedType)) { 177 return false; 178 } 179 if (flags != other.flags) { 180 return false; 181 } 182 return true; 183 } catch (ClassCastException e) { 184 } 185 return false; 186 } 187 hashCode()188 public int hashCode() { 189 return hashCode; 190 } 191 toString()192 public String toString() { 193 return "Key{" + typeName() 194 + " pkg=" + packageName + (featureId != null ? "/" + featureId : "") 195 + " intent=" 196 + (requestIntent != null 197 ? requestIntent.toShortString(false, true, false, false) : "<null>") 198 + " flags=0x" + Integer.toHexString(flags) + " u=" + userId + "}" 199 + " requestCode=" + requestCode; 200 } 201 typeName()202 String typeName() { 203 switch (type) { 204 case ActivityManager.INTENT_SENDER_ACTIVITY: 205 return "startActivity"; 206 case ActivityManager.INTENT_SENDER_BROADCAST: 207 return "broadcastIntent"; 208 case ActivityManager.INTENT_SENDER_SERVICE: 209 return "startService"; 210 case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE: 211 return "startForegroundService"; 212 case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT: 213 return "activityResult"; 214 } 215 return Integer.toString(type); 216 } 217 } 218 219 static final class TempAllowListDuration { 220 long duration; 221 int type; 222 @ReasonCode int reasonCode; 223 @Nullable String reason; 224 TempAllowListDuration(long _duration, int _type, @ReasonCode int _reasonCode, String _reason)225 TempAllowListDuration(long _duration, int _type, @ReasonCode int _reasonCode, 226 String _reason) { 227 duration = _duration; 228 type = _type; 229 reasonCode = _reasonCode; 230 reason = _reason; 231 } 232 } 233 PendingIntentRecord(PendingIntentController _controller, Key _k, int _u)234 PendingIntentRecord(PendingIntentController _controller, Key _k, int _u) { 235 controller = _controller; 236 key = _k; 237 uid = _u; 238 ref = new WeakReference<>(this); 239 } 240 setAllowlistDurationLocked(IBinder allowlistToken, long duration, int type, @ReasonCode int reasonCode, @Nullable String reason)241 void setAllowlistDurationLocked(IBinder allowlistToken, long duration, int type, 242 @ReasonCode int reasonCode, @Nullable String reason) { 243 if (duration > 0) { 244 if (mAllowlistDuration == null) { 245 mAllowlistDuration = new ArrayMap<>(); 246 } 247 mAllowlistDuration.put(allowlistToken, 248 new TempAllowListDuration(duration, type, reasonCode, reason)); 249 } else if (mAllowlistDuration != null) { 250 mAllowlistDuration.remove(allowlistToken); 251 if (mAllowlistDuration.size() <= 0) { 252 mAllowlistDuration = null; 253 } 254 } 255 this.stringName = null; 256 } 257 setAllowBgActivityStarts(IBinder token, int flags)258 void setAllowBgActivityStarts(IBinder token, int flags) { 259 if (token == null) return; 260 if ((flags & FLAG_ACTIVITY_SENDER) != 0) { 261 mAllowBgActivityStartsForActivitySender.add(token); 262 } 263 if ((flags & FLAG_BROADCAST_SENDER) != 0) { 264 mAllowBgActivityStartsForBroadcastSender.add(token); 265 } 266 if ((flags & FLAG_SERVICE_SENDER) != 0) { 267 mAllowBgActivityStartsForServiceSender.add(token); 268 } 269 } 270 clearAllowBgActivityStarts(IBinder token)271 void clearAllowBgActivityStarts(IBinder token) { 272 if (token == null) return; 273 mAllowBgActivityStartsForActivitySender.remove(token); 274 mAllowBgActivityStartsForBroadcastSender.remove(token); 275 mAllowBgActivityStartsForServiceSender.remove(token); 276 } 277 registerCancelListenerLocked(IResultReceiver receiver)278 public void registerCancelListenerLocked(IResultReceiver receiver) { 279 if (mCancelCallbacks == null) { 280 mCancelCallbacks = new RemoteCallbackList<>(); 281 } 282 mCancelCallbacks.register(receiver); 283 } 284 unregisterCancelListenerLocked(IResultReceiver receiver)285 public void unregisterCancelListenerLocked(IResultReceiver receiver) { 286 if (mCancelCallbacks == null) { 287 return; // Already unregistered or detached. 288 } 289 mCancelCallbacks.unregister(receiver); 290 if (mCancelCallbacks.getRegisteredCallbackCount() <= 0) { 291 mCancelCallbacks = null; 292 } 293 } 294 detachCancelListenersLocked()295 public RemoteCallbackList<IResultReceiver> detachCancelListenersLocked() { 296 RemoteCallbackList<IResultReceiver> listeners = mCancelCallbacks; 297 mCancelCallbacks = null; 298 return listeners; 299 } 300 send(int code, Intent intent, String resolvedType, IBinder allowlistToken, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options)301 public void send(int code, Intent intent, String resolvedType, IBinder allowlistToken, 302 IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { 303 sendInner(code, intent, resolvedType, allowlistToken, finishedReceiver, 304 requiredPermission, null, null, 0, 0, 0, options); 305 } 306 sendWithResult(int code, Intent intent, String resolvedType, IBinder allowlistToken, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options)307 public int sendWithResult(int code, Intent intent, String resolvedType, IBinder allowlistToken, 308 IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { 309 return sendInner(code, intent, resolvedType, allowlistToken, finishedReceiver, 310 requiredPermission, null, null, 0, 0, 0, options); 311 } 312 sendInner(int code, Intent intent, String resolvedType, IBinder allowlistToken, IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo, String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle options)313 public int sendInner(int code, Intent intent, String resolvedType, IBinder allowlistToken, 314 IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo, 315 String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle options) { 316 if (intent != null) intent.setDefusable(true); 317 if (options != null) options.setDefusable(true); 318 319 TempAllowListDuration duration = null; 320 Intent finalIntent = null; 321 Intent[] allIntents = null; 322 String[] allResolvedTypes = null; 323 SafeActivityOptions mergedOptions = null; 324 synchronized (controller.mLock) { 325 if (canceled) { 326 return ActivityManager.START_CANCELED; 327 } 328 329 sent = true; 330 if ((key.flags & PendingIntent.FLAG_ONE_SHOT) != 0) { 331 controller.cancelIntentSender(this, true); 332 } 333 334 finalIntent = key.requestIntent != null ? new Intent(key.requestIntent) : new Intent(); 335 336 final boolean immutable = (key.flags & PendingIntent.FLAG_IMMUTABLE) != 0; 337 if (!immutable) { 338 if (intent != null) { 339 int changes = finalIntent.fillIn(intent, key.flags); 340 if ((changes & Intent.FILL_IN_DATA) == 0) { 341 resolvedType = key.requestResolvedType; 342 } 343 } else { 344 resolvedType = key.requestResolvedType; 345 } 346 flagsMask &= ~Intent.IMMUTABLE_FLAGS; 347 flagsValues &= flagsMask; 348 finalIntent.setFlags((finalIntent.getFlags() & ~flagsMask) | flagsValues); 349 } else { 350 resolvedType = key.requestResolvedType; 351 } 352 353 // Apply any launch flags from the ActivityOptions. This is to ensure that the caller 354 // can specify a consistent launch mode even if the PendingIntent is immutable 355 final ActivityOptions opts = ActivityOptions.fromBundle(options); 356 if (opts != null) { 357 finalIntent.addFlags(opts.getPendingIntentLaunchFlags()); 358 } 359 360 // Extract options before clearing calling identity 361 mergedOptions = key.options; 362 if (mergedOptions == null) { 363 mergedOptions = new SafeActivityOptions(opts); 364 } else { 365 mergedOptions.setCallerOptions(opts); 366 } 367 368 if (mAllowlistDuration != null) { 369 duration = mAllowlistDuration.get(allowlistToken); 370 } 371 372 if (key.type == ActivityManager.INTENT_SENDER_ACTIVITY 373 && key.allIntents != null && key.allIntents.length > 1) { 374 // Copy all intents and resolved types while we have the controller lock so we can 375 // use it later when the lock isn't held. 376 allIntents = new Intent[key.allIntents.length]; 377 allResolvedTypes = new String[key.allIntents.length]; 378 System.arraycopy(key.allIntents, 0, allIntents, 0, key.allIntents.length); 379 if (key.allResolvedTypes != null) { 380 System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0, 381 key.allResolvedTypes.length); 382 } 383 allIntents[allIntents.length - 1] = finalIntent; 384 allResolvedTypes[allResolvedTypes.length - 1] = resolvedType; 385 } 386 387 } 388 // We don't hold the controller lock beyond this point as we will be calling into AM and WM. 389 390 final int callingUid = Binder.getCallingUid(); 391 final int callingPid = Binder.getCallingPid(); 392 final long origId = Binder.clearCallingIdentity(); 393 394 int res = START_SUCCESS; 395 try { 396 if (duration != null) { 397 StringBuilder tag = new StringBuilder(64); 398 tag.append("setPendingIntentAllowlistDuration,reason:"); 399 tag.append(duration.reason == null ? "" : duration.reason); 400 tag.append(",pendingintent:"); 401 UserHandle.formatUid(tag, callingUid); 402 tag.append(":"); 403 if (finalIntent.getAction() != null) { 404 tag.append(finalIntent.getAction()); 405 } else if (finalIntent.getComponent() != null) { 406 finalIntent.getComponent().appendShortString(tag); 407 } else if (finalIntent.getData() != null) { 408 tag.append(finalIntent.getData().toSafeString()); 409 } 410 controller.mAmInternal.tempAllowlistForPendingIntent(callingPid, callingUid, 411 uid, duration.duration, duration.type, duration.reasonCode, tag.toString()); 412 } else if (key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE 413 && options != null) { 414 // If this is a getForegroundService() type pending intent, use its BroadcastOptions 415 // temp allowlist duration as its pending intent temp allowlist duration. 416 BroadcastOptions brOptions = new BroadcastOptions(options); 417 if (brOptions.getTemporaryAppAllowlistDuration() > 0) { 418 controller.mAmInternal.tempAllowlistForPendingIntent(callingPid, callingUid, 419 uid, brOptions.getTemporaryAppAllowlistDuration(), 420 brOptions.getTemporaryAppAllowlistType(), 421 brOptions.getTemporaryAppAllowlistReasonCode(), 422 brOptions.getTemporaryAppAllowlistReason()); 423 } 424 } 425 426 boolean sendFinish = finishedReceiver != null; 427 int userId = key.userId; 428 if (userId == UserHandle.USER_CURRENT) { 429 userId = controller.mUserController.getCurrentOrTargetUserId(); 430 } 431 // temporarily allow receivers and services to open activities from background if the 432 // PendingIntent.send() caller was foreground at the time of sendInner() call 433 final boolean allowTrampoline = uid != callingUid 434 && controller.mAtmInternal.isUidForeground(callingUid); 435 436 // note: we on purpose don't pass in the information about the PendingIntent's creator, 437 // like pid or ProcessRecord, to the ActivityTaskManagerInternal calls below, because 438 // it's not unusual for the creator's process to not be alive at this time 439 switch (key.type) { 440 case ActivityManager.INTENT_SENDER_ACTIVITY: 441 try { 442 // Note when someone has a pending intent, even from different 443 // users, then there's no need to ensure the calling user matches 444 // the target user, so validateIncomingUser is always false below. 445 446 if (key.allIntents != null && key.allIntents.length > 1) { 447 res = controller.mAtmInternal.startActivitiesInPackage( 448 uid, callingPid, callingUid, key.packageName, key.featureId, 449 allIntents, allResolvedTypes, resultTo, mergedOptions, userId, 450 false /* validateIncomingUser */, 451 this /* originatingPendingIntent */, 452 mAllowBgActivityStartsForActivitySender.contains( 453 allowlistToken)); 454 } else { 455 res = controller.mAtmInternal.startActivityInPackage(uid, callingPid, 456 callingUid, key.packageName, key.featureId, finalIntent, 457 resolvedType, resultTo, resultWho, requestCode, 0, 458 mergedOptions, userId, null, "PendingIntentRecord", 459 false /* validateIncomingUser */, 460 this /* originatingPendingIntent */, 461 mAllowBgActivityStartsForActivitySender.contains( 462 allowlistToken)); 463 } 464 } catch (RuntimeException e) { 465 Slog.w(TAG, "Unable to send startActivity intent", e); 466 } 467 break; 468 case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT: 469 controller.mAtmInternal.sendActivityResult(-1, key.activity, key.who, 470 key.requestCode, code, finalIntent); 471 break; 472 case ActivityManager.INTENT_SENDER_BROADCAST: 473 try { 474 final boolean allowedByToken = 475 mAllowBgActivityStartsForBroadcastSender.contains(allowlistToken); 476 final IBinder bgStartsToken = (allowedByToken) ? allowlistToken : null; 477 478 // If a completion callback has been requested, require 479 // that the broadcast be delivered synchronously 480 int sent = controller.mAmInternal.broadcastIntentInPackage(key.packageName, 481 key.featureId, uid, callingUid, callingPid, finalIntent, 482 resolvedType, finishedReceiver, code, null, null, 483 requiredPermission, options, (finishedReceiver != null), false, 484 userId, allowedByToken || allowTrampoline, bgStartsToken); 485 if (sent == ActivityManager.BROADCAST_SUCCESS) { 486 sendFinish = false; 487 } 488 } catch (RuntimeException e) { 489 Slog.w(TAG, "Unable to send startActivity intent", e); 490 } 491 break; 492 case ActivityManager.INTENT_SENDER_SERVICE: 493 case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE: 494 try { 495 final boolean allowedByToken = 496 mAllowBgActivityStartsForServiceSender.contains(allowlistToken); 497 final IBinder bgStartsToken = (allowedByToken) ? allowlistToken : null; 498 499 controller.mAmInternal.startServiceInPackage(uid, finalIntent, resolvedType, 500 key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE, 501 key.packageName, key.featureId, userId, 502 allowedByToken || allowTrampoline, bgStartsToken); 503 } catch (RuntimeException e) { 504 Slog.w(TAG, "Unable to send startService intent", e); 505 } catch (TransactionTooLargeException e) { 506 res = ActivityManager.START_CANCELED; 507 } 508 break; 509 } 510 511 if (sendFinish && res != ActivityManager.START_CANCELED) { 512 try { 513 finishedReceiver.performReceive(new Intent(finalIntent), 0, 514 null, null, false, false, key.userId); 515 } catch (RemoteException e) { 516 } 517 } 518 } finally { 519 Binder.restoreCallingIdentity(origId); 520 } 521 522 return res; 523 } 524 525 @Override finalize()526 protected void finalize() throws Throwable { 527 try { 528 if (!canceled) { 529 controller.mH.sendMessage(PooledLambda.obtainMessage( 530 PendingIntentRecord::completeFinalize, this)); 531 } 532 } finally { 533 super.finalize(); 534 } 535 } 536 completeFinalize()537 private void completeFinalize() { 538 synchronized(controller.mLock) { 539 WeakReference<PendingIntentRecord> current = controller.mIntentSenderRecords.get(key); 540 if (current == ref) { 541 controller.mIntentSenderRecords.remove(key); 542 controller.decrementUidStatLocked(this); 543 } 544 } 545 } 546 dump(PrintWriter pw, String prefix)547 public void dump(PrintWriter pw, String prefix) { 548 pw.print(prefix); pw.print("uid="); pw.print(uid); 549 pw.print(" packageName="); pw.print(key.packageName); 550 pw.print(" featureId="); pw.print(key.featureId); 551 pw.print(" type="); pw.print(key.typeName()); 552 pw.print(" flags=0x"); pw.println(Integer.toHexString(key.flags)); 553 if (key.activity != null || key.who != null) { 554 pw.print(prefix); pw.print("activity="); pw.print(key.activity); 555 pw.print(" who="); pw.println(key.who); 556 } 557 if (key.requestCode != 0 || key.requestResolvedType != null) { 558 pw.print(prefix); pw.print("requestCode="); pw.print(key.requestCode); 559 pw.print(" requestResolvedType="); pw.println(key.requestResolvedType); 560 } 561 if (key.requestIntent != null) { 562 pw.print(prefix); pw.print("requestIntent="); 563 pw.println(key.requestIntent.toShortString(false, true, true, false)); 564 } 565 if (sent || canceled) { 566 pw.print(prefix); pw.print("sent="); pw.print(sent); 567 pw.print(" canceled="); pw.println(canceled); 568 } 569 if (mAllowlistDuration != null) { 570 pw.print(prefix); 571 pw.print("allowlistDuration="); 572 for (int i = 0; i < mAllowlistDuration.size(); i++) { 573 if (i != 0) { 574 pw.print(", "); 575 } 576 TempAllowListDuration entry = mAllowlistDuration.valueAt(i); 577 pw.print(Integer.toHexString(System.identityHashCode(mAllowlistDuration.keyAt(i)))); 578 pw.print(":"); 579 TimeUtils.formatDuration(entry.duration, pw); 580 pw.print("/"); 581 pw.print(entry.type); 582 pw.print("/"); 583 pw.print(PowerWhitelistManager.reasonCodeToString(entry.reasonCode)); 584 pw.print("/"); 585 pw.print(entry.reason); 586 } 587 pw.println(); 588 } 589 if (mCancelCallbacks != null) { 590 pw.print(prefix); pw.println("mCancelCallbacks:"); 591 for (int i = 0; i < mCancelCallbacks.getRegisteredCallbackCount(); i++) { 592 pw.print(prefix); pw.print(" #"); pw.print(i); pw.print(": "); 593 pw.println(mCancelCallbacks.getRegisteredCallbackItem(i)); 594 } 595 } 596 } 597 toString()598 public String toString() { 599 if (stringName != null) { 600 return stringName; 601 } 602 StringBuilder sb = new StringBuilder(128); 603 sb.append("PendingIntentRecord{"); 604 sb.append(Integer.toHexString(System.identityHashCode(this))); 605 sb.append(' '); 606 sb.append(key.packageName); 607 if (key.featureId != null) { 608 sb.append('/'); 609 sb.append(key.featureId); 610 } 611 sb.append(' '); 612 sb.append(key.typeName()); 613 if (mAllowlistDuration != null) { 614 sb.append(" (allowlist: "); 615 for (int i = 0; i < mAllowlistDuration.size(); i++) { 616 if (i != 0) { 617 sb.append(","); 618 } 619 TempAllowListDuration entry = mAllowlistDuration.valueAt(i); 620 sb.append(Integer.toHexString(System.identityHashCode( 621 mAllowlistDuration.keyAt(i)))); 622 sb.append(":"); 623 TimeUtils.formatDuration(entry.duration, sb); 624 sb.append("/"); 625 sb.append(entry.type); 626 sb.append("/"); 627 sb.append(PowerWhitelistManager.reasonCodeToString(entry.reasonCode)); 628 sb.append("/"); 629 sb.append(entry.reason); 630 } 631 sb.append(")"); 632 } 633 sb.append('}'); 634 return stringName = sb.toString(); 635 } 636 } 637