Home | History | Annotate | Download | only in am
      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 android.app.PendingIntent;
     20 import android.net.Uri;
     21 import android.provider.Settings;
     22 import com.android.internal.os.BatteryStatsImpl;
     23 import com.android.server.NotificationManagerService;
     24 
     25 import android.app.INotificationManager;
     26 import android.app.Notification;
     27 import android.app.NotificationManager;
     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.os.Binder;
     35 import android.os.IBinder;
     36 import android.os.RemoteException;
     37 import android.os.SystemClock;
     38 import android.os.UserHandle;
     39 import android.util.Slog;
     40 import android.util.TimeUtils;
     41 
     42 import java.io.PrintWriter;
     43 import java.util.ArrayList;
     44 import java.util.HashMap;
     45 import java.util.HashSet;
     46 import java.util.Iterator;
     47 import java.util.List;
     48 
     49 /**
     50  * A running application service.
     51  */
     52 class ServiceRecord extends Binder {
     53     // Maximum number of delivery attempts before giving up.
     54     static final int MAX_DELIVERY_COUNT = 3;
     55 
     56     // Maximum number of times it can fail during execution before giving up.
     57     static final int MAX_DONE_EXECUTING_COUNT = 6;
     58 
     59     final ActivityManagerService ams;
     60     final BatteryStatsImpl.Uid.Pkg.Serv stats;
     61     final ComponentName name; // service component.
     62     final String shortName; // name.flattenToShortString().
     63     final Intent.FilterComparison intent;
     64                             // original intent used to find service.
     65     final ServiceInfo serviceInfo;
     66                             // all information about the service.
     67     final ApplicationInfo appInfo;
     68                             // information about service's app.
     69     final int userId;       // user that this service is running as
     70     final String packageName; // the package implementing intent's component
     71     final String processName; // process where this component wants to run
     72     final String permission;// permission needed to access service
     73     final String baseDir;   // where activity source (resources etc) located
     74     final String resDir;   // where public activity source (public resources etc) located
     75     final String dataDir;   // where activity data should go
     76     final boolean exported; // from ServiceInfo.exported
     77     final Runnable restarter; // used to schedule retries of starting the service
     78     final long createTime;  // when this service was created
     79     final HashMap<Intent.FilterComparison, IntentBindRecord> bindings
     80             = new HashMap<Intent.FilterComparison, IntentBindRecord>();
     81                             // All active bindings to the service.
     82     final HashMap<IBinder, ArrayList<ConnectionRecord>> connections
     83             = new HashMap<IBinder, ArrayList<ConnectionRecord>>();
     84                             // IBinder -> ConnectionRecord of all bound clients
     85 
     86     ProcessRecord app;      // where this service is running or null.
     87     ProcessRecord isolatedProc; // keep track of isolated process, if requested
     88     boolean isForeground;   // is service currently in foreground mode?
     89     int foregroundId;       // Notification ID of last foreground req.
     90     Notification foregroundNoti; // Notification record of foreground state.
     91     long lastActivity;      // last time there was some activity on the service.
     92     boolean startRequested; // someone explicitly called start?
     93     boolean stopIfKilled;   // last onStart() said to stop if service killed?
     94     boolean callStart;      // last onStart() has asked to alway be called on restart.
     95     int executeNesting;     // number of outstanding operations keeping foreground.
     96     long executingStart;    // start time of last execute request.
     97     int crashCount;         // number of times proc has crashed with service running
     98     int totalRestartCount;  // number of times we have had to restart.
     99     int restartCount;       // number of restarts performed in a row.
    100     long restartDelay;      // delay until next restart attempt.
    101     long restartTime;       // time of last restart.
    102     long nextRestartTime;   // time when restartDelay will expire.
    103 
    104     String stringName;      // caching of toString
    105 
    106     private int lastStartId;    // identifier of most recent start request.
    107 
    108     static class StartItem {
    109         final ServiceRecord sr;
    110         final boolean taskRemoved;
    111         final int id;
    112         final Intent intent;
    113         final ActivityManagerService.NeededUriGrants neededGrants;
    114         long deliveredTime;
    115         int deliveryCount;
    116         int doneExecutingCount;
    117         UriPermissionOwner uriPermissions;
    118 
    119         String stringName;      // caching of toString
    120 
    121         StartItem(ServiceRecord _sr, boolean _taskRemoved, int _id, Intent _intent,
    122                 ActivityManagerService.NeededUriGrants _neededGrants) {
    123             sr = _sr;
    124             taskRemoved = _taskRemoved;
    125             id = _id;
    126             intent = _intent;
    127             neededGrants = _neededGrants;
    128         }
    129 
    130         UriPermissionOwner getUriPermissionsLocked() {
    131             if (uriPermissions == null) {
    132                 uriPermissions = new UriPermissionOwner(sr.ams, this);
    133             }
    134             return uriPermissions;
    135         }
    136 
    137         void removeUriPermissionsLocked() {
    138             if (uriPermissions != null) {
    139                 uriPermissions.removeUriPermissionsLocked();
    140                 uriPermissions = null;
    141             }
    142         }
    143 
    144         public String toString() {
    145             if (stringName != null) {
    146                 return stringName;
    147             }
    148             StringBuilder sb = new StringBuilder(128);
    149             sb.append("ServiceRecord{")
    150                 .append(Integer.toHexString(System.identityHashCode(sr)))
    151                 .append(' ').append(sr.shortName)
    152                 .append(" StartItem ")
    153                 .append(Integer.toHexString(System.identityHashCode(this)))
    154                 .append(" id=").append(id).append('}');
    155             return stringName = sb.toString();
    156         }
    157     }
    158 
    159     final ArrayList<StartItem> deliveredStarts = new ArrayList<StartItem>();
    160                             // start() arguments which been delivered.
    161     final ArrayList<StartItem> pendingStarts = new ArrayList<StartItem>();
    162                             // start() arguments that haven't yet been delivered.
    163 
    164     void dumpStartList(PrintWriter pw, String prefix, List<StartItem> list, long now) {
    165         final int N = list.size();
    166         for (int i=0; i<N; i++) {
    167             StartItem si = list.get(i);
    168             pw.print(prefix); pw.print("#"); pw.print(i);
    169                     pw.print(" id="); pw.print(si.id);
    170                     if (now != 0) {
    171                         pw.print(" dur=");
    172                         TimeUtils.formatDuration(si.deliveredTime, now, pw);
    173                     }
    174                     if (si.deliveryCount != 0) {
    175                         pw.print(" dc="); pw.print(si.deliveryCount);
    176                     }
    177                     if (si.doneExecutingCount != 0) {
    178                         pw.print(" dxc="); pw.print(si.doneExecutingCount);
    179                     }
    180                     pw.println("");
    181             pw.print(prefix); pw.print("  intent=");
    182                     if (si.intent != null) pw.println(si.intent.toString());
    183                     else pw.println("null");
    184             if (si.neededGrants != null) {
    185                 pw.print(prefix); pw.print("  neededGrants=");
    186                         pw.println(si.neededGrants);
    187             }
    188             if (si.uriPermissions != null) {
    189                 if (si.uriPermissions.readUriPermissions != null) {
    190                     pw.print(prefix); pw.print("  readUriPermissions=");
    191                             pw.println(si.uriPermissions.readUriPermissions);
    192                 }
    193                 if (si.uriPermissions.writeUriPermissions != null) {
    194                     pw.print(prefix); pw.print("  writeUriPermissions=");
    195                             pw.println(si.uriPermissions.writeUriPermissions);
    196                 }
    197             }
    198         }
    199     }
    200 
    201     void dump(PrintWriter pw, String prefix) {
    202         pw.print(prefix); pw.print("intent={");
    203                 pw.print(intent.getIntent().toShortString(false, true, false, true));
    204                 pw.println('}');
    205         pw.print(prefix); pw.print("packageName="); pw.println(packageName);
    206         pw.print(prefix); pw.print("processName="); pw.println(processName);
    207         if (permission != null) {
    208             pw.print(prefix); pw.print("permission="); pw.println(permission);
    209         }
    210         long now = SystemClock.uptimeMillis();
    211         long nowReal = SystemClock.elapsedRealtime();
    212         pw.print(prefix); pw.print("baseDir="); pw.println(baseDir);
    213         if (!resDir.equals(baseDir)) {
    214             pw.print(prefix); pw.print("resDir="); pw.println(resDir);
    215         }
    216         pw.print(prefix); pw.print("dataDir="); pw.println(dataDir);
    217         pw.print(prefix); pw.print("app="); pw.println(app);
    218         if (isolatedProc != null) {
    219             pw.print(prefix); pw.print("isolatedProc="); pw.println(isolatedProc);
    220         }
    221         if (isForeground || foregroundId != 0) {
    222             pw.print(prefix); pw.print("isForeground="); pw.print(isForeground);
    223                     pw.print(" foregroundId="); pw.print(foregroundId);
    224                     pw.print(" foregroundNoti="); pw.println(foregroundNoti);
    225         }
    226         pw.print(prefix); pw.print("createTime=");
    227                 TimeUtils.formatDuration(createTime, nowReal, pw);
    228                 pw.print(" lastActivity=");
    229                 TimeUtils.formatDuration(lastActivity, now, pw);
    230                 pw.println("");
    231         pw.print(prefix); pw.print("executingStart=");
    232                 TimeUtils.formatDuration(executingStart, now, pw);
    233                 pw.print(" restartTime=");
    234                 TimeUtils.formatDuration(restartTime, now, pw);
    235                 pw.println("");
    236         if (startRequested || lastStartId != 0) {
    237             pw.print(prefix); pw.print("startRequested="); pw.print(startRequested);
    238                     pw.print(" stopIfKilled="); pw.print(stopIfKilled);
    239                     pw.print(" callStart="); pw.print(callStart);
    240                     pw.print(" lastStartId="); pw.println(lastStartId);
    241         }
    242         if (executeNesting != 0 || crashCount != 0 || restartCount != 0
    243                 || restartDelay != 0 || nextRestartTime != 0) {
    244             pw.print(prefix); pw.print("executeNesting="); pw.print(executeNesting);
    245                     pw.print(" restartCount="); pw.print(restartCount);
    246                     pw.print(" restartDelay=");
    247                     TimeUtils.formatDuration(restartDelay, now, pw);
    248                     pw.print(" nextRestartTime=");
    249                     TimeUtils.formatDuration(nextRestartTime, now, pw);
    250                     pw.print(" crashCount="); pw.println(crashCount);
    251         }
    252         if (deliveredStarts.size() > 0) {
    253             pw.print(prefix); pw.println("Delivered Starts:");
    254             dumpStartList(pw, prefix, deliveredStarts, now);
    255         }
    256         if (pendingStarts.size() > 0) {
    257             pw.print(prefix); pw.println("Pending Starts:");
    258             dumpStartList(pw, prefix, pendingStarts, 0);
    259         }
    260         if (bindings.size() > 0) {
    261             Iterator<IntentBindRecord> it = bindings.values().iterator();
    262             pw.print(prefix); pw.println("Bindings:");
    263             while (it.hasNext()) {
    264                 IntentBindRecord b = it.next();
    265                 pw.print(prefix); pw.print("* IntentBindRecord{");
    266                         pw.print(Integer.toHexString(System.identityHashCode(b)));
    267                         if ((b.collectFlags()&Context.BIND_AUTO_CREATE) != 0) {
    268                             pw.append(" CREATE");
    269                         }
    270                         pw.println("}:");
    271                 b.dumpInService(pw, prefix + "  ");
    272             }
    273         }
    274         if (connections.size() > 0) {
    275             pw.print(prefix); pw.println("All Connections:");
    276             Iterator<ArrayList<ConnectionRecord>> it = connections.values().iterator();
    277             while (it.hasNext()) {
    278                 ArrayList<ConnectionRecord> c = it.next();
    279                 for (int i=0; i<c.size(); i++) {
    280                     pw.print(prefix); pw.print("  "); pw.println(c.get(i));
    281                 }
    282             }
    283         }
    284     }
    285 
    286     ServiceRecord(ActivityManagerService ams,
    287             BatteryStatsImpl.Uid.Pkg.Serv servStats, ComponentName name,
    288             Intent.FilterComparison intent, ServiceInfo sInfo, Runnable restarter) {
    289         this.ams = ams;
    290         this.stats = servStats;
    291         this.name = name;
    292         shortName = name.flattenToShortString();
    293         this.intent = intent;
    294         serviceInfo = sInfo;
    295         appInfo = sInfo.applicationInfo;
    296         packageName = sInfo.applicationInfo.packageName;
    297         processName = sInfo.processName;
    298         permission = sInfo.permission;
    299         baseDir = sInfo.applicationInfo.sourceDir;
    300         resDir = sInfo.applicationInfo.publicSourceDir;
    301         dataDir = sInfo.applicationInfo.dataDir;
    302         exported = sInfo.exported;
    303         this.restarter = restarter;
    304         createTime = SystemClock.elapsedRealtime();
    305         lastActivity = SystemClock.uptimeMillis();
    306         userId = UserHandle.getUserId(appInfo.uid);
    307     }
    308 
    309     public AppBindRecord retrieveAppBindingLocked(Intent intent,
    310             ProcessRecord app) {
    311         Intent.FilterComparison filter = new Intent.FilterComparison(intent);
    312         IntentBindRecord i = bindings.get(filter);
    313         if (i == null) {
    314             i = new IntentBindRecord(this, filter);
    315             bindings.put(filter, i);
    316         }
    317         AppBindRecord a = i.apps.get(app);
    318         if (a != null) {
    319             return a;
    320         }
    321         a = new AppBindRecord(this, i, app);
    322         i.apps.put(app, a);
    323         return a;
    324     }
    325 
    326     public void resetRestartCounter() {
    327         restartCount = 0;
    328         restartDelay = 0;
    329         restartTime = 0;
    330     }
    331 
    332     public StartItem findDeliveredStart(int id, boolean remove) {
    333         final int N = deliveredStarts.size();
    334         for (int i=0; i<N; i++) {
    335             StartItem si = deliveredStarts.get(i);
    336             if (si.id == id) {
    337                 if (remove) deliveredStarts.remove(i);
    338                 return si;
    339             }
    340         }
    341 
    342         return null;
    343     }
    344 
    345     public int getLastStartId() {
    346         return lastStartId;
    347     }
    348 
    349     public int makeNextStartId() {
    350         lastStartId++;
    351         if (lastStartId < 1) {
    352             lastStartId = 1;
    353         }
    354         return lastStartId;
    355     }
    356 
    357     public void postNotification() {
    358         final int appUid = appInfo.uid;
    359         final int appPid = app.pid;
    360         if (foregroundId != 0 && foregroundNoti != null) {
    361             // Do asynchronous communication with notification manager to
    362             // avoid deadlocks.
    363             final String localPackageName = packageName;
    364             final int localForegroundId = foregroundId;
    365             final Notification localForegroundNoti = foregroundNoti;
    366             ams.mHandler.post(new Runnable() {
    367                 public void run() {
    368                     NotificationManagerService nm =
    369                             (NotificationManagerService) NotificationManager.getService();
    370                     if (nm == null) {
    371                         return;
    372                     }
    373                     try {
    374                         if (localForegroundNoti.icon == 0) {
    375                             // It is not correct for the caller to supply a notification
    376                             // icon, but this used to be able to slip through, so for
    377                             // those dirty apps give it the app's icon.
    378                             localForegroundNoti.icon = appInfo.icon;
    379 
    380                             // Do not allow apps to present a sneaky invisible content view either.
    381                             localForegroundNoti.contentView = null;
    382                             localForegroundNoti.bigContentView = null;
    383                             CharSequence appName = appInfo.loadLabel(
    384                                     ams.mContext.getPackageManager());
    385                             if (appName == null) {
    386                                 appName = appInfo.packageName;
    387                             }
    388                             Context ctx = null;
    389                             try {
    390                                 ctx = ams.mContext.createPackageContext(
    391                                         appInfo.packageName, 0);
    392                                 Intent runningIntent = new Intent(
    393                                         Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
    394                                 runningIntent.setData(Uri.fromParts("package",
    395                                         appInfo.packageName, null));
    396                                 PendingIntent pi = PendingIntent.getActivity(ams.mContext, 0,
    397                                         runningIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    398                                 localForegroundNoti.setLatestEventInfo(ctx,
    399                                         ams.mContext.getString(
    400                                                 com.android.internal.R.string
    401                                                         .app_running_notification_title,
    402                                                 appName),
    403                                         ams.mContext.getString(
    404                                                 com.android.internal.R.string
    405                                                         .app_running_notification_text,
    406                                                 appName),
    407                                         pi);
    408                             } catch (PackageManager.NameNotFoundException e) {
    409                                 localForegroundNoti.icon = 0;
    410                             }
    411                         }
    412                         if (localForegroundNoti.icon == 0) {
    413                             // Notifications whose icon is 0 are defined to not show
    414                             // a notification, silently ignoring it.  We don't want to
    415                             // just ignore it, we want to prevent the service from
    416                             // being foreground.
    417                             throw new RuntimeException("icon must be non-zero");
    418                         }
    419                         int[] outId = new int[1];
    420                         nm.enqueueNotificationInternal(localPackageName, localPackageName,
    421                                 appUid, appPid, null, localForegroundId, localForegroundNoti,
    422                                 outId, userId);
    423                     } catch (RuntimeException e) {
    424                         Slog.w(ActivityManagerService.TAG,
    425                                 "Error showing notification for service", e);
    426                         // If it gave us a garbage notification, it doesn't
    427                         // get to be foreground.
    428                         ams.setServiceForeground(name, ServiceRecord.this,
    429                                 0, null, true);
    430                         ams.crashApplication(appUid, appPid, localPackageName,
    431                                 "Bad notification for startForeground: " + e);
    432                     }
    433                 }
    434             });
    435         }
    436     }
    437 
    438     public void cancelNotification() {
    439         if (foregroundId != 0) {
    440             // Do asynchronous communication with notification manager to
    441             // avoid deadlocks.
    442             final String localPackageName = packageName;
    443             final int localForegroundId = foregroundId;
    444             ams.mHandler.post(new Runnable() {
    445                 public void run() {
    446                     INotificationManager inm = NotificationManager.getService();
    447                     if (inm == null) {
    448                         return;
    449                     }
    450                     try {
    451                         inm.cancelNotificationWithTag(localPackageName, null,
    452                                 localForegroundId, userId);
    453                     } catch (RuntimeException e) {
    454                         Slog.w(ActivityManagerService.TAG,
    455                                 "Error canceling notification for service", e);
    456                     } catch (RemoteException e) {
    457                     }
    458                 }
    459             });
    460         }
    461     }
    462 
    463     public void clearDeliveredStartsLocked() {
    464         for (int i=deliveredStarts.size()-1; i>=0; i--) {
    465             deliveredStarts.get(i).removeUriPermissionsLocked();
    466         }
    467         deliveredStarts.clear();
    468     }
    469 
    470     public String toString() {
    471         if (stringName != null) {
    472             return stringName;
    473         }
    474         StringBuilder sb = new StringBuilder(128);
    475         sb.append("ServiceRecord{")
    476             .append(Integer.toHexString(System.identityHashCode(this)))
    477             .append(" u").append(userId)
    478             .append(' ').append(shortName).append('}');
    479         return stringName = sb.toString();
    480     }
    481 }
    482