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 android.app.IActivityManager; 20import android.content.IIntentSender; 21import android.content.IIntentReceiver; 22import android.app.PendingIntent; 23import android.content.Intent; 24import android.os.Binder; 25import android.os.IBinder; 26import android.os.RemoteException; 27import android.util.Slog; 28 29import java.io.PrintWriter; 30import java.lang.ref.WeakReference; 31 32class PendingIntentRecord extends IIntentSender.Stub { 33 final ActivityManagerService owner; 34 final Key key; 35 final int uid; 36 final WeakReference<PendingIntentRecord> ref; 37 boolean sent = false; 38 boolean canceled = false; 39 40 String stringName; 41 42 final static class Key { 43 final int type; 44 final String packageName; 45 final ActivityRecord activity; 46 final String who; 47 final int requestCode; 48 final Intent requestIntent; 49 final String requestResolvedType; 50 final int flags; 51 final int hashCode; 52 53 private static final int ODD_PRIME_NUMBER = 37; 54 55 Key(int _t, String _p, ActivityRecord _a, String _w, 56 int _r, Intent _i, String _it, int _f) { 57 type = _t; 58 packageName = _p; 59 activity = _a; 60 who = _w; 61 requestCode = _r; 62 requestIntent = _i; 63 requestResolvedType = _it; 64 flags = _f; 65 66 int hash = 23; 67 hash = (ODD_PRIME_NUMBER*hash) + _f; 68 hash = (ODD_PRIME_NUMBER*hash) + _r; 69 if (_w != null) { 70 hash = (ODD_PRIME_NUMBER*hash) + _w.hashCode(); 71 } 72 if (_a != null) { 73 hash = (ODD_PRIME_NUMBER*hash) + _a.hashCode(); 74 } 75 if (_i != null) { 76 hash = (ODD_PRIME_NUMBER*hash) + _i.filterHashCode(); 77 } 78 if (_it != null) { 79 hash = (ODD_PRIME_NUMBER*hash) + _it.hashCode(); 80 } 81 hash = (ODD_PRIME_NUMBER*hash) + _p.hashCode(); 82 hash = (ODD_PRIME_NUMBER*hash) + _t; 83 hashCode = hash; 84 //Slog.i(ActivityManagerService.TAG, this + " hashCode=0x" 85 // + Integer.toHexString(hashCode)); 86 } 87 88 public boolean equals(Object otherObj) { 89 if (otherObj == null) { 90 return false; 91 } 92 try { 93 Key other = (Key)otherObj; 94 if (type != other.type) { 95 return false; 96 } 97 if (!packageName.equals(other.packageName)) { 98 return false; 99 } 100 if (activity != other.activity) { 101 return false; 102 } 103 if (who != other.who) { 104 if (who != null) { 105 if (!who.equals(other.who)) { 106 return false; 107 } 108 } else if (other.who != null) { 109 return false; 110 } 111 } 112 if (requestCode != other.requestCode) { 113 return false; 114 } 115 if (requestIntent != other.requestIntent) { 116 if (requestIntent != null) { 117 if (!requestIntent.filterEquals(other.requestIntent)) { 118 return false; 119 } 120 } else if (other.requestIntent != null) { 121 return false; 122 } 123 } 124 if (requestResolvedType != other.requestResolvedType) { 125 if (requestResolvedType != null) { 126 if (!requestResolvedType.equals(other.requestResolvedType)) { 127 return false; 128 } 129 } else if (other.requestResolvedType != null) { 130 return false; 131 } 132 } 133 if (flags != other.flags) { 134 return false; 135 } 136 return true; 137 } catch (ClassCastException e) { 138 } 139 return false; 140 } 141 142 public int hashCode() { 143 return hashCode; 144 } 145 146 public String toString() { 147 return "Key{" + typeName() + " pkg=" + packageName 148 + " intent=" 149 + (requestIntent != null ? requestIntent.toShortString(true, false) : "<null>") 150 + " flags=0x" + Integer.toHexString(flags) + "}"; 151 } 152 153 String typeName() { 154 switch (type) { 155 case IActivityManager.INTENT_SENDER_ACTIVITY: 156 return "startActivity"; 157 case IActivityManager.INTENT_SENDER_BROADCAST: 158 return "broadcastIntent"; 159 case IActivityManager.INTENT_SENDER_SERVICE: 160 return "startService"; 161 case IActivityManager.INTENT_SENDER_ACTIVITY_RESULT: 162 return "activityResult"; 163 } 164 return Integer.toString(type); 165 } 166 } 167 168 PendingIntentRecord(ActivityManagerService _owner, Key _k, int _u) { 169 owner = _owner; 170 key = _k; 171 uid = _u; 172 ref = new WeakReference<PendingIntentRecord>(this); 173 } 174 175 public int send(int code, Intent intent, String resolvedType, 176 IIntentReceiver finishedReceiver) { 177 return sendInner(code, intent, resolvedType, finishedReceiver, 178 null, null, 0, 0, 0); 179 } 180 181 int sendInner(int code, Intent intent, String resolvedType, 182 IIntentReceiver finishedReceiver, 183 IBinder resultTo, String resultWho, int requestCode, 184 int flagsMask, int flagsValues) { 185 synchronized(owner) { 186 if (!canceled) { 187 sent = true; 188 if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) { 189 owner.cancelIntentSenderLocked(this, true); 190 canceled = true; 191 } 192 Intent finalIntent = key.requestIntent != null 193 ? new Intent(key.requestIntent) : new Intent(); 194 if (intent != null) { 195 int changes = finalIntent.fillIn(intent, key.flags); 196 if ((changes&Intent.FILL_IN_DATA) == 0) { 197 resolvedType = key.requestResolvedType; 198 } 199 } else { 200 resolvedType = key.requestResolvedType; 201 } 202 flagsMask &= ~Intent.IMMUTABLE_FLAGS; 203 flagsValues &= flagsMask; 204 finalIntent.setFlags((finalIntent.getFlags()&~flagsMask) | flagsValues); 205 206 final long origId = Binder.clearCallingIdentity(); 207 208 boolean sendFinish = finishedReceiver != null; 209 switch (key.type) { 210 case IActivityManager.INTENT_SENDER_ACTIVITY: 211 try { 212 owner.startActivityInPackage(uid, 213 finalIntent, resolvedType, 214 resultTo, resultWho, requestCode, false); 215 } catch (RuntimeException e) { 216 Slog.w(ActivityManagerService.TAG, 217 "Unable to send startActivity intent", e); 218 } 219 break; 220 case IActivityManager.INTENT_SENDER_ACTIVITY_RESULT: 221 key.activity.stack.sendActivityResultLocked(-1, key.activity, 222 key.who, key.requestCode, code, finalIntent); 223 break; 224 case IActivityManager.INTENT_SENDER_BROADCAST: 225 try { 226 // If a completion callback has been requested, require 227 // that the broadcast be delivered synchronously 228 owner.broadcastIntentInPackage(key.packageName, uid, 229 finalIntent, resolvedType, 230 finishedReceiver, code, null, null, null, 231 (finishedReceiver != null), false); 232 sendFinish = false; 233 } catch (RuntimeException e) { 234 Slog.w(ActivityManagerService.TAG, 235 "Unable to send startActivity intent", e); 236 } 237 break; 238 case IActivityManager.INTENT_SENDER_SERVICE: 239 try { 240 owner.startServiceInPackage(uid, 241 finalIntent, resolvedType); 242 } catch (RuntimeException e) { 243 Slog.w(ActivityManagerService.TAG, 244 "Unable to send startService intent", e); 245 } 246 break; 247 } 248 249 if (sendFinish) { 250 try { 251 finishedReceiver.performReceive(new Intent(finalIntent), 0, 252 null, null, false, false); 253 } catch (RemoteException e) { 254 } 255 } 256 257 Binder.restoreCallingIdentity(origId); 258 259 return 0; 260 } 261 } 262 return IActivityManager.START_CANCELED; 263 } 264 265 protected void finalize() throws Throwable { 266 try { 267 if (!canceled) { 268 owner.mHandler.sendMessage(owner.mHandler.obtainMessage( 269 ActivityManagerService.FINALIZE_PENDING_INTENT_MSG, this)); 270 } 271 } finally { 272 super.finalize(); 273 } 274 } 275 276 public void completeFinalize() { 277 synchronized(owner) { 278 WeakReference<PendingIntentRecord> current = 279 owner.mIntentSenderRecords.get(key); 280 if (current == ref) { 281 owner.mIntentSenderRecords.remove(key); 282 } 283 } 284 } 285 286 void dump(PrintWriter pw, String prefix) { 287 pw.print(prefix); pw.print("uid="); pw.print(uid); 288 pw.print(" packageName="); pw.print(key.packageName); 289 pw.print(" type="); pw.print(key.typeName()); 290 pw.print(" flags=0x"); pw.println(Integer.toHexString(key.flags)); 291 if (key.activity != null || key.who != null) { 292 pw.print(prefix); pw.print("activity="); pw.print(key.activity); 293 pw.print(" who="); pw.println(key.who); 294 } 295 if (key.requestCode != 0 || key.requestResolvedType != null) { 296 pw.print(prefix); pw.print("requestCode="); pw.print(key.requestCode); 297 pw.print(" requestResolvedType="); pw.println(key.requestResolvedType); 298 } 299 if (key.requestIntent != null) { 300 pw.print(prefix); pw.print("requestIntent="); 301 pw.println(key.requestIntent.toShortString(true, true)); 302 } 303 if (sent || canceled) { 304 pw.print(prefix); pw.print("sent="); pw.print(sent); 305 pw.print(" canceled="); pw.println(canceled); 306 } 307 } 308 309 public String toString() { 310 if (stringName != null) { 311 return stringName; 312 } 313 StringBuilder sb = new StringBuilder(128); 314 sb.append("PendingIntentRecord{"); 315 sb.append(Integer.toHexString(System.identityHashCode(this))); 316 sb.append(' '); 317 sb.append(key.packageName); 318 sb.append(' '); 319 sb.append(key.typeName()); 320 sb.append('}'); 321 return stringName = sb.toString(); 322 } 323} 324