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 com.android.server.am.ActivityManagerDebugConfig.TAG_AM; 20 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; 21 22 import android.app.ActivityManager; 23 import android.app.IActivityContainer; 24 import android.content.IIntentSender; 25 import android.content.IIntentReceiver; 26 import android.app.PendingIntent; 27 import android.content.Intent; 28 import android.os.Binder; 29 import android.os.Bundle; 30 import android.os.IBinder; 31 import android.os.RemoteException; 32 import android.os.TransactionTooLargeException; 33 import android.os.UserHandle; 34 import android.util.Slog; 35 import android.util.TimeUtils; 36 37 import com.android.server.am.ActivityStackSupervisor.ActivityContainer; 38 39 import java.io.PrintWriter; 40 import java.lang.ref.WeakReference; 41 42 final class PendingIntentRecord extends IIntentSender.Stub { 43 private static final String TAG = TAG_WITH_CLASS_NAME ? "PendingIntentRecord" : TAG_AM; 44 45 final ActivityManagerService owner; 46 final Key key; 47 final int uid; 48 final WeakReference<PendingIntentRecord> ref; 49 boolean sent = false; 50 boolean canceled = false; 51 private long whitelistDuration = 0; 52 53 String stringName; 54 String lastTagPrefix; 55 String lastTag; 56 57 final static class Key { 58 final int type; 59 final String packageName; 60 final ActivityRecord activity; 61 final String who; 62 final int requestCode; 63 final Intent requestIntent; 64 final String requestResolvedType; 65 final Bundle options; 66 Intent[] allIntents; 67 String[] allResolvedTypes; 68 final int flags; 69 final int hashCode; 70 final int userId; 71 72 private static final int ODD_PRIME_NUMBER = 37; 73 Key(int _t, String _p, ActivityRecord _a, String _w, int _r, Intent[] _i, String[] _it, int _f, Bundle _o, int _userId)74 Key(int _t, String _p, ActivityRecord _a, String _w, 75 int _r, Intent[] _i, String[] _it, int _f, Bundle _o, int _userId) { 76 type = _t; 77 packageName = _p; 78 activity = _a; 79 who = _w; 80 requestCode = _r; 81 requestIntent = _i != null ? _i[_i.length-1] : null; 82 requestResolvedType = _it != null ? _it[_it.length-1] : null; 83 allIntents = _i; 84 allResolvedTypes = _it; 85 flags = _f; 86 options = _o; 87 userId = _userId; 88 89 int hash = 23; 90 hash = (ODD_PRIME_NUMBER*hash) + _f; 91 hash = (ODD_PRIME_NUMBER*hash) + _r; 92 hash = (ODD_PRIME_NUMBER*hash) + _userId; 93 if (_w != null) { 94 hash = (ODD_PRIME_NUMBER*hash) + _w.hashCode(); 95 } 96 if (_a != null) { 97 hash = (ODD_PRIME_NUMBER*hash) + _a.hashCode(); 98 } 99 if (requestIntent != null) { 100 hash = (ODD_PRIME_NUMBER*hash) + requestIntent.filterHashCode(); 101 } 102 if (requestResolvedType != null) { 103 hash = (ODD_PRIME_NUMBER*hash) + requestResolvedType.hashCode(); 104 } 105 hash = (ODD_PRIME_NUMBER*hash) + _p.hashCode(); 106 hash = (ODD_PRIME_NUMBER*hash) + _t; 107 hashCode = hash; 108 //Slog.i(ActivityManagerService.TAG, this + " hashCode=0x" 109 // + Integer.toHexString(hashCode)); 110 } 111 equals(Object otherObj)112 public boolean equals(Object otherObj) { 113 if (otherObj == null) { 114 return false; 115 } 116 try { 117 Key other = (Key)otherObj; 118 if (type != other.type) { 119 return false; 120 } 121 if (userId != other.userId){ 122 return false; 123 } 124 if (!packageName.equals(other.packageName)) { 125 return false; 126 } 127 if (activity != other.activity) { 128 return false; 129 } 130 if (who != other.who) { 131 if (who != null) { 132 if (!who.equals(other.who)) { 133 return false; 134 } 135 } else if (other.who != null) { 136 return false; 137 } 138 } 139 if (requestCode != other.requestCode) { 140 return false; 141 } 142 if (requestIntent != other.requestIntent) { 143 if (requestIntent != null) { 144 if (!requestIntent.filterEquals(other.requestIntent)) { 145 return false; 146 } 147 } else if (other.requestIntent != null) { 148 return false; 149 } 150 } 151 if (requestResolvedType != other.requestResolvedType) { 152 if (requestResolvedType != null) { 153 if (!requestResolvedType.equals(other.requestResolvedType)) { 154 return false; 155 } 156 } else if (other.requestResolvedType != null) { 157 return false; 158 } 159 } 160 if (flags != other.flags) { 161 return false; 162 } 163 return true; 164 } catch (ClassCastException e) { 165 } 166 return false; 167 } 168 hashCode()169 public int hashCode() { 170 return hashCode; 171 } 172 toString()173 public String toString() { 174 return "Key{" + typeName() + " pkg=" + packageName 175 + " intent=" 176 + (requestIntent != null 177 ? requestIntent.toShortString(false, true, false, false) : "<null>") 178 + " flags=0x" + Integer.toHexString(flags) + " u=" + userId + "}"; 179 } 180 typeName()181 String typeName() { 182 switch (type) { 183 case ActivityManager.INTENT_SENDER_ACTIVITY: 184 return "startActivity"; 185 case ActivityManager.INTENT_SENDER_BROADCAST: 186 return "broadcastIntent"; 187 case ActivityManager.INTENT_SENDER_SERVICE: 188 return "startService"; 189 case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT: 190 return "activityResult"; 191 } 192 return Integer.toString(type); 193 } 194 } 195 PendingIntentRecord(ActivityManagerService _owner, Key _k, int _u)196 PendingIntentRecord(ActivityManagerService _owner, Key _k, int _u) { 197 owner = _owner; 198 key = _k; 199 uid = _u; 200 ref = new WeakReference<PendingIntentRecord>(this); 201 } 202 setWhitelistDuration(long duration)203 void setWhitelistDuration(long duration) { 204 this.whitelistDuration = duration; 205 this.stringName = null; 206 } 207 send(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options)208 public void send(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, 209 String requiredPermission, Bundle options) { 210 sendInner(code, intent, resolvedType, finishedReceiver, 211 requiredPermission, null, null, 0, 0, 0, options, null); 212 } 213 sendWithResult(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options)214 public int sendWithResult(int code, Intent intent, String resolvedType, 215 IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { 216 return sendInner(code, intent, resolvedType, finishedReceiver, 217 requiredPermission, null, null, 0, 0, 0, options, null); 218 } 219 sendInner(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo, String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle options, IActivityContainer container)220 int sendInner(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, 221 String requiredPermission, IBinder resultTo, String resultWho, int requestCode, 222 int flagsMask, int flagsValues, Bundle options, IActivityContainer container) { 223 if (intent != null) intent.setDefusable(true); 224 if (options != null) options.setDefusable(true); 225 226 if (whitelistDuration > 0 && !canceled) { 227 // Must call before acquiring the lock. It's possible the method return before sending 228 // the intent due to some validations inside the lock, in which case the UID shouldn't 229 // be whitelisted, but since the whitelist is temporary, that would be ok. 230 owner.tempWhitelistAppForPowerSave(Binder.getCallingPid(), Binder.getCallingUid(), uid, 231 whitelistDuration); 232 } 233 234 synchronized (owner) { 235 final ActivityContainer activityContainer = (ActivityContainer)container; 236 if (activityContainer != null && activityContainer.mParentActivity != null && 237 activityContainer.mParentActivity.state 238 != ActivityStack.ActivityState.RESUMED) { 239 // Cannot start a child activity if the parent is not resumed. 240 return ActivityManager.START_CANCELED; 241 } 242 if (!canceled) { 243 sent = true; 244 if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) { 245 owner.cancelIntentSenderLocked(this, true); 246 canceled = true; 247 } 248 249 Intent finalIntent = key.requestIntent != null 250 ? new Intent(key.requestIntent) : new Intent(); 251 252 final boolean immutable = (key.flags & PendingIntent.FLAG_IMMUTABLE) != 0; 253 if (!immutable) { 254 if (intent != null) { 255 int changes = finalIntent.fillIn(intent, key.flags); 256 if ((changes & Intent.FILL_IN_DATA) == 0) { 257 resolvedType = key.requestResolvedType; 258 } 259 } else { 260 resolvedType = key.requestResolvedType; 261 } 262 flagsMask &= ~Intent.IMMUTABLE_FLAGS; 263 flagsValues &= flagsMask; 264 finalIntent.setFlags((finalIntent.getFlags() & ~flagsMask) | flagsValues); 265 } else { 266 resolvedType = key.requestResolvedType; 267 } 268 269 final long origId = Binder.clearCallingIdentity(); 270 271 boolean sendFinish = finishedReceiver != null; 272 int userId = key.userId; 273 if (userId == UserHandle.USER_CURRENT) { 274 userId = owner.mUserController.getCurrentOrTargetUserIdLocked(); 275 } 276 int res = 0; 277 switch (key.type) { 278 case ActivityManager.INTENT_SENDER_ACTIVITY: 279 if (options == null) { 280 options = key.options; 281 } else if (key.options != null) { 282 Bundle opts = new Bundle(key.options); 283 opts.putAll(options); 284 options = opts; 285 } 286 try { 287 if (key.allIntents != null && key.allIntents.length > 1) { 288 Intent[] allIntents = new Intent[key.allIntents.length]; 289 String[] allResolvedTypes = new String[key.allIntents.length]; 290 System.arraycopy(key.allIntents, 0, allIntents, 0, 291 key.allIntents.length); 292 if (key.allResolvedTypes != null) { 293 System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0, 294 key.allResolvedTypes.length); 295 } 296 allIntents[allIntents.length-1] = finalIntent; 297 allResolvedTypes[allResolvedTypes.length-1] = resolvedType; 298 owner.startActivitiesInPackage(uid, key.packageName, allIntents, 299 allResolvedTypes, resultTo, options, userId); 300 } else { 301 owner.startActivityInPackage(uid, key.packageName, finalIntent, 302 resolvedType, resultTo, resultWho, requestCode, 0, 303 options, userId, container, null); 304 } 305 } catch (RuntimeException e) { 306 Slog.w(TAG, "Unable to send startActivity intent", e); 307 } 308 break; 309 case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT: 310 if (key.activity.task.stack != null) { 311 key.activity.task.stack.sendActivityResultLocked(-1, key.activity, 312 key.who, key.requestCode, code, finalIntent); 313 } 314 break; 315 case ActivityManager.INTENT_SENDER_BROADCAST: 316 try { 317 // If a completion callback has been requested, require 318 // that the broadcast be delivered synchronously 319 int sent = owner.broadcastIntentInPackage(key.packageName, uid, 320 finalIntent, resolvedType, finishedReceiver, code, null, null, 321 requiredPermission, options, (finishedReceiver != null), 322 false, userId); 323 if (sent == ActivityManager.BROADCAST_SUCCESS) { 324 sendFinish = false; 325 } 326 } catch (RuntimeException e) { 327 Slog.w(TAG, "Unable to send startActivity intent", e); 328 } 329 break; 330 case ActivityManager.INTENT_SENDER_SERVICE: 331 try { 332 owner.startServiceInPackage(uid, finalIntent, 333 resolvedType, key.packageName, userId); 334 } catch (RuntimeException e) { 335 Slog.w(TAG, "Unable to send startService intent", e); 336 } catch (TransactionTooLargeException e) { 337 res = ActivityManager.START_CANCELED; 338 } 339 break; 340 } 341 342 if (sendFinish && res != ActivityManager.START_CANCELED) { 343 try { 344 finishedReceiver.performReceive(new Intent(finalIntent), 0, 345 null, null, false, false, key.userId); 346 } catch (RemoteException e) { 347 } 348 } 349 350 Binder.restoreCallingIdentity(origId); 351 352 return res; 353 } 354 } 355 return ActivityManager.START_CANCELED; 356 } 357 358 @Override finalize()359 protected void finalize() throws Throwable { 360 try { 361 if (!canceled) { 362 owner.mHandler.sendMessage(owner.mHandler.obtainMessage( 363 ActivityManagerService.FINALIZE_PENDING_INTENT_MSG, this)); 364 } 365 } finally { 366 super.finalize(); 367 } 368 } 369 completeFinalize()370 public void completeFinalize() { 371 synchronized(owner) { 372 WeakReference<PendingIntentRecord> current = 373 owner.mIntentSenderRecords.get(key); 374 if (current == ref) { 375 owner.mIntentSenderRecords.remove(key); 376 } 377 } 378 } 379 dump(PrintWriter pw, String prefix)380 void dump(PrintWriter pw, String prefix) { 381 pw.print(prefix); pw.print("uid="); pw.print(uid); 382 pw.print(" packageName="); pw.print(key.packageName); 383 pw.print(" type="); pw.print(key.typeName()); 384 pw.print(" flags=0x"); pw.println(Integer.toHexString(key.flags)); 385 if (key.activity != null || key.who != null) { 386 pw.print(prefix); pw.print("activity="); pw.print(key.activity); 387 pw.print(" who="); pw.println(key.who); 388 } 389 if (key.requestCode != 0 || key.requestResolvedType != null) { 390 pw.print(prefix); pw.print("requestCode="); pw.print(key.requestCode); 391 pw.print(" requestResolvedType="); pw.println(key.requestResolvedType); 392 } 393 if (key.requestIntent != null) { 394 pw.print(prefix); pw.print("requestIntent="); 395 pw.println(key.requestIntent.toShortString(false, true, true, true)); 396 } 397 if (sent || canceled) { 398 pw.print(prefix); pw.print("sent="); pw.print(sent); 399 pw.print(" canceled="); pw.println(canceled); 400 } 401 if (whitelistDuration != 0) { 402 pw.print(prefix); 403 pw.print("whitelistDuration="); 404 TimeUtils.formatDuration(whitelistDuration, pw); 405 pw.println(); 406 } 407 } 408 toString()409 public String toString() { 410 if (stringName != null) { 411 return stringName; 412 } 413 StringBuilder sb = new StringBuilder(128); 414 sb.append("PendingIntentRecord{"); 415 sb.append(Integer.toHexString(System.identityHashCode(this))); 416 sb.append(' '); 417 sb.append(key.packageName); 418 sb.append(' '); 419 sb.append(key.typeName()); 420 if (whitelistDuration > 0) { 421 sb.append( " (whitelist: "); 422 TimeUtils.formatDuration(whitelistDuration, sb); 423 sb.append(")"); 424 } 425 sb.append('}'); 426 return stringName = sb.toString(); 427 } 428 } 429