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.app.ProcessStats;
20 import com.android.internal.os.BatteryStatsImpl;
21 import com.android.server.LocalServices;
22 import com.android.server.notification.NotificationManagerInternal;
23 
24 import android.app.INotificationManager;
25 import android.app.Notification;
26 import android.app.NotificationManager;
27 import android.app.PendingIntent;
28 import android.content.ComponentName;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.pm.ApplicationInfo;
32 import android.content.pm.PackageManager;
33 import android.content.pm.ServiceInfo;
34 import android.net.Uri;
35 import android.os.Binder;
36 import android.os.IBinder;
37 import android.os.RemoteException;
38 import android.os.SystemClock;
39 import android.os.UserHandle;
40 import android.provider.Settings;
41 import android.util.ArrayMap;
42 import android.util.Slog;
43 import android.util.TimeUtils;
44 
45 import java.io.PrintWriter;
46 import java.util.ArrayList;
47 import java.util.List;
48 import java.util.Objects;
49 
50 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
51 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
52 
53 /**
54  * A running application service.
55  */
56 final class ServiceRecord extends Binder {
57     private static final String TAG = TAG_WITH_CLASS_NAME ? "ServiceRecord" : TAG_AM;
58 
59     // Maximum number of delivery attempts before giving up.
60     static final int MAX_DELIVERY_COUNT = 3;
61 
62     // Maximum number of times it can fail during execution before giving up.
63     static final int MAX_DONE_EXECUTING_COUNT = 6;
64 
65     final ActivityManagerService ams;
66     final BatteryStatsImpl.Uid.Pkg.Serv stats;
67     final ComponentName name; // service component.
68     final String shortName; // name.flattenToShortString().
69     final Intent.FilterComparison intent;
70                             // original intent used to find service.
71     final ServiceInfo serviceInfo;
72                             // all information about the service.
73     final ApplicationInfo appInfo;
74                             // information about service's app.
75     final int userId;       // user that this service is running as
76     final String packageName; // the package implementing intent's component
77     final String processName; // process where this component wants to run
78     final String permission;// permission needed to access service
79     final boolean exported; // from ServiceInfo.exported
80     final Runnable restarter; // used to schedule retries of starting the service
81     final long createTime;  // when this service was created
82     final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings
83             = new ArrayMap<Intent.FilterComparison, IntentBindRecord>();
84                             // All active bindings to the service.
85     final ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections
86             = new ArrayMap<IBinder, ArrayList<ConnectionRecord>>();
87                             // IBinder -> ConnectionRecord of all bound clients
88 
89     ProcessRecord app;      // where this service is running or null.
90     ProcessRecord isolatedProc; // keep track of isolated process, if requested
91     ProcessStats.ServiceState tracker; // tracking service execution, may be null
92     ProcessStats.ServiceState restartTracker; // tracking service restart
93     boolean delayed;        // are we waiting to start this service in the background?
94     boolean isForeground;   // is service currently in foreground mode?
95     int foregroundId;       // Notification ID of last foreground req.
96     Notification foregroundNoti; // Notification record of foreground state.
97     long lastActivity;      // last time there was some activity on the service.
98     long startingBgTimeout;  // time at which we scheduled this for a delayed start.
99     boolean startRequested; // someone explicitly called start?
100     boolean delayedStop;    // service has been stopped but is in a delayed start?
101     boolean stopIfKilled;   // last onStart() said to stop if service killed?
102     boolean callStart;      // last onStart() has asked to alway be called on restart.
103     int executeNesting;     // number of outstanding operations keeping foreground.
104     boolean executeFg;      // should we be executing in the foreground?
105     long executingStart;    // start time of last execute request.
106     boolean createdFromFg;  // was this service last created due to a foreground process call?
107     int crashCount;         // number of times proc has crashed with service running
108     int totalRestartCount;  // number of times we have had to restart.
109     int restartCount;       // number of restarts performed in a row.
110     long restartDelay;      // delay until next restart attempt.
111     long restartTime;       // time of last restart.
112     long nextRestartTime;   // time when restartDelay will expire.
113     boolean destroying;     // set when we have started destroying the service
114     long destroyTime;       // time at which destory was initiated.
115 
116     String stringName;      // caching of toString
117 
118     private int lastStartId;    // identifier of most recent start request.
119 
120     static class StartItem {
121         final ServiceRecord sr;
122         final boolean taskRemoved;
123         final int id;
124         final Intent intent;
125         final ActivityManagerService.NeededUriGrants neededGrants;
126         long deliveredTime;
127         int deliveryCount;
128         int doneExecutingCount;
129         UriPermissionOwner uriPermissions;
130 
131         String stringName;      // caching of toString
132 
StartItem(ServiceRecord _sr, boolean _taskRemoved, int _id, Intent _intent, ActivityManagerService.NeededUriGrants _neededGrants)133         StartItem(ServiceRecord _sr, boolean _taskRemoved, int _id, Intent _intent,
134                 ActivityManagerService.NeededUriGrants _neededGrants) {
135             sr = _sr;
136             taskRemoved = _taskRemoved;
137             id = _id;
138             intent = _intent;
139             neededGrants = _neededGrants;
140         }
141 
getUriPermissionsLocked()142         UriPermissionOwner getUriPermissionsLocked() {
143             if (uriPermissions == null) {
144                 uriPermissions = new UriPermissionOwner(sr.ams, this);
145             }
146             return uriPermissions;
147         }
148 
removeUriPermissionsLocked()149         void removeUriPermissionsLocked() {
150             if (uriPermissions != null) {
151                 uriPermissions.removeUriPermissionsLocked();
152                 uriPermissions = null;
153             }
154         }
155 
toString()156         public String toString() {
157             if (stringName != null) {
158                 return stringName;
159             }
160             StringBuilder sb = new StringBuilder(128);
161             sb.append("ServiceRecord{")
162                 .append(Integer.toHexString(System.identityHashCode(sr)))
163                 .append(' ').append(sr.shortName)
164                 .append(" StartItem ")
165                 .append(Integer.toHexString(System.identityHashCode(this)))
166                 .append(" id=").append(id).append('}');
167             return stringName = sb.toString();
168         }
169     }
170 
171     final ArrayList<StartItem> deliveredStarts = new ArrayList<StartItem>();
172                             // start() arguments which been delivered.
173     final ArrayList<StartItem> pendingStarts = new ArrayList<StartItem>();
174                             // start() arguments that haven't yet been delivered.
175 
dumpStartList(PrintWriter pw, String prefix, List<StartItem> list, long now)176     void dumpStartList(PrintWriter pw, String prefix, List<StartItem> list, long now) {
177         final int N = list.size();
178         for (int i=0; i<N; i++) {
179             StartItem si = list.get(i);
180             pw.print(prefix); pw.print("#"); pw.print(i);
181                     pw.print(" id="); pw.print(si.id);
182                     if (now != 0) {
183                         pw.print(" dur=");
184                         TimeUtils.formatDuration(si.deliveredTime, now, pw);
185                     }
186                     if (si.deliveryCount != 0) {
187                         pw.print(" dc="); pw.print(si.deliveryCount);
188                     }
189                     if (si.doneExecutingCount != 0) {
190                         pw.print(" dxc="); pw.print(si.doneExecutingCount);
191                     }
192                     pw.println("");
193             pw.print(prefix); pw.print("  intent=");
194                     if (si.intent != null) pw.println(si.intent.toString());
195                     else pw.println("null");
196             if (si.neededGrants != null) {
197                 pw.print(prefix); pw.print("  neededGrants=");
198                         pw.println(si.neededGrants);
199             }
200             if (si.uriPermissions != null) {
201                 si.uriPermissions.dump(pw, prefix);
202             }
203         }
204     }
205 
dump(PrintWriter pw, String prefix)206     void dump(PrintWriter pw, String prefix) {
207         pw.print(prefix); pw.print("intent={");
208                 pw.print(intent.getIntent().toShortString(false, true, false, true));
209                 pw.println('}');
210         pw.print(prefix); pw.print("packageName="); pw.println(packageName);
211         pw.print(prefix); pw.print("processName="); pw.println(processName);
212         if (permission != null) {
213             pw.print(prefix); pw.print("permission="); pw.println(permission);
214         }
215         long now = SystemClock.uptimeMillis();
216         long nowReal = SystemClock.elapsedRealtime();
217         if (appInfo != null) {
218             pw.print(prefix); pw.print("baseDir="); pw.println(appInfo.sourceDir);
219             if (!Objects.equals(appInfo.sourceDir, appInfo.publicSourceDir)) {
220                 pw.print(prefix); pw.print("resDir="); pw.println(appInfo.publicSourceDir);
221             }
222             pw.print(prefix); pw.print("dataDir="); pw.println(appInfo.dataDir);
223         }
224         pw.print(prefix); pw.print("app="); pw.println(app);
225         if (isolatedProc != null) {
226             pw.print(prefix); pw.print("isolatedProc="); pw.println(isolatedProc);
227         }
228         if (delayed) {
229             pw.print(prefix); pw.print("delayed="); pw.println(delayed);
230         }
231         if (isForeground || foregroundId != 0) {
232             pw.print(prefix); pw.print("isForeground="); pw.print(isForeground);
233                     pw.print(" foregroundId="); pw.print(foregroundId);
234                     pw.print(" foregroundNoti="); pw.println(foregroundNoti);
235         }
236         pw.print(prefix); pw.print("createTime=");
237                 TimeUtils.formatDuration(createTime, nowReal, pw);
238                 pw.print(" startingBgTimeout=");
239                 TimeUtils.formatDuration(startingBgTimeout, now, pw);
240                 pw.println();
241         pw.print(prefix); pw.print("lastActivity=");
242                 TimeUtils.formatDuration(lastActivity, now, pw);
243                 pw.print(" restartTime=");
244                 TimeUtils.formatDuration(restartTime, now, pw);
245                 pw.print(" createdFromFg="); pw.println(createdFromFg);
246         if (startRequested || delayedStop || lastStartId != 0) {
247             pw.print(prefix); pw.print("startRequested="); pw.print(startRequested);
248                     pw.print(" delayedStop="); pw.print(delayedStop);
249                     pw.print(" stopIfKilled="); pw.print(stopIfKilled);
250                     pw.print(" callStart="); pw.print(callStart);
251                     pw.print(" lastStartId="); pw.println(lastStartId);
252         }
253         if (executeNesting != 0) {
254             pw.print(prefix); pw.print("executeNesting="); pw.print(executeNesting);
255                     pw.print(" executeFg="); pw.print(executeFg);
256                     pw.print(" executingStart=");
257                     TimeUtils.formatDuration(executingStart, now, pw);
258                     pw.println();
259         }
260         if (destroying || destroyTime != 0) {
261             pw.print(prefix); pw.print("destroying="); pw.print(destroying);
262                     pw.print(" destroyTime=");
263                     TimeUtils.formatDuration(destroyTime, now, pw);
264                     pw.println();
265         }
266         if (crashCount != 0 || restartCount != 0
267                 || restartDelay != 0 || nextRestartTime != 0) {
268             pw.print(prefix); pw.print("restartCount="); pw.print(restartCount);
269                     pw.print(" restartDelay=");
270                     TimeUtils.formatDuration(restartDelay, now, pw);
271                     pw.print(" nextRestartTime=");
272                     TimeUtils.formatDuration(nextRestartTime, now, pw);
273                     pw.print(" crashCount="); pw.println(crashCount);
274         }
275         if (deliveredStarts.size() > 0) {
276             pw.print(prefix); pw.println("Delivered Starts:");
277             dumpStartList(pw, prefix, deliveredStarts, now);
278         }
279         if (pendingStarts.size() > 0) {
280             pw.print(prefix); pw.println("Pending Starts:");
281             dumpStartList(pw, prefix, pendingStarts, 0);
282         }
283         if (bindings.size() > 0) {
284             pw.print(prefix); pw.println("Bindings:");
285             for (int i=0; i<bindings.size(); i++) {
286                 IntentBindRecord b = bindings.valueAt(i);
287                 pw.print(prefix); pw.print("* IntentBindRecord{");
288                         pw.print(Integer.toHexString(System.identityHashCode(b)));
289                         if ((b.collectFlags()&Context.BIND_AUTO_CREATE) != 0) {
290                             pw.append(" CREATE");
291                         }
292                         pw.println("}:");
293                 b.dumpInService(pw, prefix + "  ");
294             }
295         }
296         if (connections.size() > 0) {
297             pw.print(prefix); pw.println("All Connections:");
298             for (int conni=0; conni<connections.size(); conni++) {
299                 ArrayList<ConnectionRecord> c = connections.valueAt(conni);
300                 for (int i=0; i<c.size(); i++) {
301                     pw.print(prefix); pw.print("  "); pw.println(c.get(i));
302                 }
303             }
304         }
305     }
306 
ServiceRecord(ActivityManagerService ams, BatteryStatsImpl.Uid.Pkg.Serv servStats, ComponentName name, Intent.FilterComparison intent, ServiceInfo sInfo, boolean callerIsFg, Runnable restarter)307     ServiceRecord(ActivityManagerService ams,
308             BatteryStatsImpl.Uid.Pkg.Serv servStats, ComponentName name,
309             Intent.FilterComparison intent, ServiceInfo sInfo, boolean callerIsFg,
310             Runnable restarter) {
311         this.ams = ams;
312         this.stats = servStats;
313         this.name = name;
314         shortName = name.flattenToShortString();
315         this.intent = intent;
316         serviceInfo = sInfo;
317         appInfo = sInfo.applicationInfo;
318         packageName = sInfo.applicationInfo.packageName;
319         processName = sInfo.processName;
320         permission = sInfo.permission;
321         exported = sInfo.exported;
322         this.restarter = restarter;
323         createTime = SystemClock.elapsedRealtime();
324         lastActivity = SystemClock.uptimeMillis();
325         userId = UserHandle.getUserId(appInfo.uid);
326         createdFromFg = callerIsFg;
327     }
328 
getTracker()329     public ProcessStats.ServiceState getTracker() {
330         if (tracker != null) {
331             return tracker;
332         }
333         if ((serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
334             tracker = ams.mProcessStats.getServiceStateLocked(serviceInfo.packageName,
335                     serviceInfo.applicationInfo.uid, serviceInfo.applicationInfo.versionCode,
336                     serviceInfo.processName, serviceInfo.name);
337             tracker.applyNewOwner(this);
338         }
339         return tracker;
340     }
341 
forceClearTracker()342     public void forceClearTracker() {
343         if (tracker != null) {
344             tracker.clearCurrentOwner(this, true);
345             tracker = null;
346         }
347     }
348 
makeRestarting(int memFactor, long now)349     public void makeRestarting(int memFactor, long now) {
350         if (restartTracker == null) {
351             if ((serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
352                 restartTracker = ams.mProcessStats.getServiceStateLocked(serviceInfo.packageName,
353                         serviceInfo.applicationInfo.uid, serviceInfo.applicationInfo.versionCode,
354                         serviceInfo.processName, serviceInfo.name);
355             }
356             if (restartTracker == null) {
357                 return;
358             }
359         }
360         restartTracker.setRestarting(true, memFactor, now);
361     }
362 
retrieveAppBindingLocked(Intent intent, ProcessRecord app)363     public AppBindRecord retrieveAppBindingLocked(Intent intent,
364             ProcessRecord app) {
365         Intent.FilterComparison filter = new Intent.FilterComparison(intent);
366         IntentBindRecord i = bindings.get(filter);
367         if (i == null) {
368             i = new IntentBindRecord(this, filter);
369             bindings.put(filter, i);
370         }
371         AppBindRecord a = i.apps.get(app);
372         if (a != null) {
373             return a;
374         }
375         a = new AppBindRecord(this, i, app);
376         i.apps.put(app, a);
377         return a;
378     }
379 
hasAutoCreateConnections()380     public boolean hasAutoCreateConnections() {
381         // XXX should probably keep a count of the number of auto-create
382         // connections directly in the service.
383         for (int conni=connections.size()-1; conni>=0; conni--) {
384             ArrayList<ConnectionRecord> cr = connections.valueAt(conni);
385             for (int i=0; i<cr.size(); i++) {
386                 if ((cr.get(i).flags&Context.BIND_AUTO_CREATE) != 0) {
387                     return true;
388                 }
389             }
390         }
391         return false;
392     }
393 
resetRestartCounter()394     public void resetRestartCounter() {
395         restartCount = 0;
396         restartDelay = 0;
397         restartTime = 0;
398     }
399 
findDeliveredStart(int id, boolean remove)400     public StartItem findDeliveredStart(int id, boolean remove) {
401         final int N = deliveredStarts.size();
402         for (int i=0; i<N; i++) {
403             StartItem si = deliveredStarts.get(i);
404             if (si.id == id) {
405                 if (remove) deliveredStarts.remove(i);
406                 return si;
407             }
408         }
409 
410         return null;
411     }
412 
getLastStartId()413     public int getLastStartId() {
414         return lastStartId;
415     }
416 
makeNextStartId()417     public int makeNextStartId() {
418         lastStartId++;
419         if (lastStartId < 1) {
420             lastStartId = 1;
421         }
422         return lastStartId;
423     }
424 
postNotification()425     public void postNotification() {
426         final int appUid = appInfo.uid;
427         final int appPid = app.pid;
428         if (foregroundId != 0 && foregroundNoti != null) {
429             // Do asynchronous communication with notification manager to
430             // avoid deadlocks.
431             final String localPackageName = packageName;
432             final int localForegroundId = foregroundId;
433             final Notification _foregroundNoti = foregroundNoti;
434             ams.mHandler.post(new Runnable() {
435                 public void run() {
436                     NotificationManagerInternal nm = LocalServices.getService(
437                             NotificationManagerInternal.class);
438                     if (nm == null) {
439                         return;
440                     }
441                     Notification localForegroundNoti = _foregroundNoti;
442                     try {
443                         if (localForegroundNoti.getSmallIcon() == null) {
444                             // It is not correct for the caller to supply a notification
445                             // icon, but this used to be able to slip through, so for
446                             // those dirty apps we will create a notification clearly
447                             // blaming the app.
448                             Slog.v(TAG, "Attempted to start a foreground service ("
449                                     + name
450                                     + ") with a broken notification (no icon: "
451                                     + localForegroundNoti
452                                     + ")");
453 
454                             CharSequence appName = appInfo.loadLabel(
455                                     ams.mContext.getPackageManager());
456                             if (appName == null) {
457                                 appName = appInfo.packageName;
458                             }
459                             Context ctx = null;
460                             try {
461                                 ctx = ams.mContext.createPackageContext(
462                                         appInfo.packageName, 0);
463 
464                                 Notification.Builder notiBuilder = new Notification.Builder(ctx);
465 
466                                 // it's ugly, but it clearly identifies the app
467                                 notiBuilder.setSmallIcon(appInfo.icon);
468 
469                                 // mark as foreground
470                                 notiBuilder.setFlag(Notification.FLAG_FOREGROUND_SERVICE, true);
471 
472                                 // we are doing the app a kindness here
473                                 notiBuilder.setPriority(Notification.PRIORITY_MIN);
474 
475                                 Intent runningIntent = new Intent(
476                                         Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
477                                 runningIntent.setData(Uri.fromParts("package",
478                                         appInfo.packageName, null));
479                                 PendingIntent pi = PendingIntent.getActivity(ams.mContext, 0,
480                                         runningIntent, PendingIntent.FLAG_UPDATE_CURRENT);
481                                 notiBuilder.setColor(ams.mContext.getColor(
482                                         com.android.internal
483                                                 .R.color.system_notification_accent_color));
484                                 notiBuilder.setContentTitle(
485                                         ams.mContext.getString(
486                                                 com.android.internal.R.string
487                                                         .app_running_notification_title,
488                                                 appName));
489                                 notiBuilder.setContentText(
490                                         ams.mContext.getString(
491                                                 com.android.internal.R.string
492                                                         .app_running_notification_text,
493                                                 appName));
494                                 notiBuilder.setContentIntent(pi);
495 
496                                 localForegroundNoti = notiBuilder.build();
497                             } catch (PackageManager.NameNotFoundException e) {
498                             }
499                         }
500                         if (localForegroundNoti.getSmallIcon() == null) {
501                             // Notifications whose icon is 0 are defined to not show
502                             // a notification, silently ignoring it.  We don't want to
503                             // just ignore it, we want to prevent the service from
504                             // being foreground.
505                             throw new RuntimeException("invalid service notification: "
506                                     + foregroundNoti);
507                         }
508                         int[] outId = new int[1];
509                         nm.enqueueNotification(localPackageName, localPackageName,
510                                 appUid, appPid, null, localForegroundId, localForegroundNoti,
511                                 outId, userId);
512 
513                         foregroundNoti = localForegroundNoti; // save it for amending next time
514                     } catch (RuntimeException e) {
515                         Slog.w(TAG, "Error showing notification for service", e);
516                         // If it gave us a garbage notification, it doesn't
517                         // get to be foreground.
518                         ams.setServiceForeground(name, ServiceRecord.this,
519                                 0, null, true);
520                         ams.crashApplication(appUid, appPid, localPackageName,
521                                 "Bad notification for startForeground: " + e);
522                     }
523                 }
524             });
525         }
526     }
527 
cancelNotification()528     public void cancelNotification() {
529         if (foregroundId != 0) {
530             // Do asynchronous communication with notification manager to
531             // avoid deadlocks.
532             final String localPackageName = packageName;
533             final int localForegroundId = foregroundId;
534             ams.mHandler.post(new Runnable() {
535                 public void run() {
536                     INotificationManager inm = NotificationManager.getService();
537                     if (inm == null) {
538                         return;
539                     }
540                     try {
541                         inm.cancelNotificationWithTag(localPackageName, null,
542                                 localForegroundId, userId);
543                     } catch (RuntimeException e) {
544                         Slog.w(TAG, "Error canceling notification for service", e);
545                     } catch (RemoteException e) {
546                     }
547                 }
548             });
549         }
550     }
551 
stripForegroundServiceFlagFromNotification()552     public void stripForegroundServiceFlagFromNotification() {
553         if (foregroundId == 0) {
554             return;
555         }
556 
557         final int localForegroundId = foregroundId;
558         final int localUserId = userId;
559         final String localPackageName = packageName;
560 
561         // Do asynchronous communication with notification manager to
562         // avoid deadlocks.
563         ams.mHandler.post(new Runnable() {
564             @Override
565             public void run() {
566                 NotificationManagerInternal nmi = LocalServices.getService(
567                         NotificationManagerInternal.class);
568                 if (nmi == null) {
569                     return;
570                 }
571                 nmi.removeForegroundServiceFlagFromNotification(localPackageName, localForegroundId,
572                         localUserId);
573             }
574         });
575     }
576 
clearDeliveredStartsLocked()577     public void clearDeliveredStartsLocked() {
578         for (int i=deliveredStarts.size()-1; i>=0; i--) {
579             deliveredStarts.get(i).removeUriPermissionsLocked();
580         }
581         deliveredStarts.clear();
582     }
583 
toString()584     public String toString() {
585         if (stringName != null) {
586             return stringName;
587         }
588         StringBuilder sb = new StringBuilder(128);
589         sb.append("ServiceRecord{")
590             .append(Integer.toHexString(System.identityHashCode(this)))
591             .append(" u").append(userId)
592             .append(' ').append(shortName).append('}');
593         return stringName = sb.toString();
594     }
595 }
596