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