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