• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 executeNesting;     // number of outstanding operations keeping foreground.
88     long executingStart;    // start time of last execute request.
89     int crashCount;         // number of times proc has crashed with service running
90     int totalRestartCount;  // number of times we have had to restart.
91     int restartCount;       // number of restarts performed in a row.
92     long restartDelay;      // delay until next restart attempt.
93     long restartTime;       // time of last restart.
94     long nextRestartTime;   // time when restartDelay will expire.
95 
96     String stringName;      // caching of toString
97 
98     private int lastStartId;    // identifier of most recent start request.
99 
100     static class StartItem {
101         final ServiceRecord sr;
102         final boolean taskRemoved;
103         final int id;
104         final Intent intent;
105         final int targetPermissionUid;
106         long deliveredTime;
107         int deliveryCount;
108         int doneExecutingCount;
109         UriPermissionOwner uriPermissions;
110 
111         String stringName;      // caching of toString
112 
StartItem(ServiceRecord _sr, boolean _taskRemoved, int _id, Intent _intent, int _targetPermissionUid)113         StartItem(ServiceRecord _sr, boolean _taskRemoved, int _id, Intent _intent,
114                 int _targetPermissionUid) {
115             sr = _sr;
116             taskRemoved = _taskRemoved;
117             id = _id;
118             intent = _intent;
119             targetPermissionUid = _targetPermissionUid;
120         }
121 
getUriPermissionsLocked()122         UriPermissionOwner getUriPermissionsLocked() {
123             if (uriPermissions == null) {
124                 uriPermissions = new UriPermissionOwner(sr.ams, this);
125             }
126             return uriPermissions;
127         }
128 
removeUriPermissionsLocked()129         void removeUriPermissionsLocked() {
130             if (uriPermissions != null) {
131                 uriPermissions.removeUriPermissionsLocked();
132                 uriPermissions = null;
133             }
134         }
135 
toString()136         public String toString() {
137             if (stringName != null) {
138                 return stringName;
139             }
140             StringBuilder sb = new StringBuilder(128);
141             sb.append("ServiceRecord{")
142                 .append(Integer.toHexString(System.identityHashCode(sr)))
143                 .append(' ').append(sr.shortName)
144                 .append(" StartItem ")
145                 .append(Integer.toHexString(System.identityHashCode(this)))
146                 .append(" id=").append(id).append('}');
147             return stringName = sb.toString();
148         }
149     }
150 
151     final ArrayList<StartItem> deliveredStarts = new ArrayList<StartItem>();
152                             // start() arguments which been delivered.
153     final ArrayList<StartItem> pendingStarts = new ArrayList<StartItem>();
154                             // start() arguments that haven't yet been delivered.
155 
dumpStartList(PrintWriter pw, String prefix, List<StartItem> list, long now)156     void dumpStartList(PrintWriter pw, String prefix, List<StartItem> list, long now) {
157         final int N = list.size();
158         for (int i=0; i<N; i++) {
159             StartItem si = list.get(i);
160             pw.print(prefix); pw.print("#"); pw.print(i);
161                     pw.print(" id="); pw.print(si.id);
162                     if (now != 0) {
163                         pw.print(" dur=");
164                         TimeUtils.formatDuration(si.deliveredTime, now, pw);
165                     }
166                     if (si.deliveryCount != 0) {
167                         pw.print(" dc="); pw.print(si.deliveryCount);
168                     }
169                     if (si.doneExecutingCount != 0) {
170                         pw.print(" dxc="); pw.print(si.doneExecutingCount);
171                     }
172                     pw.println("");
173             pw.print(prefix); pw.print("  intent=");
174                     if (si.intent != null) pw.println(si.intent.toString());
175                     else pw.println("null");
176             if (si.targetPermissionUid >= 0) {
177                 pw.print(prefix); pw.print("  targetPermissionUid=");
178                         pw.println(si.targetPermissionUid);
179             }
180             if (si.uriPermissions != null) {
181                 if (si.uriPermissions.readUriPermissions != null) {
182                     pw.print(prefix); pw.print("  readUriPermissions=");
183                             pw.println(si.uriPermissions.readUriPermissions);
184                 }
185                 if (si.uriPermissions.writeUriPermissions != null) {
186                     pw.print(prefix); pw.print("  writeUriPermissions=");
187                             pw.println(si.uriPermissions.writeUriPermissions);
188                 }
189             }
190         }
191     }
192 
dump(PrintWriter pw, String prefix)193     void dump(PrintWriter pw, String prefix) {
194         pw.print(prefix); pw.print("intent={");
195                 pw.print(intent.getIntent().toShortString(false, true, false));
196                 pw.println('}');
197         pw.print(prefix); pw.print("packageName="); pw.println(packageName);
198         pw.print(prefix); pw.print("processName="); pw.println(processName);
199         if (permission != null) {
200             pw.print(prefix); pw.print("permission="); pw.println(permission);
201         }
202         long now = SystemClock.uptimeMillis();
203         long nowReal = SystemClock.elapsedRealtime();
204         pw.print(prefix); pw.print("baseDir="); pw.println(baseDir);
205         if (!resDir.equals(baseDir)) {
206             pw.print(prefix); pw.print("resDir="); pw.println(resDir);
207         }
208         pw.print(prefix); pw.print("dataDir="); pw.println(dataDir);
209         pw.print(prefix); pw.print("app="); pw.println(app);
210         if (isForeground || foregroundId != 0) {
211             pw.print(prefix); pw.print("isForeground="); pw.print(isForeground);
212                     pw.print(" foregroundId="); pw.print(foregroundId);
213                     pw.print(" foregroundNoti="); pw.println(foregroundNoti);
214         }
215         pw.print(prefix); pw.print("createTime=");
216                 TimeUtils.formatDuration(createTime, nowReal, pw);
217                 pw.print(" lastActivity=");
218                 TimeUtils.formatDuration(lastActivity, now, pw);
219                 pw.println("");
220         pw.print(prefix); pw.print("executingStart=");
221                 TimeUtils.formatDuration(executingStart, now, pw);
222                 pw.print(" restartTime=");
223                 TimeUtils.formatDuration(restartTime, now, pw);
224                 pw.println("");
225         if (startRequested || lastStartId != 0) {
226             pw.print(prefix); pw.print("startRequested="); pw.print(startRequested);
227                     pw.print(" stopIfKilled="); pw.print(stopIfKilled);
228                     pw.print(" callStart="); pw.print(callStart);
229                     pw.print(" lastStartId="); pw.println(lastStartId);
230         }
231         if (executeNesting != 0 || crashCount != 0 || restartCount != 0
232                 || restartDelay != 0 || nextRestartTime != 0) {
233             pw.print(prefix); pw.print("executeNesting="); pw.print(executeNesting);
234                     pw.print(" restartCount="); pw.print(restartCount);
235                     pw.print(" restartDelay=");
236                     TimeUtils.formatDuration(restartDelay, now, pw);
237                     pw.print(" nextRestartTime=");
238                     TimeUtils.formatDuration(nextRestartTime, now, pw);
239                     pw.print(" crashCount="); pw.println(crashCount);
240         }
241         if (deliveredStarts.size() > 0) {
242             pw.print(prefix); pw.println("Delivered Starts:");
243             dumpStartList(pw, prefix, deliveredStarts, now);
244         }
245         if (pendingStarts.size() > 0) {
246             pw.print(prefix); pw.println("Pending Starts:");
247             dumpStartList(pw, prefix, pendingStarts, 0);
248         }
249         if (bindings.size() > 0) {
250             Iterator<IntentBindRecord> it = bindings.values().iterator();
251             pw.print(prefix); pw.println("Bindings:");
252             while (it.hasNext()) {
253                 IntentBindRecord b = it.next();
254                 pw.print(prefix); pw.print("* IntentBindRecord{");
255                         pw.print(Integer.toHexString(System.identityHashCode(b)));
256                         pw.println("}:");
257                 b.dumpInService(pw, prefix + "  ");
258             }
259         }
260         if (connections.size() > 0) {
261             pw.print(prefix); pw.println("All Connections:");
262             Iterator<ArrayList<ConnectionRecord>> it = connections.values().iterator();
263             while (it.hasNext()) {
264                 ArrayList<ConnectionRecord> c = it.next();
265                 for (int i=0; i<c.size(); i++) {
266                     pw.print(prefix); pw.print("  "); pw.println(c.get(i));
267                 }
268             }
269         }
270     }
271 
ServiceRecord(ActivityManagerService ams, BatteryStatsImpl.Uid.Pkg.Serv servStats, ComponentName name, Intent.FilterComparison intent, ServiceInfo sInfo, Runnable restarter)272     ServiceRecord(ActivityManagerService ams,
273             BatteryStatsImpl.Uid.Pkg.Serv servStats, ComponentName name,
274             Intent.FilterComparison intent, ServiceInfo sInfo, Runnable restarter) {
275         this.ams = ams;
276         this.stats = servStats;
277         this.name = name;
278         shortName = name.flattenToShortString();
279         this.intent = intent;
280         serviceInfo = sInfo;
281         appInfo = sInfo.applicationInfo;
282         packageName = sInfo.applicationInfo.packageName;
283         processName = sInfo.processName;
284         permission = sInfo.permission;
285         baseDir = sInfo.applicationInfo.sourceDir;
286         resDir = sInfo.applicationInfo.publicSourceDir;
287         dataDir = sInfo.applicationInfo.dataDir;
288         exported = sInfo.exported;
289         this.restarter = restarter;
290         createTime = SystemClock.elapsedRealtime();
291         lastActivity = SystemClock.uptimeMillis();
292     }
293 
retrieveAppBindingLocked(Intent intent, ProcessRecord app)294     public AppBindRecord retrieveAppBindingLocked(Intent intent,
295             ProcessRecord app) {
296         Intent.FilterComparison filter = new Intent.FilterComparison(intent);
297         IntentBindRecord i = bindings.get(filter);
298         if (i == null) {
299             i = new IntentBindRecord(this, filter);
300             bindings.put(filter, i);
301         }
302         AppBindRecord a = i.apps.get(app);
303         if (a != null) {
304             return a;
305         }
306         a = new AppBindRecord(this, i, app);
307         i.apps.put(app, a);
308         return a;
309     }
310 
resetRestartCounter()311     public void resetRestartCounter() {
312         restartCount = 0;
313         restartDelay = 0;
314         restartTime = 0;
315     }
316 
findDeliveredStart(int id, boolean remove)317     public StartItem findDeliveredStart(int id, boolean remove) {
318         final int N = deliveredStarts.size();
319         for (int i=0; i<N; i++) {
320             StartItem si = deliveredStarts.get(i);
321             if (si.id == id) {
322                 if (remove) deliveredStarts.remove(i);
323                 return si;
324             }
325         }
326 
327         return null;
328     }
329 
getLastStartId()330     public int getLastStartId() {
331         return lastStartId;
332     }
333 
makeNextStartId()334     public int makeNextStartId() {
335         lastStartId++;
336         if (lastStartId < 1) {
337             lastStartId = 1;
338         }
339         return lastStartId;
340     }
341 
postNotification()342     public void postNotification() {
343         final int appUid = appInfo.uid;
344         final int appPid = app.pid;
345         if (foregroundId != 0 && foregroundNoti != null) {
346             // Do asynchronous communication with notification manager to
347             // avoid deadlocks.
348             final String localPackageName = packageName;
349             final int localForegroundId = foregroundId;
350             final Notification localForegroundNoti = foregroundNoti;
351             ams.mHandler.post(new Runnable() {
352                 public void run() {
353                     NotificationManagerService nm =
354                             (NotificationManagerService) NotificationManager.getService();
355                     if (nm == null) {
356                         return;
357                     }
358                     try {
359                         int[] outId = new int[1];
360                         nm.enqueueNotificationInternal(localPackageName, appUid, appPid,
361                                 null, localForegroundId, localForegroundNoti, outId);
362                     } catch (RuntimeException e) {
363                         Slog.w(ActivityManagerService.TAG,
364                                 "Error showing notification for service", e);
365                         // If it gave us a garbage notification, it doesn't
366                         // get to be foreground.
367                         ams.setServiceForeground(name, ServiceRecord.this,
368                                 0, null, true);
369                         ams.crashApplication(appUid, appPid, localPackageName,
370                                 "Bad notification for startForeground: " + e);
371                     }
372                 }
373             });
374         }
375     }
376 
cancelNotification()377     public void cancelNotification() {
378         if (foregroundId != 0) {
379             // Do asynchronous communication with notification manager to
380             // avoid deadlocks.
381             final String localPackageName = packageName;
382             final int localForegroundId = foregroundId;
383             ams.mHandler.post(new Runnable() {
384                 public void run() {
385                     INotificationManager inm = NotificationManager.getService();
386                     if (inm == null) {
387                         return;
388                     }
389                     try {
390                         inm.cancelNotification(localPackageName, localForegroundId);
391                     } catch (RuntimeException e) {
392                         Slog.w(ActivityManagerService.TAG,
393                                 "Error canceling notification for service", e);
394                     } catch (RemoteException e) {
395                     }
396                 }
397             });
398         }
399     }
400 
clearDeliveredStartsLocked()401     public void clearDeliveredStartsLocked() {
402         for (int i=deliveredStarts.size()-1; i>=0; i--) {
403             deliveredStarts.get(i).removeUriPermissionsLocked();
404         }
405         deliveredStarts.clear();
406     }
407 
toString()408     public String toString() {
409         if (stringName != null) {
410             return stringName;
411         }
412         StringBuilder sb = new StringBuilder(128);
413         sb.append("ServiceRecord{")
414             .append(Integer.toHexString(System.identityHashCode(this)))
415             .append(' ').append(shortName).append('}');
416         return stringName = sb.toString();
417     }
418 }
419