ServiceRecord.java revision 43d9ac81f7722bb539ee67023f10b9f43abbf202
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 17package com.android.server.am; 18 19import com.android.internal.os.BatteryStatsImpl; 20import com.android.server.NotificationManagerService; 21 22import android.app.INotificationManager; 23import android.app.Notification; 24import android.app.NotificationManager; 25import android.content.ComponentName; 26import android.content.Intent; 27import android.content.pm.ApplicationInfo; 28import android.content.pm.ServiceInfo; 29import android.os.Binder; 30import android.os.IBinder; 31import android.os.RemoteException; 32import android.os.SystemClock; 33import android.util.Slog; 34import android.util.TimeUtils; 35 36import java.io.PrintWriter; 37import java.util.ArrayList; 38import java.util.HashMap; 39import java.util.HashSet; 40import java.util.Iterator; 41import java.util.List; 42 43/** 44 * A running application service. 45 */ 46class 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 implements UriPermissionOwner { 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 108 String stringName; // caching of toString 109 110 HashSet<UriPermission> readUriPermissions; // special access to reading uris. 111 HashSet<UriPermission> writeUriPermissions; // special access to writing uris. 112 113 StartItem(ServiceRecord _sr, int _id, Intent _intent, int _targetPermissionUid) { 114 sr = _sr; 115 id = _id; 116 intent = _intent; 117 targetPermissionUid = _targetPermissionUid; 118 } 119 120 void removeUriPermissionsLocked() { 121 if (readUriPermissions != null) { 122 for (UriPermission perm : readUriPermissions) { 123 perm.readOwners.remove(this); 124 if (perm.readOwners.size() == 0 && (perm.globalModeFlags 125 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) { 126 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION; 127 sr.ams.removeUriPermissionIfNeededLocked(perm); 128 } 129 } 130 readUriPermissions = null; 131 } 132 if (writeUriPermissions != null) { 133 for (UriPermission perm : writeUriPermissions) { 134 perm.writeOwners.remove(this); 135 if (perm.writeOwners.size() == 0 && (perm.globalModeFlags 136 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) { 137 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 138 sr.ams.removeUriPermissionIfNeededLocked(perm); 139 } 140 } 141 writeUriPermissions = null; 142 } 143 } 144 145 @Override 146 public void addReadPermission(UriPermission perm) { 147 if (readUriPermissions == null) { 148 readUriPermissions = new HashSet<UriPermission>(); 149 } 150 readUriPermissions.add(perm); 151 } 152 153 @Override 154 public void addWritePermission(UriPermission perm) { 155 if (writeUriPermissions == null) { 156 writeUriPermissions = new HashSet<UriPermission>(); 157 } 158 writeUriPermissions.add(perm); 159 } 160 161 @Override 162 public void removeReadPermission(UriPermission perm) { 163 readUriPermissions.remove(perm); 164 if (readUriPermissions.size() == 0) { 165 readUriPermissions = null; 166 } 167 } 168 169 @Override 170 public void removeWritePermission(UriPermission perm) { 171 writeUriPermissions.remove(perm); 172 if (writeUriPermissions.size() == 0) { 173 writeUriPermissions = null; 174 } 175 } 176 177 public String toString() { 178 if (stringName != null) { 179 return stringName; 180 } 181 StringBuilder sb = new StringBuilder(128); 182 sb.append("ServiceRecord{") 183 .append(Integer.toHexString(System.identityHashCode(sr))) 184 .append(' ').append(sr.shortName) 185 .append(" StartItem ") 186 .append(Integer.toHexString(System.identityHashCode(this))) 187 .append(" id=").append(id).append('}'); 188 return stringName = sb.toString(); 189 } 190 } 191 192 final ArrayList<StartItem> deliveredStarts = new ArrayList<StartItem>(); 193 // start() arguments which been delivered. 194 final ArrayList<StartItem> pendingStarts = new ArrayList<StartItem>(); 195 // start() arguments that haven't yet been delivered. 196 197 void dumpStartList(PrintWriter pw, String prefix, List<StartItem> list, long now) { 198 final int N = list.size(); 199 for (int i=0; i<N; i++) { 200 StartItem si = list.get(i); 201 pw.print(prefix); pw.print("#"); pw.print(i); 202 pw.print(" id="); pw.print(si.id); 203 if (now != 0) { 204 pw.print(" dur="); 205 TimeUtils.formatDuration(si.deliveredTime, now, pw); 206 } 207 if (si.deliveryCount != 0) { 208 pw.print(" dc="); pw.print(si.deliveryCount); 209 } 210 if (si.doneExecutingCount != 0) { 211 pw.print(" dxc="); pw.print(si.doneExecutingCount); 212 } 213 pw.println(""); 214 pw.print(prefix); pw.print(" intent="); 215 if (si.intent != null) pw.println(si.intent.toString()); 216 else pw.println("null"); 217 if (si.targetPermissionUid >= 0) { 218 pw.print(prefix); pw.print(" targetPermissionUid="); 219 pw.println(si.targetPermissionUid); 220 } 221 if (si.readUriPermissions != null) { 222 pw.print(prefix); pw.print(" readUriPermissions="); 223 pw.println(si.readUriPermissions); 224 } 225 if (si.writeUriPermissions != null) { 226 pw.print(prefix); pw.print(" writeUriPermissions="); 227 pw.println(si.writeUriPermissions); 228 } 229 } 230 } 231 232 void dump(PrintWriter pw, String prefix) { 233 pw.print(prefix); pw.print("intent={"); 234 pw.print(intent.getIntent().toShortString(true, false)); 235 pw.println('}'); 236 pw.print(prefix); pw.print("packageName="); pw.println(packageName); 237 pw.print(prefix); pw.print("processName="); pw.println(processName); 238 if (permission != null) { 239 pw.print(prefix); pw.print("permission="); pw.println(permission); 240 } 241 long now = SystemClock.uptimeMillis(); 242 long nowReal = SystemClock.elapsedRealtime(); 243 pw.print(prefix); pw.print("baseDir="); pw.println(baseDir); 244 if (!resDir.equals(baseDir)) pw.print(prefix); pw.print("resDir="); pw.println(resDir); 245 pw.print(prefix); pw.print("dataDir="); pw.println(dataDir); 246 pw.print(prefix); pw.print("app="); pw.println(app); 247 if (isForeground || foregroundId != 0) { 248 pw.print(prefix); pw.print("isForeground="); pw.print(isForeground); 249 pw.print(" foregroundId="); pw.print(foregroundId); 250 pw.print(" foregroundNoti="); pw.println(foregroundNoti); 251 } 252 pw.print(prefix); pw.print("createTime="); 253 TimeUtils.formatDuration(createTime, nowReal, pw); 254 pw.print(" lastActivity="); 255 TimeUtils.formatDuration(lastActivity, now, pw); 256 pw.println(""); 257 pw.print(prefix); pw.print(" executingStart="); 258 TimeUtils.formatDuration(executingStart, now, pw); 259 pw.print(" restartTime="); 260 TimeUtils.formatDuration(restartTime, now, pw); 261 pw.println(""); 262 if (startRequested || lastStartId != 0) { 263 pw.print(prefix); pw.print("startRequested="); pw.print(startRequested); 264 pw.print(" stopIfKilled="); pw.print(stopIfKilled); 265 pw.print(" callStart="); pw.print(callStart); 266 pw.print(" lastStartId="); pw.println(lastStartId); 267 } 268 if (executeNesting != 0 || crashCount != 0 || restartCount != 0 269 || restartDelay != 0 || nextRestartTime != 0) { 270 pw.print(prefix); pw.print("executeNesting="); pw.print(executeNesting); 271 pw.print(" restartCount="); pw.print(restartCount); 272 pw.print(" restartDelay="); 273 TimeUtils.formatDuration(restartDelay, now, pw); 274 pw.print(" nextRestartTime="); 275 TimeUtils.formatDuration(nextRestartTime, now, pw); 276 pw.print(" crashCount="); pw.println(crashCount); 277 } 278 if (deliveredStarts.size() > 0) { 279 pw.print(prefix); pw.println("Delivered Starts:"); 280 dumpStartList(pw, prefix, deliveredStarts, now); 281 } 282 if (pendingStarts.size() > 0) { 283 pw.print(prefix); pw.println("Pending Starts:"); 284 dumpStartList(pw, prefix, pendingStarts, 0); 285 } 286 if (bindings.size() > 0) { 287 Iterator<IntentBindRecord> it = bindings.values().iterator(); 288 pw.print(prefix); pw.println("Bindings:"); 289 while (it.hasNext()) { 290 IntentBindRecord b = it.next(); 291 pw.print(prefix); pw.print("* IntentBindRecord{"); 292 pw.print(Integer.toHexString(System.identityHashCode(b))); 293 pw.println("}:"); 294 b.dumpInService(pw, prefix + " "); 295 } 296 } 297 if (connections.size() > 0) { 298 pw.print(prefix); pw.println("All Connections:"); 299 Iterator<ArrayList<ConnectionRecord>> it = connections.values().iterator(); 300 while (it.hasNext()) { 301 ArrayList<ConnectionRecord> c = it.next(); 302 for (int i=0; i<c.size(); i++) { 303 pw.print(prefix); pw.print(" "); pw.println(c.get(i)); 304 } 305 } 306 } 307 } 308 309 ServiceRecord(ActivityManagerService ams, 310 BatteryStatsImpl.Uid.Pkg.Serv servStats, ComponentName name, 311 Intent.FilterComparison intent, ServiceInfo sInfo, Runnable restarter) { 312 this.ams = ams; 313 this.stats = servStats; 314 this.name = name; 315 shortName = name.flattenToShortString(); 316 this.intent = intent; 317 serviceInfo = sInfo; 318 appInfo = sInfo.applicationInfo; 319 packageName = sInfo.applicationInfo.packageName; 320 processName = sInfo.processName; 321 permission = sInfo.permission; 322 baseDir = sInfo.applicationInfo.sourceDir; 323 resDir = sInfo.applicationInfo.publicSourceDir; 324 dataDir = sInfo.applicationInfo.dataDir; 325 exported = sInfo.exported; 326 this.restarter = restarter; 327 createTime = SystemClock.elapsedRealtime(); 328 lastActivity = SystemClock.uptimeMillis(); 329 } 330 331 public AppBindRecord retrieveAppBindingLocked(Intent intent, 332 ProcessRecord app) { 333 Intent.FilterComparison filter = new Intent.FilterComparison(intent); 334 IntentBindRecord i = bindings.get(filter); 335 if (i == null) { 336 i = new IntentBindRecord(this, filter); 337 bindings.put(filter, i); 338 } 339 AppBindRecord a = i.apps.get(app); 340 if (a != null) { 341 return a; 342 } 343 a = new AppBindRecord(this, i, app); 344 i.apps.put(app, a); 345 return a; 346 } 347 348 public void resetRestartCounter() { 349 restartCount = 0; 350 restartDelay = 0; 351 restartTime = 0; 352 } 353 354 public StartItem findDeliveredStart(int id, boolean remove) { 355 final int N = deliveredStarts.size(); 356 for (int i=0; i<N; i++) { 357 StartItem si = deliveredStarts.get(i); 358 if (si.id == id) { 359 if (remove) deliveredStarts.remove(i); 360 return si; 361 } 362 } 363 364 return null; 365 } 366 367 public void postNotification() { 368 final int appUid = appInfo.uid; 369 final int appPid = app.pid; 370 if (foregroundId != 0 && foregroundNoti != null) { 371 // Do asynchronous communication with notification manager to 372 // avoid deadlocks. 373 final String localPackageName = packageName; 374 final int localForegroundId = foregroundId; 375 final Notification localForegroundNoti = foregroundNoti; 376 ams.mHandler.post(new Runnable() { 377 public void run() { 378 NotificationManagerService nm = 379 (NotificationManagerService) NotificationManager.getService(); 380 if (nm == null) { 381 return; 382 } 383 try { 384 int[] outId = new int[1]; 385 nm.enqueueNotificationInternal(localPackageName, appUid, appPid, 386 null, localForegroundId, localForegroundNoti, outId); 387 } catch (RuntimeException e) { 388 Slog.w(ActivityManagerService.TAG, 389 "Error showing notification for service", e); 390 // If it gave us a garbage notification, it doesn't 391 // get to be foreground. 392 ams.setServiceForeground(name, ServiceRecord.this, 393 localForegroundId, null, true); 394 } 395 } 396 }); 397 } 398 } 399 400 public void cancelNotification() { 401 if (foregroundId != 0) { 402 // Do asynchronous communication with notification manager to 403 // avoid deadlocks. 404 final String localPackageName = packageName; 405 final int localForegroundId = foregroundId; 406 ams.mHandler.post(new Runnable() { 407 public void run() { 408 INotificationManager inm = NotificationManager.getService(); 409 if (inm == null) { 410 return; 411 } 412 try { 413 inm.cancelNotification(localPackageName, localForegroundId); 414 } catch (RuntimeException e) { 415 Slog.w(ActivityManagerService.TAG, 416 "Error canceling notification for service", e); 417 } catch (RemoteException e) { 418 } 419 } 420 }); 421 } 422 } 423 424 public void clearDeliveredStartsLocked() { 425 for (int i=deliveredStarts.size()-1; i>=0; i--) { 426 deliveredStarts.get(i).removeUriPermissionsLocked(); 427 } 428 deliveredStarts.clear(); 429 } 430 431 public String toString() { 432 if (stringName != null) { 433 return stringName; 434 } 435 StringBuilder sb = new StringBuilder(128); 436 sb.append("ServiceRecord{") 437 .append(Integer.toHexString(System.identityHashCode(this))) 438 .append(' ').append(shortName).append('}'); 439 return stringName = sb.toString(); 440 } 441} 442