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