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