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 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 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 169 public int hashCode() { 170 return hashCode; 171 } 172 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 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 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 203 void setWhitelistDuration(long duration) { 204 this.whitelistDuration = duration; 205 this.stringName = null; 206 } 207 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 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 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 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 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 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 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