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