ServiceRecord.java revision 43d9ac81f7722bb539ee67023f10b9f43abbf202
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 com.android.internal.os.BatteryStatsImpl;
20import com.android.server.NotificationManagerService;
21
22import android.app.INotificationManager;
23import android.app.Notification;
24import android.app.NotificationManager;
25import android.content.ComponentName;
26import android.content.Intent;
27import android.content.pm.ApplicationInfo;
28import android.content.pm.ServiceInfo;
29import android.os.Binder;
30import android.os.IBinder;
31import android.os.RemoteException;
32import android.os.SystemClock;
33import android.util.Slog;
34import android.util.TimeUtils;
35
36import java.io.PrintWriter;
37import java.util.ArrayList;
38import java.util.HashMap;
39import java.util.HashSet;
40import java.util.Iterator;
41import java.util.List;
42
43/**
44 * A running application service.
45 */
46class 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 implements UriPermissionOwner {
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
108        String stringName;      // caching of toString
109
110        HashSet<UriPermission> readUriPermissions; // special access to reading uris.
111        HashSet<UriPermission> writeUriPermissions; // special access to writing uris.
112
113        StartItem(ServiceRecord _sr, int _id, Intent _intent, int _targetPermissionUid) {
114            sr = _sr;
115            id = _id;
116            intent = _intent;
117            targetPermissionUid = _targetPermissionUid;
118        }
119
120        void removeUriPermissionsLocked() {
121            if (readUriPermissions != null) {
122                for (UriPermission perm : readUriPermissions) {
123                    perm.readOwners.remove(this);
124                    if (perm.readOwners.size() == 0 && (perm.globalModeFlags
125                            &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
126                        perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
127                        sr.ams.removeUriPermissionIfNeededLocked(perm);
128                    }
129                }
130                readUriPermissions = null;
131            }
132            if (writeUriPermissions != null) {
133                for (UriPermission perm : writeUriPermissions) {
134                    perm.writeOwners.remove(this);
135                    if (perm.writeOwners.size() == 0 && (perm.globalModeFlags
136                            &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
137                        perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
138                        sr.ams.removeUriPermissionIfNeededLocked(perm);
139                    }
140                }
141                writeUriPermissions = null;
142            }
143        }
144
145        @Override
146        public void addReadPermission(UriPermission perm) {
147            if (readUriPermissions == null) {
148                readUriPermissions = new HashSet<UriPermission>();
149            }
150            readUriPermissions.add(perm);
151        }
152
153        @Override
154        public void addWritePermission(UriPermission perm) {
155            if (writeUriPermissions == null) {
156                writeUriPermissions = new HashSet<UriPermission>();
157            }
158            writeUriPermissions.add(perm);
159        }
160
161        @Override
162        public void removeReadPermission(UriPermission perm) {
163            readUriPermissions.remove(perm);
164            if (readUriPermissions.size() == 0) {
165                readUriPermissions = null;
166            }
167        }
168
169        @Override
170        public void removeWritePermission(UriPermission perm) {
171            writeUriPermissions.remove(perm);
172            if (writeUriPermissions.size() == 0) {
173                writeUriPermissions = null;
174            }
175        }
176
177        public String toString() {
178            if (stringName != null) {
179                return stringName;
180            }
181            StringBuilder sb = new StringBuilder(128);
182            sb.append("ServiceRecord{")
183                .append(Integer.toHexString(System.identityHashCode(sr)))
184                .append(' ').append(sr.shortName)
185                .append(" StartItem ")
186                .append(Integer.toHexString(System.identityHashCode(this)))
187                .append(" id=").append(id).append('}');
188            return stringName = sb.toString();
189        }
190    }
191
192    final ArrayList<StartItem> deliveredStarts = new ArrayList<StartItem>();
193                            // start() arguments which been delivered.
194    final ArrayList<StartItem> pendingStarts = new ArrayList<StartItem>();
195                            // start() arguments that haven't yet been delivered.
196
197    void dumpStartList(PrintWriter pw, String prefix, List<StartItem> list, long now) {
198        final int N = list.size();
199        for (int i=0; i<N; i++) {
200            StartItem si = list.get(i);
201            pw.print(prefix); pw.print("#"); pw.print(i);
202                    pw.print(" id="); pw.print(si.id);
203                    if (now != 0) {
204                        pw.print(" dur=");
205                        TimeUtils.formatDuration(si.deliveredTime, now, pw);
206                    }
207                    if (si.deliveryCount != 0) {
208                        pw.print(" dc="); pw.print(si.deliveryCount);
209                    }
210                    if (si.doneExecutingCount != 0) {
211                        pw.print(" dxc="); pw.print(si.doneExecutingCount);
212                    }
213                    pw.println("");
214            pw.print(prefix); pw.print("  intent=");
215                    if (si.intent != null) pw.println(si.intent.toString());
216                    else pw.println("null");
217            if (si.targetPermissionUid >= 0) {
218                pw.print(prefix); pw.print("  targetPermissionUid=");
219                        pw.println(si.targetPermissionUid);
220            }
221            if (si.readUriPermissions != null) {
222                pw.print(prefix); pw.print("  readUriPermissions=");
223                        pw.println(si.readUriPermissions);
224            }
225            if (si.writeUriPermissions != null) {
226                pw.print(prefix); pw.print("  writeUriPermissions=");
227                        pw.println(si.writeUriPermissions);
228            }
229        }
230    }
231
232    void dump(PrintWriter pw, String prefix) {
233        pw.print(prefix); pw.print("intent={");
234                pw.print(intent.getIntent().toShortString(true, false));
235                pw.println('}');
236        pw.print(prefix); pw.print("packageName="); pw.println(packageName);
237        pw.print(prefix); pw.print("processName="); pw.println(processName);
238        if (permission != null) {
239            pw.print(prefix); pw.print("permission="); pw.println(permission);
240        }
241        long now = SystemClock.uptimeMillis();
242        long nowReal = SystemClock.elapsedRealtime();
243        pw.print(prefix); pw.print("baseDir="); pw.println(baseDir);
244        if (!resDir.equals(baseDir)) pw.print(prefix); pw.print("resDir="); pw.println(resDir);
245        pw.print(prefix); pw.print("dataDir="); pw.println(dataDir);
246        pw.print(prefix); pw.print("app="); pw.println(app);
247        if (isForeground || foregroundId != 0) {
248            pw.print(prefix); pw.print("isForeground="); pw.print(isForeground);
249                    pw.print(" foregroundId="); pw.print(foregroundId);
250                    pw.print(" foregroundNoti="); pw.println(foregroundNoti);
251        }
252        pw.print(prefix); pw.print("createTime=");
253                TimeUtils.formatDuration(createTime, nowReal, pw);
254                pw.print(" lastActivity=");
255                TimeUtils.formatDuration(lastActivity, now, pw);
256                pw.println("");
257        pw.print(prefix); pw.print(" executingStart=");
258                TimeUtils.formatDuration(executingStart, now, pw);
259                pw.print(" restartTime=");
260                TimeUtils.formatDuration(restartTime, now, pw);
261                pw.println("");
262        if (startRequested || lastStartId != 0) {
263            pw.print(prefix); pw.print("startRequested="); pw.print(startRequested);
264                    pw.print(" stopIfKilled="); pw.print(stopIfKilled);
265                    pw.print(" callStart="); pw.print(callStart);
266                    pw.print(" lastStartId="); pw.println(lastStartId);
267        }
268        if (executeNesting != 0 || crashCount != 0 || restartCount != 0
269                || restartDelay != 0 || nextRestartTime != 0) {
270            pw.print(prefix); pw.print("executeNesting="); pw.print(executeNesting);
271                    pw.print(" restartCount="); pw.print(restartCount);
272                    pw.print(" restartDelay=");
273                    TimeUtils.formatDuration(restartDelay, now, pw);
274                    pw.print(" nextRestartTime=");
275                    TimeUtils.formatDuration(nextRestartTime, now, pw);
276                    pw.print(" crashCount="); pw.println(crashCount);
277        }
278        if (deliveredStarts.size() > 0) {
279            pw.print(prefix); pw.println("Delivered Starts:");
280            dumpStartList(pw, prefix, deliveredStarts, now);
281        }
282        if (pendingStarts.size() > 0) {
283            pw.print(prefix); pw.println("Pending Starts:");
284            dumpStartList(pw, prefix, pendingStarts, 0);
285        }
286        if (bindings.size() > 0) {
287            Iterator<IntentBindRecord> it = bindings.values().iterator();
288            pw.print(prefix); pw.println("Bindings:");
289            while (it.hasNext()) {
290                IntentBindRecord b = it.next();
291                pw.print(prefix); pw.print("* IntentBindRecord{");
292                        pw.print(Integer.toHexString(System.identityHashCode(b)));
293                        pw.println("}:");
294                b.dumpInService(pw, prefix + "  ");
295            }
296        }
297        if (connections.size() > 0) {
298            pw.print(prefix); pw.println("All Connections:");
299            Iterator<ArrayList<ConnectionRecord>> it = connections.values().iterator();
300            while (it.hasNext()) {
301                ArrayList<ConnectionRecord> c = it.next();
302                for (int i=0; i<c.size(); i++) {
303                    pw.print(prefix); pw.print("  "); pw.println(c.get(i));
304                }
305            }
306        }
307    }
308
309    ServiceRecord(ActivityManagerService ams,
310            BatteryStatsImpl.Uid.Pkg.Serv servStats, ComponentName name,
311            Intent.FilterComparison intent, ServiceInfo sInfo, Runnable restarter) {
312        this.ams = ams;
313        this.stats = servStats;
314        this.name = name;
315        shortName = name.flattenToShortString();
316        this.intent = intent;
317        serviceInfo = sInfo;
318        appInfo = sInfo.applicationInfo;
319        packageName = sInfo.applicationInfo.packageName;
320        processName = sInfo.processName;
321        permission = sInfo.permission;
322        baseDir = sInfo.applicationInfo.sourceDir;
323        resDir = sInfo.applicationInfo.publicSourceDir;
324        dataDir = sInfo.applicationInfo.dataDir;
325        exported = sInfo.exported;
326        this.restarter = restarter;
327        createTime = SystemClock.elapsedRealtime();
328        lastActivity = SystemClock.uptimeMillis();
329    }
330
331    public AppBindRecord retrieveAppBindingLocked(Intent intent,
332            ProcessRecord app) {
333        Intent.FilterComparison filter = new Intent.FilterComparison(intent);
334        IntentBindRecord i = bindings.get(filter);
335        if (i == null) {
336            i = new IntentBindRecord(this, filter);
337            bindings.put(filter, i);
338        }
339        AppBindRecord a = i.apps.get(app);
340        if (a != null) {
341            return a;
342        }
343        a = new AppBindRecord(this, i, app);
344        i.apps.put(app, a);
345        return a;
346    }
347
348    public void resetRestartCounter() {
349        restartCount = 0;
350        restartDelay = 0;
351        restartTime = 0;
352    }
353
354    public StartItem findDeliveredStart(int id, boolean remove) {
355        final int N = deliveredStarts.size();
356        for (int i=0; i<N; i++) {
357            StartItem si = deliveredStarts.get(i);
358            if (si.id == id) {
359                if (remove) deliveredStarts.remove(i);
360                return si;
361            }
362        }
363
364        return null;
365    }
366
367    public void postNotification() {
368        final int appUid = appInfo.uid;
369        final int appPid = app.pid;
370        if (foregroundId != 0 && foregroundNoti != null) {
371            // Do asynchronous communication with notification manager to
372            // avoid deadlocks.
373            final String localPackageName = packageName;
374            final int localForegroundId = foregroundId;
375            final Notification localForegroundNoti = foregroundNoti;
376            ams.mHandler.post(new Runnable() {
377                public void run() {
378                    NotificationManagerService nm =
379                            (NotificationManagerService) NotificationManager.getService();
380                    if (nm == null) {
381                        return;
382                    }
383                    try {
384                        int[] outId = new int[1];
385                        nm.enqueueNotificationInternal(localPackageName, appUid, appPid,
386                                null, localForegroundId, localForegroundNoti, outId);
387                    } catch (RuntimeException e) {
388                        Slog.w(ActivityManagerService.TAG,
389                                "Error showing notification for service", e);
390                        // If it gave us a garbage notification, it doesn't
391                        // get to be foreground.
392                        ams.setServiceForeground(name, ServiceRecord.this,
393                                localForegroundId, null, true);
394                    }
395                }
396            });
397        }
398    }
399
400    public void cancelNotification() {
401        if (foregroundId != 0) {
402            // Do asynchronous communication with notification manager to
403            // avoid deadlocks.
404            final String localPackageName = packageName;
405            final int localForegroundId = foregroundId;
406            ams.mHandler.post(new Runnable() {
407                public void run() {
408                    INotificationManager inm = NotificationManager.getService();
409                    if (inm == null) {
410                        return;
411                    }
412                    try {
413                        inm.cancelNotification(localPackageName, localForegroundId);
414                    } catch (RuntimeException e) {
415                        Slog.w(ActivityManagerService.TAG,
416                                "Error canceling notification for service", e);
417                    } catch (RemoteException e) {
418                    }
419                }
420            });
421        }
422    }
423
424    public void clearDeliveredStartsLocked() {
425        for (int i=deliveredStarts.size()-1; i>=0; i--) {
426            deliveredStarts.get(i).removeUriPermissionsLocked();
427        }
428        deliveredStarts.clear();
429    }
430
431    public String toString() {
432        if (stringName != null) {
433            return stringName;
434        }
435        StringBuilder sb = new StringBuilder(128);
436        sb.append("ServiceRecord{")
437            .append(Integer.toHexString(System.identityHashCode(this)))
438            .append(' ').append(shortName).append('}');
439        return stringName = sb.toString();
440    }
441}
442