diff options
Diffstat (limited to 'services/core/java/com/android/server/am/PendingIntentRecord.java')
-rw-r--r-- | services/core/java/com/android/server/am/PendingIntentRecord.java | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java new file mode 100644 index 0000000..17f24a9 --- /dev/null +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -0,0 +1,364 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.am; + +import android.app.ActivityManager; +import android.content.IIntentSender; +import android.content.IIntentReceiver; +import android.app.PendingIntent; +import android.content.Intent; +import android.os.Binder; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.Slog; + +import java.io.PrintWriter; +import java.lang.ref.WeakReference; + +final class PendingIntentRecord extends IIntentSender.Stub { + final ActivityManagerService owner; + final Key key; + final int uid; + final WeakReference<PendingIntentRecord> ref; + boolean sent = false; + boolean canceled = false; + + String stringName; + + final static class Key { + final int type; + final String packageName; + final ActivityRecord activity; + final String who; + final int requestCode; + final Intent requestIntent; + final String requestResolvedType; + final Bundle options; + Intent[] allIntents; + String[] allResolvedTypes; + final int flags; + final int hashCode; + final int userId; + + private static final int ODD_PRIME_NUMBER = 37; + + Key(int _t, String _p, ActivityRecord _a, String _w, + int _r, Intent[] _i, String[] _it, int _f, Bundle _o, int _userId) { + type = _t; + packageName = _p; + activity = _a; + who = _w; + requestCode = _r; + requestIntent = _i != null ? _i[_i.length-1] : null; + requestResolvedType = _it != null ? _it[_it.length-1] : null; + allIntents = _i; + allResolvedTypes = _it; + flags = _f; + options = _o; + userId = _userId; + + int hash = 23; + hash = (ODD_PRIME_NUMBER*hash) + _f; + hash = (ODD_PRIME_NUMBER*hash) + _r; + hash = (ODD_PRIME_NUMBER*hash) + _userId; + if (_w != null) { + hash = (ODD_PRIME_NUMBER*hash) + _w.hashCode(); + } + if (_a != null) { + hash = (ODD_PRIME_NUMBER*hash) + _a.hashCode(); + } + if (requestIntent != null) { + hash = (ODD_PRIME_NUMBER*hash) + requestIntent.filterHashCode(); + } + if (requestResolvedType != null) { + hash = (ODD_PRIME_NUMBER*hash) + requestResolvedType.hashCode(); + } + hash = (ODD_PRIME_NUMBER*hash) + _p.hashCode(); + hash = (ODD_PRIME_NUMBER*hash) + _t; + hashCode = hash; + //Slog.i(ActivityManagerService.TAG, this + " hashCode=0x" + // + Integer.toHexString(hashCode)); + } + + public boolean equals(Object otherObj) { + if (otherObj == null) { + return false; + } + try { + Key other = (Key)otherObj; + if (type != other.type) { + return false; + } + if (userId != other.userId){ + return false; + } + if (!packageName.equals(other.packageName)) { + return false; + } + if (activity != other.activity) { + return false; + } + if (who != other.who) { + if (who != null) { + if (!who.equals(other.who)) { + return false; + } + } else if (other.who != null) { + return false; + } + } + if (requestCode != other.requestCode) { + return false; + } + if (requestIntent != other.requestIntent) { + if (requestIntent != null) { + if (!requestIntent.filterEquals(other.requestIntent)) { + return false; + } + } else if (other.requestIntent != null) { + return false; + } + } + if (requestResolvedType != other.requestResolvedType) { + if (requestResolvedType != null) { + if (!requestResolvedType.equals(other.requestResolvedType)) { + return false; + } + } else if (other.requestResolvedType != null) { + return false; + } + } + if (flags != other.flags) { + return false; + } + return true; + } catch (ClassCastException e) { + } + return false; + } + + public int hashCode() { + return hashCode; + } + + public String toString() { + return "Key{" + typeName() + " pkg=" + packageName + + " intent=" + + (requestIntent != null + ? requestIntent.toShortString(false, true, false, false) : "<null>") + + " flags=0x" + Integer.toHexString(flags) + " u=" + userId + "}"; + } + + String typeName() { + switch (type) { + case ActivityManager.INTENT_SENDER_ACTIVITY: + return "startActivity"; + case ActivityManager.INTENT_SENDER_BROADCAST: + return "broadcastIntent"; + case ActivityManager.INTENT_SENDER_SERVICE: + return "startService"; + case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT: + return "activityResult"; + } + return Integer.toString(type); + } + } + + PendingIntentRecord(ActivityManagerService _owner, Key _k, int _u) { + owner = _owner; + key = _k; + uid = _u; + ref = new WeakReference<PendingIntentRecord>(this); + } + + public int send(int code, Intent intent, String resolvedType, + IIntentReceiver finishedReceiver, String requiredPermission) { + return sendInner(code, intent, resolvedType, finishedReceiver, + requiredPermission, null, null, 0, 0, 0, null); + } + + int sendInner(int code, Intent intent, String resolvedType, + IIntentReceiver finishedReceiver, String requiredPermission, + IBinder resultTo, String resultWho, int requestCode, + int flagsMask, int flagsValues, Bundle options) { + synchronized(owner) { + if (!canceled) { + sent = true; + if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) { + owner.cancelIntentSenderLocked(this, true); + canceled = true; + } + Intent finalIntent = key.requestIntent != null + ? new Intent(key.requestIntent) : new Intent(); + if (intent != null) { + int changes = finalIntent.fillIn(intent, key.flags); + if ((changes&Intent.FILL_IN_DATA) == 0) { + resolvedType = key.requestResolvedType; + } + } else { + resolvedType = key.requestResolvedType; + } + flagsMask &= ~Intent.IMMUTABLE_FLAGS; + flagsValues &= flagsMask; + finalIntent.setFlags((finalIntent.getFlags()&~flagsMask) | flagsValues); + + final long origId = Binder.clearCallingIdentity(); + + boolean sendFinish = finishedReceiver != null; + int userId = key.userId; + if (userId == UserHandle.USER_CURRENT) { + userId = owner.getCurrentUserIdLocked(); + } + switch (key.type) { + case ActivityManager.INTENT_SENDER_ACTIVITY: + if (options == null) { + options = key.options; + } else if (key.options != null) { + Bundle opts = new Bundle(key.options); + opts.putAll(options); + options = opts; + } + try { + if (key.allIntents != null && key.allIntents.length > 1) { + Intent[] allIntents = new Intent[key.allIntents.length]; + String[] allResolvedTypes = new String[key.allIntents.length]; + System.arraycopy(key.allIntents, 0, allIntents, 0, + key.allIntents.length); + if (key.allResolvedTypes != null) { + System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0, + key.allResolvedTypes.length); + } + allIntents[allIntents.length-1] = finalIntent; + allResolvedTypes[allResolvedTypes.length-1] = resolvedType; + owner.startActivitiesInPackage(uid, key.packageName, allIntents, + allResolvedTypes, resultTo, options, userId); + } else { + owner.startActivityInPackage(uid, key.packageName, finalIntent, + resolvedType, resultTo, resultWho, requestCode, 0, + options, userId); + } + } catch (RuntimeException e) { + Slog.w(ActivityManagerService.TAG, + "Unable to send startActivity intent", e); + } + break; + case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT: + key.activity.task.stack.sendActivityResultLocked(-1, key.activity, + key.who, key.requestCode, code, finalIntent); + break; + case ActivityManager.INTENT_SENDER_BROADCAST: + try { + // If a completion callback has been requested, require + // that the broadcast be delivered synchronously + owner.broadcastIntentInPackage(key.packageName, uid, + finalIntent, resolvedType, + finishedReceiver, code, null, null, + requiredPermission, (finishedReceiver != null), false, userId); + sendFinish = false; + } catch (RuntimeException e) { + Slog.w(ActivityManagerService.TAG, + "Unable to send startActivity intent", e); + } + break; + case ActivityManager.INTENT_SENDER_SERVICE: + try { + owner.startServiceInPackage(uid, + finalIntent, resolvedType, userId); + } catch (RuntimeException e) { + Slog.w(ActivityManagerService.TAG, + "Unable to send startService intent", e); + } + break; + } + + if (sendFinish) { + try { + finishedReceiver.performReceive(new Intent(finalIntent), 0, + null, null, false, false, key.userId); + } catch (RemoteException e) { + } + } + + Binder.restoreCallingIdentity(origId); + + return 0; + } + } + return ActivityManager.START_CANCELED; + } + + protected void finalize() throws Throwable { + try { + if (!canceled) { + owner.mHandler.sendMessage(owner.mHandler.obtainMessage( + ActivityManagerService.FINALIZE_PENDING_INTENT_MSG, this)); + } + } finally { + super.finalize(); + } + } + + public void completeFinalize() { + synchronized(owner) { + WeakReference<PendingIntentRecord> current = + owner.mIntentSenderRecords.get(key); + if (current == ref) { + owner.mIntentSenderRecords.remove(key); + } + } + } + + void dump(PrintWriter pw, String prefix) { + pw.print(prefix); pw.print("uid="); pw.print(uid); + pw.print(" packageName="); pw.print(key.packageName); + pw.print(" type="); pw.print(key.typeName()); + pw.print(" flags=0x"); pw.println(Integer.toHexString(key.flags)); + if (key.activity != null || key.who != null) { + pw.print(prefix); pw.print("activity="); pw.print(key.activity); + pw.print(" who="); pw.println(key.who); + } + if (key.requestCode != 0 || key.requestResolvedType != null) { + pw.print(prefix); pw.print("requestCode="); pw.print(key.requestCode); + pw.print(" requestResolvedType="); pw.println(key.requestResolvedType); + } + if (key.requestIntent != null) { + pw.print(prefix); pw.print("requestIntent="); + pw.println(key.requestIntent.toShortString(false, true, true, true)); + } + if (sent || canceled) { + pw.print(prefix); pw.print("sent="); pw.print(sent); + pw.print(" canceled="); pw.println(canceled); + } + } + + public String toString() { + if (stringName != null) { + return stringName; + } + StringBuilder sb = new StringBuilder(128); + sb.append("PendingIntentRecord{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(' '); + sb.append(key.packageName); + sb.append(' '); + sb.append(key.typeName()); + sb.append('}'); + return stringName = sb.toString(); + } +} |