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