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.app.IActivityContainer;
     24 import android.content.IIntentSender;
     25 import android.content.IIntentReceiver;
     26 import android.app.PendingIntent;
     27 import android.content.Intent;
     28 import android.os.Binder;
     29 import android.os.Bundle;
     30 import android.os.IBinder;
     31 import android.os.RemoteException;
     32 import android.os.TransactionTooLargeException;
     33 import android.os.UserHandle;
     34 import android.util.Slog;
     35 import android.util.TimeUtils;
     36 
     37 import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
     38 
     39 import java.io.PrintWriter;
     40 import java.lang.ref.WeakReference;
     41 import java.util.Objects;
     42 
     43 final 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