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