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