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