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