OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / frameworks / base / services / java / com / android / server / am / ServiceRecord.java
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 com.android.internal.os.BatteryStatsImpl;
20 import com.android.server.NotificationManagerService;
21
22 import android.app.INotificationManager;
23 import android.app.Notification;
24 import android.app.NotificationManager;
25 import android.content.ComponentName;
26 import android.content.Intent;
27 import android.content.pm.ApplicationInfo;
28 import android.content.pm.ServiceInfo;
29 import android.os.Binder;
30 import android.os.IBinder;
31 import android.os.RemoteException;
32 import android.os.SystemClock;
33 import android.util.Slog;
34 import android.util.TimeUtils;
35
36 import java.io.PrintWriter;
37 import java.util.ArrayList;
38 import java.util.HashMap;
39 import java.util.HashSet;
40 import java.util.Iterator;
41 import java.util.List;
42
43 /**
44  * A running application service.
45  */
46 class ServiceRecord extends Binder {
47     // Maximum number of delivery attempts before giving up.
48     static final int MAX_DELIVERY_COUNT = 3;
49
50     // Maximum number of times it can fail during execution before giving up.
51     static final int MAX_DONE_EXECUTING_COUNT = 6;
52
53     final ActivityManagerService ams;
54     final BatteryStatsImpl.Uid.Pkg.Serv stats;
55     final ComponentName name; // service component.
56     final String shortName; // name.flattenToShortString().
57     final Intent.FilterComparison intent;
58                             // original intent used to find service.
59     final ServiceInfo serviceInfo;
60                             // all information about the service.
61     final ApplicationInfo appInfo;
62                             // information about service's app.
63     final String packageName; // the package implementing intent's component
64     final String processName; // process where this component wants to run
65     final String permission;// permission needed to access service
66     final String baseDir;   // where activity source (resources etc) located
67     final String resDir;   // where public activity source (public resources etc) located
68     final String dataDir;   // where activity data should go
69     final boolean exported; // from ServiceInfo.exported
70     final Runnable restarter; // used to schedule retries of starting the service
71     final long createTime;  // when this service was created
72     final HashMap<Intent.FilterComparison, IntentBindRecord> bindings
73             = new HashMap<Intent.FilterComparison, IntentBindRecord>();
74                             // All active bindings to the service.
75     final HashMap<IBinder, ArrayList<ConnectionRecord>> connections
76             = new HashMap<IBinder, ArrayList<ConnectionRecord>>();
77                             // IBinder -> ConnectionRecord of all bound clients
78
79     ProcessRecord app;      // where this service is running or null.
80     boolean isForeground;   // is service currently in foreground mode?
81     int foregroundId;       // Notification ID of last foreground req.
82     Notification foregroundNoti; // Notification record of foreground state.
83     long lastActivity;      // last time there was some activity on the service.
84     boolean startRequested; // someone explicitly called start?
85     boolean stopIfKilled;   // last onStart() said to stop if service killed?
86     boolean callStart;      // last onStart() has asked to alway be called on restart.
87     int lastStartId;        // identifier of most recent start request.
88     int executeNesting;     // number of outstanding operations keeping foreground.
89     long executingStart;    // start time of last execute request.
90     int crashCount;         // number of times proc has crashed with service running
91     int totalRestartCount;  // number of times we have had to restart.
92     int restartCount;       // number of restarts performed in a row.
93     long restartDelay;      // delay until next restart attempt.
94     long restartTime;       // time of last restart.
95     long nextRestartTime;   // time when restartDelay will expire.
96
97     String stringName;      // caching of toString
98     
99     static class StartItem {
100         final ServiceRecord sr;
101         final int id;
102         final Intent intent;
103         final int targetPermissionUid;
104         long deliveredTime;
105         int deliveryCount;
106         int doneExecutingCount;
107         UriPermissionOwner uriPermissions;
108
109         String stringName;      // caching of toString
110
111         StartItem(ServiceRecord _sr, int _id, Intent _intent, int _targetPermissionUid) {
112             sr = _sr;
113             id = _id;
114             intent = _intent;
115             targetPermissionUid = _targetPermissionUid;
116         }
117
118         UriPermissionOwner getUriPermissionsLocked() {
119             if (uriPermissions == null) {
120                 uriPermissions = new UriPermissionOwner(sr.ams, this);
121             }
122             return uriPermissions;
123         }
124
125         void removeUriPermissionsLocked() {
126             if (uriPermissions != null) {
127                 uriPermissions.removeUriPermissionsLocked();
128                 uriPermissions = null;
129             }
130         }
131
132         public String toString() {
133             if (stringName != null) {
134                 return stringName;
135             }
136             StringBuilder sb = new StringBuilder(128);
137             sb.append("ServiceRecord{")
138                 .append(Integer.toHexString(System.identityHashCode(sr)))
139                 .append(' ').append(sr.shortName)
140                 .append(" StartItem ")
141                 .append(Integer.toHexString(System.identityHashCode(this)))
142                 .append(" id=").append(id).append('}');
143             return stringName = sb.toString();
144         }
145     }
146
147     final ArrayList<StartItem> deliveredStarts = new ArrayList<StartItem>();
148                             // start() arguments which been delivered.
149     final ArrayList<StartItem> pendingStarts = new ArrayList<StartItem>();
150                             // start() arguments that haven't yet been delivered.
151
152     void dumpStartList(PrintWriter pw, String prefix, List<StartItem> list, long now) {
153         final int N = list.size();
154         for (int i=0; i<N; i++) {
155             StartItem si = list.get(i);
156             pw.print(prefix); pw.print("#"); pw.print(i);
157                     pw.print(" id="); pw.print(si.id);
158                     if (now != 0) {
159                         pw.print(" dur=");
160                         TimeUtils.formatDuration(si.deliveredTime, now, pw);
161                     }
162                     if (si.deliveryCount != 0) {
163                         pw.print(" dc="); pw.print(si.deliveryCount);
164                     }
165                     if (si.doneExecutingCount != 0) {
166                         pw.print(" dxc="); pw.print(si.doneExecutingCount);
167                     }
168                     pw.println("");
169             pw.print(prefix); pw.print("  intent=");
170                     if (si.intent != null) pw.println(si.intent.toString());
171                     else pw.println("null");
172             if (si.targetPermissionUid >= 0) {
173                 pw.print(prefix); pw.print("  targetPermissionUid=");
174                         pw.println(si.targetPermissionUid);
175             }
176             if (si.uriPermissions != null) {
177                 if (si.uriPermissions.readUriPermissions != null) {
178                     pw.print(prefix); pw.print("  readUriPermissions=");
179                             pw.println(si.uriPermissions.readUriPermissions);
180                 }
181                 if (si.uriPermissions.writeUriPermissions != null) {
182                     pw.print(prefix); pw.print("  writeUriPermissions=");
183                             pw.println(si.uriPermissions.writeUriPermissions);
184                 }
185             }
186         }
187     }
188     
189     void dump(PrintWriter pw, String prefix) {
190         pw.print(prefix); pw.print("intent={");
191                 pw.print(intent.getIntent().toShortString(true, false));
192                 pw.println('}');
193         pw.print(prefix); pw.print("packageName="); pw.println(packageName);
194         pw.print(prefix); pw.print("processName="); pw.println(processName);
195         if (permission != null) {
196             pw.print(prefix); pw.print("permission="); pw.println(permission);
197         }
198         long now = SystemClock.uptimeMillis();
199         long nowReal = SystemClock.elapsedRealtime();
200         pw.print(prefix); pw.print("baseDir="); pw.println(baseDir);
201         if (!resDir.equals(baseDir)) pw.print(prefix); pw.print("resDir="); pw.println(resDir);
202         pw.print(prefix); pw.print("dataDir="); pw.println(dataDir);
203         pw.print(prefix); pw.print("app="); pw.println(app);
204         if (isForeground || foregroundId != 0) {
205             pw.print(prefix); pw.print("isForeground="); pw.print(isForeground);
206                     pw.print(" foregroundId="); pw.print(foregroundId);
207                     pw.print(" foregroundNoti="); pw.println(foregroundNoti);
208         }
209         pw.print(prefix); pw.print("createTime=");
210                 TimeUtils.formatDuration(createTime, nowReal, pw);
211                 pw.print(" lastActivity=");
212                 TimeUtils.formatDuration(lastActivity, now, pw);
213                 pw.println("");
214         pw.print(prefix); pw.print(" executingStart=");
215                 TimeUtils.formatDuration(executingStart, now, pw);
216                 pw.print(" restartTime=");
217                 TimeUtils.formatDuration(restartTime, now, pw);
218                 pw.println("");
219         if (startRequested || lastStartId != 0) {
220             pw.print(prefix); pw.print("startRequested="); pw.print(startRequested);
221                     pw.print(" stopIfKilled="); pw.print(stopIfKilled);
222                     pw.print(" callStart="); pw.print(callStart);
223                     pw.print(" lastStartId="); pw.println(lastStartId);
224         }
225         if (executeNesting != 0 || crashCount != 0 || restartCount != 0
226                 || restartDelay != 0 || nextRestartTime != 0) {
227             pw.print(prefix); pw.print("executeNesting="); pw.print(executeNesting);
228                     pw.print(" restartCount="); pw.print(restartCount);
229                     pw.print(" restartDelay=");
230                     TimeUtils.formatDuration(restartDelay, now, pw);
231                     pw.print(" nextRestartTime=");
232                     TimeUtils.formatDuration(nextRestartTime, now, pw);
233                     pw.print(" crashCount="); pw.println(crashCount);
234         }
235         if (deliveredStarts.size() > 0) {
236             pw.print(prefix); pw.println("Delivered Starts:");
237             dumpStartList(pw, prefix, deliveredStarts, now);
238         }
239         if (pendingStarts.size() > 0) {
240             pw.print(prefix); pw.println("Pending Starts:");
241             dumpStartList(pw, prefix, pendingStarts, 0);
242         }
243         if (bindings.size() > 0) {
244             Iterator<IntentBindRecord> it = bindings.values().iterator();
245             pw.print(prefix); pw.println("Bindings:");
246             while (it.hasNext()) {
247                 IntentBindRecord b = it.next();
248                 pw.print(prefix); pw.print("* IntentBindRecord{");
249                         pw.print(Integer.toHexString(System.identityHashCode(b)));
250                         pw.println("}:");
251                 b.dumpInService(pw, prefix + "  ");
252             }
253         }
254         if (connections.size() > 0) {
255             pw.print(prefix); pw.println("All Connections:");
256             Iterator<ArrayList<ConnectionRecord>> it = connections.values().iterator();
257             while (it.hasNext()) {
258                 ArrayList<ConnectionRecord> c = it.next();
259                 for (int i=0; i<c.size(); i++) {
260                     pw.print(prefix); pw.print("  "); pw.println(c.get(i));
261                 }
262             }
263         }
264     }
265
266     ServiceRecord(ActivityManagerService ams,
267             BatteryStatsImpl.Uid.Pkg.Serv servStats, ComponentName name,
268             Intent.FilterComparison intent, ServiceInfo sInfo, Runnable restarter) {
269         this.ams = ams;
270         this.stats = servStats;
271         this.name = name;
272         shortName = name.flattenToShortString();
273         this.intent = intent;
274         serviceInfo = sInfo;
275         appInfo = sInfo.applicationInfo;
276         packageName = sInfo.applicationInfo.packageName;
277         processName = sInfo.processName;
278         permission = sInfo.permission;
279         baseDir = sInfo.applicationInfo.sourceDir;
280         resDir = sInfo.applicationInfo.publicSourceDir;
281         dataDir = sInfo.applicationInfo.dataDir;
282         exported = sInfo.exported;
283         this.restarter = restarter;
284         createTime = SystemClock.elapsedRealtime();
285         lastActivity = SystemClock.uptimeMillis();
286     }
287
288     public AppBindRecord retrieveAppBindingLocked(Intent intent,
289             ProcessRecord app) {
290         Intent.FilterComparison filter = new Intent.FilterComparison(intent);
291         IntentBindRecord i = bindings.get(filter);
292         if (i == null) {
293             i = new IntentBindRecord(this, filter);
294             bindings.put(filter, i);
295         }
296         AppBindRecord a = i.apps.get(app);
297         if (a != null) {
298             return a;
299         }
300         a = new AppBindRecord(this, i, app);
301         i.apps.put(app, a);
302         return a;
303     }
304
305     public void resetRestartCounter() {
306         restartCount = 0;
307         restartDelay = 0;
308         restartTime = 0;
309     }
310     
311     public StartItem findDeliveredStart(int id, boolean remove) {
312         final int N = deliveredStarts.size();
313         for (int i=0; i<N; i++) {
314             StartItem si = deliveredStarts.get(i);
315             if (si.id == id) {
316                 if (remove) deliveredStarts.remove(i);
317                 return si;
318             }
319         }
320         
321         return null;
322     }
323     
324     public void postNotification() {
325         final int appUid = appInfo.uid;
326         final int appPid = app.pid;
327         if (foregroundId != 0 && foregroundNoti != null) {
328             // Do asynchronous communication with notification manager to
329             // avoid deadlocks.
330             final String localPackageName = packageName;
331             final int localForegroundId = foregroundId;
332             final Notification localForegroundNoti = foregroundNoti;
333             ams.mHandler.post(new Runnable() {
334                 public void run() {
335                     NotificationManagerService nm =
336                             (NotificationManagerService) NotificationManager.getService();
337                     if (nm == null) {
338                         return;
339                     }
340                     try {
341                         int[] outId = new int[1];
342                         nm.enqueueNotificationInternal(localPackageName, appUid, appPid,
343                                 null, localForegroundId, localForegroundNoti, outId);
344                     } catch (RuntimeException e) {
345                         Slog.w(ActivityManagerService.TAG,
346                                 "Error showing notification for service", e);
347                         // If it gave us a garbage notification, it doesn't
348                         // get to be foreground.
349                         ams.setServiceForeground(name, ServiceRecord.this,
350                                 0, null, true);
351                         ams.crashApplication(appUid, appPid, localPackageName,
352                                 "Bad notification for startForeground: " + e);
353                     }
354                 }
355             });
356         }
357     }
358     
359     public void cancelNotification() {
360         if (foregroundId != 0) {
361             // Do asynchronous communication with notification manager to
362             // avoid deadlocks.
363             final String localPackageName = packageName;
364             final int localForegroundId = foregroundId;
365             ams.mHandler.post(new Runnable() {
366                 public void run() {
367                     INotificationManager inm = NotificationManager.getService();
368                     if (inm == null) {
369                         return;
370                     }
371                     try {
372                         inm.cancelNotification(localPackageName, localForegroundId);
373                     } catch (RuntimeException e) {
374                         Slog.w(ActivityManagerService.TAG,
375                                 "Error canceling notification for service", e);
376                     } catch (RemoteException e) {
377                     }
378                 }
379             });
380         }
381     }
382     
383     public void clearDeliveredStartsLocked() {
384         for (int i=deliveredStarts.size()-1; i>=0; i--) {
385             deliveredStarts.get(i).removeUriPermissionsLocked();
386         }
387         deliveredStarts.clear();
388     }
389
390     public String toString() {
391         if (stringName != null) {
392             return stringName;
393         }
394         StringBuilder sb = new StringBuilder(128);
395         sb.append("ServiceRecord{")
396             .append(Integer.toHexString(System.identityHashCode(this)))
397             .append(' ').append(shortName).append('}');
398         return stringName = sb.toString();
399     }
400 }