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