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