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