Home | History | Annotate | Download | only in am
      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 
     17 package com.android.server.am;
     18 
     19 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
     20 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
     21 
     22 import android.app.ActivityManager;
     23 import android.content.IIntentSender;
     24 import android.content.IIntentReceiver;
     25 import android.app.PendingIntent;
     26 import android.content.Intent;
     27 import android.os.Binder;
     28 import android.os.Bundle;
     29 import android.os.IBinder;
     30 import android.os.RemoteCallbackList;
     31 import android.os.RemoteException;
     32 import android.os.TransactionTooLargeException;
     33 import android.os.UserHandle;
     34 import android.util.ArrayMap;
     35 import android.util.Slog;
     36 import android.util.TimeUtils;
     37 
     38 import com.android.internal.os.IResultReceiver;
     39 
     40 import java.io.PrintWriter;
     41 import java.lang.ref.WeakReference;
     42 import java.util.Objects;
     43 
     44 final 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