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