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