• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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