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 android.app.ActivityManager;
     20 import android.content.IIntentSender;
     21 import android.content.IIntentReceiver;
     22 import android.app.PendingIntent;
     23 import android.content.Intent;
     24 import android.os.Binder;
     25 import android.os.Bundle;
     26 import android.os.IBinder;
     27 import android.os.RemoteException;
     28 import android.os.UserHandle;
     29 import android.util.Slog;
     30 
     31 import java.io.PrintWriter;
     32 import java.lang.ref.WeakReference;
     33 
     34 class PendingIntentRecord extends IIntentSender.Stub {
     35     final ActivityManagerService owner;
     36     final Key key;
     37     final int uid;
     38     final WeakReference<PendingIntentRecord> ref;
     39     boolean sent = false;
     40     boolean canceled = false;
     41 
     42     String stringName;
     43 
     44     final static class Key {
     45         final int type;
     46         final String packageName;
     47         final ActivityRecord activity;
     48         final String who;
     49         final int requestCode;
     50         final Intent requestIntent;
     51         final String requestResolvedType;
     52         final Bundle options;
     53         Intent[] allIntents;
     54         String[] allResolvedTypes;
     55         final int flags;
     56         final int hashCode;
     57         final int userId;
     58 
     59         private static final int ODD_PRIME_NUMBER = 37;
     60 
     61         Key(int _t, String _p, ActivityRecord _a, String _w,
     62                 int _r, Intent[] _i, String[] _it, int _f, Bundle _o, int _userId) {
     63             type = _t;
     64             packageName = _p;
     65             activity = _a;
     66             who = _w;
     67             requestCode = _r;
     68             requestIntent = _i != null ? _i[_i.length-1] : null;
     69             requestResolvedType = _it != null ? _it[_it.length-1] : null;
     70             allIntents = _i;
     71             allResolvedTypes = _it;
     72             flags = _f;
     73             options = _o;
     74             userId = _userId;
     75 
     76             int hash = 23;
     77             hash = (ODD_PRIME_NUMBER*hash) + _f;
     78             hash = (ODD_PRIME_NUMBER*hash) + _r;
     79             hash = (ODD_PRIME_NUMBER*hash) + _userId;
     80             if (_w != null) {
     81                 hash = (ODD_PRIME_NUMBER*hash) + _w.hashCode();
     82             }
     83             if (_a != null) {
     84                 hash = (ODD_PRIME_NUMBER*hash) + _a.hashCode();
     85             }
     86             if (requestIntent != null) {
     87                 hash = (ODD_PRIME_NUMBER*hash) + requestIntent.filterHashCode();
     88             }
     89             if (requestResolvedType != null) {
     90                 hash = (ODD_PRIME_NUMBER*hash) + requestResolvedType.hashCode();
     91             }
     92             hash = (ODD_PRIME_NUMBER*hash) + _p.hashCode();
     93             hash = (ODD_PRIME_NUMBER*hash) + _t;
     94             hashCode = hash;
     95             //Slog.i(ActivityManagerService.TAG, this + " hashCode=0x"
     96             //        + Integer.toHexString(hashCode));
     97         }
     98 
     99         public boolean equals(Object otherObj) {
    100             if (otherObj == null) {
    101                 return false;
    102             }
    103             try {
    104                 Key other = (Key)otherObj;
    105                 if (type != other.type) {
    106                     return false;
    107                 }
    108                 if (userId != other.userId){
    109                     return false;
    110                 }
    111                 if (!packageName.equals(other.packageName)) {
    112                     return false;
    113                 }
    114                 if (activity != other.activity) {
    115                     return false;
    116                 }
    117                 if (who != other.who) {
    118                     if (who != null) {
    119                         if (!who.equals(other.who)) {
    120                             return false;
    121                         }
    122                     } else if (other.who != null) {
    123                         return false;
    124                     }
    125                 }
    126                 if (requestCode != other.requestCode) {
    127                     return false;
    128                 }
    129                 if (requestIntent != other.requestIntent) {
    130                     if (requestIntent != null) {
    131                         if (!requestIntent.filterEquals(other.requestIntent)) {
    132                             return false;
    133                         }
    134                     } else if (other.requestIntent != null) {
    135                         return false;
    136                     }
    137                 }
    138                 if (requestResolvedType != other.requestResolvedType) {
    139                     if (requestResolvedType != null) {
    140                         if (!requestResolvedType.equals(other.requestResolvedType)) {
    141                             return false;
    142                         }
    143                     } else if (other.requestResolvedType != null) {
    144                         return false;
    145                     }
    146                 }
    147                 if (flags != other.flags) {
    148                     return false;
    149                 }
    150                 return true;
    151             } catch (ClassCastException e) {
    152             }
    153             return false;
    154         }
    155 
    156         public int hashCode() {
    157             return hashCode;
    158         }
    159 
    160         public String toString() {
    161             return "Key{" + typeName() + " pkg=" + packageName
    162                 + " intent="
    163                 + (requestIntent != null
    164                         ? requestIntent.toShortString(false, true, false, false) : "<null>")
    165                 + " flags=0x" + Integer.toHexString(flags) + " u=" + userId + "}";
    166         }
    167 
    168         String typeName() {
    169             switch (type) {
    170                 case ActivityManager.INTENT_SENDER_ACTIVITY:
    171                     return "startActivity";
    172                 case ActivityManager.INTENT_SENDER_BROADCAST:
    173                     return "broadcastIntent";
    174                 case ActivityManager.INTENT_SENDER_SERVICE:
    175                     return "startService";
    176                 case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
    177                     return "activityResult";
    178             }
    179             return Integer.toString(type);
    180         }
    181     }
    182 
    183     PendingIntentRecord(ActivityManagerService _owner, Key _k, int _u) {
    184         owner = _owner;
    185         key = _k;
    186         uid = _u;
    187         ref = new WeakReference<PendingIntentRecord>(this);
    188     }
    189 
    190     public int send(int code, Intent intent, String resolvedType,
    191             IIntentReceiver finishedReceiver, String requiredPermission) {
    192         return sendInner(code, intent, resolvedType, finishedReceiver,
    193                 requiredPermission, null, null, 0, 0, 0, null);
    194     }
    195 
    196     int sendInner(int code, Intent intent, String resolvedType,
    197             IIntentReceiver finishedReceiver, String requiredPermission,
    198             IBinder resultTo, String resultWho, int requestCode,
    199             int flagsMask, int flagsValues, Bundle options) {
    200         synchronized(owner) {
    201             if (!canceled) {
    202                 sent = true;
    203                 if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) {
    204                     owner.cancelIntentSenderLocked(this, true);
    205                     canceled = true;
    206                 }
    207                 Intent finalIntent = key.requestIntent != null
    208                         ? new Intent(key.requestIntent) : new Intent();
    209                 if (intent != null) {
    210                     int changes = finalIntent.fillIn(intent, key.flags);
    211                     if ((changes&Intent.FILL_IN_DATA) == 0) {
    212                         resolvedType = key.requestResolvedType;
    213                     }
    214                 } else {
    215                     resolvedType = key.requestResolvedType;
    216                 }
    217                 flagsMask &= ~Intent.IMMUTABLE_FLAGS;
    218                 flagsValues &= flagsMask;
    219                 finalIntent.setFlags((finalIntent.getFlags()&~flagsMask) | flagsValues);
    220 
    221                 final long origId = Binder.clearCallingIdentity();
    222 
    223                 boolean sendFinish = finishedReceiver != null;
    224                 int userId = key.userId;
    225                 if (userId == UserHandle.USER_CURRENT) {
    226                     userId = owner.getCurrentUserIdLocked();
    227                 }
    228                 switch (key.type) {
    229                     case ActivityManager.INTENT_SENDER_ACTIVITY:
    230                         if (options == null) {
    231                             options = key.options;
    232                         } else if (key.options != null) {
    233                             Bundle opts = new Bundle(key.options);
    234                             opts.putAll(options);
    235                             options = opts;
    236                         }
    237                         try {
    238                             if (key.allIntents != null && key.allIntents.length > 1) {
    239                                 Intent[] allIntents = new Intent[key.allIntents.length];
    240                                 String[] allResolvedTypes = new String[key.allIntents.length];
    241                                 System.arraycopy(key.allIntents, 0, allIntents, 0,
    242                                         key.allIntents.length);
    243                                 if (key.allResolvedTypes != null) {
    244                                     System.arraycopy(key.allResolvedTypes, 0, allResolvedTypes, 0,
    245                                             key.allResolvedTypes.length);
    246                                 }
    247                                 allIntents[allIntents.length-1] = finalIntent;
    248                                 allResolvedTypes[allResolvedTypes.length-1] = resolvedType;
    249                                 owner.startActivitiesInPackage(uid, key.packageName, allIntents,
    250                                         allResolvedTypes, resultTo, options, userId);
    251                             } else {
    252                                 owner.startActivityInPackage(uid, key.packageName, finalIntent,
    253                                         resolvedType, resultTo, resultWho, requestCode, 0,
    254                                         options, userId);
    255                             }
    256                         } catch (RuntimeException e) {
    257                             Slog.w(ActivityManagerService.TAG,
    258                                     "Unable to send startActivity intent", e);
    259                         }
    260                         break;
    261                     case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
    262                         key.activity.stack.sendActivityResultLocked(-1, key.activity,
    263                                 key.who, key.requestCode, code, finalIntent);
    264                         break;
    265                     case ActivityManager.INTENT_SENDER_BROADCAST:
    266                         try {
    267                             // If a completion callback has been requested, require
    268                             // that the broadcast be delivered synchronously
    269                             owner.broadcastIntentInPackage(key.packageName, uid,
    270                                     finalIntent, resolvedType,
    271                                     finishedReceiver, code, null, null,
    272                                 requiredPermission, (finishedReceiver != null), false, userId);
    273                             sendFinish = false;
    274                         } catch (RuntimeException e) {
    275                             Slog.w(ActivityManagerService.TAG,
    276                                     "Unable to send startActivity intent", e);
    277                         }
    278                         break;
    279                     case ActivityManager.INTENT_SENDER_SERVICE:
    280                         try {
    281                             owner.startServiceInPackage(uid,
    282                                     finalIntent, resolvedType, userId);
    283                         } catch (RuntimeException e) {
    284                             Slog.w(ActivityManagerService.TAG,
    285                                     "Unable to send startService intent", e);
    286                         }
    287                         break;
    288                 }
    289 
    290                 if (sendFinish) {
    291                     try {
    292                         finishedReceiver.performReceive(new Intent(finalIntent), 0,
    293                                 null, null, false, false, key.userId);
    294                     } catch (RemoteException e) {
    295                     }
    296                 }
    297 
    298                 Binder.restoreCallingIdentity(origId);
    299 
    300                 return 0;
    301             }
    302         }
    303         return ActivityManager.START_CANCELED;
    304     }
    305 
    306     protected void finalize() throws Throwable {
    307         try {
    308             if (!canceled) {
    309                 owner.mHandler.sendMessage(owner.mHandler.obtainMessage(
    310                         ActivityManagerService.FINALIZE_PENDING_INTENT_MSG, this));
    311             }
    312         } finally {
    313             super.finalize();
    314         }
    315     }
    316 
    317     public void completeFinalize() {
    318         synchronized(owner) {
    319             WeakReference<PendingIntentRecord> current =
    320                     owner.mIntentSenderRecords.get(key);
    321             if (current == ref) {
    322                 owner.mIntentSenderRecords.remove(key);
    323             }
    324         }
    325     }
    326 
    327     void dump(PrintWriter pw, String prefix) {
    328         pw.print(prefix); pw.print("uid="); pw.print(uid);
    329                 pw.print(" packageName="); pw.print(key.packageName);
    330                 pw.print(" type="); pw.print(key.typeName());
    331                 pw.print(" flags=0x"); pw.println(Integer.toHexString(key.flags));
    332         if (key.activity != null || key.who != null) {
    333             pw.print(prefix); pw.print("activity="); pw.print(key.activity);
    334                     pw.print(" who="); pw.println(key.who);
    335         }
    336         if (key.requestCode != 0 || key.requestResolvedType != null) {
    337             pw.print(prefix); pw.print("requestCode="); pw.print(key.requestCode);
    338                     pw.print(" requestResolvedType="); pw.println(key.requestResolvedType);
    339         }
    340         if (key.requestIntent != null) {
    341             pw.print(prefix); pw.print("requestIntent=");
    342                     pw.println(key.requestIntent.toShortString(false, true, true, true));
    343         }
    344         if (sent || canceled) {
    345             pw.print(prefix); pw.print("sent="); pw.print(sent);
    346                     pw.print(" canceled="); pw.println(canceled);
    347         }
    348     }
    349 
    350     public String toString() {
    351         if (stringName != null) {
    352             return stringName;
    353         }
    354         StringBuilder sb = new StringBuilder(128);
    355         sb.append("PendingIntentRecord{");
    356         sb.append(Integer.toHexString(System.identityHashCode(this)));
    357         sb.append(' ');
    358         sb.append(key.packageName);
    359         sb.append(' ');
    360         sb.append(key.typeName());
    361         sb.append('}');
    362         return stringName = sb.toString();
    363     }
    364 }
    365