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