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 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; 21 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; 22 23 import android.app.ActivityManager; 24 import android.app.ActivityOptions; 25 import android.content.IIntentSender; 26 import android.content.IIntentReceiver; 27 import android.app.PendingIntent; 28 import android.content.Intent; 29 import android.os.Binder; 30 import android.os.Bundle; 31 import android.os.IBinder; 32 import android.os.RemoteCallbackList; 33 import android.os.RemoteException; 34 import android.os.TransactionTooLargeException; 35 import android.os.UserHandle; 36 import android.util.ArrayMap; 37 import android.util.Slog; 38 import android.util.TimeUtils; 39 40 import com.android.internal.os.IResultReceiver; 41 42 import java.io.PrintWriter; 43 import java.lang.ref.WeakReference; 44 import java.util.Objects; 45 46 final class PendingIntentRecord extends IIntentSender.Stub { 47 private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM; 48 49 final ActivityManagerService owner; 50 final Key key; 51 final int uid; 52 final WeakReference<PendingIntentRecord> ref; 53 boolean sent = false; 54 boolean canceled = false; 55 private ArrayMap<IBinder, Long> whitelistDuration; 56 private RemoteCallbackList<IResultReceiver> mCancelCallbacks; 57 58 String stringName; 59 String lastTagPrefix; 60 String lastTag; 61 62 final static class Key { 63 final int type; 64 final String packageName; 65 final ActivityRecord activity; 66 final String who; 67 final int requestCode; 68 final Intent requestIntent; 69 final String requestResolvedType; 70 final SafeActivityOptions options; 71 Intent[] allIntents; 72 String[] allResolvedTypes; 73 final int flags; 74 final int hashCode; 75 final int userId; 76 77 private static final int ODD_PRIME_NUMBER = 37; 78 79 Key(int _t, String _p, ActivityRecord _a, String _w, 80 int _r, Intent[] _i, String[] _it, int _f, SafeActivityOptions _o, int _userId) { 81 type = _t; 82 packageName = _p; 83 activity = _a; 84 who = _w; 85 requestCode = _r; 86 requestIntent = _i != null ? _i[_i.length-1] : null; 87 requestResolvedType = _it != null ? _it[_it.length-1] : null; 88 allIntents = _i; 89 allResolvedTypes = _it; 90 flags = _f; 91 options = _o; 92 userId = _userId; 93 94 int hash = 23; 95 hash = (ODD_PRIME_NUMBER*hash) + _f; 96 hash = (ODD_PRIME_NUMBER*hash) + _r; 97 hash = (ODD_PRIME_NUMBER*hash) + _userId; 98 if (_w != null) { 99 hash = (ODD_PRIME_NUMBER*hash) + _w.hashCode(); 100 } 101 if (_a != null) { 102 hash = (ODD_PRIME_NUMBER*hash) + _a.hashCode(); 103 } 104 if (requestIntent != null) { 105 hash = (ODD_PRIME_NUMBER*hash) + requestIntent.filterHashCode(); 106 } 107 if (requestResolvedType != null) { 108 hash = (ODD_PRIME_NUMBER*hash) + requestResolvedType.hashCode(); 109 } 110 hash = (ODD_PRIME_NUMBER*hash) + (_p != null ? _p.hashCode() : 0); 111 hash = (ODD_PRIME_NUMBER*hash) + _t; 112 hashCode = hash; 113 //Slog.i(ActivityManagerService.TAG, this + " hashCode=0x" 114 // + Integer.toHexString(hashCode)); 115 } 116 117 public boolean equals(Object otherObj) { 118 if (otherObj == null) { 119 return false; 120 } 121 try { 122 Key other = (Key)otherObj; 123 if (type != other.type) { 124 return false; 125 } 126 if (userId != other.userId){ 127 return false; 128 } 129 if (!Objects.equals(packageName, other.packageName)) { 130 return false; 131 } 132 if (activity != other.activity) { 133 return false; 134 } 135 if (!Objects.equals(who, other.who)) { 136 return false; 137 } 138 if (requestCode != other.requestCode) { 139 return false; 140 } 141 if (requestIntent != other.requestIntent) { 142 if (requestIntent != null) { 143 if (!requestIntent.filterEquals(other.requestIntent)) { 144 return false; 145 } 146 } else if (other.requestIntent != null) { 147 return false; 148 } 149 } 150 if (!Objects.equals(requestResolvedType, other.requestResolvedType)) { 151 return false; 152 } 153 if (flags != other.flags) { 154 return false; 155 } 156 return true; 157 } catch (ClassCastException e) { 158 } 159 return false; 160 } 161 162 public int hashCode() { 163 return hashCode; 164 } 165 166 public String toString() { 167 return "Key{" + typeName() + " pkg=" + packageName 168 + " intent=" 169 + (requestIntent != null 170 ? requestIntent.toShortString(false, true, false, false) : "<null>") 171 + " flags=0x" + Integer.toHexString(flags) + " u=" + userId + "}"; 172 } 173 174 String typeName() { 175 switch (type) { 176 case ActivityManager.INTENT_SENDER_ACTIVITY: 177 return "startActivity"; 178 case ActivityManager.INTENT_SENDER_BROADCAST: 179 return "broadcastIntent"; 180 case ActivityManager.INTENT_SENDER_SERVICE: 181 return "startService"; 182 case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE: 183 return "startForegroundService"; 184 case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT: 185 return "activityResult"; 186 } 187 return Integer.toString(type); 188 } 189 } 190 191 PendingIntentRecord(ActivityManagerService _owner, Key _k, int _u) { 192 owner = _owner; 193 key = _k; 194 uid = _u; 195 ref = new WeakReference<PendingIntentRecord>(this); 196 } 197 198 void setWhitelistDurationLocked(IBinder whitelistToken, long duration) { 199 if (duration > 0) { 200 if (whitelistDuration == null) { 201 whitelistDuration = new ArrayMap<>(); 202 } 203 whitelistDuration.put(whitelistToken, duration); 204 } else if (whitelistDuration != null) { 205 whitelistDuration.remove(whitelistToken); 206 if (whitelistDuration.size() <= 0) { 207 whitelistDuration = null; 208 } 209 210 } 211 this.stringName = null; 212 } 213 214 public void registerCancelListenerLocked(IResultReceiver receiver) { 215 if (mCancelCallbacks == null) { 216 mCancelCallbacks = new RemoteCallbackList<>(); 217 } 218 mCancelCallbacks.register(receiver); 219 } 220 221 public void unregisterCancelListenerLocked(IResultReceiver receiver) { 222 if (mCancelCallbacks == null) { 223 return; // Already unregistered or detached. 224 } 225 mCancelCallbacks.unregister(receiver); 226 if (mCancelCallbacks.getRegisteredCallbackCount() <= 0) { 227 mCancelCallbacks = null; 228 } 229 } 230 231 public RemoteCallbackList<IResultReceiver> detachCancelListenersLocked() { 232 RemoteCallbackList<IResultReceiver> listeners = mCancelCallbacks; 233 mCancelCallbacks = null; 234 return listeners; 235 } 236 237 public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken, 238 IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { 239 sendInner(code, intent, resolvedType, whitelistToken, finishedReceiver, 240 requiredPermission, null, null, 0, 0, 0, options); 241 } 242 243 public int sendWithResult(int code, Intent intent, String resolvedType, IBinder whitelistToken, 244 IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { 245 return sendInner(code, intent, resolvedType, whitelistToken, finishedReceiver, 246 requiredPermission, null, null, 0, 0, 0, options); 247 } 248 249 int sendInner(int code, Intent intent, String resolvedType, IBinder whitelistToken, 250 IIntentReceiver finishedReceiver, 251 String requiredPermission, IBinder resultTo, String resultWho, int requestCode, 252 int flagsMask, int flagsValues, Bundle options) { 253 if (intent != null) intent.setDefusable(true); 254 if (options != null) options.setDefusable(true); 255 256 synchronized (owner) { 257 if (!canceled) { 258 sent = true; 259 if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) { 260 owner.cancelIntentSenderLocked(this, true); 261 } 262 263 Intent finalIntent = key.requestIntent != null 264 ? new Intent(key.requestIntent) : new Intent(); 265 266 final boolean immutable = (key.flags & PendingIntent.FLAG_IMMUTABLE) != 0; 267 if (!immutable) { 268 if (intent != null) { 269 int changes = finalIntent.fillIn(intent, key.flags); 270 if ((changes & Intent.FILL_IN_DATA) == 0) { 271 resolvedType = key.requestResolvedType; 272 } 273 } else { 274 resolvedType = key.requestResolvedType; 275 } 276 flagsMask &= ~Intent.IMMUTABLE_FLAGS; 277 flagsValues &= flagsMask; 278 finalIntent.setFlags((finalIntent.getFlags() & ~flagsMask) | flagsValues); 279 } else { 280 resolvedType = key.requestResolvedType; 281 } 282 283 final int callingUid = Binder.getCallingUid(); 284 final int callingPid = Binder.getCallingPid(); 285 286 // Extract options before clearing calling identity 287 SafeActivityOptions mergedOptions = key.options; 288 if (mergedOptions == null) { 289 mergedOptions = SafeActivityOptions.fromBundle(options); 290 } else { 291 mergedOptions.setCallerOptions(ActivityOptions.fromBundle(options)); 292 } 293 294 final long origId = Binder.clearCallingIdentity(); 295 296 if (whitelistDuration != null) { 297 Long duration = whitelistDuration.get(whitelistToken); 298 if (duration != null) { 299 int procState = owner.getUidState(callingUid); 300 if (!ActivityManager.isProcStateBackground(procState)) { 301 StringBuilder tag = new StringBuilder(64); 302 tag.append("pendingintent:"); 303 UserHandle.formatUid(tag, callingUid); 304 tag.append(":"); 305 if (finalIntent.getAction() != null) { 306 tag.append(finalIntent.getAction()); 307 } else if (finalIntent.getComponent() != null) { 308 finalIntent.getComponent().appendShortString(tag); 309 } else if (finalIntent.getData() != null) { 310 tag.append(finalIntent.getData()); 311 } 312 owner.tempWhitelistForPendingIntentLocked(callingPid, 313 callingUid, uid, duration, tag.toString()); 314 } else { 315 Slog.w(TAG, "Not doing whitelist " + this + ": caller state=" 316 + procState); 317 } 318 } 319 } 320 321 boolean sendFinish = finishedReceiver != null; 322 int userId = key.userId; 323 if (userId == UserHandle.USER_CURRENT) { 324 userId = owner.mUserController.getCurrentOrTargetUserId(); 325 } 326 int res = START_SUCCESS; 327 switch (key.type) { 328 case ActivityManager.INTENT_SENDER_ACTIVITY: 329 try { 330 // Note when someone has a pending intent, even from different 331 // users, then there's no need to ensure the calling user matches 332 // the target user, so validateIncomingUser is always false below. 333 334 if (key.allIntents != null && key.allIntents.length > 1) { 335 Intent[] allIntents = new Intent[key.allIntents.length]; 336 String[] allResolvedTypes = new String[key.allIntents.length]; 337 System.arraycopy(key.allIntents, 0, allIntents, 0, 338 key.allIntents.length); 339 if (key.allResolvedTypes != null) { 340 System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0, 341 key.allResolvedTypes.length); 342 } 343 allIntents[allIntents.length-1] = finalIntent; 344 allResolvedTypes[allResolvedTypes.length-1] = resolvedType; 345 346 res = owner.getActivityStartController().startActivitiesInPackage( 347 uid, key.packageName, allIntents, allResolvedTypes, 348 resultTo, mergedOptions, userId, 349 false /* validateIncomingUser */); 350 } else { 351 res = owner.getActivityStartController().startActivityInPackage(uid, 352 callingPid, callingUid, key.packageName, finalIntent, 353 resolvedType, resultTo, resultWho, requestCode, 0, 354 mergedOptions, userId, null, "PendingIntentRecord", 355 false /* validateIncomingUser */); 356 } 357 } catch (RuntimeException e) { 358 Slog.w(TAG, "Unable to send startActivity intent", e); 359 } 360 break; 361 case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT: 362 final ActivityStack stack = key.activity.getStack(); 363 if (stack != null) { 364 stack.sendActivityResultLocked(-1, key.activity, key.who, 365 key.requestCode, code, finalIntent); 366 } 367 break; 368 case ActivityManager.INTENT_SENDER_BROADCAST: 369 try { 370 // If a completion callback has been requested, require 371 // that the broadcast be delivered synchronously 372 int sent = owner.broadcastIntentInPackage(key.packageName, uid, 373 finalIntent, resolvedType, finishedReceiver, code, null, null, 374 requiredPermission, options, (finishedReceiver != null), 375 false, userId); 376 if (sent == ActivityManager.BROADCAST_SUCCESS) { 377 sendFinish = false; 378 } 379 } catch (RuntimeException e) { 380 Slog.w(TAG, "Unable to send startActivity intent", e); 381 } 382 break; 383 case ActivityManager.INTENT_SENDER_SERVICE: 384 case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE: 385 try { 386 owner.startServiceInPackage(uid, finalIntent, resolvedType, 387 key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE, 388 key.packageName, userId); 389 } catch (RuntimeException e) { 390 Slog.w(TAG, "Unable to send startService intent", e); 391 } catch (TransactionTooLargeException e) { 392 res = ActivityManager.START_CANCELED; 393 } 394 break; 395 } 396 397 if (sendFinish && res != ActivityManager.START_CANCELED) { 398 try { 399 finishedReceiver.performReceive(new Intent(finalIntent), 0, 400 null, null, false, false, key.userId); 401 } catch (RemoteException e) { 402 } 403 } 404 405 Binder.restoreCallingIdentity(origId); 406 407 return res; 408 } 409 } 410 return ActivityManager.START_CANCELED; 411 } 412 413 @Override 414 protected void finalize() throws Throwable { 415 try { 416 if (!canceled) { 417 owner.mHandler.sendMessage(owner.mHandler.obtainMessage( 418 ActivityManagerService.FINALIZE_PENDING_INTENT_MSG, this)); 419 } 420 } finally { 421 super.finalize(); 422 } 423 } 424 425 public void completeFinalize() { 426 synchronized(owner) { 427 WeakReference<PendingIntentRecord> current = 428 owner.mIntentSenderRecords.get(key); 429 if (current == ref) { 430 owner.mIntentSenderRecords.remove(key); 431 } 432 } 433 } 434 435 void dump(PrintWriter pw, String prefix) { 436 pw.print(prefix); pw.print("uid="); pw.print(uid); 437 pw.print(" packageName="); pw.print(key.packageName); 438 pw.print(" type="); pw.print(key.typeName()); 439 pw.print(" flags=0x"); pw.println(Integer.toHexString(key.flags)); 440 if (key.activity != null || key.who != null) { 441 pw.print(prefix); pw.print("activity="); pw.print(key.activity); 442 pw.print(" who="); pw.println(key.who); 443 } 444 if (key.requestCode != 0 || key.requestResolvedType != null) { 445 pw.print(prefix); pw.print("requestCode="); pw.print(key.requestCode); 446 pw.print(" requestResolvedType="); pw.println(key.requestResolvedType); 447 } 448 if (key.requestIntent != null) { 449 pw.print(prefix); pw.print("requestIntent="); 450 pw.println(key.requestIntent.toShortString(false, true, true, true)); 451 } 452 if (sent || canceled) { 453 pw.print(prefix); pw.print("sent="); pw.print(sent); 454 pw.print(" canceled="); pw.println(canceled); 455 } 456 if (whitelistDuration != null) { 457 pw.print(prefix); 458 pw.print("whitelistDuration="); 459 for (int i = 0; i < whitelistDuration.size(); i++) { 460 if (i != 0) { 461 pw.print(", "); 462 } 463 pw.print(Integer.toHexString(System.identityHashCode(whitelistDuration.keyAt(i)))); 464 pw.print(":"); 465 TimeUtils.formatDuration(whitelistDuration.valueAt(i), pw); 466 } 467 pw.println(); 468 } 469 if (mCancelCallbacks != null) { 470 pw.print(prefix); pw.println("mCancelCallbacks:"); 471 for (int i = 0; i < mCancelCallbacks.getRegisteredCallbackCount(); i++) { 472 pw.print(prefix); pw.print(" #"); pw.print(i); pw.print(": "); 473 pw.println(mCancelCallbacks.getRegisteredCallbackItem(i)); 474 } 475 } 476 } 477 478 public String toString() { 479 if (stringName != null) { 480 return stringName; 481 } 482 StringBuilder sb = new StringBuilder(128); 483 sb.append("PendingIntentRecord{"); 484 sb.append(Integer.toHexString(System.identityHashCode(this))); 485 sb.append(' '); 486 sb.append(key.packageName); 487 sb.append(' '); 488 sb.append(key.typeName()); 489 if (whitelistDuration != null) { 490 sb.append( " (whitelist: "); 491 for (int i = 0; i < whitelistDuration.size(); i++) { 492 if (i != 0) { 493 sb.append(","); 494 } 495 sb.append(Integer.toHexString(System.identityHashCode(whitelistDuration.keyAt(i)))); 496 sb.append(":"); 497 TimeUtils.formatDuration(whitelistDuration.valueAt(i), sb); 498 } 499 sb.append(")"); 500 } 501 sb.append('}'); 502 return stringName = sb.toString(); 503 } 504 } 505