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