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
17package com.android.server.am;
18
19import android.app.IActivityManager;
20import android.content.IIntentSender;
21import android.content.IIntentReceiver;
22import android.app.PendingIntent;
23import android.content.Intent;
24import android.os.Binder;
25import android.os.IBinder;
26import android.os.RemoteException;
27import android.util.Slog;
28
29import java.io.PrintWriter;
30import java.lang.ref.WeakReference;
31
32class 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