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