blob: d917d170817596ac7d03d6fac602f6e76e98873b [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2008 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;
Dianne Hackbornde7faf62009-06-30 13:27:30 -070020import com.android.server.AttributeCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import com.android.server.IntentResolver;
22import com.android.server.ProcessMap;
23import com.android.server.ProcessStats;
24import com.android.server.SystemServer;
25import com.android.server.Watchdog;
26import com.android.server.WindowManagerService;
27
28import android.app.Activity;
29import android.app.ActivityManager;
30import android.app.ActivityManagerNative;
31import android.app.ActivityThread;
32import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020033import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.app.Dialog;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070035import android.app.IActivityController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.app.IActivityWatcher;
37import android.app.IApplicationThread;
38import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.app.IServiceConnection;
40import android.app.IThumbnailReceiver;
41import android.app.Instrumentation;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070042import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.app.PendingIntent;
44import android.app.ResultInfo;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070045import android.app.Service;
Christopher Tate181fafa2009-05-14 11:12:14 -070046import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020047import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.ComponentName;
49import android.content.ContentResolver;
50import android.content.Context;
51import android.content.Intent;
52import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070053import android.content.IIntentReceiver;
54import android.content.IIntentSender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -070055import android.content.IntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.content.pm.ActivityInfo;
57import android.content.pm.ApplicationInfo;
58import android.content.pm.ConfigurationInfo;
59import android.content.pm.IPackageDataObserver;
60import android.content.pm.IPackageManager;
61import android.content.pm.InstrumentationInfo;
62import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070063import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import android.content.pm.ProviderInfo;
65import android.content.pm.ResolveInfo;
66import android.content.pm.ServiceInfo;
67import android.content.res.Configuration;
68import android.graphics.Bitmap;
69import android.net.Uri;
70import android.os.Binder;
71import android.os.Bundle;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070072import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.os.Environment;
74import android.os.FileUtils;
75import android.os.Handler;
76import android.os.IBinder;
77import android.os.IPermissionController;
78import android.os.Looper;
79import android.os.Message;
80import android.os.Parcel;
81import android.os.ParcelFileDescriptor;
82import android.os.PowerManager;
83import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070084import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.os.RemoteException;
86import android.os.ServiceManager;
87import android.os.SystemClock;
88import android.os.SystemProperties;
89import android.provider.Checkin;
90import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020091import android.server.data.CrashData;
92import android.server.data.StackTraceElementData;
93import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094import android.text.TextUtils;
95import android.util.Config;
96import android.util.EventLog;
97import android.util.Log;
98import android.util.PrintWriterPrinter;
99import android.util.SparseArray;
100import android.view.Gravity;
101import android.view.LayoutInflater;
102import android.view.View;
103import android.view.WindowManager;
104import android.view.WindowManagerPolicy;
105
106import dalvik.system.Zygote;
107
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200108import java.io.ByteArrayInputStream;
109import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110import java.io.File;
111import java.io.FileDescriptor;
112import java.io.FileInputStream;
113import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200114import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115import java.io.PrintWriter;
116import java.lang.IllegalStateException;
117import java.lang.ref.WeakReference;
118import java.util.ArrayList;
119import java.util.HashMap;
120import java.util.HashSet;
121import java.util.Iterator;
122import java.util.List;
123import java.util.Locale;
124import java.util.Map;
125
126public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
127 static final String TAG = "ActivityManager";
128 static final boolean DEBUG = false;
129 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
130 static final boolean DEBUG_SWITCH = localLOGV || false;
131 static final boolean DEBUG_TASKS = localLOGV || false;
132 static final boolean DEBUG_PAUSE = localLOGV || false;
133 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
134 static final boolean DEBUG_TRANSITION = localLOGV || false;
135 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700136 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 static final boolean DEBUG_SERVICE = localLOGV || false;
138 static final boolean DEBUG_VISBILITY = localLOGV || false;
139 static final boolean DEBUG_PROCESSES = localLOGV || false;
Dianne Hackborna1e989b2009-09-01 19:54:29 -0700140 static final boolean DEBUG_PROVIDER = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700142 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700143 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 static final boolean VALIDATE_TOKENS = false;
145 static final boolean SHOW_ACTIVITY_START_TIME = true;
146
147 // Control over CPU and battery monitoring.
148 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
149 static final boolean MONITOR_CPU_USAGE = true;
150 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
151 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
152 static final boolean MONITOR_THREAD_CPU_USAGE = false;
153
154 // Event log tags
155 static final int LOG_CONFIGURATION_CHANGED = 2719;
156 static final int LOG_CPU = 2721;
157 static final int LOG_AM_FINISH_ACTIVITY = 30001;
158 static final int LOG_TASK_TO_FRONT = 30002;
159 static final int LOG_AM_NEW_INTENT = 30003;
160 static final int LOG_AM_CREATE_TASK = 30004;
161 static final int LOG_AM_CREATE_ACTIVITY = 30005;
162 static final int LOG_AM_RESTART_ACTIVITY = 30006;
163 static final int LOG_AM_RESUME_ACTIVITY = 30007;
164 static final int LOG_ANR = 30008;
165 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
166 static final int LOG_AM_PROCESS_BOUND = 30010;
167 static final int LOG_AM_PROCESS_DIED = 30011;
168 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
169 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
170 static final int LOG_AM_PROCESS_START = 30014;
171 static final int LOG_AM_PROCESS_BAD = 30015;
172 static final int LOG_AM_PROCESS_GOOD = 30016;
173 static final int LOG_AM_LOW_MEMORY = 30017;
174 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
175 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
176 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
177 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
178 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
179 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
180 static final int LOG_AM_CREATE_SERVICE = 30030;
181 static final int LOG_AM_DESTROY_SERVICE = 30031;
182 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
183 static final int LOG_AM_DROP_PROCESS = 30033;
184 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
185 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
186 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
187
188 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
189 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
190
Dianne Hackborn1655be42009-05-08 14:29:01 -0700191 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700192 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700193
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 private static final String SYSTEM_SECURE = "ro.secure";
195
196 // This is the maximum number of application processes we would like
197 // to have running. Due to the asynchronous nature of things, we can
198 // temporarily go beyond this limit.
199 static final int MAX_PROCESSES = 2;
200
201 // Set to false to leave processes running indefinitely, relying on
202 // the kernel killing them as resources are required.
203 static final boolean ENFORCE_PROCESS_LIMIT = false;
204
205 // This is the maximum number of activities that we would like to have
206 // running at a given time.
207 static final int MAX_ACTIVITIES = 20;
208
209 // Maximum number of recent tasks that we can remember.
210 static final int MAX_RECENT_TASKS = 20;
211
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700212 // Amount of time after a call to stopAppSwitches() during which we will
213 // prevent further untrusted switches from happening.
214 static final long APP_SWITCH_DELAY_TIME = 5*1000;
215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 // How long until we reset a task when the user returns to it. Currently
217 // 30 minutes.
218 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
219
220 // Set to true to disable the icon that is shown while a new activity
221 // is being started.
222 static final boolean SHOW_APP_STARTING_ICON = true;
223
224 // How long we wait until giving up on the last activity to pause. This
225 // is short because it directly impacts the responsiveness of starting the
226 // next activity.
227 static final int PAUSE_TIMEOUT = 500;
228
229 /**
230 * How long we can hold the launch wake lock before giving up.
231 */
232 static final int LAUNCH_TIMEOUT = 10*1000;
233
234 // How long we wait for a launched process to attach to the activity manager
235 // before we decide it's never going to come up for real.
236 static final int PROC_START_TIMEOUT = 10*1000;
237
238 // How long we wait until giving up on the last activity telling us it
239 // is idle.
240 static final int IDLE_TIMEOUT = 10*1000;
241
242 // How long to wait after going idle before forcing apps to GC.
243 static final int GC_TIMEOUT = 5*1000;
244
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700245 // The minimum amount of time between successive GC requests for a process.
246 static final int GC_MIN_INTERVAL = 60*1000;
247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 // How long we wait until giving up on an activity telling us it has
249 // finished destroying itself.
250 static final int DESTROY_TIMEOUT = 10*1000;
251
252 // How long we allow a receiver to run before giving up on it.
253 static final int BROADCAST_TIMEOUT = 10*1000;
254
255 // How long we wait for a service to finish executing.
256 static final int SERVICE_TIMEOUT = 20*1000;
257
258 // How long a service needs to be running until restarting its process
259 // is no longer considered to be a relaunch of the service.
260 static final int SERVICE_RESTART_DURATION = 5*1000;
261
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700262 // How long a service needs to be running until it will start back at
263 // SERVICE_RESTART_DURATION after being killed.
264 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
265
266 // Multiplying factor to increase restart duration time by, for each time
267 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
268 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
269
270 // The minimum amount of time between restarting services that we allow.
271 // That is, when multiple services are restarting, we won't allow each
272 // to restart less than this amount of time from the last one.
273 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
274
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 // Maximum amount of time for there to be no activity on a service before
276 // we consider it non-essential and allow its process to go on the
277 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700278 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279
280 // How long we wait until we timeout on key dispatching.
281 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
282
283 // The minimum time we allow between crashes, for us to consider this
284 // application to be bad and stop and its services and reject broadcasts.
285 static final int MIN_CRASH_INTERVAL = 60*1000;
286
287 // How long we wait until we timeout on key dispatching during instrumentation.
288 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
289
290 // OOM adjustments for processes in various states:
291
292 // This is a process without anything currently running in it. Definitely
293 // the first to go! Value set in system/rootdir/init.rc on startup.
294 // This value is initalized in the constructor, careful when refering to
295 // this static variable externally.
296 static int EMPTY_APP_ADJ;
297
298 // This is a process with a content provider that does not have any clients
299 // attached to it. If it did have any clients, its adjustment would be the
300 // one for the highest-priority of those processes.
301 static int CONTENT_PROVIDER_ADJ;
302
303 // This is a process only hosting activities that are not visible,
304 // so it can be killed without any disruption. Value set in
305 // system/rootdir/init.rc on startup.
306 final int HIDDEN_APP_MAX_ADJ;
307 static int HIDDEN_APP_MIN_ADJ;
308
The Android Open Source Project4df24232009-03-05 14:34:35 -0800309 // This is a process holding the home application -- we want to try
310 // avoiding killing it, even if it would normally be in the background,
311 // because the user interacts with it so much.
312 final int HOME_APP_ADJ;
313
Christopher Tate6fa95972009-06-05 18:43:55 -0700314 // This is a process currently hosting a backup operation. Killing it
315 // is not entirely fatal but is generally a bad idea.
316 final int BACKUP_APP_ADJ;
317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 // This is a process holding a secondary server -- killing it will not
319 // have much of an impact as far as the user is concerned. Value set in
320 // system/rootdir/init.rc on startup.
321 final int SECONDARY_SERVER_ADJ;
322
323 // This is a process only hosting activities that are visible to the
324 // user, so we'd prefer they don't disappear. Value set in
325 // system/rootdir/init.rc on startup.
326 final int VISIBLE_APP_ADJ;
327
328 // This is the process running the current foreground app. We'd really
329 // rather not kill it! Value set in system/rootdir/init.rc on startup.
330 final int FOREGROUND_APP_ADJ;
331
332 // This is a process running a core server, such as telephony. Definitely
333 // don't want to kill it, but doing so is not completely fatal.
334 static final int CORE_SERVER_ADJ = -12;
335
336 // The system process runs at the default adjustment.
337 static final int SYSTEM_ADJ = -16;
338
339 // Memory pages are 4K.
340 static final int PAGE_SIZE = 4*1024;
341
Jacek Surazski82a73df2009-06-17 14:33:18 +0200342 // System property defining error report receiver for system apps
343 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
344
345 // System property defining default error report receiver
346 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 // Corresponding memory levels for above adjustments.
349 final int EMPTY_APP_MEM;
350 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800351 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700352 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 final int SECONDARY_SERVER_MEM;
354 final int VISIBLE_APP_MEM;
355 final int FOREGROUND_APP_MEM;
356
357 final int MY_PID;
358
359 static final String[] EMPTY_STRING_ARRAY = new String[0];
360
361 enum ActivityState {
362 INITIALIZING,
363 RESUMED,
364 PAUSING,
365 PAUSED,
366 STOPPING,
367 STOPPED,
368 FINISHING,
369 DESTROYING,
370 DESTROYED
371 }
372
373 /**
374 * The back history of all previous (and possibly still
375 * running) activities. It contains HistoryRecord objects.
376 */
377 final ArrayList mHistory = new ArrayList();
378
379 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700380 * Description of a request to start a new activity, which has been held
381 * due to app switches being disabled.
382 */
383 class PendingActivityLaunch {
384 HistoryRecord r;
385 HistoryRecord sourceRecord;
386 Uri[] grantedUriPermissions;
387 int grantedMode;
388 boolean onlyIfNeeded;
389 }
390
391 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
392 = new ArrayList<PendingActivityLaunch>();
393
394 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 * List of all active broadcasts that are to be executed immediately
396 * (without waiting for another broadcast to finish). Currently this only
397 * contains broadcasts to registered receivers, to avoid spinning up
398 * a bunch of processes to execute IntentReceiver components.
399 */
400 final ArrayList<BroadcastRecord> mParallelBroadcasts
401 = new ArrayList<BroadcastRecord>();
402
403 /**
404 * List of all active broadcasts that are to be executed one at a time.
405 * The object at the top of the list is the currently activity broadcasts;
406 * those after it are waiting for the top to finish..
407 */
408 final ArrayList<BroadcastRecord> mOrderedBroadcasts
409 = new ArrayList<BroadcastRecord>();
410
411 /**
412 * Set when we current have a BROADCAST_INTENT_MSG in flight.
413 */
414 boolean mBroadcastsScheduled = false;
415
416 /**
417 * Set to indicate whether to issue an onUserLeaving callback when a
418 * newly launched activity is being brought in front of us.
419 */
420 boolean mUserLeaving = false;
421
422 /**
423 * When we are in the process of pausing an activity, before starting the
424 * next one, this variable holds the activity that is currently being paused.
425 */
426 HistoryRecord mPausingActivity = null;
427
428 /**
429 * Current activity that is resumed, or null if there is none.
430 */
431 HistoryRecord mResumedActivity = null;
432
433 /**
434 * Activity we have told the window manager to have key focus.
435 */
436 HistoryRecord mFocusedActivity = null;
437
438 /**
439 * This is the last activity that we put into the paused state. This is
440 * used to determine if we need to do an activity transition while sleeping,
441 * when we normally hold the top activity paused.
442 */
443 HistoryRecord mLastPausedActivity = null;
444
445 /**
446 * List of activities that are waiting for a new activity
447 * to become visible before completing whatever operation they are
448 * supposed to do.
449 */
450 final ArrayList mWaitingVisibleActivities = new ArrayList();
451
452 /**
453 * List of activities that are ready to be stopped, but waiting
454 * for the next activity to settle down before doing so. It contains
455 * HistoryRecord objects.
456 */
457 final ArrayList<HistoryRecord> mStoppingActivities
458 = new ArrayList<HistoryRecord>();
459
460 /**
Dianne Hackbornbfe319e2009-09-21 00:34:05 -0700461 * Animations that for the current transition have requested not to
462 * be considered for the transition animation.
463 */
464 final ArrayList<HistoryRecord> mNoAnimActivities
465 = new ArrayList<HistoryRecord>();
466
467 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 * List of intents that were used to start the most recent tasks.
469 */
470 final ArrayList<TaskRecord> mRecentTasks
471 = new ArrayList<TaskRecord>();
472
473 /**
474 * List of activities that are ready to be finished, but waiting
475 * for the previous activity to settle down before doing so. It contains
476 * HistoryRecord objects.
477 */
478 final ArrayList mFinishingActivities = new ArrayList();
479
480 /**
481 * All of the applications we currently have running organized by name.
482 * The keys are strings of the application package name (as
483 * returned by the package manager), and the keys are ApplicationRecord
484 * objects.
485 */
486 final ProcessMap<ProcessRecord> mProcessNames
487 = new ProcessMap<ProcessRecord>();
488
489 /**
490 * The last time that various processes have crashed.
491 */
492 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
493
494 /**
495 * Set of applications that we consider to be bad, and will reject
496 * incoming broadcasts from (which the user has no control over).
497 * Processes are added to this set when they have crashed twice within
498 * a minimum amount of time; they are removed from it when they are
499 * later restarted (hopefully due to some user action). The value is the
500 * time it was added to the list.
501 */
502 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
503
504 /**
505 * All of the processes we currently have running organized by pid.
506 * The keys are the pid running the application.
507 *
508 * <p>NOTE: This object is protected by its own lock, NOT the global
509 * activity manager lock!
510 */
511 final SparseArray<ProcessRecord> mPidsSelfLocked
512 = new SparseArray<ProcessRecord>();
513
514 /**
515 * All of the processes that have been forced to be foreground. The key
516 * is the pid of the caller who requested it (we hold a death
517 * link on it).
518 */
519 abstract class ForegroundToken implements IBinder.DeathRecipient {
520 int pid;
521 IBinder token;
522 }
523 final SparseArray<ForegroundToken> mForegroundProcesses
524 = new SparseArray<ForegroundToken>();
525
526 /**
527 * List of records for processes that someone had tried to start before the
528 * system was ready. We don't start them at that point, but ensure they
529 * are started by the time booting is complete.
530 */
531 final ArrayList<ProcessRecord> mProcessesOnHold
532 = new ArrayList<ProcessRecord>();
533
534 /**
535 * List of records for processes that we have started and are waiting
536 * for them to call back. This is really only needed when running in
537 * single processes mode, in which case we do not have a unique pid for
538 * each process.
539 */
540 final ArrayList<ProcessRecord> mStartingProcesses
541 = new ArrayList<ProcessRecord>();
542
543 /**
544 * List of persistent applications that are in the process
545 * of being started.
546 */
547 final ArrayList<ProcessRecord> mPersistentStartingProcesses
548 = new ArrayList<ProcessRecord>();
549
550 /**
551 * Processes that are being forcibly torn down.
552 */
553 final ArrayList<ProcessRecord> mRemovedProcesses
554 = new ArrayList<ProcessRecord>();
555
556 /**
557 * List of running applications, sorted by recent usage.
558 * The first entry in the list is the least recently used.
559 * It contains ApplicationRecord objects. This list does NOT include
560 * any persistent application records (since we never want to exit them).
561 */
562 final ArrayList<ProcessRecord> mLRUProcesses
563 = new ArrayList<ProcessRecord>();
564
565 /**
566 * List of processes that should gc as soon as things are idle.
567 */
568 final ArrayList<ProcessRecord> mProcessesToGc
569 = new ArrayList<ProcessRecord>();
570
571 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800572 * This is the process holding what we currently consider to be
573 * the "home" activity.
574 */
575 private ProcessRecord mHomeProcess;
576
577 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 * List of running activities, sorted by recent usage.
579 * The first entry in the list is the least recently used.
580 * It contains HistoryRecord objects.
581 */
582 private final ArrayList mLRUActivities = new ArrayList();
583
584 /**
585 * Set of PendingResultRecord objects that are currently active.
586 */
587 final HashSet mPendingResultRecords = new HashSet();
588
589 /**
590 * Set of IntentSenderRecord objects that are currently active.
591 */
592 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
593 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
594
595 /**
596 * Intent broadcast that we have tried to start, but are
597 * waiting for its application's process to be created. We only
598 * need one (instead of a list) because we always process broadcasts
599 * one at a time, so no others can be started while waiting for this
600 * one.
601 */
602 BroadcastRecord mPendingBroadcast = null;
603
604 /**
605 * Keeps track of all IIntentReceivers that have been registered for
606 * broadcasts. Hash keys are the receiver IBinder, hash value is
607 * a ReceiverList.
608 */
609 final HashMap mRegisteredReceivers = new HashMap();
610
611 /**
612 * Resolver for broadcast intents to registered receivers.
613 * Holds BroadcastFilter (subclass of IntentFilter).
614 */
615 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
616 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
617 @Override
618 protected boolean allowFilterResult(
619 BroadcastFilter filter, List<BroadcastFilter> dest) {
620 IBinder target = filter.receiverList.receiver.asBinder();
621 for (int i=dest.size()-1; i>=0; i--) {
622 if (dest.get(i).receiverList.receiver.asBinder() == target) {
623 return false;
624 }
625 }
626 return true;
627 }
628 };
629
630 /**
631 * State of all active sticky broadcasts. Keys are the action of the
632 * sticky Intent, values are an ArrayList of all broadcasted intents with
633 * that action (which should usually be one).
634 */
635 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
636 new HashMap<String, ArrayList<Intent>>();
637
638 /**
639 * All currently running services.
640 */
641 final HashMap<ComponentName, ServiceRecord> mServices =
642 new HashMap<ComponentName, ServiceRecord>();
643
644 /**
645 * All currently running services indexed by the Intent used to start them.
646 */
647 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
648 new HashMap<Intent.FilterComparison, ServiceRecord>();
649
650 /**
651 * All currently bound service connections. Keys are the IBinder of
652 * the client's IServiceConnection.
653 */
654 final HashMap<IBinder, ConnectionRecord> mServiceConnections
655 = new HashMap<IBinder, ConnectionRecord>();
656
657 /**
658 * List of services that we have been asked to start,
659 * but haven't yet been able to. It is used to hold start requests
660 * while waiting for their corresponding application thread to get
661 * going.
662 */
663 final ArrayList<ServiceRecord> mPendingServices
664 = new ArrayList<ServiceRecord>();
665
666 /**
667 * List of services that are scheduled to restart following a crash.
668 */
669 final ArrayList<ServiceRecord> mRestartingServices
670 = new ArrayList<ServiceRecord>();
671
672 /**
673 * List of services that are in the process of being stopped.
674 */
675 final ArrayList<ServiceRecord> mStoppingServices
676 = new ArrayList<ServiceRecord>();
677
678 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700679 * Backup/restore process management
680 */
681 String mBackupAppName = null;
682 BackupRecord mBackupTarget = null;
683
684 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 * List of PendingThumbnailsRecord objects of clients who are still
686 * waiting to receive all of the thumbnails for a task.
687 */
688 final ArrayList mPendingThumbnails = new ArrayList();
689
690 /**
691 * List of HistoryRecord objects that have been finished and must
692 * still report back to a pending thumbnail receiver.
693 */
694 final ArrayList mCancelledThumbnails = new ArrayList();
695
696 /**
697 * All of the currently running global content providers. Keys are a
698 * string containing the provider name and values are a
699 * ContentProviderRecord object containing the data about it. Note
700 * that a single provider may be published under multiple names, so
701 * there may be multiple entries here for a single one in mProvidersByClass.
702 */
703 final HashMap mProvidersByName = new HashMap();
704
705 /**
706 * All of the currently running global content providers. Keys are a
707 * string containing the provider's implementation class and values are a
708 * ContentProviderRecord object containing the data about it.
709 */
710 final HashMap mProvidersByClass = new HashMap();
711
712 /**
713 * List of content providers who have clients waiting for them. The
714 * application is currently being launched and the provider will be
715 * removed from this list once it is published.
716 */
717 final ArrayList mLaunchingProviders = new ArrayList();
718
719 /**
720 * Global set of specific Uri permissions that have been granted.
721 */
722 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
723 = new SparseArray<HashMap<Uri, UriPermission>>();
724
725 /**
726 * Thread-local storage used to carry caller permissions over through
727 * indirect content-provider access.
728 * @see #ActivityManagerService.openContentUri()
729 */
730 private class Identity {
731 public int pid;
732 public int uid;
733
734 Identity(int _pid, int _uid) {
735 pid = _pid;
736 uid = _uid;
737 }
738 }
739 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
740
741 /**
742 * All information we have collected about the runtime performance of
743 * any user id that can impact battery performance.
744 */
745 final BatteryStatsService mBatteryStatsService;
746
747 /**
748 * information about component usage
749 */
750 final UsageStatsService mUsageStatsService;
751
752 /**
753 * Current configuration information. HistoryRecord objects are given
754 * a reference to this object to indicate which configuration they are
755 * currently running in, so this object must be kept immutable.
756 */
757 Configuration mConfiguration = new Configuration();
758
759 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700760 * Hardware-reported OpenGLES version.
761 */
762 final int GL_ES_VERSION;
763
764 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 * List of initialization arguments to pass to all processes when binding applications to them.
766 * For example, references to the commonly used services.
767 */
768 HashMap<String, IBinder> mAppBindArgs;
769
770 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700771 * Temporary to avoid allocations. Protected by main lock.
772 */
773 final StringBuilder mStringBuilder = new StringBuilder(256);
774
775 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 * Used to control how we initialize the service.
777 */
778 boolean mStartRunning = false;
779 ComponentName mTopComponent;
780 String mTopAction;
781 String mTopData;
782 boolean mSystemReady = false;
783 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700784 boolean mWaitingUpdate = false;
785 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786
787 Context mContext;
788
789 int mFactoryTest;
790
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700791 boolean mCheckedForSetup;
792
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700794 * The time at which we will allow normal application switches again,
795 * after a call to {@link #stopAppSwitches()}.
796 */
797 long mAppSwitchesAllowedTime;
798
799 /**
800 * This is set to true after the first switch after mAppSwitchesAllowedTime
801 * is set; any switches after that will clear the time.
802 */
803 boolean mDidAppSwitch;
804
805 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806 * Set while we are wanting to sleep, to prevent any
807 * activities from being started/resumed.
808 */
809 boolean mSleeping = false;
810
811 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700812 * Set if we are shutting down the system, similar to sleeping.
813 */
814 boolean mShuttingDown = false;
815
816 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 * Set when the system is going to sleep, until we have
818 * successfully paused the current activity and released our wake lock.
819 * At that point the system is allowed to actually sleep.
820 */
821 PowerManager.WakeLock mGoingToSleep;
822
823 /**
824 * We don't want to allow the device to go to sleep while in the process
825 * of launching an activity. This is primarily to allow alarm intent
826 * receivers to launch an activity and get that to run before the device
827 * goes back to sleep.
828 */
829 PowerManager.WakeLock mLaunchingActivity;
830
831 /**
832 * Task identifier that activities are currently being started
833 * in. Incremented each time a new task is created.
834 * todo: Replace this with a TokenSpace class that generates non-repeating
835 * integers that won't wrap.
836 */
837 int mCurTask = 1;
838
839 /**
840 * Current sequence id for oom_adj computation traversal.
841 */
842 int mAdjSeq = 0;
843
844 /**
845 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
846 * is set, indicating the user wants processes started in such a way
847 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
848 * running in each process (thus no pre-initialized process, etc).
849 */
850 boolean mSimpleProcessManagement = false;
851
852 /**
853 * System monitoring: number of processes that died since the last
854 * N procs were started.
855 */
856 int[] mProcDeaths = new int[20];
857
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700858 /**
859 * This is set if we had to do a delayed dexopt of an app before launching
860 * it, to increasing the ANR timeouts in that case.
861 */
862 boolean mDidDexOpt;
863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 String mDebugApp = null;
865 boolean mWaitForDebugger = false;
866 boolean mDebugTransient = false;
867 String mOrigDebugApp = null;
868 boolean mOrigWaitForDebugger = false;
869 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700870 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700872 final RemoteCallbackList<IActivityWatcher> mWatchers
873 = new RemoteCallbackList<IActivityWatcher>();
874
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 /**
876 * Callback of last caller to {@link #requestPss}.
877 */
878 Runnable mRequestPssCallback;
879
880 /**
881 * Remaining processes for which we are waiting results from the last
882 * call to {@link #requestPss}.
883 */
884 final ArrayList<ProcessRecord> mRequestPssList
885 = new ArrayList<ProcessRecord>();
886
887 /**
888 * Runtime statistics collection thread. This object's lock is used to
889 * protect all related state.
890 */
891 final Thread mProcessStatsThread;
892
893 /**
894 * Used to collect process stats when showing not responding dialog.
895 * Protected by mProcessStatsThread.
896 */
897 final ProcessStats mProcessStats = new ProcessStats(
898 MONITOR_THREAD_CPU_USAGE);
899 long mLastCpuTime = 0;
900 long mLastWriteTime = 0;
901
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700902 long mInitialStartTime = 0;
903
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 /**
905 * Set to true after the system has finished booting.
906 */
907 boolean mBooted = false;
908
909 int mProcessLimit = 0;
910
911 WindowManagerService mWindowManager;
912
913 static ActivityManagerService mSelf;
914 static ActivityThread mSystemThread;
915
916 private final class AppDeathRecipient implements IBinder.DeathRecipient {
917 final ProcessRecord mApp;
918 final int mPid;
919 final IApplicationThread mAppThread;
920
921 AppDeathRecipient(ProcessRecord app, int pid,
922 IApplicationThread thread) {
923 if (localLOGV) Log.v(
924 TAG, "New death recipient " + this
925 + " for thread " + thread.asBinder());
926 mApp = app;
927 mPid = pid;
928 mAppThread = thread;
929 }
930
931 public void binderDied() {
932 if (localLOGV) Log.v(
933 TAG, "Death received in " + this
934 + " for thread " + mAppThread.asBinder());
935 removeRequestedPss(mApp);
936 synchronized(ActivityManagerService.this) {
937 appDiedLocked(mApp, mPid, mAppThread);
938 }
939 }
940 }
941
942 static final int SHOW_ERROR_MSG = 1;
943 static final int SHOW_NOT_RESPONDING_MSG = 2;
944 static final int SHOW_FACTORY_ERROR_MSG = 3;
945 static final int UPDATE_CONFIGURATION_MSG = 4;
946 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
947 static final int WAIT_FOR_DEBUGGER_MSG = 6;
948 static final int BROADCAST_INTENT_MSG = 7;
949 static final int BROADCAST_TIMEOUT_MSG = 8;
950 static final int PAUSE_TIMEOUT_MSG = 9;
951 static final int IDLE_TIMEOUT_MSG = 10;
952 static final int IDLE_NOW_MSG = 11;
953 static final int SERVICE_TIMEOUT_MSG = 12;
954 static final int UPDATE_TIME_ZONE = 13;
955 static final int SHOW_UID_ERROR_MSG = 14;
956 static final int IM_FEELING_LUCKY_MSG = 15;
957 static final int LAUNCH_TIMEOUT_MSG = 16;
958 static final int DESTROY_TIMEOUT_MSG = 17;
959 static final int SERVICE_ERROR_MSG = 18;
960 static final int RESUME_TOP_ACTIVITY_MSG = 19;
961 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700962 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700963 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964
965 AlertDialog mUidAlert;
966
967 final Handler mHandler = new Handler() {
968 //public Handler() {
969 // if (localLOGV) Log.v(TAG, "Handler started!");
970 //}
971
972 public void handleMessage(Message msg) {
973 switch (msg.what) {
974 case SHOW_ERROR_MSG: {
975 HashMap data = (HashMap) msg.obj;
976 byte[] crashData = (byte[])data.get("crashData");
977 if (crashData != null) {
978 // This needs to be *un*synchronized to avoid deadlock.
979 ContentResolver resolver = mContext.getContentResolver();
980 Checkin.reportCrash(resolver, crashData);
981 }
982 synchronized (ActivityManagerService.this) {
983 ProcessRecord proc = (ProcessRecord)data.get("app");
984 if (proc != null && proc.crashDialog != null) {
985 Log.e(TAG, "App already has crash dialog: " + proc);
986 return;
987 }
988 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700989 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800990 Dialog d = new AppErrorDialog(
991 mContext, res, proc,
992 (Integer)data.get("flags"),
993 (String)data.get("shortMsg"),
994 (String)data.get("longMsg"));
995 d.show();
996 proc.crashDialog = d;
997 } else {
998 // The device is asleep, so just pretend that the user
999 // saw a crash dialog and hit "force quit".
1000 res.set(0);
1001 }
1002 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001003
1004 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005 } break;
1006 case SHOW_NOT_RESPONDING_MSG: {
1007 synchronized (ActivityManagerService.this) {
1008 HashMap data = (HashMap) msg.obj;
1009 ProcessRecord proc = (ProcessRecord)data.get("app");
1010 if (proc != null && proc.anrDialog != null) {
1011 Log.e(TAG, "App already has anr dialog: " + proc);
1012 return;
1013 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001014
1015 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1016 null, null, 0, null, null, null,
1017 false, false, MY_PID, Process.SYSTEM_UID);
1018
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1020 mContext, proc, (HistoryRecord)data.get("activity"));
1021 d.show();
1022 proc.anrDialog = d;
1023 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001024
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001025 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 } break;
1027 case SHOW_FACTORY_ERROR_MSG: {
1028 Dialog d = new FactoryErrorDialog(
1029 mContext, msg.getData().getCharSequence("msg"));
1030 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001031 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001032 } break;
1033 case UPDATE_CONFIGURATION_MSG: {
1034 final ContentResolver resolver = mContext.getContentResolver();
1035 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1036 } break;
1037 case GC_BACKGROUND_PROCESSES_MSG: {
1038 synchronized (ActivityManagerService.this) {
1039 performAppGcsIfAppropriateLocked();
1040 }
1041 } break;
1042 case WAIT_FOR_DEBUGGER_MSG: {
1043 synchronized (ActivityManagerService.this) {
1044 ProcessRecord app = (ProcessRecord)msg.obj;
1045 if (msg.arg1 != 0) {
1046 if (!app.waitedForDebugger) {
1047 Dialog d = new AppWaitingForDebuggerDialog(
1048 ActivityManagerService.this,
1049 mContext, app);
1050 app.waitDialog = d;
1051 app.waitedForDebugger = true;
1052 d.show();
1053 }
1054 } else {
1055 if (app.waitDialog != null) {
1056 app.waitDialog.dismiss();
1057 app.waitDialog = null;
1058 }
1059 }
1060 }
1061 } break;
1062 case BROADCAST_INTENT_MSG: {
1063 if (DEBUG_BROADCAST) Log.v(
1064 TAG, "Received BROADCAST_INTENT_MSG");
1065 processNextBroadcast(true);
1066 } break;
1067 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001068 if (mDidDexOpt) {
1069 mDidDexOpt = false;
1070 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1071 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1072 return;
1073 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 broadcastTimeout();
1075 } break;
1076 case PAUSE_TIMEOUT_MSG: {
1077 IBinder token = (IBinder)msg.obj;
1078 // We don't at this point know if the activity is fullscreen,
1079 // so we need to be conservative and assume it isn't.
1080 Log.w(TAG, "Activity pause timeout for " + token);
1081 activityPaused(token, null, true);
1082 } break;
1083 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001084 if (mDidDexOpt) {
1085 mDidDexOpt = false;
1086 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1087 nmsg.obj = msg.obj;
1088 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1089 return;
1090 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091 // We don't at this point know if the activity is fullscreen,
1092 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001093 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 Log.w(TAG, "Activity idle timeout for " + token);
1095 activityIdleInternal(token, true);
1096 } break;
1097 case DESTROY_TIMEOUT_MSG: {
1098 IBinder token = (IBinder)msg.obj;
1099 // We don't at this point know if the activity is fullscreen,
1100 // so we need to be conservative and assume it isn't.
1101 Log.w(TAG, "Activity destroy timeout for " + token);
1102 activityDestroyed(token);
1103 } break;
1104 case IDLE_NOW_MSG: {
1105 IBinder token = (IBinder)msg.obj;
1106 activityIdle(token);
1107 } break;
1108 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001109 if (mDidDexOpt) {
1110 mDidDexOpt = false;
1111 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1112 nmsg.obj = msg.obj;
1113 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1114 return;
1115 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116 serviceTimeout((ProcessRecord)msg.obj);
1117 } break;
1118 case UPDATE_TIME_ZONE: {
1119 synchronized (ActivityManagerService.this) {
1120 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1121 ProcessRecord r = mLRUProcesses.get(i);
1122 if (r.thread != null) {
1123 try {
1124 r.thread.updateTimeZone();
1125 } catch (RemoteException ex) {
1126 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1127 }
1128 }
1129 }
1130 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001131 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132 case SHOW_UID_ERROR_MSG: {
1133 // XXX This is a temporary dialog, no need to localize.
1134 AlertDialog d = new BaseErrorDialog(mContext);
1135 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1136 d.setCancelable(false);
1137 d.setTitle("System UIDs Inconsistent");
1138 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1139 d.setButton("I'm Feeling Lucky",
1140 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1141 mUidAlert = d;
1142 d.show();
1143 } break;
1144 case IM_FEELING_LUCKY_MSG: {
1145 if (mUidAlert != null) {
1146 mUidAlert.dismiss();
1147 mUidAlert = null;
1148 }
1149 } break;
1150 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001151 if (mDidDexOpt) {
1152 mDidDexOpt = false;
1153 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1154 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1155 return;
1156 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 synchronized (ActivityManagerService.this) {
1158 if (mLaunchingActivity.isHeld()) {
1159 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1160 mLaunchingActivity.release();
1161 }
1162 }
1163 } break;
1164 case SERVICE_ERROR_MSG: {
1165 ServiceRecord srv = (ServiceRecord)msg.obj;
1166 // This needs to be *un*synchronized to avoid deadlock.
1167 Checkin.logEvent(mContext.getContentResolver(),
1168 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1169 srv.name.toShortString());
1170 } break;
1171 case RESUME_TOP_ACTIVITY_MSG: {
1172 synchronized (ActivityManagerService.this) {
1173 resumeTopActivityLocked(null);
1174 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001175 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001177 if (mDidDexOpt) {
1178 mDidDexOpt = false;
1179 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1180 nmsg.obj = msg.obj;
1181 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1182 return;
1183 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 ProcessRecord app = (ProcessRecord)msg.obj;
1185 synchronized (ActivityManagerService.this) {
1186 processStartTimedOutLocked(app);
1187 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001188 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001189 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1190 synchronized (ActivityManagerService.this) {
1191 doPendingActivityLaunchesLocked(true);
1192 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001193 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001194 case KILL_APPLICATION_MSG: {
1195 synchronized (ActivityManagerService.this) {
1196 int uid = msg.arg1;
1197 boolean restart = (msg.arg2 == 1);
1198 String pkg = (String) msg.obj;
1199 uninstallPackageLocked(pkg, uid, restart);
1200 }
1201 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 }
1203 }
1204 };
1205
1206 public static void setSystemProcess() {
1207 try {
1208 ActivityManagerService m = mSelf;
1209
1210 ServiceManager.addService("activity", m);
1211 ServiceManager.addService("meminfo", new MemBinder(m));
1212 if (MONITOR_CPU_USAGE) {
1213 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1214 }
1215 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1216 ServiceManager.addService("activity.services", new ServicesBinder(m));
1217 ServiceManager.addService("activity.senders", new SendersBinder(m));
1218 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1219 ServiceManager.addService("permission", new PermissionController(m));
1220
1221 ApplicationInfo info =
1222 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001223 "android", STOCK_PM_FLAGS);
Mike Cleron432b7132009-09-24 15:28:29 -07001224 mSystemThread.installSystemApplicationInfo(info);
1225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 synchronized (mSelf) {
1227 ProcessRecord app = mSelf.newProcessRecordLocked(
1228 mSystemThread.getApplicationThread(), info,
1229 info.processName);
1230 app.persistent = true;
1231 app.pid = Process.myPid();
1232 app.maxAdj = SYSTEM_ADJ;
1233 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1234 synchronized (mSelf.mPidsSelfLocked) {
1235 mSelf.mPidsSelfLocked.put(app.pid, app);
1236 }
1237 mSelf.updateLRUListLocked(app, true);
1238 }
1239 } catch (PackageManager.NameNotFoundException e) {
1240 throw new RuntimeException(
1241 "Unable to find android system package", e);
1242 }
1243 }
1244
1245 public void setWindowManager(WindowManagerService wm) {
1246 mWindowManager = wm;
1247 }
1248
1249 public static final Context main(int factoryTest) {
1250 AThread thr = new AThread();
1251 thr.start();
1252
1253 synchronized (thr) {
1254 while (thr.mService == null) {
1255 try {
1256 thr.wait();
1257 } catch (InterruptedException e) {
1258 }
1259 }
1260 }
1261
1262 ActivityManagerService m = thr.mService;
1263 mSelf = m;
1264 ActivityThread at = ActivityThread.systemMain();
1265 mSystemThread = at;
1266 Context context = at.getSystemContext();
1267 m.mContext = context;
1268 m.mFactoryTest = factoryTest;
1269 PowerManager pm =
1270 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1271 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1272 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1273 m.mLaunchingActivity.setReferenceCounted(false);
1274
1275 m.mBatteryStatsService.publish(context);
1276 m.mUsageStatsService.publish(context);
1277
1278 synchronized (thr) {
1279 thr.mReady = true;
1280 thr.notifyAll();
1281 }
1282
1283 m.startRunning(null, null, null, null);
1284
1285 return context;
1286 }
1287
1288 public static ActivityManagerService self() {
1289 return mSelf;
1290 }
1291
1292 static class AThread extends Thread {
1293 ActivityManagerService mService;
1294 boolean mReady = false;
1295
1296 public AThread() {
1297 super("ActivityManager");
1298 }
1299
1300 public void run() {
1301 Looper.prepare();
1302
1303 android.os.Process.setThreadPriority(
1304 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1305
1306 ActivityManagerService m = new ActivityManagerService();
1307
1308 synchronized (this) {
1309 mService = m;
1310 notifyAll();
1311 }
1312
1313 synchronized (this) {
1314 while (!mReady) {
1315 try {
1316 wait();
1317 } catch (InterruptedException e) {
1318 }
1319 }
1320 }
1321
1322 Looper.loop();
1323 }
1324 }
1325
1326 static class BroadcastsBinder extends Binder {
1327 ActivityManagerService mActivityManagerService;
1328 BroadcastsBinder(ActivityManagerService activityManagerService) {
1329 mActivityManagerService = activityManagerService;
1330 }
1331
1332 @Override
1333 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1334 mActivityManagerService.dumpBroadcasts(pw);
1335 }
1336 }
1337
1338 static class ServicesBinder extends Binder {
1339 ActivityManagerService mActivityManagerService;
1340 ServicesBinder(ActivityManagerService activityManagerService) {
1341 mActivityManagerService = activityManagerService;
1342 }
1343
1344 @Override
1345 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1346 mActivityManagerService.dumpServices(pw);
1347 }
1348 }
1349
1350 static class SendersBinder extends Binder {
1351 ActivityManagerService mActivityManagerService;
1352 SendersBinder(ActivityManagerService activityManagerService) {
1353 mActivityManagerService = activityManagerService;
1354 }
1355
1356 @Override
1357 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1358 mActivityManagerService.dumpSenders(pw);
1359 }
1360 }
1361
1362 static class ProvidersBinder extends Binder {
1363 ActivityManagerService mActivityManagerService;
1364 ProvidersBinder(ActivityManagerService activityManagerService) {
1365 mActivityManagerService = activityManagerService;
1366 }
1367
1368 @Override
1369 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1370 mActivityManagerService.dumpProviders(pw);
1371 }
1372 }
1373
1374 static class MemBinder extends Binder {
1375 ActivityManagerService mActivityManagerService;
1376 MemBinder(ActivityManagerService activityManagerService) {
1377 mActivityManagerService = activityManagerService;
1378 }
1379
1380 @Override
1381 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1382 ActivityManagerService service = mActivityManagerService;
1383 ArrayList<ProcessRecord> procs;
1384 synchronized (mActivityManagerService) {
1385 if (args != null && args.length > 0
1386 && args[0].charAt(0) != '-') {
1387 procs = new ArrayList<ProcessRecord>();
1388 int pid = -1;
1389 try {
1390 pid = Integer.parseInt(args[0]);
1391 } catch (NumberFormatException e) {
1392
1393 }
1394 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1395 ProcessRecord proc = service.mLRUProcesses.get(i);
1396 if (proc.pid == pid) {
1397 procs.add(proc);
1398 } else if (proc.processName.equals(args[0])) {
1399 procs.add(proc);
1400 }
1401 }
1402 if (procs.size() <= 0) {
1403 pw.println("No process found for: " + args[0]);
1404 return;
1405 }
1406 } else {
1407 procs = service.mLRUProcesses;
1408 }
1409 }
1410 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1411 }
1412 }
1413
1414 static class CpuBinder extends Binder {
1415 ActivityManagerService mActivityManagerService;
1416 CpuBinder(ActivityManagerService activityManagerService) {
1417 mActivityManagerService = activityManagerService;
1418 }
1419
1420 @Override
1421 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1422 synchronized (mActivityManagerService.mProcessStatsThread) {
1423 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1424 }
1425 }
1426 }
1427
1428 private ActivityManagerService() {
1429 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1430 if (v != null && Integer.getInteger(v) != 0) {
1431 mSimpleProcessManagement = true;
1432 }
1433 v = System.getenv("ANDROID_DEBUG_APP");
1434 if (v != null) {
1435 mSimpleProcessManagement = true;
1436 }
1437
1438 MY_PID = Process.myPid();
1439
1440 File dataDir = Environment.getDataDirectory();
1441 File systemDir = new File(dataDir, "system");
1442 systemDir.mkdirs();
1443 mBatteryStatsService = new BatteryStatsService(new File(
1444 systemDir, "batterystats.bin").toString());
1445 mBatteryStatsService.getActiveStatistics().readLocked();
1446 mBatteryStatsService.getActiveStatistics().writeLocked();
1447
1448 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001449 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001450
Jack Palevichb90d28c2009-07-22 15:35:24 -07001451 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1452 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1453
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001454 mConfiguration.makeDefault();
1455 mProcessStats.init();
1456
1457 // Add ourself to the Watchdog monitors.
1458 Watchdog.getInstance().addMonitor(this);
1459
1460 // These values are set in system/rootdir/init.rc on startup.
1461 FOREGROUND_APP_ADJ =
1462 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1463 VISIBLE_APP_ADJ =
1464 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1465 SECONDARY_SERVER_ADJ =
1466 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001467 BACKUP_APP_ADJ =
1468 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001469 HOME_APP_ADJ =
1470 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001471 HIDDEN_APP_MIN_ADJ =
1472 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1473 CONTENT_PROVIDER_ADJ =
1474 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1475 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1476 EMPTY_APP_ADJ =
1477 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1478 FOREGROUND_APP_MEM =
1479 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1480 VISIBLE_APP_MEM =
1481 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1482 SECONDARY_SERVER_MEM =
1483 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001484 BACKUP_APP_MEM =
1485 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001486 HOME_APP_MEM =
1487 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001488 HIDDEN_APP_MEM =
1489 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1490 EMPTY_APP_MEM =
1491 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1492
1493 mProcessStatsThread = new Thread("ProcessStats") {
1494 public void run() {
1495 while (true) {
1496 try {
1497 try {
1498 synchronized(this) {
1499 final long now = SystemClock.uptimeMillis();
1500 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1501 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1502 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1503 // + ", write delay=" + nextWriteDelay);
1504 if (nextWriteDelay < nextCpuDelay) {
1505 nextCpuDelay = nextWriteDelay;
1506 }
1507 if (nextCpuDelay > 0) {
1508 this.wait(nextCpuDelay);
1509 }
1510 }
1511 } catch (InterruptedException e) {
1512 }
1513
1514 updateCpuStatsNow();
1515 } catch (Exception e) {
1516 Log.e(TAG, "Unexpected exception collecting process stats", e);
1517 }
1518 }
1519 }
1520 };
1521 mProcessStatsThread.start();
1522 }
1523
1524 @Override
1525 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1526 throws RemoteException {
1527 try {
1528 return super.onTransact(code, data, reply, flags);
1529 } catch (RuntimeException e) {
1530 // The activity manager only throws security exceptions, so let's
1531 // log all others.
1532 if (!(e instanceof SecurityException)) {
1533 Log.e(TAG, "Activity Manager Crash", e);
1534 }
1535 throw e;
1536 }
1537 }
1538
1539 void updateCpuStats() {
1540 synchronized (mProcessStatsThread) {
1541 final long now = SystemClock.uptimeMillis();
1542 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1543 mProcessStatsThread.notify();
1544 }
1545 }
1546 }
1547
1548 void updateCpuStatsNow() {
1549 synchronized (mProcessStatsThread) {
1550 final long now = SystemClock.uptimeMillis();
1551 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001552
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 if (MONITOR_CPU_USAGE &&
1554 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1555 mLastCpuTime = now;
1556 haveNewCpuStats = true;
1557 mProcessStats.update();
1558 //Log.i(TAG, mProcessStats.printCurrentState());
1559 //Log.i(TAG, "Total CPU usage: "
1560 // + mProcessStats.getTotalCpuPercent() + "%");
1561
1562 // Log the cpu usage if the property is set.
1563 if ("true".equals(SystemProperties.get("events.cpu"))) {
1564 int user = mProcessStats.getLastUserTime();
1565 int system = mProcessStats.getLastSystemTime();
1566 int iowait = mProcessStats.getLastIoWaitTime();
1567 int irq = mProcessStats.getLastIrqTime();
1568 int softIrq = mProcessStats.getLastSoftIrqTime();
1569 int idle = mProcessStats.getLastIdleTime();
1570
1571 int total = user + system + iowait + irq + softIrq + idle;
1572 if (total == 0) total = 1;
1573
1574 EventLog.writeEvent(LOG_CPU,
1575 ((user+system+iowait+irq+softIrq) * 100) / total,
1576 (user * 100) / total,
1577 (system * 100) / total,
1578 (iowait * 100) / total,
1579 (irq * 100) / total,
1580 (softIrq * 100) / total);
1581 }
1582 }
1583
Amith Yamasanie43530a2009-08-21 13:11:37 -07001584 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001585 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001586 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001587 synchronized(mPidsSelfLocked) {
1588 if (haveNewCpuStats) {
1589 if (mBatteryStatsService.isOnBattery()) {
1590 final int N = mProcessStats.countWorkingStats();
1591 for (int i=0; i<N; i++) {
1592 ProcessStats.Stats st
1593 = mProcessStats.getWorkingStats(i);
1594 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1595 if (pr != null) {
1596 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1597 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001598 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001599 } else {
1600 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001601 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001602 if (ps != null) {
1603 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001604 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001605 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001606 }
1607 }
1608 }
1609 }
1610 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001612 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1613 mLastWriteTime = now;
1614 mBatteryStatsService.getActiveStatistics().writeLocked();
1615 }
1616 }
1617 }
1618 }
1619
1620 /**
1621 * Initialize the application bind args. These are passed to each
1622 * process when the bindApplication() IPC is sent to the process. They're
1623 * lazily setup to make sure the services are running when they're asked for.
1624 */
1625 private HashMap<String, IBinder> getCommonServicesLocked() {
1626 if (mAppBindArgs == null) {
1627 mAppBindArgs = new HashMap<String, IBinder>();
1628
1629 // Setup the application init args
1630 mAppBindArgs.put("package", ServiceManager.getService("package"));
1631 mAppBindArgs.put("window", ServiceManager.getService("window"));
1632 mAppBindArgs.put(Context.ALARM_SERVICE,
1633 ServiceManager.getService(Context.ALARM_SERVICE));
1634 }
1635 return mAppBindArgs;
1636 }
1637
1638 private final void setFocusedActivityLocked(HistoryRecord r) {
1639 if (mFocusedActivity != r) {
1640 mFocusedActivity = r;
1641 mWindowManager.setFocusedApp(r, true);
1642 }
1643 }
1644
1645 private final void updateLRUListLocked(ProcessRecord app,
1646 boolean oomAdj) {
1647 // put it on the LRU to keep track of when it should be exited.
1648 int lrui = mLRUProcesses.indexOf(app);
1649 if (lrui >= 0) mLRUProcesses.remove(lrui);
1650 mLRUProcesses.add(app);
1651 //Log.i(TAG, "Putting proc to front: " + app.processName);
1652 if (oomAdj) {
1653 updateOomAdjLocked();
1654 }
1655 }
1656
1657 private final boolean updateLRUListLocked(HistoryRecord r) {
1658 final boolean hadit = mLRUActivities.remove(r);
1659 mLRUActivities.add(r);
1660 return hadit;
1661 }
1662
1663 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1664 int i = mHistory.size()-1;
1665 while (i >= 0) {
1666 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1667 if (!r.finishing && r != notTop) {
1668 return r;
1669 }
1670 i--;
1671 }
1672 return null;
1673 }
1674
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001675 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1676 int i = mHistory.size()-1;
1677 while (i >= 0) {
1678 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1679 if (!r.finishing && !r.delayedResume && r != notTop) {
1680 return r;
1681 }
1682 i--;
1683 }
1684 return null;
1685 }
1686
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001687 /**
1688 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001689 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 *
1691 * @param token If non-null, any history records matching this token will be skipped.
1692 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1693 *
1694 * @return Returns the HistoryRecord of the next activity on the stack.
1695 */
1696 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1697 int i = mHistory.size()-1;
1698 while (i >= 0) {
1699 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1700 // Note: the taskId check depends on real taskId fields being non-zero
1701 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1702 return r;
1703 }
1704 i--;
1705 }
1706 return null;
1707 }
1708
1709 private final ProcessRecord getProcessRecordLocked(
1710 String processName, int uid) {
1711 if (uid == Process.SYSTEM_UID) {
1712 // The system gets to run in any process. If there are multiple
1713 // processes with the same uid, just pick the first (this
1714 // should never happen).
1715 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1716 processName);
1717 return procs != null ? procs.valueAt(0) : null;
1718 }
1719 ProcessRecord proc = mProcessNames.get(processName, uid);
1720 return proc;
1721 }
1722
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001723 private void ensurePackageDexOpt(String packageName) {
1724 IPackageManager pm = ActivityThread.getPackageManager();
1725 try {
1726 if (pm.performDexOpt(packageName)) {
1727 mDidDexOpt = true;
1728 }
1729 } catch (RemoteException e) {
1730 }
1731 }
1732
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001733 private boolean isNextTransitionForward() {
1734 int transit = mWindowManager.getPendingAppTransition();
1735 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1736 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1737 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1738 }
1739
1740 private final boolean realStartActivityLocked(HistoryRecord r,
1741 ProcessRecord app, boolean andResume, boolean checkConfig)
1742 throws RemoteException {
1743
1744 r.startFreezingScreenLocked(app, 0);
1745 mWindowManager.setAppVisibility(r, true);
1746
1747 // Have the window manager re-evaluate the orientation of
1748 // the screen based on the new activity order. Note that
1749 // as a result of this, it can call back into the activity
1750 // manager with a new orientation. We don't care about that,
1751 // because the activity is not currently running so we are
1752 // just restarting it anyway.
1753 if (checkConfig) {
1754 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001755 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001756 r.mayFreezeScreenLocked(app) ? r : null);
1757 updateConfigurationLocked(config, r);
1758 }
1759
1760 r.app = app;
1761
1762 if (localLOGV) Log.v(TAG, "Launching: " + r);
1763
1764 int idx = app.activities.indexOf(r);
1765 if (idx < 0) {
1766 app.activities.add(r);
1767 }
1768 updateLRUListLocked(app, true);
1769
1770 try {
1771 if (app.thread == null) {
1772 throw new RemoteException();
1773 }
1774 List<ResultInfo> results = null;
1775 List<Intent> newIntents = null;
1776 if (andResume) {
1777 results = r.results;
1778 newIntents = r.newIntents;
1779 }
1780 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1781 + " icicle=" + r.icicle
1782 + " with results=" + results + " newIntents=" + newIntents
1783 + " andResume=" + andResume);
1784 if (andResume) {
1785 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1786 System.identityHashCode(r),
1787 r.task.taskId, r.shortComponentName);
1788 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001789 if (r.isHomeActivity) {
1790 mHomeProcess = app;
1791 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001792 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001793 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001794 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001795 r.info, r.icicle, results, newIntents, !andResume,
1796 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001797 } catch (RemoteException e) {
1798 if (r.launchFailed) {
1799 // This is the second time we failed -- finish activity
1800 // and give up.
1801 Log.e(TAG, "Second failure launching "
1802 + r.intent.getComponent().flattenToShortString()
1803 + ", giving up", e);
1804 appDiedLocked(app, app.pid, app.thread);
1805 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1806 "2nd-crash");
1807 return false;
1808 }
1809
1810 // This is the first time we failed -- restart process and
1811 // retry.
1812 app.activities.remove(r);
1813 throw e;
1814 }
1815
1816 r.launchFailed = false;
1817 if (updateLRUListLocked(r)) {
1818 Log.w(TAG, "Activity " + r
1819 + " being launched, but already in LRU list");
1820 }
1821
1822 if (andResume) {
1823 // As part of the process of launching, ActivityThread also performs
1824 // a resume.
1825 r.state = ActivityState.RESUMED;
1826 r.icicle = null;
1827 r.haveState = false;
1828 r.stopped = false;
1829 mResumedActivity = r;
1830 r.task.touchActiveTime();
1831 completeResumeLocked(r);
1832 pauseIfSleepingLocked();
1833 } else {
1834 // This activity is not starting in the resumed state... which
1835 // should look like we asked it to pause+stop (but remain visible),
1836 // and it has done so and reported back the current icicle and
1837 // other state.
1838 r.state = ActivityState.STOPPED;
1839 r.stopped = true;
1840 }
1841
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001842 // Launch the new version setup screen if needed. We do this -after-
1843 // launching the initial activity (that is, home), so that it can have
1844 // a chance to initialize itself while in the background, making the
1845 // switch back to it faster and look better.
1846 startSetupActivityLocked();
1847
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001848 return true;
1849 }
1850
1851 private final void startSpecificActivityLocked(HistoryRecord r,
1852 boolean andResume, boolean checkConfig) {
1853 // Is this activity's application already running?
1854 ProcessRecord app = getProcessRecordLocked(r.processName,
1855 r.info.applicationInfo.uid);
1856
1857 if (r.startTime == 0) {
1858 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001859 if (mInitialStartTime == 0) {
1860 mInitialStartTime = r.startTime;
1861 }
1862 } else if (mInitialStartTime == 0) {
1863 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001864 }
1865
1866 if (app != null && app.thread != null) {
1867 try {
1868 realStartActivityLocked(r, app, andResume, checkConfig);
1869 return;
1870 } catch (RemoteException e) {
1871 Log.w(TAG, "Exception when starting activity "
1872 + r.intent.getComponent().flattenToShortString(), e);
1873 }
1874
1875 // If a dead object exception was thrown -- fall through to
1876 // restart the application.
1877 }
1878
1879 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001880 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001881 }
1882
1883 private final ProcessRecord startProcessLocked(String processName,
1884 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001885 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001886 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1887 // We don't have to do anything more if:
1888 // (1) There is an existing application record; and
1889 // (2) The caller doesn't think it is dead, OR there is no thread
1890 // object attached to it so we know it couldn't have crashed; and
1891 // (3) There is a pid assigned to it, so it is either starting or
1892 // already running.
1893 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1894 + " app=" + app + " knownToBeDead=" + knownToBeDead
1895 + " thread=" + (app != null ? app.thread : null)
1896 + " pid=" + (app != null ? app.pid : -1));
1897 if (app != null &&
1898 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1899 return app;
1900 }
1901
1902 String hostingNameStr = hostingName != null
1903 ? hostingName.flattenToShortString() : null;
1904
1905 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1906 // If we are in the background, then check to see if this process
1907 // is bad. If so, we will just silently fail.
1908 if (mBadProcesses.get(info.processName, info.uid) != null) {
1909 return null;
1910 }
1911 } else {
1912 // When the user is explicitly starting a process, then clear its
1913 // crash count so that we won't make it bad until they see at
1914 // least one crash dialog again, and make the process good again
1915 // if it had been bad.
1916 mProcessCrashTimes.remove(info.processName, info.uid);
1917 if (mBadProcesses.get(info.processName, info.uid) != null) {
1918 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1919 info.processName);
1920 mBadProcesses.remove(info.processName, info.uid);
1921 if (app != null) {
1922 app.bad = false;
1923 }
1924 }
1925 }
1926
1927 if (app == null) {
1928 app = newProcessRecordLocked(null, info, processName);
1929 mProcessNames.put(processName, info.uid, app);
1930 } else {
1931 // If this is a new package in the process, add the package to the list
1932 app.addPackage(info.packageName);
1933 }
1934
1935 // If the system is not ready yet, then hold off on starting this
1936 // process until it is.
1937 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001938 && !isAllowedWhileBooting(info)
1939 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001940 if (!mProcessesOnHold.contains(app)) {
1941 mProcessesOnHold.add(app);
1942 }
1943 return app;
1944 }
1945
1946 startProcessLocked(app, hostingType, hostingNameStr);
1947 return (app.pid != 0) ? app : null;
1948 }
1949
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001950 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1951 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1952 }
1953
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001954 private final void startProcessLocked(ProcessRecord app,
1955 String hostingType, String hostingNameStr) {
1956 if (app.pid > 0 && app.pid != MY_PID) {
1957 synchronized (mPidsSelfLocked) {
1958 mPidsSelfLocked.remove(app.pid);
1959 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1960 }
1961 app.pid = 0;
1962 }
1963
1964 mProcessesOnHold.remove(app);
1965
1966 updateCpuStats();
1967
1968 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1969 mProcDeaths[0] = 0;
1970
1971 try {
1972 int uid = app.info.uid;
1973 int[] gids = null;
1974 try {
1975 gids = mContext.getPackageManager().getPackageGids(
1976 app.info.packageName);
1977 } catch (PackageManager.NameNotFoundException e) {
1978 Log.w(TAG, "Unable to retrieve gids", e);
1979 }
1980 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1981 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1982 && mTopComponent != null
1983 && app.processName.equals(mTopComponent.getPackageName())) {
1984 uid = 0;
1985 }
1986 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1987 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1988 uid = 0;
1989 }
1990 }
1991 int debugFlags = 0;
1992 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1993 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1994 }
1995 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1996 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1997 }
1998 if ("1".equals(SystemProperties.get("debug.assert"))) {
1999 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
2000 }
2001 int pid = Process.start("android.app.ActivityThread",
2002 mSimpleProcessManagement ? app.processName : null, uid, uid,
2003 gids, debugFlags, null);
2004 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
2005 synchronized (bs) {
2006 if (bs.isOnBattery()) {
2007 app.batteryStats.incStartsLocked();
2008 }
2009 }
2010
2011 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
2012 app.processName, hostingType,
2013 hostingNameStr != null ? hostingNameStr : "");
2014
2015 if (app.persistent) {
2016 Watchdog.getInstance().processStarted(app, app.processName, pid);
2017 }
2018
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07002019 StringBuilder buf = mStringBuilder;
2020 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002021 buf.append("Start proc ");
2022 buf.append(app.processName);
2023 buf.append(" for ");
2024 buf.append(hostingType);
2025 if (hostingNameStr != null) {
2026 buf.append(" ");
2027 buf.append(hostingNameStr);
2028 }
2029 buf.append(": pid=");
2030 buf.append(pid);
2031 buf.append(" uid=");
2032 buf.append(uid);
2033 buf.append(" gids={");
2034 if (gids != null) {
2035 for (int gi=0; gi<gids.length; gi++) {
2036 if (gi != 0) buf.append(", ");
2037 buf.append(gids[gi]);
2038
2039 }
2040 }
2041 buf.append("}");
2042 Log.i(TAG, buf.toString());
2043 if (pid == 0 || pid == MY_PID) {
2044 // Processes are being emulated with threads.
2045 app.pid = MY_PID;
2046 app.removed = false;
2047 mStartingProcesses.add(app);
2048 } else if (pid > 0) {
2049 app.pid = pid;
2050 app.removed = false;
2051 synchronized (mPidsSelfLocked) {
2052 this.mPidsSelfLocked.put(pid, app);
2053 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2054 msg.obj = app;
2055 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2056 }
2057 } else {
2058 app.pid = 0;
2059 RuntimeException e = new RuntimeException(
2060 "Failure starting process " + app.processName
2061 + ": returned pid=" + pid);
2062 Log.e(TAG, e.getMessage(), e);
2063 }
2064 } catch (RuntimeException e) {
2065 // XXX do better error recovery.
2066 app.pid = 0;
2067 Log.e(TAG, "Failure starting process " + app.processName, e);
2068 }
2069 }
2070
2071 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2072 if (mPausingActivity != null) {
2073 RuntimeException e = new RuntimeException();
2074 Log.e(TAG, "Trying to pause when pause is already pending for "
2075 + mPausingActivity, e);
2076 }
2077 HistoryRecord prev = mResumedActivity;
2078 if (prev == null) {
2079 RuntimeException e = new RuntimeException();
2080 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2081 resumeTopActivityLocked(null);
2082 return;
2083 }
2084 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2085 mResumedActivity = null;
2086 mPausingActivity = prev;
2087 mLastPausedActivity = prev;
2088 prev.state = ActivityState.PAUSING;
2089 prev.task.touchActiveTime();
2090
2091 updateCpuStats();
2092
2093 if (prev.app != null && prev.app.thread != null) {
2094 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2095 try {
2096 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2097 System.identityHashCode(prev),
2098 prev.shortComponentName);
2099 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2100 prev.configChangeFlags);
2101 updateUsageStats(prev, false);
2102 } catch (Exception e) {
2103 // Ignore exception, if process died other code will cleanup.
2104 Log.w(TAG, "Exception thrown during pause", e);
2105 mPausingActivity = null;
2106 mLastPausedActivity = null;
2107 }
2108 } else {
2109 mPausingActivity = null;
2110 mLastPausedActivity = null;
2111 }
2112
2113 // If we are not going to sleep, we want to ensure the device is
2114 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002115 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002116 mLaunchingActivity.acquire();
2117 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2118 // To be safe, don't allow the wake lock to be held for too long.
2119 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2120 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2121 }
2122 }
2123
2124
2125 if (mPausingActivity != null) {
2126 // Have the window manager pause its key dispatching until the new
2127 // activity has started. If we're pausing the activity just because
2128 // the screen is being turned off and the UI is sleeping, don't interrupt
2129 // key dispatch; the same activity will pick it up again on wakeup.
2130 if (!uiSleeping) {
2131 prev.pauseKeyDispatchingLocked();
2132 } else {
2133 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2134 }
2135
2136 // Schedule a pause timeout in case the app doesn't respond.
2137 // We don't give it much time because this directly impacts the
2138 // responsiveness seen by the user.
2139 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2140 msg.obj = prev;
2141 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2142 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2143 } else {
2144 // This activity failed to schedule the
2145 // pause, so just treat it as being paused now.
2146 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2147 resumeTopActivityLocked(null);
2148 }
2149 }
2150
2151 private final void completePauseLocked() {
2152 HistoryRecord prev = mPausingActivity;
2153 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2154
2155 if (prev != null) {
2156 if (prev.finishing) {
2157 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2158 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2159 } else if (prev.app != null) {
2160 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2161 if (prev.waitingVisible) {
2162 prev.waitingVisible = false;
2163 mWaitingVisibleActivities.remove(prev);
2164 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2165 TAG, "Complete pause, no longer waiting: " + prev);
2166 }
2167 if (prev.configDestroy) {
2168 // The previous is being paused because the configuration
2169 // is changing, which means it is actually stopping...
2170 // To juggle the fact that we are also starting a new
2171 // instance right now, we need to first completely stop
2172 // the current instance before starting the new one.
2173 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2174 destroyActivityLocked(prev, true);
2175 } else {
2176 mStoppingActivities.add(prev);
2177 if (mStoppingActivities.size() > 3) {
2178 // If we already have a few activities waiting to stop,
2179 // then give up on things going idle and start clearing
2180 // them out.
2181 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2182 Message msg = Message.obtain();
2183 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2184 mHandler.sendMessage(msg);
2185 }
2186 }
2187 } else {
2188 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2189 prev = null;
2190 }
2191 mPausingActivity = null;
2192 }
2193
Dianne Hackborn55280a92009-05-07 15:53:46 -07002194 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002195 resumeTopActivityLocked(prev);
2196 } else {
2197 if (mGoingToSleep.isHeld()) {
2198 mGoingToSleep.release();
2199 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002200 if (mShuttingDown) {
2201 notifyAll();
2202 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002203 }
2204
2205 if (prev != null) {
2206 prev.resumeKeyDispatchingLocked();
2207 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002208
2209 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2210 long diff = 0;
2211 synchronized (mProcessStatsThread) {
2212 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2213 }
2214 if (diff > 0) {
2215 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2216 synchronized (bsi) {
2217 BatteryStatsImpl.Uid.Proc ps =
2218 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2219 prev.info.packageName);
2220 if (ps != null) {
2221 ps.addForegroundTimeLocked(diff);
2222 }
2223 }
2224 }
2225 }
2226 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002227 }
2228
2229 /**
2230 * Once we know that we have asked an application to put an activity in
2231 * the resumed state (either by launching it or explicitly telling it),
2232 * this function updates the rest of our state to match that fact.
2233 */
2234 private final void completeResumeLocked(HistoryRecord next) {
2235 next.idle = false;
2236 next.results = null;
2237 next.newIntents = null;
2238
2239 // schedule an idle timeout in case the app doesn't do it for us.
2240 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2241 msg.obj = next;
2242 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2243
2244 if (false) {
2245 // The activity was never told to pause, so just keep
2246 // things going as-is. To maintain our own state,
2247 // we need to emulate it coming back and saying it is
2248 // idle.
2249 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2250 msg.obj = next;
2251 mHandler.sendMessage(msg);
2252 }
2253
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002254 reportResumedActivity(next);
2255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002256 next.thumbnail = null;
2257 setFocusedActivityLocked(next);
2258 next.resumeKeyDispatchingLocked();
2259 ensureActivitiesVisibleLocked(null, 0);
2260 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002261 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002262
2263 // Mark the point when the activity is resuming
2264 // TODO: To be more accurate, the mark should be before the onCreate,
2265 // not after the onResume. But for subsequent starts, onResume is fine.
2266 if (next.app != null) {
2267 synchronized (mProcessStatsThread) {
2268 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2269 }
2270 } else {
2271 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2272 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002273 }
2274
2275 /**
2276 * Make sure that all activities that need to be visible (that is, they
2277 * currently can be seen by the user) actually are.
2278 */
2279 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2280 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2281 if (DEBUG_VISBILITY) Log.v(
2282 TAG, "ensureActivitiesVisible behind " + top
2283 + " configChanges=0x" + Integer.toHexString(configChanges));
2284
2285 // If the top activity is not fullscreen, then we need to
2286 // make sure any activities under it are now visible.
2287 final int count = mHistory.size();
2288 int i = count-1;
2289 while (mHistory.get(i) != top) {
2290 i--;
2291 }
2292 HistoryRecord r;
2293 boolean behindFullscreen = false;
2294 for (; i>=0; i--) {
2295 r = (HistoryRecord)mHistory.get(i);
2296 if (DEBUG_VISBILITY) Log.v(
2297 TAG, "Make visible? " + r + " finishing=" + r.finishing
2298 + " state=" + r.state);
2299 if (r.finishing) {
2300 continue;
2301 }
2302
2303 final boolean doThisProcess = onlyThisProcess == null
2304 || onlyThisProcess.equals(r.processName);
2305
2306 // First: if this is not the current activity being started, make
2307 // sure it matches the current configuration.
2308 if (r != starting && doThisProcess) {
2309 ensureActivityConfigurationLocked(r, 0);
2310 }
2311
2312 if (r.app == null || r.app.thread == null) {
2313 if (onlyThisProcess == null
2314 || onlyThisProcess.equals(r.processName)) {
2315 // This activity needs to be visible, but isn't even
2316 // running... get it started, but don't resume it
2317 // at this point.
2318 if (DEBUG_VISBILITY) Log.v(
2319 TAG, "Start and freeze screen for " + r);
2320 if (r != starting) {
2321 r.startFreezingScreenLocked(r.app, configChanges);
2322 }
2323 if (!r.visible) {
2324 if (DEBUG_VISBILITY) Log.v(
2325 TAG, "Starting and making visible: " + r);
2326 mWindowManager.setAppVisibility(r, true);
2327 }
2328 if (r != starting) {
2329 startSpecificActivityLocked(r, false, false);
2330 }
2331 }
2332
2333 } else if (r.visible) {
2334 // If this activity is already visible, then there is nothing
2335 // else to do here.
2336 if (DEBUG_VISBILITY) Log.v(
2337 TAG, "Skipping: already visible at " + r);
2338 r.stopFreezingScreenLocked(false);
2339
2340 } else if (onlyThisProcess == null) {
2341 // This activity is not currently visible, but is running.
2342 // Tell it to become visible.
2343 r.visible = true;
2344 if (r.state != ActivityState.RESUMED && r != starting) {
2345 // If this activity is paused, tell it
2346 // to now show its window.
2347 if (DEBUG_VISBILITY) Log.v(
2348 TAG, "Making visible and scheduling visibility: " + r);
2349 try {
2350 mWindowManager.setAppVisibility(r, true);
2351 r.app.thread.scheduleWindowVisibility(r, true);
2352 r.stopFreezingScreenLocked(false);
2353 } catch (Exception e) {
2354 // Just skip on any failure; we'll make it
2355 // visible when it next restarts.
2356 Log.w(TAG, "Exception thrown making visibile: "
2357 + r.intent.getComponent(), e);
2358 }
2359 }
2360 }
2361
2362 // Aggregate current change flags.
2363 configChanges |= r.configChangeFlags;
2364
2365 if (r.fullscreen) {
2366 // At this point, nothing else needs to be shown
2367 if (DEBUG_VISBILITY) Log.v(
2368 TAG, "Stopping: fullscreen at " + r);
2369 behindFullscreen = true;
2370 i--;
2371 break;
2372 }
2373 }
2374
2375 // Now for any activities that aren't visible to the user, make
2376 // sure they no longer are keeping the screen frozen.
2377 while (i >= 0) {
2378 r = (HistoryRecord)mHistory.get(i);
2379 if (DEBUG_VISBILITY) Log.v(
2380 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2381 + " state=" + r.state
2382 + " behindFullscreen=" + behindFullscreen);
2383 if (!r.finishing) {
2384 if (behindFullscreen) {
2385 if (r.visible) {
2386 if (DEBUG_VISBILITY) Log.v(
2387 TAG, "Making invisible: " + r);
2388 r.visible = false;
2389 try {
2390 mWindowManager.setAppVisibility(r, false);
2391 if ((r.state == ActivityState.STOPPING
2392 || r.state == ActivityState.STOPPED)
2393 && r.app != null && r.app.thread != null) {
2394 if (DEBUG_VISBILITY) Log.v(
2395 TAG, "Scheduling invisibility: " + r);
2396 r.app.thread.scheduleWindowVisibility(r, false);
2397 }
2398 } catch (Exception e) {
2399 // Just skip on any failure; we'll make it
2400 // visible when it next restarts.
2401 Log.w(TAG, "Exception thrown making hidden: "
2402 + r.intent.getComponent(), e);
2403 }
2404 } else {
2405 if (DEBUG_VISBILITY) Log.v(
2406 TAG, "Already invisible: " + r);
2407 }
2408 } else if (r.fullscreen) {
2409 if (DEBUG_VISBILITY) Log.v(
2410 TAG, "Now behindFullscreen: " + r);
2411 behindFullscreen = true;
2412 }
2413 }
2414 i--;
2415 }
2416 }
2417
2418 /**
2419 * Version of ensureActivitiesVisible that can easily be called anywhere.
2420 */
2421 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2422 int configChanges) {
2423 HistoryRecord r = topRunningActivityLocked(null);
2424 if (r != null) {
2425 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2426 }
2427 }
2428
2429 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2430 if (resumed) {
2431 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2432 } else {
2433 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2434 }
2435 }
2436
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002437 private boolean startHomeActivityLocked() {
2438 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2439 && mTopAction == null) {
2440 // We are running in factory test mode, but unable to find
2441 // the factory test app, so just sit around displaying the
2442 // error message and don't try to start anything.
2443 return false;
2444 }
2445 Intent intent = new Intent(
2446 mTopAction,
2447 mTopData != null ? Uri.parse(mTopData) : null);
2448 intent.setComponent(mTopComponent);
2449 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2450 intent.addCategory(Intent.CATEGORY_HOME);
2451 }
2452 ActivityInfo aInfo =
2453 intent.resolveActivityInfo(mContext.getPackageManager(),
2454 STOCK_PM_FLAGS);
2455 if (aInfo != null) {
2456 intent.setComponent(new ComponentName(
2457 aInfo.applicationInfo.packageName, aInfo.name));
2458 // Don't do this if the home app is currently being
2459 // instrumented.
2460 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2461 aInfo.applicationInfo.uid);
2462 if (app == null || app.instrumentationClass == null) {
2463 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2464 startActivityLocked(null, intent, null, null, 0, aInfo,
2465 null, null, 0, 0, 0, false, false);
2466 }
2467 }
2468
2469
2470 return true;
2471 }
2472
2473 /**
2474 * Starts the "new version setup screen" if appropriate.
2475 */
2476 private void startSetupActivityLocked() {
2477 // Only do this once per boot.
2478 if (mCheckedForSetup) {
2479 return;
2480 }
2481
2482 // We will show this screen if the current one is a different
2483 // version than the last one shown, and we are not running in
2484 // low-level factory test mode.
2485 final ContentResolver resolver = mContext.getContentResolver();
2486 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2487 Settings.Secure.getInt(resolver,
2488 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2489 mCheckedForSetup = true;
2490
2491 // See if we should be showing the platform update setup UI.
2492 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2493 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2494 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2495
2496 // We don't allow third party apps to replace this.
2497 ResolveInfo ri = null;
2498 for (int i=0; ris != null && i<ris.size(); i++) {
2499 if ((ris.get(i).activityInfo.applicationInfo.flags
2500 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2501 ri = ris.get(i);
2502 break;
2503 }
2504 }
2505
2506 if (ri != null) {
2507 String vers = ri.activityInfo.metaData != null
2508 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2509 : null;
2510 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2511 vers = ri.activityInfo.applicationInfo.metaData.getString(
2512 Intent.METADATA_SETUP_VERSION);
2513 }
2514 String lastVers = Settings.Secure.getString(
2515 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2516 if (vers != null && !vers.equals(lastVers)) {
2517 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2518 intent.setComponent(new ComponentName(
2519 ri.activityInfo.packageName, ri.activityInfo.name));
2520 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2521 null, null, 0, 0, 0, false, false);
2522 }
2523 }
2524 }
2525 }
2526
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002527 private void reportResumedActivity(HistoryRecord r) {
2528 //Log.i(TAG, "**** REPORT RESUME: " + r);
2529
2530 final int identHash = System.identityHashCode(r);
2531 updateUsageStats(r, true);
2532
2533 int i = mWatchers.beginBroadcast();
2534 while (i > 0) {
2535 i--;
2536 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2537 if (w != null) {
2538 try {
2539 w.activityResuming(identHash);
2540 } catch (RemoteException e) {
2541 }
2542 }
2543 }
2544 mWatchers.finishBroadcast();
2545 }
2546
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002547 /**
2548 * Ensure that the top activity in the stack is resumed.
2549 *
2550 * @param prev The previously resumed activity, for when in the process
2551 * of pausing; can be null to call from elsewhere.
2552 *
2553 * @return Returns true if something is being resumed, or false if
2554 * nothing happened.
2555 */
2556 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2557 // Find the first activity that is not finishing.
2558 HistoryRecord next = topRunningActivityLocked(null);
2559
2560 // Remember how we'll process this pause/resume situation, and ensure
2561 // that the state is reset however we wind up proceeding.
2562 final boolean userLeaving = mUserLeaving;
2563 mUserLeaving = false;
2564
2565 if (next == null) {
2566 // There are no more activities! Let's just start up the
2567 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002568 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002569 }
2570
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002571 next.delayedResume = false;
2572
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002573 // If the top activity is the resumed one, nothing to do.
2574 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2575 // Make sure we have executed any pending transitions, since there
2576 // should be nothing left to do at this point.
2577 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002578 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002579 return false;
2580 }
2581
2582 // If we are sleeping, and there is no resumed activity, and the top
2583 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002584 if ((mSleeping || mShuttingDown)
2585 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002586 // Make sure we have executed any pending transitions, since there
2587 // should be nothing left to do at this point.
2588 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002589 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002590 return false;
2591 }
2592
2593 // The activity may be waiting for stop, but that is no longer
2594 // appropriate for it.
2595 mStoppingActivities.remove(next);
2596 mWaitingVisibleActivities.remove(next);
2597
2598 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2599
2600 // If we are currently pausing an activity, then don't do anything
2601 // until that is done.
2602 if (mPausingActivity != null) {
2603 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2604 return false;
2605 }
2606
2607 // We need to start pausing the current activity so the top one
2608 // can be resumed...
2609 if (mResumedActivity != null) {
2610 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2611 startPausingLocked(userLeaving, false);
2612 return true;
2613 }
2614
2615 if (prev != null && prev != next) {
2616 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2617 prev.waitingVisible = true;
2618 mWaitingVisibleActivities.add(prev);
2619 if (DEBUG_SWITCH) Log.v(
2620 TAG, "Resuming top, waiting visible to hide: " + prev);
2621 } else {
2622 // The next activity is already visible, so hide the previous
2623 // activity's windows right now so we can show the new one ASAP.
2624 // We only do this if the previous is finishing, which should mean
2625 // it is on top of the one being resumed so hiding it quickly
2626 // is good. Otherwise, we want to do the normal route of allowing
2627 // the resumed activity to be shown so we can decide if the
2628 // previous should actually be hidden depending on whether the
2629 // new one is found to be full-screen or not.
2630 if (prev.finishing) {
2631 mWindowManager.setAppVisibility(prev, false);
2632 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2633 + prev + ", waitingVisible="
2634 + (prev != null ? prev.waitingVisible : null)
2635 + ", nowVisible=" + next.nowVisible);
2636 } else {
2637 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2638 + prev + ", waitingVisible="
2639 + (prev != null ? prev.waitingVisible : null)
2640 + ", nowVisible=" + next.nowVisible);
2641 }
2642 }
2643 }
2644
2645 // We are starting up the next activity, so tell the window manager
2646 // that the previous one will be hidden soon. This way it can know
2647 // to ignore it when computing the desired screen orientation.
2648 if (prev != null) {
2649 if (prev.finishing) {
2650 if (DEBUG_TRANSITION) Log.v(TAG,
2651 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002652 if (mNoAnimActivities.contains(prev)) {
2653 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2654 } else {
2655 mWindowManager.prepareAppTransition(prev.task == next.task
2656 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2657 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2658 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002659 mWindowManager.setAppWillBeHidden(prev);
2660 mWindowManager.setAppVisibility(prev, false);
2661 } else {
2662 if (DEBUG_TRANSITION) Log.v(TAG,
2663 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002664 if (mNoAnimActivities.contains(next)) {
2665 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2666 } else {
2667 mWindowManager.prepareAppTransition(prev.task == next.task
2668 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2669 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2670 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002671 }
2672 if (false) {
2673 mWindowManager.setAppWillBeHidden(prev);
2674 mWindowManager.setAppVisibility(prev, false);
2675 }
2676 } else if (mHistory.size() > 1) {
2677 if (DEBUG_TRANSITION) Log.v(TAG,
2678 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002679 if (mNoAnimActivities.contains(next)) {
2680 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2681 } else {
2682 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2683 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002684 }
2685
2686 if (next.app != null && next.app.thread != null) {
2687 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2688
2689 // This activity is now becoming visible.
2690 mWindowManager.setAppVisibility(next, true);
2691
2692 HistoryRecord lastResumedActivity = mResumedActivity;
2693 ActivityState lastState = next.state;
2694
2695 updateCpuStats();
2696
2697 next.state = ActivityState.RESUMED;
2698 mResumedActivity = next;
2699 next.task.touchActiveTime();
2700 updateLRUListLocked(next.app, true);
2701 updateLRUListLocked(next);
2702
2703 // Have the window manager re-evaluate the orientation of
2704 // the screen based on the new activity order.
2705 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002706 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002707 next.mayFreezeScreenLocked(next.app) ? next : null);
2708 if (config != null) {
2709 next.frozenBeforeDestroy = true;
2710 }
2711 if (!updateConfigurationLocked(config, next)) {
2712 // The configuration update wasn't able to keep the existing
2713 // instance of the activity, and instead started a new one.
2714 // We should be all done, but let's just make sure our activity
2715 // is still at the top and schedule another run if something
2716 // weird happened.
2717 HistoryRecord nextNext = topRunningActivityLocked(null);
2718 if (DEBUG_SWITCH) Log.i(TAG,
2719 "Activity config changed during resume: " + next
2720 + ", new next: " + nextNext);
2721 if (nextNext != next) {
2722 // Do over!
2723 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2724 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002725 setFocusedActivityLocked(next);
2726 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002727 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002728 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002729 return true;
2730 }
2731
2732 try {
2733 // Deliver all pending results.
2734 ArrayList a = next.results;
2735 if (a != null) {
2736 final int N = a.size();
2737 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002738 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002739 TAG, "Delivering results to " + next
2740 + ": " + a);
2741 next.app.thread.scheduleSendResult(next, a);
2742 }
2743 }
2744
2745 if (next.newIntents != null) {
2746 next.app.thread.scheduleNewIntent(next.newIntents, next);
2747 }
2748
2749 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2750 System.identityHashCode(next),
2751 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002752
2753 next.app.thread.scheduleResumeActivity(next,
2754 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002755
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002756 pauseIfSleepingLocked();
2757
2758 } catch (Exception e) {
2759 // Whoops, need to restart this activity!
2760 next.state = lastState;
2761 mResumedActivity = lastResumedActivity;
2762 if (Config.LOGD) Log.d(TAG,
2763 "Restarting because process died: " + next);
2764 if (!next.hasBeenLaunched) {
2765 next.hasBeenLaunched = true;
2766 } else {
2767 if (SHOW_APP_STARTING_ICON) {
2768 mWindowManager.setAppStartingWindow(
2769 next, next.packageName, next.theme,
2770 next.nonLocalizedLabel,
2771 next.labelRes, next.icon, null, true);
2772 }
2773 }
2774 startSpecificActivityLocked(next, true, false);
2775 return true;
2776 }
2777
2778 // From this point on, if something goes wrong there is no way
2779 // to recover the activity.
2780 try {
2781 next.visible = true;
2782 completeResumeLocked(next);
2783 } catch (Exception e) {
2784 // If any exception gets thrown, toss away this
2785 // activity and try the next one.
2786 Log.w(TAG, "Exception thrown during resume of " + next, e);
2787 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2788 "resume-exception");
2789 return true;
2790 }
2791
2792 // Didn't need to use the icicle, and it is now out of date.
2793 next.icicle = null;
2794 next.haveState = false;
2795 next.stopped = false;
2796
2797 } else {
2798 // Whoops, need to restart this activity!
2799 if (!next.hasBeenLaunched) {
2800 next.hasBeenLaunched = true;
2801 } else {
2802 if (SHOW_APP_STARTING_ICON) {
2803 mWindowManager.setAppStartingWindow(
2804 next, next.packageName, next.theme,
2805 next.nonLocalizedLabel,
2806 next.labelRes, next.icon, null, true);
2807 }
2808 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2809 }
2810 startSpecificActivityLocked(next, true, true);
2811 }
2812
2813 return true;
2814 }
2815
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002816 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2817 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002818 final int NH = mHistory.size();
2819
2820 int addPos = -1;
2821
2822 if (!newTask) {
2823 // If starting in an existing task, find where that is...
2824 HistoryRecord next = null;
2825 boolean startIt = true;
2826 for (int i = NH-1; i >= 0; i--) {
2827 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2828 if (p.finishing) {
2829 continue;
2830 }
2831 if (p.task == r.task) {
2832 // Here it is! Now, if this is not yet visible to the
2833 // user, then just add it without starting; it will
2834 // get started when the user navigates back to it.
2835 addPos = i+1;
2836 if (!startIt) {
2837 mHistory.add(addPos, r);
2838 r.inHistory = true;
2839 r.task.numActivities++;
2840 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2841 r.info.screenOrientation, r.fullscreen);
2842 if (VALIDATE_TOKENS) {
2843 mWindowManager.validateAppTokens(mHistory);
2844 }
2845 return;
2846 }
2847 break;
2848 }
2849 if (p.fullscreen) {
2850 startIt = false;
2851 }
2852 next = p;
2853 }
2854 }
2855
2856 // Place a new activity at top of stack, so it is next to interact
2857 // with the user.
2858 if (addPos < 0) {
2859 addPos = mHistory.size();
2860 }
2861
2862 // If we are not placing the new activity frontmost, we do not want
2863 // to deliver the onUserLeaving callback to the actual frontmost
2864 // activity
2865 if (addPos < NH) {
2866 mUserLeaving = false;
2867 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2868 }
2869
2870 // Slot the activity into the history stack and proceed
2871 mHistory.add(addPos, r);
2872 r.inHistory = true;
2873 r.frontOfTask = newTask;
2874 r.task.numActivities++;
2875 if (NH > 0) {
2876 // We want to show the starting preview window if we are
2877 // switching to a new task, or the next activity's process is
2878 // not currently running.
2879 boolean showStartingIcon = newTask;
2880 ProcessRecord proc = r.app;
2881 if (proc == null) {
2882 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2883 }
2884 if (proc == null || proc.thread == null) {
2885 showStartingIcon = true;
2886 }
2887 if (DEBUG_TRANSITION) Log.v(TAG,
2888 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002889 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2890 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2891 mNoAnimActivities.add(r);
2892 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2893 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2894 mNoAnimActivities.remove(r);
2895 } else {
2896 mWindowManager.prepareAppTransition(newTask
2897 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2898 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2899 mNoAnimActivities.remove(r);
2900 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002901 mWindowManager.addAppToken(
2902 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2903 boolean doShow = true;
2904 if (newTask) {
2905 // Even though this activity is starting fresh, we still need
2906 // to reset it to make sure we apply affinities to move any
2907 // existing activities from other tasks in to it.
2908 // If the caller has requested that the target task be
2909 // reset, then do so.
2910 if ((r.intent.getFlags()
2911 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2912 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002913 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002914 }
2915 }
2916 if (SHOW_APP_STARTING_ICON && doShow) {
2917 // Figure out if we are transitioning from another activity that is
2918 // "has the same starting icon" as the next one. This allows the
2919 // window manager to keep the previous window it had previously
2920 // created, if it still had one.
2921 HistoryRecord prev = mResumedActivity;
2922 if (prev != null) {
2923 // We don't want to reuse the previous starting preview if:
2924 // (1) The current activity is in a different task.
2925 if (prev.task != r.task) prev = null;
2926 // (2) The current activity is already displayed.
2927 else if (prev.nowVisible) prev = null;
2928 }
2929 mWindowManager.setAppStartingWindow(
2930 r, r.packageName, r.theme, r.nonLocalizedLabel,
2931 r.labelRes, r.icon, prev, showStartingIcon);
2932 }
2933 } else {
2934 // If this is the first activity, don't do any fancy animations,
2935 // because there is nothing for it to animate on top of.
2936 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2937 r.info.screenOrientation, r.fullscreen);
2938 }
2939 if (VALIDATE_TOKENS) {
2940 mWindowManager.validateAppTokens(mHistory);
2941 }
2942
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002943 if (doResume) {
2944 resumeTopActivityLocked(null);
2945 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002946 }
2947
2948 /**
2949 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002950 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2951 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002952 * an instance of that activity in the stack and, if found, finish all
2953 * activities on top of it and return the instance.
2954 *
2955 * @param newR Description of the new activity being started.
2956 * @return Returns the old activity that should be continue to be used,
2957 * or null if none was found.
2958 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002959 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002960 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002961 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002962
2963 // First find the requested task.
2964 while (i > 0) {
2965 i--;
2966 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2967 if (r.task.taskId == taskId) {
2968 i++;
2969 break;
2970 }
2971 }
2972
2973 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002974 while (i > 0) {
2975 i--;
2976 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2977 if (r.finishing) {
2978 continue;
2979 }
2980 if (r.task.taskId != taskId) {
2981 return null;
2982 }
2983 if (r.realActivity.equals(newR.realActivity)) {
2984 // Here it is! Now finish everything in front...
2985 HistoryRecord ret = r;
2986 if (doClear) {
2987 while (i < (mHistory.size()-1)) {
2988 i++;
2989 r = (HistoryRecord)mHistory.get(i);
2990 if (r.finishing) {
2991 continue;
2992 }
2993 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2994 null, "clear")) {
2995 i--;
2996 }
2997 }
2998 }
2999
3000 // Finally, if this is a normal launch mode (that is, not
3001 // expecting onNewIntent()), then we will finish the current
3002 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003003 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
3004 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003005 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003006 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003007 if (index >= 0) {
3008 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
3009 null, "clear");
3010 }
3011 return null;
3012 }
3013 }
3014
3015 return ret;
3016 }
3017 }
3018
3019 return null;
3020 }
3021
3022 /**
3023 * Find the activity in the history stack within the given task. Returns
3024 * the index within the history at which it's found, or < 0 if not found.
3025 */
3026 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3027 int i = mHistory.size();
3028 while (i > 0) {
3029 i--;
3030 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3031 if (candidate.task.taskId != task) {
3032 break;
3033 }
3034 if (candidate.realActivity.equals(r.realActivity)) {
3035 return i;
3036 }
3037 }
3038
3039 return -1;
3040 }
3041
3042 /**
3043 * Reorder the history stack so that the activity at the given index is
3044 * brought to the front.
3045 */
3046 private final HistoryRecord moveActivityToFrontLocked(int where) {
3047 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3048 int top = mHistory.size();
3049 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3050 mHistory.add(top, newTop);
3051 oldTop.frontOfTask = false;
3052 newTop.frontOfTask = true;
3053 return newTop;
3054 }
3055
3056 /**
3057 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3058 * method will be called at the proper time.
3059 */
3060 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3061 boolean sent = false;
3062 if (r.state == ActivityState.RESUMED
3063 && r.app != null && r.app.thread != null) {
3064 try {
3065 ArrayList<Intent> ar = new ArrayList<Intent>();
3066 ar.add(new Intent(intent));
3067 r.app.thread.scheduleNewIntent(ar, r);
3068 sent = true;
3069 } catch (Exception e) {
3070 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3071 }
3072 }
3073 if (!sent) {
3074 r.addNewIntentLocked(new Intent(intent));
3075 }
3076 }
3077
3078 private final void logStartActivity(int tag, HistoryRecord r,
3079 TaskRecord task) {
3080 EventLog.writeEvent(tag,
3081 System.identityHashCode(r), task.taskId,
3082 r.shortComponentName, r.intent.getAction(),
3083 r.intent.getType(), r.intent.getDataString(),
3084 r.intent.getFlags());
3085 }
3086
3087 private final int startActivityLocked(IApplicationThread caller,
3088 Intent intent, String resolvedType,
3089 Uri[] grantedUriPermissions,
3090 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3091 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003092 int callingPid, int callingUid, boolean onlyIfNeeded,
3093 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003094 Log.i(TAG, "Starting activity: " + intent);
3095
3096 HistoryRecord sourceRecord = null;
3097 HistoryRecord resultRecord = null;
3098 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003099 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003100 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003101 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3102 if (index >= 0) {
3103 sourceRecord = (HistoryRecord)mHistory.get(index);
3104 if (requestCode >= 0 && !sourceRecord.finishing) {
3105 resultRecord = sourceRecord;
3106 }
3107 }
3108 }
3109
3110 int launchFlags = intent.getFlags();
3111
3112 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3113 && sourceRecord != null) {
3114 // Transfer the result target from the source activity to the new
3115 // one being started, including any failures.
3116 if (requestCode >= 0) {
3117 return START_FORWARD_AND_REQUEST_CONFLICT;
3118 }
3119 resultRecord = sourceRecord.resultTo;
3120 resultWho = sourceRecord.resultWho;
3121 requestCode = sourceRecord.requestCode;
3122 sourceRecord.resultTo = null;
3123 if (resultRecord != null) {
3124 resultRecord.removeResultsLocked(
3125 sourceRecord, resultWho, requestCode);
3126 }
3127 }
3128
3129 int err = START_SUCCESS;
3130
3131 if (intent.getComponent() == null) {
3132 // We couldn't find a class that can handle the given Intent.
3133 // That's the end of that!
3134 err = START_INTENT_NOT_RESOLVED;
3135 }
3136
3137 if (err == START_SUCCESS && aInfo == null) {
3138 // We couldn't find the specific class specified in the Intent.
3139 // Also the end of the line.
3140 err = START_CLASS_NOT_FOUND;
3141 }
3142
3143 ProcessRecord callerApp = null;
3144 if (err == START_SUCCESS && caller != null) {
3145 callerApp = getRecordForAppLocked(caller);
3146 if (callerApp != null) {
3147 callingPid = callerApp.pid;
3148 callingUid = callerApp.info.uid;
3149 } else {
3150 Log.w(TAG, "Unable to find app for caller " + caller
3151 + " (pid=" + callingPid + ") when starting: "
3152 + intent.toString());
3153 err = START_PERMISSION_DENIED;
3154 }
3155 }
3156
3157 if (err != START_SUCCESS) {
3158 if (resultRecord != null) {
3159 sendActivityResultLocked(-1,
3160 resultRecord, resultWho, requestCode,
3161 Activity.RESULT_CANCELED, null);
3162 }
3163 return err;
3164 }
3165
3166 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3167 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3168 if (perm != PackageManager.PERMISSION_GRANTED) {
3169 if (resultRecord != null) {
3170 sendActivityResultLocked(-1,
3171 resultRecord, resultWho, requestCode,
3172 Activity.RESULT_CANCELED, null);
3173 }
3174 String msg = "Permission Denial: starting " + intent.toString()
3175 + " from " + callerApp + " (pid=" + callingPid
3176 + ", uid=" + callingUid + ")"
3177 + " requires " + aInfo.permission;
3178 Log.w(TAG, msg);
3179 throw new SecurityException(msg);
3180 }
3181
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003182 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003183 boolean abort = false;
3184 try {
3185 // The Intent we give to the watcher has the extra data
3186 // stripped off, since it can contain private information.
3187 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003188 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003189 aInfo.applicationInfo.packageName);
3190 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003191 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003192 }
3193
3194 if (abort) {
3195 if (resultRecord != null) {
3196 sendActivityResultLocked(-1,
3197 resultRecord, resultWho, requestCode,
3198 Activity.RESULT_CANCELED, null);
3199 }
3200 // We pretend to the caller that it was really started, but
3201 // they will just get a cancel result.
3202 return START_SUCCESS;
3203 }
3204 }
3205
3206 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3207 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003208 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003209
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003210 if (mResumedActivity == null
3211 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3212 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3213 PendingActivityLaunch pal = new PendingActivityLaunch();
3214 pal.r = r;
3215 pal.sourceRecord = sourceRecord;
3216 pal.grantedUriPermissions = grantedUriPermissions;
3217 pal.grantedMode = grantedMode;
3218 pal.onlyIfNeeded = onlyIfNeeded;
3219 mPendingActivityLaunches.add(pal);
3220 return START_SWITCHES_CANCELED;
3221 }
3222 }
3223
3224 if (mDidAppSwitch) {
3225 // This is the second allowed switch since we stopped switches,
3226 // so now just generally allow switches. Use case: user presses
3227 // home (switches disabled, switch to home, mDidAppSwitch now true);
3228 // user taps a home icon (coming from home so allowed, we hit here
3229 // and now allow anyone to switch again).
3230 mAppSwitchesAllowedTime = 0;
3231 } else {
3232 mDidAppSwitch = true;
3233 }
3234
3235 doPendingActivityLaunchesLocked(false);
3236
3237 return startActivityUncheckedLocked(r, sourceRecord,
3238 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3239 }
3240
3241 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3242 final int N = mPendingActivityLaunches.size();
3243 if (N <= 0) {
3244 return;
3245 }
3246 for (int i=0; i<N; i++) {
3247 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3248 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3249 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3250 doResume && i == (N-1));
3251 }
3252 mPendingActivityLaunches.clear();
3253 }
3254
3255 private final int startActivityUncheckedLocked(HistoryRecord r,
3256 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3257 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3258 final Intent intent = r.intent;
3259 final int callingUid = r.launchedFromUid;
3260
3261 int launchFlags = intent.getFlags();
3262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003263 // We'll invoke onUserLeaving before onPause only if the launching
3264 // activity did not explicitly state that this is an automated launch.
3265 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3266 if (DEBUG_USER_LEAVING) Log.v(TAG,
3267 "startActivity() => mUserLeaving=" + mUserLeaving);
3268
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003269 // If the caller has asked not to resume at this point, we make note
3270 // of this in the record so that we can skip it when trying to find
3271 // the top running activity.
3272 if (!doResume) {
3273 r.delayedResume = true;
3274 }
3275
3276 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3277 != 0 ? r : null;
3278
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003279 // If the onlyIfNeeded flag is set, then we can do this if the activity
3280 // being launched is the same as the one making the call... or, as
3281 // a special case, if we do not know the caller then we count the
3282 // current top activity as the caller.
3283 if (onlyIfNeeded) {
3284 HistoryRecord checkedCaller = sourceRecord;
3285 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003286 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003287 }
3288 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3289 // Caller is not the same as launcher, so always needed.
3290 onlyIfNeeded = false;
3291 }
3292 }
3293
3294 if (grantedUriPermissions != null && callingUid > 0) {
3295 for (int i=0; i<grantedUriPermissions.length; i++) {
3296 grantUriPermissionLocked(callingUid, r.packageName,
3297 grantedUriPermissions[i], grantedMode, r);
3298 }
3299 }
3300
3301 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3302 intent, r);
3303
3304 if (sourceRecord == null) {
3305 // This activity is not being started from another... in this
3306 // case we -always- start a new task.
3307 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3308 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3309 + intent);
3310 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3311 }
3312 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3313 // The original activity who is starting us is running as a single
3314 // instance... this new activity it is starting must go on its
3315 // own task.
3316 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3317 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3318 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3319 // The activity being started is a single instance... it always
3320 // gets launched into its own task.
3321 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3322 }
3323
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003324 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003325 // For whatever reason this activity is being launched into a new
3326 // task... yet the caller has requested a result back. Well, that
3327 // is pretty messed up, so instead immediately send back a cancel
3328 // and let the new task continue launched as normal without a
3329 // dependency on its originator.
3330 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3331 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003332 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003333 Activity.RESULT_CANCELED, null);
3334 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003335 }
3336
3337 boolean addingToTask = false;
3338 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3339 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3340 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3341 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3342 // If bring to front is requested, and no result is requested, and
3343 // we can find a task that was started with this same
3344 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003345 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003346 // See if there is a task to bring to the front. If this is
3347 // a SINGLE_INSTANCE activity, there can be one and only one
3348 // instance of it in the history, and it is always in its own
3349 // unique task, so we do a special search.
3350 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3351 ? findTaskLocked(intent, r.info)
3352 : findActivityLocked(intent, r.info);
3353 if (taskTop != null) {
3354 if (taskTop.task.intent == null) {
3355 // This task was started because of movement of
3356 // the activity based on affinity... now that we
3357 // are actually launching it, we can assign the
3358 // base intent.
3359 taskTop.task.setIntent(intent, r.info);
3360 }
3361 // If the target task is not in the front, then we need
3362 // to bring it to the front... except... well, with
3363 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3364 // to have the same behavior as if a new instance was
3365 // being started, which means not bringing it to the front
3366 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003367 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003368 if (curTop.task != taskTop.task) {
3369 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3370 boolean callerAtFront = sourceRecord == null
3371 || curTop.task == sourceRecord.task;
3372 if (callerAtFront) {
3373 // We really do want to push this one into the
3374 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003375 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003376 }
3377 }
3378 // If the caller has requested that the target task be
3379 // reset, then do so.
3380 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3381 taskTop = resetTaskIfNeededLocked(taskTop, r);
3382 }
3383 if (onlyIfNeeded) {
3384 // We don't need to start a new activity, and
3385 // the client said not to do anything if that
3386 // is the case, so this is it! And for paranoia, make
3387 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003388 if (doResume) {
3389 resumeTopActivityLocked(null);
3390 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003391 return START_RETURN_INTENT_TO_CALLER;
3392 }
3393 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3394 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3395 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3396 // In this situation we want to remove all activities
3397 // from the task up to the one being started. In most
3398 // cases this means we are resetting the task to its
3399 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003400 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003401 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003402 if (top != null) {
3403 if (top.frontOfTask) {
3404 // Activity aliases may mean we use different
3405 // intents for the top activity, so make sure
3406 // the task now has the identity of the new
3407 // intent.
3408 top.task.setIntent(r.intent, r.info);
3409 }
3410 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3411 deliverNewIntentLocked(top, r.intent);
3412 } else {
3413 // A special case: we need to
3414 // start the activity because it is not currently
3415 // running, and the caller has asked to clear the
3416 // current task to have this activity at the top.
3417 addingToTask = true;
3418 // Now pretend like this activity is being started
3419 // by the top of its task, so it is put in the
3420 // right place.
3421 sourceRecord = taskTop;
3422 }
3423 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3424 // In this case the top activity on the task is the
3425 // same as the one being launched, so we take that
3426 // as a request to bring the task to the foreground.
3427 // If the top activity in the task is the root
3428 // activity, deliver this new intent to it if it
3429 // desires.
3430 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3431 && taskTop.realActivity.equals(r.realActivity)) {
3432 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3433 if (taskTop.frontOfTask) {
3434 taskTop.task.setIntent(r.intent, r.info);
3435 }
3436 deliverNewIntentLocked(taskTop, r.intent);
3437 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3438 // In this case we are launching the root activity
3439 // of the task, but with a different intent. We
3440 // should start a new instance on top.
3441 addingToTask = true;
3442 sourceRecord = taskTop;
3443 }
3444 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3445 // In this case an activity is being launched in to an
3446 // existing task, without resetting that task. This
3447 // is typically the situation of launching an activity
3448 // from a notification or shortcut. We want to place
3449 // the new activity on top of the current task.
3450 addingToTask = true;
3451 sourceRecord = taskTop;
3452 } else if (!taskTop.task.rootWasReset) {
3453 // In this case we are launching in to an existing task
3454 // that has not yet been started from its front door.
3455 // The current task has been brought to the front.
3456 // Ideally, we'd probably like to place this new task
3457 // at the bottom of its stack, but that's a little hard
3458 // to do with the current organization of the code so
3459 // for now we'll just drop it.
3460 taskTop.task.setIntent(r.intent, r.info);
3461 }
3462 if (!addingToTask) {
3463 // We didn't do anything... but it was needed (a.k.a., client
3464 // don't use that intent!) And for paranoia, make
3465 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003466 if (doResume) {
3467 resumeTopActivityLocked(null);
3468 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003469 return START_TASK_TO_FRONT;
3470 }
3471 }
3472 }
3473 }
3474
3475 //String uri = r.intent.toURI();
3476 //Intent intent2 = new Intent(uri);
3477 //Log.i(TAG, "Given intent: " + r.intent);
3478 //Log.i(TAG, "URI is: " + uri);
3479 //Log.i(TAG, "To intent: " + intent2);
3480
3481 if (r.packageName != null) {
3482 // If the activity being launched is the same as the one currently
3483 // at the top, then we need to check if it should only be launched
3484 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003485 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3486 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003487 if (top.realActivity.equals(r.realActivity)) {
3488 if (top.app != null && top.app.thread != null) {
3489 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3490 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3491 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3492 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3493 // For paranoia, make sure we have correctly
3494 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003495 if (doResume) {
3496 resumeTopActivityLocked(null);
3497 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003498 if (onlyIfNeeded) {
3499 // We don't need to start a new activity, and
3500 // the client said not to do anything if that
3501 // is the case, so this is it!
3502 return START_RETURN_INTENT_TO_CALLER;
3503 }
3504 deliverNewIntentLocked(top, r.intent);
3505 return START_DELIVERED_TO_TOP;
3506 }
3507 }
3508 }
3509 }
3510
3511 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003512 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003513 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003514 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003515 Activity.RESULT_CANCELED, null);
3516 }
3517 return START_CLASS_NOT_FOUND;
3518 }
3519
3520 boolean newTask = false;
3521
3522 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003523 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003524 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3525 // todo: should do better management of integers.
3526 mCurTask++;
3527 if (mCurTask <= 0) {
3528 mCurTask = 1;
3529 }
3530 r.task = new TaskRecord(mCurTask, r.info, intent,
3531 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3532 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3533 + " in new task " + r.task);
3534 newTask = true;
3535 addRecentTask(r.task);
3536
3537 } else if (sourceRecord != null) {
3538 if (!addingToTask &&
3539 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3540 // In this case, we are adding the activity to an existing
3541 // task, but the caller has asked to clear that task if the
3542 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003543 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003544 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003545 if (top != null) {
3546 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3547 deliverNewIntentLocked(top, r.intent);
3548 // For paranoia, make sure we have correctly
3549 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003550 if (doResume) {
3551 resumeTopActivityLocked(null);
3552 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003553 return START_DELIVERED_TO_TOP;
3554 }
3555 } else if (!addingToTask &&
3556 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3557 // In this case, we are launching an activity in our own task
3558 // that may already be running somewhere in the history, and
3559 // we want to shuffle it to the front of the stack if so.
3560 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3561 if (where >= 0) {
3562 HistoryRecord top = moveActivityToFrontLocked(where);
3563 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3564 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003565 if (doResume) {
3566 resumeTopActivityLocked(null);
3567 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003568 return START_DELIVERED_TO_TOP;
3569 }
3570 }
3571 // An existing activity is starting this new activity, so we want
3572 // to keep the new one in the same task as the one that is starting
3573 // it.
3574 r.task = sourceRecord.task;
3575 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3576 + " in existing task " + r.task);
3577
3578 } else {
3579 // This not being started from an existing activity, and not part
3580 // of a new task... just put it in the top task, though these days
3581 // this case should never happen.
3582 final int N = mHistory.size();
3583 HistoryRecord prev =
3584 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3585 r.task = prev != null
3586 ? prev.task
3587 : new TaskRecord(mCurTask, r.info, intent,
3588 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3589 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3590 + " in new guessed " + r.task);
3591 }
3592 if (newTask) {
3593 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3594 }
3595 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003596 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003597 return START_SUCCESS;
3598 }
3599
3600 public final int startActivity(IApplicationThread caller,
3601 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3602 int grantedMode, IBinder resultTo,
3603 String resultWho, int requestCode, boolean onlyIfNeeded,
3604 boolean debug) {
3605 // Refuse possible leaked file descriptors
3606 if (intent != null && intent.hasFileDescriptors()) {
3607 throw new IllegalArgumentException("File descriptors passed in Intent");
3608 }
3609
The Android Open Source Project4df24232009-03-05 14:34:35 -08003610 final boolean componentSpecified = intent.getComponent() != null;
3611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003612 // Don't modify the client's object!
3613 intent = new Intent(intent);
3614
3615 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003616 ActivityInfo aInfo;
3617 try {
3618 ResolveInfo rInfo =
3619 ActivityThread.getPackageManager().resolveIntent(
3620 intent, resolvedType,
3621 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003622 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003623 aInfo = rInfo != null ? rInfo.activityInfo : null;
3624 } catch (RemoteException e) {
3625 aInfo = null;
3626 }
3627
3628 if (aInfo != null) {
3629 // Store the found target back into the intent, because now that
3630 // we have it we never want to do this again. For example, if the
3631 // user navigates back to this point in the history, we should
3632 // always restart the exact same activity.
3633 intent.setComponent(new ComponentName(
3634 aInfo.applicationInfo.packageName, aInfo.name));
3635
3636 // Don't debug things in the system process
3637 if (debug) {
3638 if (!aInfo.processName.equals("system")) {
3639 setDebugApp(aInfo.processName, true, false);
3640 }
3641 }
3642 }
3643
3644 synchronized(this) {
3645 final long origId = Binder.clearCallingIdentity();
3646 int res = startActivityLocked(caller, intent, resolvedType,
3647 grantedUriPermissions, grantedMode, aInfo,
3648 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003649 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003650 Binder.restoreCallingIdentity(origId);
3651 return res;
3652 }
3653 }
3654
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003655 public int startActivityIntentSender(IApplicationThread caller,
3656 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003657 IBinder resultTo, String resultWho, int requestCode,
3658 int flagsMask, int flagsValues) {
3659 // Refuse possible leaked file descriptors
3660 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3661 throw new IllegalArgumentException("File descriptors passed in Intent");
3662 }
3663
3664 IIntentSender sender = intent.getTarget();
3665 if (!(sender instanceof PendingIntentRecord)) {
3666 throw new IllegalArgumentException("Bad PendingIntent object");
3667 }
3668
3669 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003670
3671 synchronized (this) {
3672 // If this is coming from the currently resumed activity, it is
3673 // effectively saying that app switches are allowed at this point.
3674 if (mResumedActivity != null
3675 && mResumedActivity.info.applicationInfo.uid ==
3676 Binder.getCallingUid()) {
3677 mAppSwitchesAllowedTime = 0;
3678 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003679 }
3680
3681 return pir.sendInner(0, fillInIntent, resolvedType,
3682 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3683 }
3684
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003685 public boolean startNextMatchingActivity(IBinder callingActivity,
3686 Intent intent) {
3687 // Refuse possible leaked file descriptors
3688 if (intent != null && intent.hasFileDescriptors() == true) {
3689 throw new IllegalArgumentException("File descriptors passed in Intent");
3690 }
3691
3692 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003693 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003694 if (index < 0) {
3695 return false;
3696 }
3697 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3698 if (r.app == null || r.app.thread == null) {
3699 // The caller is not running... d'oh!
3700 return false;
3701 }
3702 intent = new Intent(intent);
3703 // The caller is not allowed to change the data.
3704 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3705 // And we are resetting to find the next component...
3706 intent.setComponent(null);
3707
3708 ActivityInfo aInfo = null;
3709 try {
3710 List<ResolveInfo> resolves =
3711 ActivityThread.getPackageManager().queryIntentActivities(
3712 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003713 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003714
3715 // Look for the original activity in the list...
3716 final int N = resolves != null ? resolves.size() : 0;
3717 for (int i=0; i<N; i++) {
3718 ResolveInfo rInfo = resolves.get(i);
3719 if (rInfo.activityInfo.packageName.equals(r.packageName)
3720 && rInfo.activityInfo.name.equals(r.info.name)) {
3721 // We found the current one... the next matching is
3722 // after it.
3723 i++;
3724 if (i<N) {
3725 aInfo = resolves.get(i).activityInfo;
3726 }
3727 break;
3728 }
3729 }
3730 } catch (RemoteException e) {
3731 }
3732
3733 if (aInfo == null) {
3734 // Nobody who is next!
3735 return false;
3736 }
3737
3738 intent.setComponent(new ComponentName(
3739 aInfo.applicationInfo.packageName, aInfo.name));
3740 intent.setFlags(intent.getFlags()&~(
3741 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3742 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3743 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3744 Intent.FLAG_ACTIVITY_NEW_TASK));
3745
3746 // Okay now we need to start the new activity, replacing the
3747 // currently running activity. This is a little tricky because
3748 // we want to start the new one as if the current one is finished,
3749 // but not finish the current one first so that there is no flicker.
3750 // And thus...
3751 final boolean wasFinishing = r.finishing;
3752 r.finishing = true;
3753
3754 // Propagate reply information over to the new activity.
3755 final HistoryRecord resultTo = r.resultTo;
3756 final String resultWho = r.resultWho;
3757 final int requestCode = r.requestCode;
3758 r.resultTo = null;
3759 if (resultTo != null) {
3760 resultTo.removeResultsLocked(r, resultWho, requestCode);
3761 }
3762
3763 final long origId = Binder.clearCallingIdentity();
3764 // XXX we are not dealing with propagating grantedUriPermissions...
3765 // those are not yet exposed to user code, so there is no need.
3766 int res = startActivityLocked(r.app.thread, intent,
3767 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003768 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003769 Binder.restoreCallingIdentity(origId);
3770
3771 r.finishing = wasFinishing;
3772 if (res != START_SUCCESS) {
3773 return false;
3774 }
3775 return true;
3776 }
3777 }
3778
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003779 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003780 Intent intent, String resolvedType, IBinder resultTo,
3781 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003782
3783 // This is so super not safe, that only the system (or okay root)
3784 // can do it.
3785 final int callingUid = Binder.getCallingUid();
3786 if (callingUid != 0 && callingUid != Process.myUid()) {
3787 throw new SecurityException(
3788 "startActivityInPackage only available to the system");
3789 }
3790
The Android Open Source Project4df24232009-03-05 14:34:35 -08003791 final boolean componentSpecified = intent.getComponent() != null;
3792
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003793 // Don't modify the client's object!
3794 intent = new Intent(intent);
3795
3796 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003797 ActivityInfo aInfo;
3798 try {
3799 ResolveInfo rInfo =
3800 ActivityThread.getPackageManager().resolveIntent(
3801 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003802 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003803 aInfo = rInfo != null ? rInfo.activityInfo : null;
3804 } catch (RemoteException e) {
3805 aInfo = null;
3806 }
3807
3808 if (aInfo != null) {
3809 // Store the found target back into the intent, because now that
3810 // we have it we never want to do this again. For example, if the
3811 // user navigates back to this point in the history, we should
3812 // always restart the exact same activity.
3813 intent.setComponent(new ComponentName(
3814 aInfo.applicationInfo.packageName, aInfo.name));
3815 }
3816
3817 synchronized(this) {
3818 return startActivityLocked(null, intent, resolvedType,
3819 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003820 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003821 }
3822 }
3823
3824 private final void addRecentTask(TaskRecord task) {
3825 // Remove any existing entries that are the same kind of task.
3826 int N = mRecentTasks.size();
3827 for (int i=0; i<N; i++) {
3828 TaskRecord tr = mRecentTasks.get(i);
3829 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3830 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3831 mRecentTasks.remove(i);
3832 i--;
3833 N--;
3834 if (task.intent == null) {
3835 // If the new recent task we are adding is not fully
3836 // specified, then replace it with the existing recent task.
3837 task = tr;
3838 }
3839 }
3840 }
3841 if (N >= MAX_RECENT_TASKS) {
3842 mRecentTasks.remove(N-1);
3843 }
3844 mRecentTasks.add(0, task);
3845 }
3846
3847 public void setRequestedOrientation(IBinder token,
3848 int requestedOrientation) {
3849 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003850 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003851 if (index < 0) {
3852 return;
3853 }
3854 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3855 final long origId = Binder.clearCallingIdentity();
3856 mWindowManager.setAppOrientation(r, requestedOrientation);
3857 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003858 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003859 r.mayFreezeScreenLocked(r.app) ? r : null);
3860 if (config != null) {
3861 r.frozenBeforeDestroy = true;
3862 if (!updateConfigurationLocked(config, r)) {
3863 resumeTopActivityLocked(null);
3864 }
3865 }
3866 Binder.restoreCallingIdentity(origId);
3867 }
3868 }
3869
3870 public int getRequestedOrientation(IBinder token) {
3871 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003872 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003873 if (index < 0) {
3874 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3875 }
3876 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3877 return mWindowManager.getAppOrientation(r);
3878 }
3879 }
3880
3881 private final void stopActivityLocked(HistoryRecord r) {
3882 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3883 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3884 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3885 if (!r.finishing) {
3886 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3887 "no-history");
3888 }
3889 } else if (r.app != null && r.app.thread != null) {
3890 if (mFocusedActivity == r) {
3891 setFocusedActivityLocked(topRunningActivityLocked(null));
3892 }
3893 r.resumeKeyDispatchingLocked();
3894 try {
3895 r.stopped = false;
3896 r.state = ActivityState.STOPPING;
3897 if (DEBUG_VISBILITY) Log.v(
3898 TAG, "Stopping visible=" + r.visible + " for " + r);
3899 if (!r.visible) {
3900 mWindowManager.setAppVisibility(r, false);
3901 }
3902 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3903 } catch (Exception e) {
3904 // Maybe just ignore exceptions here... if the process
3905 // has crashed, our death notification will clean things
3906 // up.
3907 Log.w(TAG, "Exception thrown during pause", e);
3908 // Just in case, assume it to be stopped.
3909 r.stopped = true;
3910 r.state = ActivityState.STOPPED;
3911 if (r.configDestroy) {
3912 destroyActivityLocked(r, true);
3913 }
3914 }
3915 }
3916 }
3917
3918 /**
3919 * @return Returns true if the activity is being finished, false if for
3920 * some reason it is being left as-is.
3921 */
3922 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3923 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003924 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003925 TAG, "Finishing activity: token=" + token
3926 + ", result=" + resultCode + ", data=" + resultData);
3927
Dianne Hackborn75b03852009-06-12 15:43:26 -07003928 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003929 if (index < 0) {
3930 return false;
3931 }
3932 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3933
3934 // Is this the last activity left?
3935 boolean lastActivity = true;
3936 for (int i=mHistory.size()-1; i>=0; i--) {
3937 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3938 if (!p.finishing && p != r) {
3939 lastActivity = false;
3940 break;
3941 }
3942 }
3943
3944 // If this is the last activity, but it is the home activity, then
3945 // just don't finish it.
3946 if (lastActivity) {
3947 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3948 return false;
3949 }
3950 }
3951
3952 finishActivityLocked(r, index, resultCode, resultData, reason);
3953 return true;
3954 }
3955
3956 /**
3957 * @return Returns true if this activity has been removed from the history
3958 * list, or false if it is still in the list and will be removed later.
3959 */
3960 private final boolean finishActivityLocked(HistoryRecord r, int index,
3961 int resultCode, Intent resultData, String reason) {
3962 if (r.finishing) {
3963 Log.w(TAG, "Duplicate finish request for " + r);
3964 return false;
3965 }
3966
3967 r.finishing = true;
3968 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3969 System.identityHashCode(r),
3970 r.task.taskId, r.shortComponentName, reason);
3971 r.task.numActivities--;
3972 if (r.frontOfTask && index < (mHistory.size()-1)) {
3973 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3974 if (next.task == r.task) {
3975 next.frontOfTask = true;
3976 }
3977 }
3978
3979 r.pauseKeyDispatchingLocked();
3980 if (mFocusedActivity == r) {
3981 setFocusedActivityLocked(topRunningActivityLocked(null));
3982 }
3983
3984 // send the result
3985 HistoryRecord resultTo = r.resultTo;
3986 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003987 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3988 + " who=" + r.resultWho + " req=" + r.requestCode
3989 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003990 if (r.info.applicationInfo.uid > 0) {
3991 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3992 r.packageName, resultData, r);
3993 }
3994 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3995 resultData);
3996 r.resultTo = null;
3997 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003998 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003999
4000 // Make sure this HistoryRecord is not holding on to other resources,
4001 // because clients have remote IPC references to this object so we
4002 // can't assume that will go away and want to avoid circular IPC refs.
4003 r.results = null;
4004 r.pendingResults = null;
4005 r.newIntents = null;
4006 r.icicle = null;
4007
4008 if (mPendingThumbnails.size() > 0) {
4009 // There are clients waiting to receive thumbnails so, in case
4010 // this is an activity that someone is waiting for, add it
4011 // to the pending list so we can correctly update the clients.
4012 mCancelledThumbnails.add(r);
4013 }
4014
4015 if (mResumedActivity == r) {
4016 boolean endTask = index <= 0
4017 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
4018 if (DEBUG_TRANSITION) Log.v(TAG,
4019 "Prepare close transition: finishing " + r);
4020 mWindowManager.prepareAppTransition(endTask
4021 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
4022 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
4023
4024 // Tell window manager to prepare for this one to be removed.
4025 mWindowManager.setAppVisibility(r, false);
4026
4027 if (mPausingActivity == null) {
4028 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4029 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4030 startPausingLocked(false, false);
4031 }
4032
4033 } else if (r.state != ActivityState.PAUSING) {
4034 // If the activity is PAUSING, we will complete the finish once
4035 // it is done pausing; else we can just directly finish it here.
4036 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4037 return finishCurrentActivityLocked(r, index,
4038 FINISH_AFTER_PAUSE) == null;
4039 } else {
4040 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4041 }
4042
4043 return false;
4044 }
4045
4046 private static final int FINISH_IMMEDIATELY = 0;
4047 private static final int FINISH_AFTER_PAUSE = 1;
4048 private static final int FINISH_AFTER_VISIBLE = 2;
4049
4050 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4051 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004052 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004053 if (index < 0) {
4054 return null;
4055 }
4056
4057 return finishCurrentActivityLocked(r, index, mode);
4058 }
4059
4060 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4061 int index, int mode) {
4062 // First things first: if this activity is currently visible,
4063 // and the resumed activity is not yet visible, then hold off on
4064 // finishing until the resumed one becomes visible.
4065 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4066 if (!mStoppingActivities.contains(r)) {
4067 mStoppingActivities.add(r);
4068 if (mStoppingActivities.size() > 3) {
4069 // If we already have a few activities waiting to stop,
4070 // then give up on things going idle and start clearing
4071 // them out.
4072 Message msg = Message.obtain();
4073 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4074 mHandler.sendMessage(msg);
4075 }
4076 }
4077 r.state = ActivityState.STOPPING;
4078 updateOomAdjLocked();
4079 return r;
4080 }
4081
4082 // make sure the record is cleaned out of other places.
4083 mStoppingActivities.remove(r);
4084 mWaitingVisibleActivities.remove(r);
4085 if (mResumedActivity == r) {
4086 mResumedActivity = null;
4087 }
4088 final ActivityState prevState = r.state;
4089 r.state = ActivityState.FINISHING;
4090
4091 if (mode == FINISH_IMMEDIATELY
4092 || prevState == ActivityState.STOPPED
4093 || prevState == ActivityState.INITIALIZING) {
4094 // If this activity is already stopped, we can just finish
4095 // it right now.
4096 return destroyActivityLocked(r, true) ? null : r;
4097 } else {
4098 // Need to go through the full pause cycle to get this
4099 // activity into the stopped state and then finish it.
4100 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4101 mFinishingActivities.add(r);
4102 resumeTopActivityLocked(null);
4103 }
4104 return r;
4105 }
4106
4107 /**
4108 * This is the internal entry point for handling Activity.finish().
4109 *
4110 * @param token The Binder token referencing the Activity we want to finish.
4111 * @param resultCode Result code, if any, from this Activity.
4112 * @param resultData Result data (Intent), if any, from this Activity.
4113 *
4114 * @result Returns true if the activity successfully finished, or false if it is still running.
4115 */
4116 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4117 // Refuse possible leaked file descriptors
4118 if (resultData != null && resultData.hasFileDescriptors() == true) {
4119 throw new IllegalArgumentException("File descriptors passed in Intent");
4120 }
4121
4122 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004123 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004124 // Find the first activity that is not finishing.
4125 HistoryRecord next = topRunningActivityLocked(token, 0);
4126 if (next != null) {
4127 // ask watcher if this is allowed
4128 boolean resumeOK = true;
4129 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004130 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004131 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004132 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004133 }
4134
4135 if (!resumeOK) {
4136 return false;
4137 }
4138 }
4139 }
4140 final long origId = Binder.clearCallingIdentity();
4141 boolean res = requestFinishActivityLocked(token, resultCode,
4142 resultData, "app-request");
4143 Binder.restoreCallingIdentity(origId);
4144 return res;
4145 }
4146 }
4147
4148 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4149 String resultWho, int requestCode, int resultCode, Intent data) {
4150
4151 if (callingUid > 0) {
4152 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4153 data, r);
4154 }
4155
The Android Open Source Project10592532009-03-18 17:39:46 -07004156 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4157 + " : who=" + resultWho + " req=" + requestCode
4158 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004159 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4160 try {
4161 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4162 list.add(new ResultInfo(resultWho, requestCode,
4163 resultCode, data));
4164 r.app.thread.scheduleSendResult(r, list);
4165 return;
4166 } catch (Exception e) {
4167 Log.w(TAG, "Exception thrown sending result to " + r, e);
4168 }
4169 }
4170
4171 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4172 }
4173
4174 public final void finishSubActivity(IBinder token, String resultWho,
4175 int requestCode) {
4176 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004177 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004178 if (index < 0) {
4179 return;
4180 }
4181 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4182
4183 final long origId = Binder.clearCallingIdentity();
4184
4185 int i;
4186 for (i=mHistory.size()-1; i>=0; i--) {
4187 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4188 if (r.resultTo == self && r.requestCode == requestCode) {
4189 if ((r.resultWho == null && resultWho == null) ||
4190 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4191 finishActivityLocked(r, i,
4192 Activity.RESULT_CANCELED, null, "request-sub");
4193 }
4194 }
4195 }
4196
4197 Binder.restoreCallingIdentity(origId);
4198 }
4199 }
4200
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004201 public void overridePendingTransition(IBinder token, String packageName,
4202 int enterAnim, int exitAnim) {
4203 synchronized(this) {
4204 int index = indexOfTokenLocked(token);
4205 if (index < 0) {
4206 return;
4207 }
4208 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4209
4210 final long origId = Binder.clearCallingIdentity();
4211
4212 if (self.state == ActivityState.RESUMED
4213 || self.state == ActivityState.PAUSING) {
4214 mWindowManager.overridePendingAppTransition(packageName,
4215 enterAnim, exitAnim);
4216 }
4217
4218 Binder.restoreCallingIdentity(origId);
4219 }
4220 }
4221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004222 /**
4223 * Perform clean-up of service connections in an activity record.
4224 */
4225 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4226 // Throw away any services that have been bound by this activity.
4227 if (r.connections != null) {
4228 Iterator<ConnectionRecord> it = r.connections.iterator();
4229 while (it.hasNext()) {
4230 ConnectionRecord c = it.next();
4231 removeConnectionLocked(c, null, r);
4232 }
4233 r.connections = null;
4234 }
4235 }
4236
4237 /**
4238 * Perform the common clean-up of an activity record. This is called both
4239 * as part of destroyActivityLocked() (when destroying the client-side
4240 * representation) and cleaning things up as a result of its hosting
4241 * processing going away, in which case there is no remaining client-side
4242 * state to destroy so only the cleanup here is needed.
4243 */
4244 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4245 if (mResumedActivity == r) {
4246 mResumedActivity = null;
4247 }
4248 if (mFocusedActivity == r) {
4249 mFocusedActivity = null;
4250 }
4251
4252 r.configDestroy = false;
4253 r.frozenBeforeDestroy = false;
4254
4255 // Make sure this record is no longer in the pending finishes list.
4256 // This could happen, for example, if we are trimming activities
4257 // down to the max limit while they are still waiting to finish.
4258 mFinishingActivities.remove(r);
4259 mWaitingVisibleActivities.remove(r);
4260
4261 // Remove any pending results.
4262 if (r.finishing && r.pendingResults != null) {
4263 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4264 PendingIntentRecord rec = apr.get();
4265 if (rec != null) {
4266 cancelIntentSenderLocked(rec, false);
4267 }
4268 }
4269 r.pendingResults = null;
4270 }
4271
4272 if (cleanServices) {
4273 cleanUpActivityServicesLocked(r);
4274 }
4275
4276 if (mPendingThumbnails.size() > 0) {
4277 // There are clients waiting to receive thumbnails so, in case
4278 // this is an activity that someone is waiting for, add it
4279 // to the pending list so we can correctly update the clients.
4280 mCancelledThumbnails.add(r);
4281 }
4282
4283 // Get rid of any pending idle timeouts.
4284 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4285 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4286 }
4287
4288 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4289 if (r.state != ActivityState.DESTROYED) {
4290 mHistory.remove(r);
4291 r.inHistory = false;
4292 r.state = ActivityState.DESTROYED;
4293 mWindowManager.removeAppToken(r);
4294 if (VALIDATE_TOKENS) {
4295 mWindowManager.validateAppTokens(mHistory);
4296 }
4297 cleanUpActivityServicesLocked(r);
4298 removeActivityUriPermissionsLocked(r);
4299 }
4300 }
4301
4302 /**
4303 * Destroy the current CLIENT SIDE instance of an activity. This may be
4304 * called both when actually finishing an activity, or when performing
4305 * a configuration switch where we destroy the current client-side object
4306 * but then create a new client-side object for this same HistoryRecord.
4307 */
4308 private final boolean destroyActivityLocked(HistoryRecord r,
4309 boolean removeFromApp) {
4310 if (DEBUG_SWITCH) Log.v(
4311 TAG, "Removing activity: token=" + r
4312 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4313 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4314 System.identityHashCode(r),
4315 r.task.taskId, r.shortComponentName);
4316
4317 boolean removedFromHistory = false;
4318
4319 cleanUpActivityLocked(r, false);
4320
4321 if (r.app != null) {
4322 if (removeFromApp) {
4323 int idx = r.app.activities.indexOf(r);
4324 if (idx >= 0) {
4325 r.app.activities.remove(idx);
4326 }
4327 if (r.persistent) {
4328 decPersistentCountLocked(r.app);
4329 }
4330 }
4331
4332 boolean skipDestroy = false;
4333
4334 try {
4335 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4336 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4337 r.configChangeFlags);
4338 } catch (Exception e) {
4339 // We can just ignore exceptions here... if the process
4340 // has crashed, our death notification will clean things
4341 // up.
4342 //Log.w(TAG, "Exception thrown during finish", e);
4343 if (r.finishing) {
4344 removeActivityFromHistoryLocked(r);
4345 removedFromHistory = true;
4346 skipDestroy = true;
4347 }
4348 }
4349
4350 r.app = null;
4351 r.nowVisible = false;
4352
4353 if (r.finishing && !skipDestroy) {
4354 r.state = ActivityState.DESTROYING;
4355 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4356 msg.obj = r;
4357 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4358 } else {
4359 r.state = ActivityState.DESTROYED;
4360 }
4361 } else {
4362 // remove this record from the history.
4363 if (r.finishing) {
4364 removeActivityFromHistoryLocked(r);
4365 removedFromHistory = true;
4366 } else {
4367 r.state = ActivityState.DESTROYED;
4368 }
4369 }
4370
4371 r.configChangeFlags = 0;
4372
4373 if (!mLRUActivities.remove(r)) {
4374 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4375 }
4376
4377 return removedFromHistory;
4378 }
4379
4380 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4381 ProcessRecord app)
4382 {
4383 int i = list.size();
4384 if (localLOGV) Log.v(
4385 TAG, "Removing app " + app + " from list " + list
4386 + " with " + i + " entries");
4387 while (i > 0) {
4388 i--;
4389 HistoryRecord r = (HistoryRecord)list.get(i);
4390 if (localLOGV) Log.v(
4391 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4392 if (r.app == app) {
4393 if (localLOGV) Log.v(TAG, "Removing this entry!");
4394 list.remove(i);
4395 }
4396 }
4397 }
4398
4399 /**
4400 * Main function for removing an existing process from the activity manager
4401 * as a result of that process going away. Clears out all connections
4402 * to the process.
4403 */
4404 private final void handleAppDiedLocked(ProcessRecord app,
4405 boolean restarting) {
4406 cleanUpApplicationRecordLocked(app, restarting, -1);
4407 if (!restarting) {
4408 mLRUProcesses.remove(app);
4409 }
4410
4411 // Just in case...
4412 if (mPausingActivity != null && mPausingActivity.app == app) {
4413 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4414 mPausingActivity = null;
4415 }
4416 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4417 mLastPausedActivity = null;
4418 }
4419
4420 // Remove this application's activities from active lists.
4421 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4422 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4423 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4424 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4425
4426 boolean atTop = true;
4427 boolean hasVisibleActivities = false;
4428
4429 // Clean out the history list.
4430 int i = mHistory.size();
4431 if (localLOGV) Log.v(
4432 TAG, "Removing app " + app + " from history with " + i + " entries");
4433 while (i > 0) {
4434 i--;
4435 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4436 if (localLOGV) Log.v(
4437 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4438 if (r.app == app) {
4439 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4440 if (localLOGV) Log.v(
4441 TAG, "Removing this entry! frozen=" + r.haveState
4442 + " finishing=" + r.finishing);
4443 mHistory.remove(i);
4444
4445 r.inHistory = false;
4446 mWindowManager.removeAppToken(r);
4447 if (VALIDATE_TOKENS) {
4448 mWindowManager.validateAppTokens(mHistory);
4449 }
4450 removeActivityUriPermissionsLocked(r);
4451
4452 } else {
4453 // We have the current state for this activity, so
4454 // it can be restarted later when needed.
4455 if (localLOGV) Log.v(
4456 TAG, "Keeping entry, setting app to null");
4457 if (r.visible) {
4458 hasVisibleActivities = true;
4459 }
4460 r.app = null;
4461 r.nowVisible = false;
4462 if (!r.haveState) {
4463 r.icicle = null;
4464 }
4465 }
4466
4467 cleanUpActivityLocked(r, true);
4468 r.state = ActivityState.STOPPED;
4469 }
4470 atTop = false;
4471 }
4472
4473 app.activities.clear();
4474
4475 if (app.instrumentationClass != null) {
4476 Log.w(TAG, "Crash of app " + app.processName
4477 + " running instrumentation " + app.instrumentationClass);
4478 Bundle info = new Bundle();
4479 info.putString("shortMsg", "Process crashed.");
4480 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4481 }
4482
4483 if (!restarting) {
4484 if (!resumeTopActivityLocked(null)) {
4485 // If there was nothing to resume, and we are not already
4486 // restarting this process, but there is a visible activity that
4487 // is hosted by the process... then make sure all visible
4488 // activities are running, taking care of restarting this
4489 // process.
4490 if (hasVisibleActivities) {
4491 ensureActivitiesVisibleLocked(null, 0);
4492 }
4493 }
4494 }
4495 }
4496
4497 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4498 IBinder threadBinder = thread.asBinder();
4499
4500 // Find the application record.
4501 int count = mLRUProcesses.size();
4502 int i;
4503 for (i=0; i<count; i++) {
4504 ProcessRecord rec = mLRUProcesses.get(i);
4505 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4506 return i;
4507 }
4508 }
4509 return -1;
4510 }
4511
4512 private final ProcessRecord getRecordForAppLocked(
4513 IApplicationThread thread) {
4514 if (thread == null) {
4515 return null;
4516 }
4517
4518 int appIndex = getLRURecordIndexForAppLocked(thread);
4519 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4520 }
4521
4522 private final void appDiedLocked(ProcessRecord app, int pid,
4523 IApplicationThread thread) {
4524
4525 mProcDeaths[0]++;
4526
4527 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4528 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4529 + ") has died.");
4530 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4531 if (localLOGV) Log.v(
4532 TAG, "Dying app: " + app + ", pid: " + pid
4533 + ", thread: " + thread.asBinder());
4534 boolean doLowMem = app.instrumentationClass == null;
4535 handleAppDiedLocked(app, false);
4536
4537 if (doLowMem) {
4538 // If there are no longer any background processes running,
4539 // and the app that died was not running instrumentation,
4540 // then tell everyone we are now low on memory.
4541 boolean haveBg = false;
4542 int count = mLRUProcesses.size();
4543 int i;
4544 for (i=0; i<count; i++) {
4545 ProcessRecord rec = mLRUProcesses.get(i);
4546 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4547 haveBg = true;
4548 break;
4549 }
4550 }
4551
4552 if (!haveBg) {
4553 Log.i(TAG, "Low Memory: No more background processes.");
4554 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004555 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004556 for (i=0; i<count; i++) {
4557 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004558 if (rec.thread != null &&
4559 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4560 // The low memory report is overriding any current
4561 // state for a GC request. Make sure to do
4562 // visible/foreground processes first.
4563 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4564 rec.lastRequestedGc = 0;
4565 } else {
4566 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004567 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004568 rec.reportLowMemory = true;
4569 rec.lastLowMemory = now;
4570 mProcessesToGc.remove(rec);
4571 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004572 }
4573 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004574 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004575 }
4576 }
4577 } else if (Config.LOGD) {
4578 Log.d(TAG, "Received spurious death notification for thread "
4579 + thread.asBinder());
4580 }
4581 }
4582
4583 final String readFile(String filename) {
4584 try {
4585 FileInputStream fs = new FileInputStream(filename);
4586 byte[] inp = new byte[8192];
4587 int size = fs.read(inp);
4588 fs.close();
4589 return new String(inp, 0, 0, size);
4590 } catch (java.io.IOException e) {
4591 }
4592 return "";
4593 }
4594
4595 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004596 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004597 if (app.notResponding || app.crashing) {
4598 return;
4599 }
4600
4601 // Log the ANR to the event log.
4602 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4603
4604 // If we are on a secure build and the application is not interesting to the user (it is
4605 // not visible or in the background), just kill it instead of displaying a dialog.
4606 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4607 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4608 Process.killProcess(app.pid);
4609 return;
4610 }
4611
4612 // DeviceMonitor.start();
4613
4614 String processInfo = null;
4615 if (MONITOR_CPU_USAGE) {
4616 updateCpuStatsNow();
4617 synchronized (mProcessStatsThread) {
4618 processInfo = mProcessStats.printCurrentState();
4619 }
4620 }
4621
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004622 StringBuilder info = mStringBuilder;
4623 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004624 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004625 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004626 if (reportedActivity != null && reportedActivity.app != null) {
4627 info.append(" (last in ");
4628 info.append(reportedActivity.app.processName);
4629 info.append(")");
4630 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004631 if (annotation != null) {
4632 info.append("\nAnnotation: ");
4633 info.append(annotation);
4634 }
4635 if (MONITOR_CPU_USAGE) {
4636 info.append("\nCPU usage:\n");
4637 info.append(processInfo);
4638 }
4639 Log.i(TAG, info.toString());
4640
4641 // The application is not responding. Dump as many thread traces as we can.
4642 boolean fileDump = prepareTraceFile(true);
4643 if (!fileDump) {
4644 // Dumping traces to the log, just dump the process that isn't responding so
4645 // we don't overflow the log
4646 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4647 } else {
4648 // Dumping traces to a file so dump all active processes we know about
4649 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004650 // First, these are the most important processes.
4651 final int[] imppids = new int[3];
4652 int i=0;
4653 imppids[0] = app.pid;
4654 i++;
4655 if (reportedActivity != null && reportedActivity.app != null
4656 && reportedActivity.app.thread != null
4657 && reportedActivity.app.pid != app.pid) {
4658 imppids[i] = reportedActivity.app.pid;
4659 i++;
4660 }
4661 imppids[i] = Process.myPid();
4662 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4663 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4664 synchronized (this) {
4665 try {
4666 wait(200);
4667 } catch (InterruptedException e) {
4668 }
4669 }
4670 }
4671 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004672 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004673 boolean done = false;
4674 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4675 if (imppids[j] == r.pid) {
4676 done = true;
4677 break;
4678 }
4679 }
4680 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004681 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004682 synchronized (this) {
4683 try {
4684 wait(200);
4685 } catch (InterruptedException e) {
4686 }
4687 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004688 }
4689 }
4690 }
4691 }
4692
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004693 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004694 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004695 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004696 app.pid, info.toString());
4697 if (res != 0) {
4698 if (res < 0) {
4699 // wait until the SIGQUIT has had a chance to process before killing the
4700 // process.
4701 try {
4702 wait(2000);
4703 } catch (InterruptedException e) {
4704 }
4705
4706 Process.killProcess(app.pid);
4707 return;
4708 }
4709 }
4710 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004711 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004712 }
4713 }
4714
4715 makeAppNotRespondingLocked(app,
4716 activity != null ? activity.shortComponentName : null,
4717 annotation != null ? "ANR " + annotation : "ANR",
4718 info.toString(), null);
4719 Message msg = Message.obtain();
4720 HashMap map = new HashMap();
4721 msg.what = SHOW_NOT_RESPONDING_MSG;
4722 msg.obj = map;
4723 map.put("app", app);
4724 if (activity != null) {
4725 map.put("activity", activity);
4726 }
4727
4728 mHandler.sendMessage(msg);
4729 return;
4730 }
4731
4732 /**
4733 * If a stack trace file has been configured, prepare the filesystem
4734 * by creating the directory if it doesn't exist and optionally
4735 * removing the old trace file.
4736 *
4737 * @param removeExisting If set, the existing trace file will be removed.
4738 * @return Returns true if the trace file preparations succeeded
4739 */
4740 public static boolean prepareTraceFile(boolean removeExisting) {
4741 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4742 boolean fileReady = false;
4743 if (!TextUtils.isEmpty(tracesPath)) {
4744 File f = new File(tracesPath);
4745 if (!f.exists()) {
4746 // Ensure the enclosing directory exists
4747 File dir = f.getParentFile();
4748 if (!dir.exists()) {
4749 fileReady = dir.mkdirs();
4750 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004751 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004752 } else if (dir.isDirectory()) {
4753 fileReady = true;
4754 }
4755 } else if (removeExisting) {
4756 // Remove the previous traces file, so we don't fill the disk.
4757 // The VM will recreate it
4758 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4759 fileReady = f.delete();
4760 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004761
4762 if (removeExisting) {
4763 try {
4764 f.createNewFile();
4765 FileUtils.setPermissions(f.getAbsolutePath(),
4766 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4767 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4768 fileReady = true;
4769 } catch (IOException e) {
4770 Log.w(TAG, "Unable to make ANR traces file", e);
4771 }
4772 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004773 }
4774
4775 return fileReady;
4776 }
4777
4778
4779 private final void decPersistentCountLocked(ProcessRecord app)
4780 {
4781 app.persistentActivities--;
4782 if (app.persistentActivities > 0) {
4783 // Still more of 'em...
4784 return;
4785 }
4786 if (app.persistent) {
4787 // Ah, but the application itself is persistent. Whatever!
4788 return;
4789 }
4790
4791 // App is no longer persistent... make sure it and the ones
4792 // following it in the LRU list have the correc oom_adj.
4793 updateOomAdjLocked();
4794 }
4795
4796 public void setPersistent(IBinder token, boolean isPersistent) {
4797 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4798 != PackageManager.PERMISSION_GRANTED) {
4799 String msg = "Permission Denial: setPersistent() from pid="
4800 + Binder.getCallingPid()
4801 + ", uid=" + Binder.getCallingUid()
4802 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4803 Log.w(TAG, msg);
4804 throw new SecurityException(msg);
4805 }
4806
4807 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004808 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004809 if (index < 0) {
4810 return;
4811 }
4812 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4813 ProcessRecord app = r.app;
4814
4815 if (localLOGV) Log.v(
4816 TAG, "Setting persistence " + isPersistent + ": " + r);
4817
4818 if (isPersistent) {
4819 if (r.persistent) {
4820 // Okay okay, I heard you already!
4821 if (localLOGV) Log.v(TAG, "Already persistent!");
4822 return;
4823 }
4824 r.persistent = true;
4825 app.persistentActivities++;
4826 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4827 if (app.persistentActivities > 1) {
4828 // We aren't the first...
4829 if (localLOGV) Log.v(TAG, "Not the first!");
4830 return;
4831 }
4832 if (app.persistent) {
4833 // This would be redundant.
4834 if (localLOGV) Log.v(TAG, "App is persistent!");
4835 return;
4836 }
4837
4838 // App is now persistent... make sure it and the ones
4839 // following it now have the correct oom_adj.
4840 final long origId = Binder.clearCallingIdentity();
4841 updateOomAdjLocked();
4842 Binder.restoreCallingIdentity(origId);
4843
4844 } else {
4845 if (!r.persistent) {
4846 // Okay okay, I heard you already!
4847 return;
4848 }
4849 r.persistent = false;
4850 final long origId = Binder.clearCallingIdentity();
4851 decPersistentCountLocked(app);
4852 Binder.restoreCallingIdentity(origId);
4853
4854 }
4855 }
4856 }
4857
4858 public boolean clearApplicationUserData(final String packageName,
4859 final IPackageDataObserver observer) {
4860 int uid = Binder.getCallingUid();
4861 int pid = Binder.getCallingPid();
4862 long callingId = Binder.clearCallingIdentity();
4863 try {
4864 IPackageManager pm = ActivityThread.getPackageManager();
4865 int pkgUid = -1;
4866 synchronized(this) {
4867 try {
4868 pkgUid = pm.getPackageUid(packageName);
4869 } catch (RemoteException e) {
4870 }
4871 if (pkgUid == -1) {
4872 Log.w(TAG, "Invalid packageName:" + packageName);
4873 return false;
4874 }
4875 if (uid == pkgUid || checkComponentPermission(
4876 android.Manifest.permission.CLEAR_APP_USER_DATA,
4877 pid, uid, -1)
4878 == PackageManager.PERMISSION_GRANTED) {
4879 restartPackageLocked(packageName, pkgUid);
4880 } else {
4881 throw new SecurityException(pid+" does not have permission:"+
4882 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4883 "for process:"+packageName);
4884 }
4885 }
4886
4887 try {
4888 //clear application user data
4889 pm.clearApplicationUserData(packageName, observer);
4890 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4891 Uri.fromParts("package", packageName, null));
4892 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4893 broadcastIntentLocked(null, null, intent,
4894 null, null, 0, null, null, null,
4895 false, false, MY_PID, Process.SYSTEM_UID);
4896 } catch (RemoteException e) {
4897 }
4898 } finally {
4899 Binder.restoreCallingIdentity(callingId);
4900 }
4901 return true;
4902 }
4903
4904 public void restartPackage(final String packageName) {
4905 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4906 != PackageManager.PERMISSION_GRANTED) {
4907 String msg = "Permission Denial: restartPackage() from pid="
4908 + Binder.getCallingPid()
4909 + ", uid=" + Binder.getCallingUid()
4910 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4911 Log.w(TAG, msg);
4912 throw new SecurityException(msg);
4913 }
4914
4915 long callingId = Binder.clearCallingIdentity();
4916 try {
4917 IPackageManager pm = ActivityThread.getPackageManager();
4918 int pkgUid = -1;
4919 synchronized(this) {
4920 try {
4921 pkgUid = pm.getPackageUid(packageName);
4922 } catch (RemoteException e) {
4923 }
4924 if (pkgUid == -1) {
4925 Log.w(TAG, "Invalid packageName: " + packageName);
4926 return;
4927 }
4928 restartPackageLocked(packageName, pkgUid);
4929 }
4930 } finally {
4931 Binder.restoreCallingIdentity(callingId);
4932 }
4933 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004934
4935 /*
4936 * The pkg name and uid have to be specified.
4937 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4938 */
4939 public void killApplicationWithUid(String pkg, int uid) {
4940 if (pkg == null) {
4941 return;
4942 }
4943 // Make sure the uid is valid.
4944 if (uid < 0) {
4945 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4946 return;
4947 }
4948 int callerUid = Binder.getCallingUid();
4949 // Only the system server can kill an application
4950 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004951 // Post an aysnc message to kill the application
4952 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4953 msg.arg1 = uid;
4954 msg.arg2 = 0;
4955 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004956 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004957 } else {
4958 throw new SecurityException(callerUid + " cannot kill pkg: " +
4959 pkg);
4960 }
4961 }
4962
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004963 public void closeSystemDialogs(String reason) {
4964 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4965 if (reason != null) {
4966 intent.putExtra("reason", reason);
4967 }
4968
4969 final int uid = Binder.getCallingUid();
4970 final long origId = Binder.clearCallingIdentity();
4971 synchronized (this) {
4972 int i = mWatchers.beginBroadcast();
4973 while (i > 0) {
4974 i--;
4975 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4976 if (w != null) {
4977 try {
4978 w.closingSystemDialogs(reason);
4979 } catch (RemoteException e) {
4980 }
4981 }
4982 }
4983 mWatchers.finishBroadcast();
4984
Dianne Hackbornffa42482009-09-23 22:20:11 -07004985 mWindowManager.closeSystemDialogs(reason);
4986
4987 for (i=mHistory.size()-1; i>=0; i--) {
4988 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4989 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
4990 finishActivityLocked(r, i,
4991 Activity.RESULT_CANCELED, null, "close-sys");
4992 }
4993 }
4994
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004995 broadcastIntentLocked(null, null, intent, null,
4996 null, 0, null, null, null, false, false, -1, uid);
4997 }
4998 Binder.restoreCallingIdentity(origId);
4999 }
5000
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005001 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005002 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005003 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
5004 for (int i=pids.length-1; i>=0; i--) {
5005 infos[i] = new Debug.MemoryInfo();
5006 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005007 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005008 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005009 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07005010
5011 public void killApplicationProcess(String processName, int uid) {
5012 if (processName == null) {
5013 return;
5014 }
5015
5016 int callerUid = Binder.getCallingUid();
5017 // Only the system server can kill an application
5018 if (callerUid == Process.SYSTEM_UID) {
5019 synchronized (this) {
5020 ProcessRecord app = getProcessRecordLocked(processName, uid);
5021 if (app != null) {
5022 try {
5023 app.thread.scheduleSuicide();
5024 } catch (RemoteException e) {
5025 // If the other end already died, then our work here is done.
5026 }
5027 } else {
5028 Log.w(TAG, "Process/uid not found attempting kill of "
5029 + processName + " / " + uid);
5030 }
5031 }
5032 } else {
5033 throw new SecurityException(callerUid + " cannot kill app process: " +
5034 processName);
5035 }
5036 }
5037
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005038 private void restartPackageLocked(final String packageName, int uid) {
5039 uninstallPackageLocked(packageName, uid, false);
5040 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5041 Uri.fromParts("package", packageName, null));
5042 intent.putExtra(Intent.EXTRA_UID, uid);
5043 broadcastIntentLocked(null, null, intent,
5044 null, null, 0, null, null, null,
5045 false, false, MY_PID, Process.SYSTEM_UID);
5046 }
5047
5048 private final void uninstallPackageLocked(String name, int uid,
5049 boolean callerWillRestart) {
5050 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
5051
5052 int i, N;
5053
5054 final String procNamePrefix = name + ":";
5055 if (uid < 0) {
5056 try {
5057 uid = ActivityThread.getPackageManager().getPackageUid(name);
5058 } catch (RemoteException e) {
5059 }
5060 }
5061
5062 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5063 while (badApps.hasNext()) {
5064 SparseArray<Long> ba = badApps.next();
5065 if (ba.get(uid) != null) {
5066 badApps.remove();
5067 }
5068 }
5069
5070 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
5071
5072 // Remove all processes this package may have touched: all with the
5073 // same UID (except for the system or root user), and all whose name
5074 // matches the package name.
5075 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5076 final int NA = apps.size();
5077 for (int ia=0; ia<NA; ia++) {
5078 ProcessRecord app = apps.valueAt(ia);
5079 if (app.removed) {
5080 procs.add(app);
5081 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5082 || app.processName.equals(name)
5083 || app.processName.startsWith(procNamePrefix)) {
5084 app.removed = true;
5085 procs.add(app);
5086 }
5087 }
5088 }
5089
5090 N = procs.size();
5091 for (i=0; i<N; i++) {
5092 removeProcessLocked(procs.get(i), callerWillRestart);
5093 }
5094
5095 for (i=mHistory.size()-1; i>=0; i--) {
5096 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5097 if (r.packageName.equals(name)) {
5098 if (Config.LOGD) Log.d(
5099 TAG, " Force finishing activity "
5100 + r.intent.getComponent().flattenToShortString());
5101 if (r.app != null) {
5102 r.app.removed = true;
5103 }
5104 r.app = null;
5105 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5106 }
5107 }
5108
5109 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5110 for (ServiceRecord service : mServices.values()) {
5111 if (service.packageName.equals(name)) {
5112 if (service.app != null) {
5113 service.app.removed = true;
5114 }
5115 service.app = null;
5116 services.add(service);
5117 }
5118 }
5119
5120 N = services.size();
5121 for (i=0; i<N; i++) {
5122 bringDownServiceLocked(services.get(i), true);
5123 }
5124
5125 resumeTopActivityLocked(null);
5126 }
5127
5128 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5129 final String name = app.processName;
5130 final int uid = app.info.uid;
5131 if (Config.LOGD) Log.d(
5132 TAG, "Force removing process " + app + " (" + name
5133 + "/" + uid + ")");
5134
5135 mProcessNames.remove(name, uid);
5136 boolean needRestart = false;
5137 if (app.pid > 0 && app.pid != MY_PID) {
5138 int pid = app.pid;
5139 synchronized (mPidsSelfLocked) {
5140 mPidsSelfLocked.remove(pid);
5141 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5142 }
5143 handleAppDiedLocked(app, true);
5144 mLRUProcesses.remove(app);
5145 Process.killProcess(pid);
5146
5147 if (app.persistent) {
5148 if (!callerWillRestart) {
5149 addAppLocked(app.info);
5150 } else {
5151 needRestart = true;
5152 }
5153 }
5154 } else {
5155 mRemovedProcesses.add(app);
5156 }
5157
5158 return needRestart;
5159 }
5160
5161 private final void processStartTimedOutLocked(ProcessRecord app) {
5162 final int pid = app.pid;
5163 boolean gone = false;
5164 synchronized (mPidsSelfLocked) {
5165 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5166 if (knownApp != null && knownApp.thread == null) {
5167 mPidsSelfLocked.remove(pid);
5168 gone = true;
5169 }
5170 }
5171
5172 if (gone) {
5173 Log.w(TAG, "Process " + app + " failed to attach");
5174 mProcessNames.remove(app.processName, app.info.uid);
5175 Process.killProcess(pid);
5176 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5177 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5178 mPendingBroadcast = null;
5179 scheduleBroadcastsLocked();
5180 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005181 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5182 Log.w(TAG, "Unattached app died before backup, skipping");
5183 try {
5184 IBackupManager bm = IBackupManager.Stub.asInterface(
5185 ServiceManager.getService(Context.BACKUP_SERVICE));
5186 bm.agentDisconnected(app.info.packageName);
5187 } catch (RemoteException e) {
5188 // Can't happen; the backup manager is local
5189 }
5190 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005191 } else {
5192 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5193 }
5194 }
5195
5196 private final boolean attachApplicationLocked(IApplicationThread thread,
5197 int pid) {
5198
5199 // Find the application record that is being attached... either via
5200 // the pid if we are running in multiple processes, or just pull the
5201 // next app record if we are emulating process with anonymous threads.
5202 ProcessRecord app;
5203 if (pid != MY_PID && pid >= 0) {
5204 synchronized (mPidsSelfLocked) {
5205 app = mPidsSelfLocked.get(pid);
5206 }
5207 } else if (mStartingProcesses.size() > 0) {
5208 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005209 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005210 } else {
5211 app = null;
5212 }
5213
5214 if (app == null) {
5215 Log.w(TAG, "No pending application record for pid " + pid
5216 + " (IApplicationThread " + thread + "); dropping process");
5217 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5218 if (pid > 0 && pid != MY_PID) {
5219 Process.killProcess(pid);
5220 } else {
5221 try {
5222 thread.scheduleExit();
5223 } catch (Exception e) {
5224 // Ignore exceptions.
5225 }
5226 }
5227 return false;
5228 }
5229
5230 // If this application record is still attached to a previous
5231 // process, clean it up now.
5232 if (app.thread != null) {
5233 handleAppDiedLocked(app, true);
5234 }
5235
5236 // Tell the process all about itself.
5237
5238 if (localLOGV) Log.v(
5239 TAG, "Binding process pid " + pid + " to record " + app);
5240
5241 String processName = app.processName;
5242 try {
5243 thread.asBinder().linkToDeath(new AppDeathRecipient(
5244 app, pid, thread), 0);
5245 } catch (RemoteException e) {
5246 app.resetPackageList();
5247 startProcessLocked(app, "link fail", processName);
5248 return false;
5249 }
5250
5251 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5252
5253 app.thread = thread;
5254 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005255 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005256 app.forcingToForeground = null;
5257 app.foregroundServices = false;
5258 app.debugging = false;
5259
5260 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5261
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005262 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5263 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005264
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005265 if (!normalMode) {
5266 Log.i(TAG, "Launching preboot mode app: " + app);
5267 }
5268
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005269 if (localLOGV) Log.v(
5270 TAG, "New app record " + app
5271 + " thread=" + thread.asBinder() + " pid=" + pid);
5272 try {
5273 int testMode = IApplicationThread.DEBUG_OFF;
5274 if (mDebugApp != null && mDebugApp.equals(processName)) {
5275 testMode = mWaitForDebugger
5276 ? IApplicationThread.DEBUG_WAIT
5277 : IApplicationThread.DEBUG_ON;
5278 app.debugging = true;
5279 if (mDebugTransient) {
5280 mDebugApp = mOrigDebugApp;
5281 mWaitForDebugger = mOrigWaitForDebugger;
5282 }
5283 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005284
Christopher Tate181fafa2009-05-14 11:12:14 -07005285 // If the app is being launched for restore or full backup, set it up specially
5286 boolean isRestrictedBackupMode = false;
5287 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5288 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5289 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5290 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005291
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005292 ensurePackageDexOpt(app.instrumentationInfo != null
5293 ? app.instrumentationInfo.packageName
5294 : app.info.packageName);
5295 if (app.instrumentationClass != null) {
5296 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005297 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07005298 thread.bindApplication(processName, app.instrumentationInfo != null
5299 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005300 app.instrumentationClass, app.instrumentationProfileFile,
5301 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005302 isRestrictedBackupMode || !normalMode,
5303 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005304 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005305 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005306 } catch (Exception e) {
5307 // todo: Yikes! What should we do? For now we will try to
5308 // start another process, but that could easily get us in
5309 // an infinite loop of restarting processes...
5310 Log.w(TAG, "Exception thrown during bind!", e);
5311
5312 app.resetPackageList();
5313 startProcessLocked(app, "bind fail", processName);
5314 return false;
5315 }
5316
5317 // Remove this record from the list of starting applications.
5318 mPersistentStartingProcesses.remove(app);
5319 mProcessesOnHold.remove(app);
5320
5321 boolean badApp = false;
5322 boolean didSomething = false;
5323
5324 // See if the top visible activity is waiting to run in this process...
5325 HistoryRecord hr = topRunningActivityLocked(null);
5326 if (hr != null) {
5327 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5328 && processName.equals(hr.processName)) {
5329 try {
5330 if (realStartActivityLocked(hr, app, true, true)) {
5331 didSomething = true;
5332 }
5333 } catch (Exception e) {
5334 Log.w(TAG, "Exception in new application when starting activity "
5335 + hr.intent.getComponent().flattenToShortString(), e);
5336 badApp = true;
5337 }
5338 } else {
5339 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5340 }
5341 }
5342
5343 // Find any services that should be running in this process...
5344 if (!badApp && mPendingServices.size() > 0) {
5345 ServiceRecord sr = null;
5346 try {
5347 for (int i=0; i<mPendingServices.size(); i++) {
5348 sr = mPendingServices.get(i);
5349 if (app.info.uid != sr.appInfo.uid
5350 || !processName.equals(sr.processName)) {
5351 continue;
5352 }
5353
5354 mPendingServices.remove(i);
5355 i--;
5356 realStartServiceLocked(sr, app);
5357 didSomething = true;
5358 }
5359 } catch (Exception e) {
5360 Log.w(TAG, "Exception in new application when starting service "
5361 + sr.shortName, e);
5362 badApp = true;
5363 }
5364 }
5365
5366 // Check if the next broadcast receiver is in this process...
5367 BroadcastRecord br = mPendingBroadcast;
5368 if (!badApp && br != null && br.curApp == app) {
5369 try {
5370 mPendingBroadcast = null;
5371 processCurBroadcastLocked(br, app);
5372 didSomething = true;
5373 } catch (Exception e) {
5374 Log.w(TAG, "Exception in new application when starting receiver "
5375 + br.curComponent.flattenToShortString(), e);
5376 badApp = true;
5377 logBroadcastReceiverDiscard(br);
5378 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5379 br.resultExtras, br.resultAbort, true);
5380 scheduleBroadcastsLocked();
5381 }
5382 }
5383
Christopher Tate181fafa2009-05-14 11:12:14 -07005384 // Check whether the next backup agent is in this process...
5385 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5386 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005387 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005388 try {
5389 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5390 } catch (Exception e) {
5391 Log.w(TAG, "Exception scheduling backup agent creation: ");
5392 e.printStackTrace();
5393 }
5394 }
5395
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005396 if (badApp) {
5397 // todo: Also need to kill application to deal with all
5398 // kinds of exceptions.
5399 handleAppDiedLocked(app, false);
5400 return false;
5401 }
5402
5403 if (!didSomething) {
5404 updateOomAdjLocked();
5405 }
5406
5407 return true;
5408 }
5409
5410 public final void attachApplication(IApplicationThread thread) {
5411 synchronized (this) {
5412 int callingPid = Binder.getCallingPid();
5413 final long origId = Binder.clearCallingIdentity();
5414 attachApplicationLocked(thread, callingPid);
5415 Binder.restoreCallingIdentity(origId);
5416 }
5417 }
5418
5419 public final void activityIdle(IBinder token) {
5420 final long origId = Binder.clearCallingIdentity();
5421 activityIdleInternal(token, false);
5422 Binder.restoreCallingIdentity(origId);
5423 }
5424
5425 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5426 boolean remove) {
5427 int N = mStoppingActivities.size();
5428 if (N <= 0) return null;
5429
5430 ArrayList<HistoryRecord> stops = null;
5431
5432 final boolean nowVisible = mResumedActivity != null
5433 && mResumedActivity.nowVisible
5434 && !mResumedActivity.waitingVisible;
5435 for (int i=0; i<N; i++) {
5436 HistoryRecord s = mStoppingActivities.get(i);
5437 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5438 + nowVisible + " waitingVisible=" + s.waitingVisible
5439 + " finishing=" + s.finishing);
5440 if (s.waitingVisible && nowVisible) {
5441 mWaitingVisibleActivities.remove(s);
5442 s.waitingVisible = false;
5443 if (s.finishing) {
5444 // If this activity is finishing, it is sitting on top of
5445 // everyone else but we now know it is no longer needed...
5446 // so get rid of it. Otherwise, we need to go through the
5447 // normal flow and hide it once we determine that it is
5448 // hidden by the activities in front of it.
5449 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5450 mWindowManager.setAppVisibility(s, false);
5451 }
5452 }
5453 if (!s.waitingVisible && remove) {
5454 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5455 if (stops == null) {
5456 stops = new ArrayList<HistoryRecord>();
5457 }
5458 stops.add(s);
5459 mStoppingActivities.remove(i);
5460 N--;
5461 i--;
5462 }
5463 }
5464
5465 return stops;
5466 }
5467
5468 void enableScreenAfterBoot() {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005469 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5470 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005471 mWindowManager.enableScreenAfterBoot();
5472 }
5473
5474 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5475 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5476
5477 ArrayList<HistoryRecord> stops = null;
5478 ArrayList<HistoryRecord> finishes = null;
5479 ArrayList<HistoryRecord> thumbnails = null;
5480 int NS = 0;
5481 int NF = 0;
5482 int NT = 0;
5483 IApplicationThread sendThumbnail = null;
5484 boolean booting = false;
5485 boolean enableScreen = false;
5486
5487 synchronized (this) {
5488 if (token != null) {
5489 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5490 }
5491
5492 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005493 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005494 if (index >= 0) {
5495 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5496
5497 // No longer need to keep the device awake.
5498 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5499 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5500 mLaunchingActivity.release();
5501 }
5502
5503 // We are now idle. If someone is waiting for a thumbnail from
5504 // us, we can now deliver.
5505 r.idle = true;
5506 scheduleAppGcsLocked();
5507 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5508 sendThumbnail = r.app.thread;
5509 r.thumbnailNeeded = false;
5510 }
5511
5512 // If this activity is fullscreen, set up to hide those under it.
5513
5514 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5515 ensureActivitiesVisibleLocked(null, 0);
5516
5517 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5518 if (!mBooted && !fromTimeout) {
5519 mBooted = true;
5520 enableScreen = true;
5521 }
5522 }
5523
5524 // Atomically retrieve all of the other things to do.
5525 stops = processStoppingActivitiesLocked(true);
5526 NS = stops != null ? stops.size() : 0;
5527 if ((NF=mFinishingActivities.size()) > 0) {
5528 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5529 mFinishingActivities.clear();
5530 }
5531 if ((NT=mCancelledThumbnails.size()) > 0) {
5532 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5533 mCancelledThumbnails.clear();
5534 }
5535
5536 booting = mBooting;
5537 mBooting = false;
5538 }
5539
5540 int i;
5541
5542 // Send thumbnail if requested.
5543 if (sendThumbnail != null) {
5544 try {
5545 sendThumbnail.requestThumbnail(token);
5546 } catch (Exception e) {
5547 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5548 sendPendingThumbnail(null, token, null, null, true);
5549 }
5550 }
5551
5552 // Stop any activities that are scheduled to do so but have been
5553 // waiting for the next one to start.
5554 for (i=0; i<NS; i++) {
5555 HistoryRecord r = (HistoryRecord)stops.get(i);
5556 synchronized (this) {
5557 if (r.finishing) {
5558 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5559 } else {
5560 stopActivityLocked(r);
5561 }
5562 }
5563 }
5564
5565 // Finish any activities that are scheduled to do so but have been
5566 // waiting for the next one to start.
5567 for (i=0; i<NF; i++) {
5568 HistoryRecord r = (HistoryRecord)finishes.get(i);
5569 synchronized (this) {
5570 destroyActivityLocked(r, true);
5571 }
5572 }
5573
5574 // Report back to any thumbnail receivers.
5575 for (i=0; i<NT; i++) {
5576 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5577 sendPendingThumbnail(r, null, null, null, true);
5578 }
5579
5580 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005581 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005582 }
5583
5584 trimApplications();
5585 //dump();
5586 //mWindowManager.dump();
5587
5588 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005589 enableScreenAfterBoot();
5590 }
5591 }
5592
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005593 final void finishBooting() {
5594 // Ensure that any processes we had put on hold are now started
5595 // up.
5596 final int NP = mProcessesOnHold.size();
5597 if (NP > 0) {
5598 ArrayList<ProcessRecord> procs =
5599 new ArrayList<ProcessRecord>(mProcessesOnHold);
5600 for (int ip=0; ip<NP; ip++) {
5601 this.startProcessLocked(procs.get(ip), "on-hold", null);
5602 }
5603 }
5604 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5605 // Tell anyone interested that we are done booting!
5606 synchronized (this) {
5607 broadcastIntentLocked(null, null,
5608 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5609 null, null, 0, null, null,
5610 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5611 false, false, MY_PID, Process.SYSTEM_UID);
5612 }
5613 }
5614 }
5615
5616 final void ensureBootCompleted() {
5617 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005618 boolean enableScreen;
5619 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005620 booting = mBooting;
5621 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005622 enableScreen = !mBooted;
5623 mBooted = true;
5624 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005625
5626 if (booting) {
5627 finishBooting();
5628 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005629
5630 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005631 enableScreenAfterBoot();
5632 }
5633 }
5634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005635 public final void activityPaused(IBinder token, Bundle icicle) {
5636 // Refuse possible leaked file descriptors
5637 if (icicle != null && icicle.hasFileDescriptors()) {
5638 throw new IllegalArgumentException("File descriptors passed in Bundle");
5639 }
5640
5641 final long origId = Binder.clearCallingIdentity();
5642 activityPaused(token, icicle, false);
5643 Binder.restoreCallingIdentity(origId);
5644 }
5645
5646 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5647 if (DEBUG_PAUSE) Log.v(
5648 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5649 + ", timeout=" + timeout);
5650
5651 HistoryRecord r = null;
5652
5653 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005654 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005655 if (index >= 0) {
5656 r = (HistoryRecord)mHistory.get(index);
5657 if (!timeout) {
5658 r.icicle = icicle;
5659 r.haveState = true;
5660 }
5661 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5662 if (mPausingActivity == r) {
5663 r.state = ActivityState.PAUSED;
5664 completePauseLocked();
5665 } else {
5666 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5667 System.identityHashCode(r), r.shortComponentName,
5668 mPausingActivity != null
5669 ? mPausingActivity.shortComponentName : "(none)");
5670 }
5671 }
5672 }
5673 }
5674
5675 public final void activityStopped(IBinder token, Bitmap thumbnail,
5676 CharSequence description) {
5677 if (localLOGV) Log.v(
5678 TAG, "Activity stopped: token=" + token);
5679
5680 HistoryRecord r = null;
5681
5682 final long origId = Binder.clearCallingIdentity();
5683
5684 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005685 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005686 if (index >= 0) {
5687 r = (HistoryRecord)mHistory.get(index);
5688 r.thumbnail = thumbnail;
5689 r.description = description;
5690 r.stopped = true;
5691 r.state = ActivityState.STOPPED;
5692 if (!r.finishing) {
5693 if (r.configDestroy) {
5694 destroyActivityLocked(r, true);
5695 resumeTopActivityLocked(null);
5696 }
5697 }
5698 }
5699 }
5700
5701 if (r != null) {
5702 sendPendingThumbnail(r, null, null, null, false);
5703 }
5704
5705 trimApplications();
5706
5707 Binder.restoreCallingIdentity(origId);
5708 }
5709
5710 public final void activityDestroyed(IBinder token) {
5711 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5712 synchronized (this) {
5713 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5714
Dianne Hackborn75b03852009-06-12 15:43:26 -07005715 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005716 if (index >= 0) {
5717 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5718 if (r.state == ActivityState.DESTROYING) {
5719 final long origId = Binder.clearCallingIdentity();
5720 removeActivityFromHistoryLocked(r);
5721 Binder.restoreCallingIdentity(origId);
5722 }
5723 }
5724 }
5725 }
5726
5727 public String getCallingPackage(IBinder token) {
5728 synchronized (this) {
5729 HistoryRecord r = getCallingRecordLocked(token);
5730 return r != null && r.app != null ? r.app.processName : null;
5731 }
5732 }
5733
5734 public ComponentName getCallingActivity(IBinder token) {
5735 synchronized (this) {
5736 HistoryRecord r = getCallingRecordLocked(token);
5737 return r != null ? r.intent.getComponent() : null;
5738 }
5739 }
5740
5741 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005742 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005743 if (index >= 0) {
5744 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5745 if (r != null) {
5746 return r.resultTo;
5747 }
5748 }
5749 return null;
5750 }
5751
5752 public ComponentName getActivityClassForToken(IBinder token) {
5753 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005754 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005755 if (index >= 0) {
5756 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5757 return r.intent.getComponent();
5758 }
5759 return null;
5760 }
5761 }
5762
5763 public String getPackageForToken(IBinder token) {
5764 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005765 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005766 if (index >= 0) {
5767 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5768 return r.packageName;
5769 }
5770 return null;
5771 }
5772 }
5773
5774 public IIntentSender getIntentSender(int type,
5775 String packageName, IBinder token, String resultWho,
5776 int requestCode, Intent intent, String resolvedType, int flags) {
5777 // Refuse possible leaked file descriptors
5778 if (intent != null && intent.hasFileDescriptors() == true) {
5779 throw new IllegalArgumentException("File descriptors passed in Intent");
5780 }
5781
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005782 if (type == INTENT_SENDER_BROADCAST) {
5783 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5784 throw new IllegalArgumentException(
5785 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5786 }
5787 }
5788
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005789 synchronized(this) {
5790 int callingUid = Binder.getCallingUid();
5791 try {
5792 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5793 Process.supportsProcesses()) {
5794 int uid = ActivityThread.getPackageManager()
5795 .getPackageUid(packageName);
5796 if (uid != Binder.getCallingUid()) {
5797 String msg = "Permission Denial: getIntentSender() from pid="
5798 + Binder.getCallingPid()
5799 + ", uid=" + Binder.getCallingUid()
5800 + ", (need uid=" + uid + ")"
5801 + " is not allowed to send as package " + packageName;
5802 Log.w(TAG, msg);
5803 throw new SecurityException(msg);
5804 }
5805 }
5806 } catch (RemoteException e) {
5807 throw new SecurityException(e);
5808 }
5809 HistoryRecord activity = null;
5810 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005811 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005812 if (index < 0) {
5813 return null;
5814 }
5815 activity = (HistoryRecord)mHistory.get(index);
5816 if (activity.finishing) {
5817 return null;
5818 }
5819 }
5820
5821 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5822 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5823 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5824 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5825 |PendingIntent.FLAG_UPDATE_CURRENT);
5826
5827 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5828 type, packageName, activity, resultWho,
5829 requestCode, intent, resolvedType, flags);
5830 WeakReference<PendingIntentRecord> ref;
5831 ref = mIntentSenderRecords.get(key);
5832 PendingIntentRecord rec = ref != null ? ref.get() : null;
5833 if (rec != null) {
5834 if (!cancelCurrent) {
5835 if (updateCurrent) {
5836 rec.key.requestIntent.replaceExtras(intent);
5837 }
5838 return rec;
5839 }
5840 rec.canceled = true;
5841 mIntentSenderRecords.remove(key);
5842 }
5843 if (noCreate) {
5844 return rec;
5845 }
5846 rec = new PendingIntentRecord(this, key, callingUid);
5847 mIntentSenderRecords.put(key, rec.ref);
5848 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5849 if (activity.pendingResults == null) {
5850 activity.pendingResults
5851 = new HashSet<WeakReference<PendingIntentRecord>>();
5852 }
5853 activity.pendingResults.add(rec.ref);
5854 }
5855 return rec;
5856 }
5857 }
5858
5859 public void cancelIntentSender(IIntentSender sender) {
5860 if (!(sender instanceof PendingIntentRecord)) {
5861 return;
5862 }
5863 synchronized(this) {
5864 PendingIntentRecord rec = (PendingIntentRecord)sender;
5865 try {
5866 int uid = ActivityThread.getPackageManager()
5867 .getPackageUid(rec.key.packageName);
5868 if (uid != Binder.getCallingUid()) {
5869 String msg = "Permission Denial: cancelIntentSender() from pid="
5870 + Binder.getCallingPid()
5871 + ", uid=" + Binder.getCallingUid()
5872 + " is not allowed to cancel packges "
5873 + rec.key.packageName;
5874 Log.w(TAG, msg);
5875 throw new SecurityException(msg);
5876 }
5877 } catch (RemoteException e) {
5878 throw new SecurityException(e);
5879 }
5880 cancelIntentSenderLocked(rec, true);
5881 }
5882 }
5883
5884 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5885 rec.canceled = true;
5886 mIntentSenderRecords.remove(rec.key);
5887 if (cleanActivity && rec.key.activity != null) {
5888 rec.key.activity.pendingResults.remove(rec.ref);
5889 }
5890 }
5891
5892 public String getPackageForIntentSender(IIntentSender pendingResult) {
5893 if (!(pendingResult instanceof PendingIntentRecord)) {
5894 return null;
5895 }
5896 synchronized(this) {
5897 try {
5898 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5899 return res.key.packageName;
5900 } catch (ClassCastException e) {
5901 }
5902 }
5903 return null;
5904 }
5905
5906 public void setProcessLimit(int max) {
5907 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5908 "setProcessLimit()");
5909 mProcessLimit = max;
5910 }
5911
5912 public int getProcessLimit() {
5913 return mProcessLimit;
5914 }
5915
5916 void foregroundTokenDied(ForegroundToken token) {
5917 synchronized (ActivityManagerService.this) {
5918 synchronized (mPidsSelfLocked) {
5919 ForegroundToken cur
5920 = mForegroundProcesses.get(token.pid);
5921 if (cur != token) {
5922 return;
5923 }
5924 mForegroundProcesses.remove(token.pid);
5925 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5926 if (pr == null) {
5927 return;
5928 }
5929 pr.forcingToForeground = null;
5930 pr.foregroundServices = false;
5931 }
5932 updateOomAdjLocked();
5933 }
5934 }
5935
5936 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5937 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5938 "setProcessForeground()");
5939 synchronized(this) {
5940 boolean changed = false;
5941
5942 synchronized (mPidsSelfLocked) {
5943 ProcessRecord pr = mPidsSelfLocked.get(pid);
5944 if (pr == null) {
5945 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5946 return;
5947 }
5948 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5949 if (oldToken != null) {
5950 oldToken.token.unlinkToDeath(oldToken, 0);
5951 mForegroundProcesses.remove(pid);
5952 pr.forcingToForeground = null;
5953 changed = true;
5954 }
5955 if (isForeground && token != null) {
5956 ForegroundToken newToken = new ForegroundToken() {
5957 public void binderDied() {
5958 foregroundTokenDied(this);
5959 }
5960 };
5961 newToken.pid = pid;
5962 newToken.token = token;
5963 try {
5964 token.linkToDeath(newToken, 0);
5965 mForegroundProcesses.put(pid, newToken);
5966 pr.forcingToForeground = token;
5967 changed = true;
5968 } catch (RemoteException e) {
5969 // If the process died while doing this, we will later
5970 // do the cleanup with the process death link.
5971 }
5972 }
5973 }
5974
5975 if (changed) {
5976 updateOomAdjLocked();
5977 }
5978 }
5979 }
5980
5981 // =========================================================
5982 // PERMISSIONS
5983 // =========================================================
5984
5985 static class PermissionController extends IPermissionController.Stub {
5986 ActivityManagerService mActivityManagerService;
5987 PermissionController(ActivityManagerService activityManagerService) {
5988 mActivityManagerService = activityManagerService;
5989 }
5990
5991 public boolean checkPermission(String permission, int pid, int uid) {
5992 return mActivityManagerService.checkPermission(permission, pid,
5993 uid) == PackageManager.PERMISSION_GRANTED;
5994 }
5995 }
5996
5997 /**
5998 * This can be called with or without the global lock held.
5999 */
6000 int checkComponentPermission(String permission, int pid, int uid,
6001 int reqUid) {
6002 // We might be performing an operation on behalf of an indirect binder
6003 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
6004 // client identity accordingly before proceeding.
6005 Identity tlsIdentity = sCallerIdentity.get();
6006 if (tlsIdentity != null) {
6007 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6008 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6009 uid = tlsIdentity.uid;
6010 pid = tlsIdentity.pid;
6011 }
6012
6013 // Root, system server and our own process get to do everything.
6014 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6015 !Process.supportsProcesses()) {
6016 return PackageManager.PERMISSION_GRANTED;
6017 }
6018 // If the target requires a specific UID, always fail for others.
6019 if (reqUid >= 0 && uid != reqUid) {
6020 return PackageManager.PERMISSION_DENIED;
6021 }
6022 if (permission == null) {
6023 return PackageManager.PERMISSION_GRANTED;
6024 }
6025 try {
6026 return ActivityThread.getPackageManager()
6027 .checkUidPermission(permission, uid);
6028 } catch (RemoteException e) {
6029 // Should never happen, but if it does... deny!
6030 Log.e(TAG, "PackageManager is dead?!?", e);
6031 }
6032 return PackageManager.PERMISSION_DENIED;
6033 }
6034
6035 /**
6036 * As the only public entry point for permissions checking, this method
6037 * can enforce the semantic that requesting a check on a null global
6038 * permission is automatically denied. (Internally a null permission
6039 * string is used when calling {@link #checkComponentPermission} in cases
6040 * when only uid-based security is needed.)
6041 *
6042 * This can be called with or without the global lock held.
6043 */
6044 public int checkPermission(String permission, int pid, int uid) {
6045 if (permission == null) {
6046 return PackageManager.PERMISSION_DENIED;
6047 }
6048 return checkComponentPermission(permission, pid, uid, -1);
6049 }
6050
6051 /**
6052 * Binder IPC calls go through the public entry point.
6053 * This can be called with or without the global lock held.
6054 */
6055 int checkCallingPermission(String permission) {
6056 return checkPermission(permission,
6057 Binder.getCallingPid(),
6058 Binder.getCallingUid());
6059 }
6060
6061 /**
6062 * This can be called with or without the global lock held.
6063 */
6064 void enforceCallingPermission(String permission, String func) {
6065 if (checkCallingPermission(permission)
6066 == PackageManager.PERMISSION_GRANTED) {
6067 return;
6068 }
6069
6070 String msg = "Permission Denial: " + func + " from pid="
6071 + Binder.getCallingPid()
6072 + ", uid=" + Binder.getCallingUid()
6073 + " requires " + permission;
6074 Log.w(TAG, msg);
6075 throw new SecurityException(msg);
6076 }
6077
6078 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6079 ProviderInfo pi, int uid, int modeFlags) {
6080 try {
6081 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6082 if ((pi.readPermission != null) &&
6083 (pm.checkUidPermission(pi.readPermission, uid)
6084 != PackageManager.PERMISSION_GRANTED)) {
6085 return false;
6086 }
6087 }
6088 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6089 if ((pi.writePermission != null) &&
6090 (pm.checkUidPermission(pi.writePermission, uid)
6091 != PackageManager.PERMISSION_GRANTED)) {
6092 return false;
6093 }
6094 }
6095 return true;
6096 } catch (RemoteException e) {
6097 return false;
6098 }
6099 }
6100
6101 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6102 int modeFlags) {
6103 // Root gets to do everything.
6104 if (uid == 0 || !Process.supportsProcesses()) {
6105 return true;
6106 }
6107 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6108 if (perms == null) return false;
6109 UriPermission perm = perms.get(uri);
6110 if (perm == null) return false;
6111 return (modeFlags&perm.modeFlags) == modeFlags;
6112 }
6113
6114 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6115 // Another redirected-binder-call permissions check as in
6116 // {@link checkComponentPermission}.
6117 Identity tlsIdentity = sCallerIdentity.get();
6118 if (tlsIdentity != null) {
6119 uid = tlsIdentity.uid;
6120 pid = tlsIdentity.pid;
6121 }
6122
6123 // Our own process gets to do everything.
6124 if (pid == MY_PID) {
6125 return PackageManager.PERMISSION_GRANTED;
6126 }
6127 synchronized(this) {
6128 return checkUriPermissionLocked(uri, uid, modeFlags)
6129 ? PackageManager.PERMISSION_GRANTED
6130 : PackageManager.PERMISSION_DENIED;
6131 }
6132 }
6133
6134 private void grantUriPermissionLocked(int callingUid,
6135 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6136 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6137 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6138 if (modeFlags == 0) {
6139 return;
6140 }
6141
6142 final IPackageManager pm = ActivityThread.getPackageManager();
6143
6144 // If this is not a content: uri, we can't do anything with it.
6145 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6146 return;
6147 }
6148
6149 String name = uri.getAuthority();
6150 ProviderInfo pi = null;
6151 ContentProviderRecord cpr
6152 = (ContentProviderRecord)mProvidersByName.get(name);
6153 if (cpr != null) {
6154 pi = cpr.info;
6155 } else {
6156 try {
6157 pi = pm.resolveContentProvider(name,
6158 PackageManager.GET_URI_PERMISSION_PATTERNS);
6159 } catch (RemoteException ex) {
6160 }
6161 }
6162 if (pi == null) {
6163 Log.w(TAG, "No content provider found for: " + name);
6164 return;
6165 }
6166
6167 int targetUid;
6168 try {
6169 targetUid = pm.getPackageUid(targetPkg);
6170 if (targetUid < 0) {
6171 return;
6172 }
6173 } catch (RemoteException ex) {
6174 return;
6175 }
6176
6177 // First... does the target actually need this permission?
6178 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6179 // No need to grant the target this permission.
6180 return;
6181 }
6182
6183 // Second... maybe someone else has already granted the
6184 // permission?
6185 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6186 // No need to grant the target this permission.
6187 return;
6188 }
6189
6190 // Third... is the provider allowing granting of URI permissions?
6191 if (!pi.grantUriPermissions) {
6192 throw new SecurityException("Provider " + pi.packageName
6193 + "/" + pi.name
6194 + " does not allow granting of Uri permissions (uri "
6195 + uri + ")");
6196 }
6197 if (pi.uriPermissionPatterns != null) {
6198 final int N = pi.uriPermissionPatterns.length;
6199 boolean allowed = false;
6200 for (int i=0; i<N; i++) {
6201 if (pi.uriPermissionPatterns[i] != null
6202 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6203 allowed = true;
6204 break;
6205 }
6206 }
6207 if (!allowed) {
6208 throw new SecurityException("Provider " + pi.packageName
6209 + "/" + pi.name
6210 + " does not allow granting of permission to path of Uri "
6211 + uri);
6212 }
6213 }
6214
6215 // Fourth... does the caller itself have permission to access
6216 // this uri?
6217 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6218 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6219 throw new SecurityException("Uid " + callingUid
6220 + " does not have permission to uri " + uri);
6221 }
6222 }
6223
6224 // Okay! So here we are: the caller has the assumed permission
6225 // to the uri, and the target doesn't. Let's now give this to
6226 // the target.
6227
6228 HashMap<Uri, UriPermission> targetUris
6229 = mGrantedUriPermissions.get(targetUid);
6230 if (targetUris == null) {
6231 targetUris = new HashMap<Uri, UriPermission>();
6232 mGrantedUriPermissions.put(targetUid, targetUris);
6233 }
6234
6235 UriPermission perm = targetUris.get(uri);
6236 if (perm == null) {
6237 perm = new UriPermission(targetUid, uri);
6238 targetUris.put(uri, perm);
6239
6240 }
6241 perm.modeFlags |= modeFlags;
6242 if (activity == null) {
6243 perm.globalModeFlags |= modeFlags;
6244 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6245 perm.readActivities.add(activity);
6246 if (activity.readUriPermissions == null) {
6247 activity.readUriPermissions = new HashSet<UriPermission>();
6248 }
6249 activity.readUriPermissions.add(perm);
6250 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6251 perm.writeActivities.add(activity);
6252 if (activity.writeUriPermissions == null) {
6253 activity.writeUriPermissions = new HashSet<UriPermission>();
6254 }
6255 activity.writeUriPermissions.add(perm);
6256 }
6257 }
6258
6259 private void grantUriPermissionFromIntentLocked(int callingUid,
6260 String targetPkg, Intent intent, HistoryRecord activity) {
6261 if (intent == null) {
6262 return;
6263 }
6264 Uri data = intent.getData();
6265 if (data == null) {
6266 return;
6267 }
6268 grantUriPermissionLocked(callingUid, targetPkg, data,
6269 intent.getFlags(), activity);
6270 }
6271
6272 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6273 Uri uri, int modeFlags) {
6274 synchronized(this) {
6275 final ProcessRecord r = getRecordForAppLocked(caller);
6276 if (r == null) {
6277 throw new SecurityException("Unable to find app for caller "
6278 + caller
6279 + " when granting permission to uri " + uri);
6280 }
6281 if (targetPkg == null) {
6282 Log.w(TAG, "grantUriPermission: null target");
6283 return;
6284 }
6285 if (uri == null) {
6286 Log.w(TAG, "grantUriPermission: null uri");
6287 return;
6288 }
6289
6290 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6291 null);
6292 }
6293 }
6294
6295 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6296 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6297 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6298 HashMap<Uri, UriPermission> perms
6299 = mGrantedUriPermissions.get(perm.uid);
6300 if (perms != null) {
6301 perms.remove(perm.uri);
6302 if (perms.size() == 0) {
6303 mGrantedUriPermissions.remove(perm.uid);
6304 }
6305 }
6306 }
6307 }
6308
6309 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6310 if (activity.readUriPermissions != null) {
6311 for (UriPermission perm : activity.readUriPermissions) {
6312 perm.readActivities.remove(activity);
6313 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6314 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6315 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6316 removeUriPermissionIfNeededLocked(perm);
6317 }
6318 }
6319 }
6320 if (activity.writeUriPermissions != null) {
6321 for (UriPermission perm : activity.writeUriPermissions) {
6322 perm.writeActivities.remove(activity);
6323 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6324 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6325 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6326 removeUriPermissionIfNeededLocked(perm);
6327 }
6328 }
6329 }
6330 }
6331
6332 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6333 int modeFlags) {
6334 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6335 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6336 if (modeFlags == 0) {
6337 return;
6338 }
6339
6340 final IPackageManager pm = ActivityThread.getPackageManager();
6341
6342 final String authority = uri.getAuthority();
6343 ProviderInfo pi = null;
6344 ContentProviderRecord cpr
6345 = (ContentProviderRecord)mProvidersByName.get(authority);
6346 if (cpr != null) {
6347 pi = cpr.info;
6348 } else {
6349 try {
6350 pi = pm.resolveContentProvider(authority,
6351 PackageManager.GET_URI_PERMISSION_PATTERNS);
6352 } catch (RemoteException ex) {
6353 }
6354 }
6355 if (pi == null) {
6356 Log.w(TAG, "No content provider found for: " + authority);
6357 return;
6358 }
6359
6360 // Does the caller have this permission on the URI?
6361 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6362 // Right now, if you are not the original owner of the permission,
6363 // you are not allowed to revoke it.
6364 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6365 throw new SecurityException("Uid " + callingUid
6366 + " does not have permission to uri " + uri);
6367 //}
6368 }
6369
6370 // Go through all of the permissions and remove any that match.
6371 final List<String> SEGMENTS = uri.getPathSegments();
6372 if (SEGMENTS != null) {
6373 final int NS = SEGMENTS.size();
6374 int N = mGrantedUriPermissions.size();
6375 for (int i=0; i<N; i++) {
6376 HashMap<Uri, UriPermission> perms
6377 = mGrantedUriPermissions.valueAt(i);
6378 Iterator<UriPermission> it = perms.values().iterator();
6379 toploop:
6380 while (it.hasNext()) {
6381 UriPermission perm = it.next();
6382 Uri targetUri = perm.uri;
6383 if (!authority.equals(targetUri.getAuthority())) {
6384 continue;
6385 }
6386 List<String> targetSegments = targetUri.getPathSegments();
6387 if (targetSegments == null) {
6388 continue;
6389 }
6390 if (targetSegments.size() < NS) {
6391 continue;
6392 }
6393 for (int j=0; j<NS; j++) {
6394 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6395 continue toploop;
6396 }
6397 }
6398 perm.clearModes(modeFlags);
6399 if (perm.modeFlags == 0) {
6400 it.remove();
6401 }
6402 }
6403 if (perms.size() == 0) {
6404 mGrantedUriPermissions.remove(
6405 mGrantedUriPermissions.keyAt(i));
6406 N--;
6407 i--;
6408 }
6409 }
6410 }
6411 }
6412
6413 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6414 int modeFlags) {
6415 synchronized(this) {
6416 final ProcessRecord r = getRecordForAppLocked(caller);
6417 if (r == null) {
6418 throw new SecurityException("Unable to find app for caller "
6419 + caller
6420 + " when revoking permission to uri " + uri);
6421 }
6422 if (uri == null) {
6423 Log.w(TAG, "revokeUriPermission: null uri");
6424 return;
6425 }
6426
6427 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6428 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6429 if (modeFlags == 0) {
6430 return;
6431 }
6432
6433 final IPackageManager pm = ActivityThread.getPackageManager();
6434
6435 final String authority = uri.getAuthority();
6436 ProviderInfo pi = null;
6437 ContentProviderRecord cpr
6438 = (ContentProviderRecord)mProvidersByName.get(authority);
6439 if (cpr != null) {
6440 pi = cpr.info;
6441 } else {
6442 try {
6443 pi = pm.resolveContentProvider(authority,
6444 PackageManager.GET_URI_PERMISSION_PATTERNS);
6445 } catch (RemoteException ex) {
6446 }
6447 }
6448 if (pi == null) {
6449 Log.w(TAG, "No content provider found for: " + authority);
6450 return;
6451 }
6452
6453 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6454 }
6455 }
6456
6457 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6458 synchronized (this) {
6459 ProcessRecord app =
6460 who != null ? getRecordForAppLocked(who) : null;
6461 if (app == null) return;
6462
6463 Message msg = Message.obtain();
6464 msg.what = WAIT_FOR_DEBUGGER_MSG;
6465 msg.obj = app;
6466 msg.arg1 = waiting ? 1 : 0;
6467 mHandler.sendMessage(msg);
6468 }
6469 }
6470
6471 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6472 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006473 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006474 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006475 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006476 }
6477
6478 // =========================================================
6479 // TASK MANAGEMENT
6480 // =========================================================
6481
6482 public List getTasks(int maxNum, int flags,
6483 IThumbnailReceiver receiver) {
6484 ArrayList list = new ArrayList();
6485
6486 PendingThumbnailsRecord pending = null;
6487 IApplicationThread topThumbnail = null;
6488 HistoryRecord topRecord = null;
6489
6490 synchronized(this) {
6491 if (localLOGV) Log.v(
6492 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6493 + ", receiver=" + receiver);
6494
6495 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6496 != PackageManager.PERMISSION_GRANTED) {
6497 if (receiver != null) {
6498 // If the caller wants to wait for pending thumbnails,
6499 // it ain't gonna get them.
6500 try {
6501 receiver.finished();
6502 } catch (RemoteException ex) {
6503 }
6504 }
6505 String msg = "Permission Denial: getTasks() from pid="
6506 + Binder.getCallingPid()
6507 + ", uid=" + Binder.getCallingUid()
6508 + " requires " + android.Manifest.permission.GET_TASKS;
6509 Log.w(TAG, msg);
6510 throw new SecurityException(msg);
6511 }
6512
6513 int pos = mHistory.size()-1;
6514 HistoryRecord next =
6515 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6516 HistoryRecord top = null;
6517 CharSequence topDescription = null;
6518 TaskRecord curTask = null;
6519 int numActivities = 0;
6520 int numRunning = 0;
6521 while (pos >= 0 && maxNum > 0) {
6522 final HistoryRecord r = next;
6523 pos--;
6524 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6525
6526 // Initialize state for next task if needed.
6527 if (top == null ||
6528 (top.state == ActivityState.INITIALIZING
6529 && top.task == r.task)) {
6530 top = r;
6531 topDescription = r.description;
6532 curTask = r.task;
6533 numActivities = numRunning = 0;
6534 }
6535
6536 // Add 'r' into the current task.
6537 numActivities++;
6538 if (r.app != null && r.app.thread != null) {
6539 numRunning++;
6540 }
6541 if (topDescription == null) {
6542 topDescription = r.description;
6543 }
6544
6545 if (localLOGV) Log.v(
6546 TAG, r.intent.getComponent().flattenToShortString()
6547 + ": task=" + r.task);
6548
6549 // If the next one is a different task, generate a new
6550 // TaskInfo entry for what we have.
6551 if (next == null || next.task != curTask) {
6552 ActivityManager.RunningTaskInfo ci
6553 = new ActivityManager.RunningTaskInfo();
6554 ci.id = curTask.taskId;
6555 ci.baseActivity = r.intent.getComponent();
6556 ci.topActivity = top.intent.getComponent();
6557 ci.thumbnail = top.thumbnail;
6558 ci.description = topDescription;
6559 ci.numActivities = numActivities;
6560 ci.numRunning = numRunning;
6561 //System.out.println(
6562 // "#" + maxNum + ": " + " descr=" + ci.description);
6563 if (ci.thumbnail == null && receiver != null) {
6564 if (localLOGV) Log.v(
6565 TAG, "State=" + top.state + "Idle=" + top.idle
6566 + " app=" + top.app
6567 + " thr=" + (top.app != null ? top.app.thread : null));
6568 if (top.state == ActivityState.RESUMED
6569 || top.state == ActivityState.PAUSING) {
6570 if (top.idle && top.app != null
6571 && top.app.thread != null) {
6572 topRecord = top;
6573 topThumbnail = top.app.thread;
6574 } else {
6575 top.thumbnailNeeded = true;
6576 }
6577 }
6578 if (pending == null) {
6579 pending = new PendingThumbnailsRecord(receiver);
6580 }
6581 pending.pendingRecords.add(top);
6582 }
6583 list.add(ci);
6584 maxNum--;
6585 top = null;
6586 }
6587 }
6588
6589 if (pending != null) {
6590 mPendingThumbnails.add(pending);
6591 }
6592 }
6593
6594 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6595
6596 if (topThumbnail != null) {
6597 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6598 try {
6599 topThumbnail.requestThumbnail(topRecord);
6600 } catch (Exception e) {
6601 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6602 sendPendingThumbnail(null, topRecord, null, null, true);
6603 }
6604 }
6605
6606 if (pending == null && receiver != null) {
6607 // In this case all thumbnails were available and the client
6608 // is being asked to be told when the remaining ones come in...
6609 // which is unusually, since the top-most currently running
6610 // activity should never have a canned thumbnail! Oh well.
6611 try {
6612 receiver.finished();
6613 } catch (RemoteException ex) {
6614 }
6615 }
6616
6617 return list;
6618 }
6619
6620 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6621 int flags) {
6622 synchronized (this) {
6623 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6624 "getRecentTasks()");
6625
6626 final int N = mRecentTasks.size();
6627 ArrayList<ActivityManager.RecentTaskInfo> res
6628 = new ArrayList<ActivityManager.RecentTaskInfo>(
6629 maxNum < N ? maxNum : N);
6630 for (int i=0; i<N && maxNum > 0; i++) {
6631 TaskRecord tr = mRecentTasks.get(i);
6632 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6633 || (tr.intent == null)
6634 || ((tr.intent.getFlags()
6635 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6636 ActivityManager.RecentTaskInfo rti
6637 = new ActivityManager.RecentTaskInfo();
6638 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6639 rti.baseIntent = new Intent(
6640 tr.intent != null ? tr.intent : tr.affinityIntent);
6641 rti.origActivity = tr.origActivity;
6642 res.add(rti);
6643 maxNum--;
6644 }
6645 }
6646 return res;
6647 }
6648 }
6649
6650 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6651 int j;
6652 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6653 TaskRecord jt = startTask;
6654
6655 // First look backwards
6656 for (j=startIndex-1; j>=0; j--) {
6657 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6658 if (r.task != jt) {
6659 jt = r.task;
6660 if (affinity.equals(jt.affinity)) {
6661 return j;
6662 }
6663 }
6664 }
6665
6666 // Now look forwards
6667 final int N = mHistory.size();
6668 jt = startTask;
6669 for (j=startIndex+1; j<N; j++) {
6670 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6671 if (r.task != jt) {
6672 if (affinity.equals(jt.affinity)) {
6673 return j;
6674 }
6675 jt = r.task;
6676 }
6677 }
6678
6679 // Might it be at the top?
6680 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6681 return N-1;
6682 }
6683
6684 return -1;
6685 }
6686
6687 /**
6688 * Perform a reset of the given task, if needed as part of launching it.
6689 * Returns the new HistoryRecord at the top of the task.
6690 */
6691 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6692 HistoryRecord newActivity) {
6693 boolean forceReset = (newActivity.info.flags
6694 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6695 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6696 if ((newActivity.info.flags
6697 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6698 forceReset = true;
6699 }
6700 }
6701
6702 final TaskRecord task = taskTop.task;
6703
6704 // We are going to move through the history list so that we can look
6705 // at each activity 'target' with 'below' either the interesting
6706 // activity immediately below it in the stack or null.
6707 HistoryRecord target = null;
6708 int targetI = 0;
6709 int taskTopI = -1;
6710 int replyChainEnd = -1;
6711 int lastReparentPos = -1;
6712 for (int i=mHistory.size()-1; i>=-1; i--) {
6713 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6714
6715 if (below != null && below.finishing) {
6716 continue;
6717 }
6718 if (target == null) {
6719 target = below;
6720 targetI = i;
6721 // If we were in the middle of a reply chain before this
6722 // task, it doesn't appear like the root of the chain wants
6723 // anything interesting, so drop it.
6724 replyChainEnd = -1;
6725 continue;
6726 }
6727
6728 final int flags = target.info.flags;
6729
6730 final boolean finishOnTaskLaunch =
6731 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6732 final boolean allowTaskReparenting =
6733 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6734
6735 if (target.task == task) {
6736 // We are inside of the task being reset... we'll either
6737 // finish this activity, push it out for another task,
6738 // or leave it as-is. We only do this
6739 // for activities that are not the root of the task (since
6740 // if we finish the root, we may no longer have the task!).
6741 if (taskTopI < 0) {
6742 taskTopI = targetI;
6743 }
6744 if (below != null && below.task == task) {
6745 final boolean clearWhenTaskReset =
6746 (target.intent.getFlags()
6747 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006748 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006749 // If this activity is sending a reply to a previous
6750 // activity, we can't do anything with it now until
6751 // we reach the start of the reply chain.
6752 // XXX note that we are assuming the result is always
6753 // to the previous activity, which is almost always
6754 // the case but we really shouldn't count on.
6755 if (replyChainEnd < 0) {
6756 replyChainEnd = targetI;
6757 }
Ed Heyl73798232009-03-24 21:32:21 -07006758 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006759 && target.taskAffinity != null
6760 && !target.taskAffinity.equals(task.affinity)) {
6761 // If this activity has an affinity for another
6762 // task, then we need to move it out of here. We will
6763 // move it as far out of the way as possible, to the
6764 // bottom of the activity stack. This also keeps it
6765 // correctly ordered with any activities we previously
6766 // moved.
6767 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6768 if (target.taskAffinity != null
6769 && target.taskAffinity.equals(p.task.affinity)) {
6770 // If the activity currently at the bottom has the
6771 // same task affinity as the one we are moving,
6772 // then merge it into the same task.
6773 target.task = p.task;
6774 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6775 + " out to bottom task " + p.task);
6776 } else {
6777 mCurTask++;
6778 if (mCurTask <= 0) {
6779 mCurTask = 1;
6780 }
6781 target.task = new TaskRecord(mCurTask, target.info, null,
6782 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6783 target.task.affinityIntent = target.intent;
6784 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6785 + " out to new task " + target.task);
6786 }
6787 mWindowManager.setAppGroupId(target, task.taskId);
6788 if (replyChainEnd < 0) {
6789 replyChainEnd = targetI;
6790 }
6791 int dstPos = 0;
6792 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6793 p = (HistoryRecord)mHistory.get(srcPos);
6794 if (p.finishing) {
6795 continue;
6796 }
6797 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6798 + " out to target's task " + target.task);
6799 task.numActivities--;
6800 p.task = target.task;
6801 target.task.numActivities++;
6802 mHistory.remove(srcPos);
6803 mHistory.add(dstPos, p);
6804 mWindowManager.moveAppToken(dstPos, p);
6805 mWindowManager.setAppGroupId(p, p.task.taskId);
6806 dstPos++;
6807 if (VALIDATE_TOKENS) {
6808 mWindowManager.validateAppTokens(mHistory);
6809 }
6810 i++;
6811 }
6812 if (taskTop == p) {
6813 taskTop = below;
6814 }
6815 if (taskTopI == replyChainEnd) {
6816 taskTopI = -1;
6817 }
6818 replyChainEnd = -1;
6819 addRecentTask(target.task);
6820 } else if (forceReset || finishOnTaskLaunch
6821 || clearWhenTaskReset) {
6822 // If the activity should just be removed -- either
6823 // because it asks for it, or the task should be
6824 // cleared -- then finish it and anything that is
6825 // part of its reply chain.
6826 if (clearWhenTaskReset) {
6827 // In this case, we want to finish this activity
6828 // and everything above it, so be sneaky and pretend
6829 // like these are all in the reply chain.
6830 replyChainEnd = targetI+1;
6831 while (replyChainEnd < mHistory.size() &&
6832 ((HistoryRecord)mHistory.get(
6833 replyChainEnd)).task == task) {
6834 replyChainEnd++;
6835 }
6836 replyChainEnd--;
6837 } else if (replyChainEnd < 0) {
6838 replyChainEnd = targetI;
6839 }
6840 HistoryRecord p = null;
6841 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6842 p = (HistoryRecord)mHistory.get(srcPos);
6843 if (p.finishing) {
6844 continue;
6845 }
6846 if (finishActivityLocked(p, srcPos,
6847 Activity.RESULT_CANCELED, null, "reset")) {
6848 replyChainEnd--;
6849 srcPos--;
6850 }
6851 }
6852 if (taskTop == p) {
6853 taskTop = below;
6854 }
6855 if (taskTopI == replyChainEnd) {
6856 taskTopI = -1;
6857 }
6858 replyChainEnd = -1;
6859 } else {
6860 // If we were in the middle of a chain, well the
6861 // activity that started it all doesn't want anything
6862 // special, so leave it all as-is.
6863 replyChainEnd = -1;
6864 }
6865 } else {
6866 // Reached the bottom of the task -- any reply chain
6867 // should be left as-is.
6868 replyChainEnd = -1;
6869 }
6870
6871 } else if (target.resultTo != null) {
6872 // If this activity is sending a reply to a previous
6873 // activity, we can't do anything with it now until
6874 // we reach the start of the reply chain.
6875 // XXX note that we are assuming the result is always
6876 // to the previous activity, which is almost always
6877 // the case but we really shouldn't count on.
6878 if (replyChainEnd < 0) {
6879 replyChainEnd = targetI;
6880 }
6881
6882 } else if (taskTopI >= 0 && allowTaskReparenting
6883 && task.affinity != null
6884 && task.affinity.equals(target.taskAffinity)) {
6885 // We are inside of another task... if this activity has
6886 // an affinity for our task, then either remove it if we are
6887 // clearing or move it over to our task. Note that
6888 // we currently punt on the case where we are resetting a
6889 // task that is not at the top but who has activities above
6890 // with an affinity to it... this is really not a normal
6891 // case, and we will need to later pull that task to the front
6892 // and usually at that point we will do the reset and pick
6893 // up those remaining activities. (This only happens if
6894 // someone starts an activity in a new task from an activity
6895 // in a task that is not currently on top.)
6896 if (forceReset || finishOnTaskLaunch) {
6897 if (replyChainEnd < 0) {
6898 replyChainEnd = targetI;
6899 }
6900 HistoryRecord p = null;
6901 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6902 p = (HistoryRecord)mHistory.get(srcPos);
6903 if (p.finishing) {
6904 continue;
6905 }
6906 if (finishActivityLocked(p, srcPos,
6907 Activity.RESULT_CANCELED, null, "reset")) {
6908 taskTopI--;
6909 lastReparentPos--;
6910 replyChainEnd--;
6911 srcPos--;
6912 }
6913 }
6914 replyChainEnd = -1;
6915 } else {
6916 if (replyChainEnd < 0) {
6917 replyChainEnd = targetI;
6918 }
6919 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6920 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6921 if (p.finishing) {
6922 continue;
6923 }
6924 if (lastReparentPos < 0) {
6925 lastReparentPos = taskTopI;
6926 taskTop = p;
6927 } else {
6928 lastReparentPos--;
6929 }
6930 mHistory.remove(srcPos);
6931 p.task.numActivities--;
6932 p.task = task;
6933 mHistory.add(lastReparentPos, p);
6934 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6935 + " in to resetting task " + task);
6936 task.numActivities++;
6937 mWindowManager.moveAppToken(lastReparentPos, p);
6938 mWindowManager.setAppGroupId(p, p.task.taskId);
6939 if (VALIDATE_TOKENS) {
6940 mWindowManager.validateAppTokens(mHistory);
6941 }
6942 }
6943 replyChainEnd = -1;
6944
6945 // Now we've moved it in to place... but what if this is
6946 // a singleTop activity and we have put it on top of another
6947 // instance of the same activity? Then we drop the instance
6948 // below so it remains singleTop.
6949 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6950 for (int j=lastReparentPos-1; j>=0; j--) {
6951 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6952 if (p.finishing) {
6953 continue;
6954 }
6955 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6956 if (finishActivityLocked(p, j,
6957 Activity.RESULT_CANCELED, null, "replace")) {
6958 taskTopI--;
6959 lastReparentPos--;
6960 }
6961 }
6962 }
6963 }
6964 }
6965 }
6966
6967 target = below;
6968 targetI = i;
6969 }
6970
6971 return taskTop;
6972 }
6973
6974 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006975 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006976 */
6977 public void moveTaskToFront(int task) {
6978 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6979 "moveTaskToFront()");
6980
6981 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006982 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6983 Binder.getCallingUid(), "Task to front")) {
6984 return;
6985 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006986 final long origId = Binder.clearCallingIdentity();
6987 try {
6988 int N = mRecentTasks.size();
6989 for (int i=0; i<N; i++) {
6990 TaskRecord tr = mRecentTasks.get(i);
6991 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07006992 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006993 return;
6994 }
6995 }
6996 for (int i=mHistory.size()-1; i>=0; i--) {
6997 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6998 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07006999 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007000 return;
7001 }
7002 }
7003 } finally {
7004 Binder.restoreCallingIdentity(origId);
7005 }
7006 }
7007 }
7008
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007009 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007010 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7011
7012 final int task = tr.taskId;
7013 int top = mHistory.size()-1;
7014
7015 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7016 // nothing to do!
7017 return;
7018 }
7019
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007020 ArrayList moved = new ArrayList();
7021
7022 // Applying the affinities may have removed entries from the history,
7023 // so get the size again.
7024 top = mHistory.size()-1;
7025 int pos = top;
7026
7027 // Shift all activities with this task up to the top
7028 // of the stack, keeping them in the same internal order.
7029 while (pos >= 0) {
7030 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7031 if (localLOGV) Log.v(
7032 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7033 boolean first = true;
7034 if (r.task.taskId == task) {
7035 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7036 mHistory.remove(pos);
7037 mHistory.add(top, r);
7038 moved.add(0, r);
7039 top--;
7040 if (first) {
7041 addRecentTask(r.task);
7042 first = false;
7043 }
7044 }
7045 pos--;
7046 }
7047
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007048 if (DEBUG_TRANSITION) Log.v(TAG,
7049 "Prepare to front transition: task=" + tr);
7050 if (reason != null &&
7051 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7052 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7053 HistoryRecord r = topRunningActivityLocked(null);
7054 if (r != null) {
7055 mNoAnimActivities.add(r);
7056 }
7057 } else {
7058 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7059 }
7060
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007061 mWindowManager.moveAppTokensToTop(moved);
7062 if (VALIDATE_TOKENS) {
7063 mWindowManager.validateAppTokens(mHistory);
7064 }
7065
7066 finishTaskMove(task);
7067 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
7068 }
7069
7070 private final void finishTaskMove(int task) {
7071 resumeTopActivityLocked(null);
7072 }
7073
7074 public void moveTaskToBack(int task) {
7075 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7076 "moveTaskToBack()");
7077
7078 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007079 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7080 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7081 Binder.getCallingUid(), "Task to back")) {
7082 return;
7083 }
7084 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007085 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007086 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007087 Binder.restoreCallingIdentity(origId);
7088 }
7089 }
7090
7091 /**
7092 * Moves an activity, and all of the other activities within the same task, to the bottom
7093 * of the history stack. The activity's order within the task is unchanged.
7094 *
7095 * @param token A reference to the activity we wish to move
7096 * @param nonRoot If false then this only works if the activity is the root
7097 * of a task; if true it will work for any activity in a task.
7098 * @return Returns true if the move completed, false if not.
7099 */
7100 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7101 synchronized(this) {
7102 final long origId = Binder.clearCallingIdentity();
7103 int taskId = getTaskForActivityLocked(token, !nonRoot);
7104 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007105 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007106 }
7107 Binder.restoreCallingIdentity(origId);
7108 }
7109 return false;
7110 }
7111
7112 /**
7113 * Worker method for rearranging history stack. Implements the function of moving all
7114 * activities for a specific task (gathering them if disjoint) into a single group at the
7115 * bottom of the stack.
7116 *
7117 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7118 * to premeptively cancel the move.
7119 *
7120 * @param task The taskId to collect and move to the bottom.
7121 * @return Returns true if the move completed, false if not.
7122 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007123 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007124 Log.i(TAG, "moveTaskToBack: " + task);
7125
7126 // If we have a watcher, preflight the move before committing to it. First check
7127 // for *other* available tasks, but if none are available, then try again allowing the
7128 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007129 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007130 HistoryRecord next = topRunningActivityLocked(null, task);
7131 if (next == null) {
7132 next = topRunningActivityLocked(null, 0);
7133 }
7134 if (next != null) {
7135 // ask watcher if this is allowed
7136 boolean moveOK = true;
7137 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007138 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007139 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007140 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007141 }
7142 if (!moveOK) {
7143 return false;
7144 }
7145 }
7146 }
7147
7148 ArrayList moved = new ArrayList();
7149
7150 if (DEBUG_TRANSITION) Log.v(TAG,
7151 "Prepare to back transition: task=" + task);
7152 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
7153
7154 final int N = mHistory.size();
7155 int bottom = 0;
7156 int pos = 0;
7157
7158 // Shift all activities with this task down to the bottom
7159 // of the stack, keeping them in the same internal order.
7160 while (pos < N) {
7161 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7162 if (localLOGV) Log.v(
7163 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7164 if (r.task.taskId == task) {
7165 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7166 mHistory.remove(pos);
7167 mHistory.add(bottom, r);
7168 moved.add(r);
7169 bottom++;
7170 }
7171 pos++;
7172 }
7173
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007174 if (reason != null &&
7175 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7176 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7177 HistoryRecord r = topRunningActivityLocked(null);
7178 if (r != null) {
7179 mNoAnimActivities.add(r);
7180 }
7181 } else {
7182 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7183 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007184 mWindowManager.moveAppTokensToBottom(moved);
7185 if (VALIDATE_TOKENS) {
7186 mWindowManager.validateAppTokens(mHistory);
7187 }
7188
7189 finishTaskMove(task);
7190 return true;
7191 }
7192
7193 public void moveTaskBackwards(int task) {
7194 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7195 "moveTaskBackwards()");
7196
7197 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007198 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7199 Binder.getCallingUid(), "Task backwards")) {
7200 return;
7201 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007202 final long origId = Binder.clearCallingIdentity();
7203 moveTaskBackwardsLocked(task);
7204 Binder.restoreCallingIdentity(origId);
7205 }
7206 }
7207
7208 private final void moveTaskBackwardsLocked(int task) {
7209 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7210 }
7211
7212 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7213 synchronized(this) {
7214 return getTaskForActivityLocked(token, onlyRoot);
7215 }
7216 }
7217
7218 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7219 final int N = mHistory.size();
7220 TaskRecord lastTask = null;
7221 for (int i=0; i<N; i++) {
7222 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7223 if (r == token) {
7224 if (!onlyRoot || lastTask != r.task) {
7225 return r.task.taskId;
7226 }
7227 return -1;
7228 }
7229 lastTask = r.task;
7230 }
7231
7232 return -1;
7233 }
7234
7235 /**
7236 * Returns the top activity in any existing task matching the given
7237 * Intent. Returns null if no such task is found.
7238 */
7239 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7240 ComponentName cls = intent.getComponent();
7241 if (info.targetActivity != null) {
7242 cls = new ComponentName(info.packageName, info.targetActivity);
7243 }
7244
7245 TaskRecord cp = null;
7246
7247 final int N = mHistory.size();
7248 for (int i=(N-1); i>=0; i--) {
7249 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7250 if (!r.finishing && r.task != cp
7251 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7252 cp = r.task;
7253 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7254 // + "/aff=" + r.task.affinity + " to new cls="
7255 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7256 if (r.task.affinity != null) {
7257 if (r.task.affinity.equals(info.taskAffinity)) {
7258 //Log.i(TAG, "Found matching affinity!");
7259 return r;
7260 }
7261 } else if (r.task.intent != null
7262 && r.task.intent.getComponent().equals(cls)) {
7263 //Log.i(TAG, "Found matching class!");
7264 //dump();
7265 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7266 return r;
7267 } else if (r.task.affinityIntent != null
7268 && r.task.affinityIntent.getComponent().equals(cls)) {
7269 //Log.i(TAG, "Found matching class!");
7270 //dump();
7271 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7272 return r;
7273 }
7274 }
7275 }
7276
7277 return null;
7278 }
7279
7280 /**
7281 * Returns the first activity (starting from the top of the stack) that
7282 * is the same as the given activity. Returns null if no such activity
7283 * is found.
7284 */
7285 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7286 ComponentName cls = intent.getComponent();
7287 if (info.targetActivity != null) {
7288 cls = new ComponentName(info.packageName, info.targetActivity);
7289 }
7290
7291 final int N = mHistory.size();
7292 for (int i=(N-1); i>=0; i--) {
7293 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7294 if (!r.finishing) {
7295 if (r.intent.getComponent().equals(cls)) {
7296 //Log.i(TAG, "Found matching class!");
7297 //dump();
7298 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7299 return r;
7300 }
7301 }
7302 }
7303
7304 return null;
7305 }
7306
7307 public void finishOtherInstances(IBinder token, ComponentName className) {
7308 synchronized(this) {
7309 final long origId = Binder.clearCallingIdentity();
7310
7311 int N = mHistory.size();
7312 TaskRecord lastTask = null;
7313 for (int i=0; i<N; i++) {
7314 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7315 if (r.realActivity.equals(className)
7316 && r != token && lastTask != r.task) {
7317 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7318 null, "others")) {
7319 i--;
7320 N--;
7321 }
7322 }
7323 lastTask = r.task;
7324 }
7325
7326 Binder.restoreCallingIdentity(origId);
7327 }
7328 }
7329
7330 // =========================================================
7331 // THUMBNAILS
7332 // =========================================================
7333
7334 public void reportThumbnail(IBinder token,
7335 Bitmap thumbnail, CharSequence description) {
7336 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7337 final long origId = Binder.clearCallingIdentity();
7338 sendPendingThumbnail(null, token, thumbnail, description, true);
7339 Binder.restoreCallingIdentity(origId);
7340 }
7341
7342 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7343 Bitmap thumbnail, CharSequence description, boolean always) {
7344 TaskRecord task = null;
7345 ArrayList receivers = null;
7346
7347 //System.out.println("Send pending thumbnail: " + r);
7348
7349 synchronized(this) {
7350 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007351 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007352 if (index < 0) {
7353 return;
7354 }
7355 r = (HistoryRecord)mHistory.get(index);
7356 }
7357 if (thumbnail == null) {
7358 thumbnail = r.thumbnail;
7359 description = r.description;
7360 }
7361 if (thumbnail == null && !always) {
7362 // If there is no thumbnail, and this entry is not actually
7363 // going away, then abort for now and pick up the next
7364 // thumbnail we get.
7365 return;
7366 }
7367 task = r.task;
7368
7369 int N = mPendingThumbnails.size();
7370 int i=0;
7371 while (i<N) {
7372 PendingThumbnailsRecord pr =
7373 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7374 //System.out.println("Looking in " + pr.pendingRecords);
7375 if (pr.pendingRecords.remove(r)) {
7376 if (receivers == null) {
7377 receivers = new ArrayList();
7378 }
7379 receivers.add(pr);
7380 if (pr.pendingRecords.size() == 0) {
7381 pr.finished = true;
7382 mPendingThumbnails.remove(i);
7383 N--;
7384 continue;
7385 }
7386 }
7387 i++;
7388 }
7389 }
7390
7391 if (receivers != null) {
7392 final int N = receivers.size();
7393 for (int i=0; i<N; i++) {
7394 try {
7395 PendingThumbnailsRecord pr =
7396 (PendingThumbnailsRecord)receivers.get(i);
7397 pr.receiver.newThumbnail(
7398 task != null ? task.taskId : -1, thumbnail, description);
7399 if (pr.finished) {
7400 pr.receiver.finished();
7401 }
7402 } catch (Exception e) {
7403 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7404 }
7405 }
7406 }
7407 }
7408
7409 // =========================================================
7410 // CONTENT PROVIDERS
7411 // =========================================================
7412
7413 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7414 List providers = null;
7415 try {
7416 providers = ActivityThread.getPackageManager().
7417 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007418 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007419 } catch (RemoteException ex) {
7420 }
7421 if (providers != null) {
7422 final int N = providers.size();
7423 for (int i=0; i<N; i++) {
7424 ProviderInfo cpi =
7425 (ProviderInfo)providers.get(i);
7426 ContentProviderRecord cpr =
7427 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7428 if (cpr == null) {
7429 cpr = new ContentProviderRecord(cpi, app.info);
7430 mProvidersByClass.put(cpi.name, cpr);
7431 }
7432 app.pubProviders.put(cpi.name, cpr);
7433 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007434 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007435 }
7436 }
7437 return providers;
7438 }
7439
7440 private final String checkContentProviderPermissionLocked(
7441 ProviderInfo cpi, ProcessRecord r, int mode) {
7442 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7443 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7444 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7445 cpi.exported ? -1 : cpi.applicationInfo.uid)
7446 == PackageManager.PERMISSION_GRANTED
7447 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7448 return null;
7449 }
7450 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7451 cpi.exported ? -1 : cpi.applicationInfo.uid)
7452 == PackageManager.PERMISSION_GRANTED) {
7453 return null;
7454 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007455
7456 PathPermission[] pps = cpi.pathPermissions;
7457 if (pps != null) {
7458 int i = pps.length;
7459 while (i > 0) {
7460 i--;
7461 PathPermission pp = pps[i];
7462 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7463 cpi.exported ? -1 : cpi.applicationInfo.uid)
7464 == PackageManager.PERMISSION_GRANTED
7465 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7466 return null;
7467 }
7468 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7469 cpi.exported ? -1 : cpi.applicationInfo.uid)
7470 == PackageManager.PERMISSION_GRANTED) {
7471 return null;
7472 }
7473 }
7474 }
7475
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007476 String msg = "Permission Denial: opening provider " + cpi.name
7477 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7478 + ", uid=" + callingUid + ") requires "
7479 + cpi.readPermission + " or " + cpi.writePermission;
7480 Log.w(TAG, msg);
7481 return msg;
7482 }
7483
7484 private final ContentProviderHolder getContentProviderImpl(
7485 IApplicationThread caller, String name) {
7486 ContentProviderRecord cpr;
7487 ProviderInfo cpi = null;
7488
7489 synchronized(this) {
7490 ProcessRecord r = null;
7491 if (caller != null) {
7492 r = getRecordForAppLocked(caller);
7493 if (r == null) {
7494 throw new SecurityException(
7495 "Unable to find app for caller " + caller
7496 + " (pid=" + Binder.getCallingPid()
7497 + ") when getting content provider " + name);
7498 }
7499 }
7500
7501 // First check if this content provider has been published...
7502 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7503 if (cpr != null) {
7504 cpi = cpr.info;
7505 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7506 return new ContentProviderHolder(cpi,
7507 cpi.readPermission != null
7508 ? cpi.readPermission : cpi.writePermission);
7509 }
7510
7511 if (r != null && cpr.canRunHere(r)) {
7512 // This provider has been published or is in the process
7513 // of being published... but it is also allowed to run
7514 // in the caller's process, so don't make a connection
7515 // and just let the caller instantiate its own instance.
7516 if (cpr.provider != null) {
7517 // don't give caller the provider object, it needs
7518 // to make its own.
7519 cpr = new ContentProviderRecord(cpr);
7520 }
7521 return cpr;
7522 }
7523
7524 final long origId = Binder.clearCallingIdentity();
7525
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007526 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007527 // return it right away.
7528 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007529 if (DEBUG_PROVIDER) Log.v(TAG,
7530 "Adding provider requested by "
7531 + r.processName + " from process "
7532 + cpr.info.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007533 r.conProviders.add(cpr);
7534 cpr.clients.add(r);
7535 } else {
7536 cpr.externals++;
7537 }
7538
7539 if (cpr.app != null) {
7540 updateOomAdjLocked(cpr.app);
7541 }
7542
7543 Binder.restoreCallingIdentity(origId);
7544
7545 } else {
7546 try {
7547 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007548 resolveContentProvider(name,
7549 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007550 } catch (RemoteException ex) {
7551 }
7552 if (cpi == null) {
7553 return null;
7554 }
7555
7556 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7557 return new ContentProviderHolder(cpi,
7558 cpi.readPermission != null
7559 ? cpi.readPermission : cpi.writePermission);
7560 }
7561
7562 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7563 final boolean firstClass = cpr == null;
7564 if (firstClass) {
7565 try {
7566 ApplicationInfo ai =
7567 ActivityThread.getPackageManager().
7568 getApplicationInfo(
7569 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007570 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007571 if (ai == null) {
7572 Log.w(TAG, "No package info for content provider "
7573 + cpi.name);
7574 return null;
7575 }
7576 cpr = new ContentProviderRecord(cpi, ai);
7577 } catch (RemoteException ex) {
7578 // pm is in same process, this will never happen.
7579 }
7580 }
7581
7582 if (r != null && cpr.canRunHere(r)) {
7583 // If this is a multiprocess provider, then just return its
7584 // info and allow the caller to instantiate it. Only do
7585 // this if the provider is the same user as the caller's
7586 // process, or can run as root (so can be in any process).
7587 return cpr;
7588 }
7589
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007590 if (DEBUG_PROVIDER) {
7591 RuntimeException e = new RuntimeException("here");
7592 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7593 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007594 }
7595
7596 // This is single process, and our app is now connecting to it.
7597 // See if we are already in the process of launching this
7598 // provider.
7599 final int N = mLaunchingProviders.size();
7600 int i;
7601 for (i=0; i<N; i++) {
7602 if (mLaunchingProviders.get(i) == cpr) {
7603 break;
7604 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007605 }
7606
7607 // If the provider is not already being launched, then get it
7608 // started.
7609 if (i >= N) {
7610 final long origId = Binder.clearCallingIdentity();
7611 ProcessRecord proc = startProcessLocked(cpi.processName,
7612 cpr.appInfo, false, 0, "content provider",
7613 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007614 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007615 if (proc == null) {
7616 Log.w(TAG, "Unable to launch app "
7617 + cpi.applicationInfo.packageName + "/"
7618 + cpi.applicationInfo.uid + " for provider "
7619 + name + ": process is bad");
7620 return null;
7621 }
7622 cpr.launchingApp = proc;
7623 mLaunchingProviders.add(cpr);
7624 Binder.restoreCallingIdentity(origId);
7625 }
7626
7627 // Make sure the provider is published (the same provider class
7628 // may be published under multiple names).
7629 if (firstClass) {
7630 mProvidersByClass.put(cpi.name, cpr);
7631 }
7632 mProvidersByName.put(name, cpr);
7633
7634 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007635 if (DEBUG_PROVIDER) Log.v(TAG,
7636 "Adding provider requested by "
7637 + r.processName + " from process "
7638 + cpr.info.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007639 r.conProviders.add(cpr);
7640 cpr.clients.add(r);
7641 } else {
7642 cpr.externals++;
7643 }
7644 }
7645 }
7646
7647 // Wait for the provider to be published...
7648 synchronized (cpr) {
7649 while (cpr.provider == null) {
7650 if (cpr.launchingApp == null) {
7651 Log.w(TAG, "Unable to launch app "
7652 + cpi.applicationInfo.packageName + "/"
7653 + cpi.applicationInfo.uid + " for provider "
7654 + name + ": launching app became null");
7655 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7656 cpi.applicationInfo.packageName,
7657 cpi.applicationInfo.uid, name);
7658 return null;
7659 }
7660 try {
7661 cpr.wait();
7662 } catch (InterruptedException ex) {
7663 }
7664 }
7665 }
7666 return cpr;
7667 }
7668
7669 public final ContentProviderHolder getContentProvider(
7670 IApplicationThread caller, String name) {
7671 if (caller == null) {
7672 String msg = "null IApplicationThread when getting content provider "
7673 + name;
7674 Log.w(TAG, msg);
7675 throw new SecurityException(msg);
7676 }
7677
7678 return getContentProviderImpl(caller, name);
7679 }
7680
7681 private ContentProviderHolder getContentProviderExternal(String name) {
7682 return getContentProviderImpl(null, name);
7683 }
7684
7685 /**
7686 * Drop a content provider from a ProcessRecord's bookkeeping
7687 * @param cpr
7688 */
7689 public void removeContentProvider(IApplicationThread caller, String name) {
7690 synchronized (this) {
7691 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7692 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007693 // remove from mProvidersByClass
7694 if (DEBUG_PROVIDER) Log.v(TAG, name +
7695 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007696 return;
7697 }
7698 final ProcessRecord r = getRecordForAppLocked(caller);
7699 if (r == null) {
7700 throw new SecurityException(
7701 "Unable to find app for caller " + caller +
7702 " when removing content provider " + name);
7703 }
7704 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007705 ContentProviderRecord localCpr = (ContentProviderRecord)
7706 mProvidersByClass.get(cpr.info.name);
7707 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7708 + r.info.processName + " from process "
7709 + localCpr.appInfo.processName);
7710 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007711 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007712 Log.w(TAG, "removeContentProvider called on local provider: "
7713 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007714 return;
7715 } else {
7716 localCpr.clients.remove(r);
7717 r.conProviders.remove(localCpr);
7718 }
7719 updateOomAdjLocked();
7720 }
7721 }
7722
7723 private void removeContentProviderExternal(String name) {
7724 synchronized (this) {
7725 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7726 if(cpr == null) {
7727 //remove from mProvidersByClass
7728 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7729 return;
7730 }
7731
7732 //update content provider record entry info
7733 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7734 localCpr.externals--;
7735 if (localCpr.externals < 0) {
7736 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7737 }
7738 updateOomAdjLocked();
7739 }
7740 }
7741
7742 public final void publishContentProviders(IApplicationThread caller,
7743 List<ContentProviderHolder> providers) {
7744 if (providers == null) {
7745 return;
7746 }
7747
7748 synchronized(this) {
7749 final ProcessRecord r = getRecordForAppLocked(caller);
7750 if (r == null) {
7751 throw new SecurityException(
7752 "Unable to find app for caller " + caller
7753 + " (pid=" + Binder.getCallingPid()
7754 + ") when publishing content providers");
7755 }
7756
7757 final long origId = Binder.clearCallingIdentity();
7758
7759 final int N = providers.size();
7760 for (int i=0; i<N; i++) {
7761 ContentProviderHolder src = providers.get(i);
7762 if (src == null || src.info == null || src.provider == null) {
7763 continue;
7764 }
7765 ContentProviderRecord dst =
7766 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7767 if (dst != null) {
7768 mProvidersByClass.put(dst.info.name, dst);
7769 String names[] = dst.info.authority.split(";");
7770 for (int j = 0; j < names.length; j++) {
7771 mProvidersByName.put(names[j], dst);
7772 }
7773
7774 int NL = mLaunchingProviders.size();
7775 int j;
7776 for (j=0; j<NL; j++) {
7777 if (mLaunchingProviders.get(j) == dst) {
7778 mLaunchingProviders.remove(j);
7779 j--;
7780 NL--;
7781 }
7782 }
7783 synchronized (dst) {
7784 dst.provider = src.provider;
7785 dst.app = r;
7786 dst.notifyAll();
7787 }
7788 updateOomAdjLocked(r);
7789 }
7790 }
7791
7792 Binder.restoreCallingIdentity(origId);
7793 }
7794 }
7795
7796 public static final void installSystemProviders() {
7797 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7798 List providers = mSelf.generateApplicationProvidersLocked(app);
7799 mSystemThread.installSystemProviders(providers);
7800 }
7801
7802 // =========================================================
7803 // GLOBAL MANAGEMENT
7804 // =========================================================
7805
7806 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7807 ApplicationInfo info, String customProcess) {
7808 String proc = customProcess != null ? customProcess : info.processName;
7809 BatteryStatsImpl.Uid.Proc ps = null;
7810 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7811 synchronized (stats) {
7812 ps = stats.getProcessStatsLocked(info.uid, proc);
7813 }
7814 return new ProcessRecord(ps, thread, info, proc);
7815 }
7816
7817 final ProcessRecord addAppLocked(ApplicationInfo info) {
7818 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7819
7820 if (app == null) {
7821 app = newProcessRecordLocked(null, info, null);
7822 mProcessNames.put(info.processName, info.uid, app);
7823 updateLRUListLocked(app, true);
7824 }
7825
7826 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7827 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7828 app.persistent = true;
7829 app.maxAdj = CORE_SERVER_ADJ;
7830 }
7831 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7832 mPersistentStartingProcesses.add(app);
7833 startProcessLocked(app, "added application", app.processName);
7834 }
7835
7836 return app;
7837 }
7838
7839 public void unhandledBack() {
7840 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7841 "unhandledBack()");
7842
7843 synchronized(this) {
7844 int count = mHistory.size();
7845 if (Config.LOGD) Log.d(
7846 TAG, "Performing unhandledBack(): stack size = " + count);
7847 if (count > 1) {
7848 final long origId = Binder.clearCallingIdentity();
7849 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7850 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7851 Binder.restoreCallingIdentity(origId);
7852 }
7853 }
7854 }
7855
7856 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7857 String name = uri.getAuthority();
7858 ContentProviderHolder cph = getContentProviderExternal(name);
7859 ParcelFileDescriptor pfd = null;
7860 if (cph != null) {
7861 // We record the binder invoker's uid in thread-local storage before
7862 // going to the content provider to open the file. Later, in the code
7863 // that handles all permissions checks, we look for this uid and use
7864 // that rather than the Activity Manager's own uid. The effect is that
7865 // we do the check against the caller's permissions even though it looks
7866 // to the content provider like the Activity Manager itself is making
7867 // the request.
7868 sCallerIdentity.set(new Identity(
7869 Binder.getCallingPid(), Binder.getCallingUid()));
7870 try {
7871 pfd = cph.provider.openFile(uri, "r");
7872 } catch (FileNotFoundException e) {
7873 // do nothing; pfd will be returned null
7874 } finally {
7875 // Ensure that whatever happens, we clean up the identity state
7876 sCallerIdentity.remove();
7877 }
7878
7879 // We've got the fd now, so we're done with the provider.
7880 removeContentProviderExternal(name);
7881 } else {
7882 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7883 }
7884 return pfd;
7885 }
7886
7887 public void goingToSleep() {
7888 synchronized(this) {
7889 mSleeping = true;
7890 mWindowManager.setEventDispatching(false);
7891
7892 if (mResumedActivity != null) {
7893 pauseIfSleepingLocked();
7894 } else {
7895 Log.w(TAG, "goingToSleep with no resumed activity!");
7896 }
7897 }
7898 }
7899
Dianne Hackborn55280a92009-05-07 15:53:46 -07007900 public boolean shutdown(int timeout) {
7901 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7902 != PackageManager.PERMISSION_GRANTED) {
7903 throw new SecurityException("Requires permission "
7904 + android.Manifest.permission.SHUTDOWN);
7905 }
7906
7907 boolean timedout = false;
7908
7909 synchronized(this) {
7910 mShuttingDown = true;
7911 mWindowManager.setEventDispatching(false);
7912
7913 if (mResumedActivity != null) {
7914 pauseIfSleepingLocked();
7915 final long endTime = System.currentTimeMillis() + timeout;
7916 while (mResumedActivity != null || mPausingActivity != null) {
7917 long delay = endTime - System.currentTimeMillis();
7918 if (delay <= 0) {
7919 Log.w(TAG, "Activity manager shutdown timed out");
7920 timedout = true;
7921 break;
7922 }
7923 try {
7924 this.wait();
7925 } catch (InterruptedException e) {
7926 }
7927 }
7928 }
7929 }
7930
7931 mUsageStatsService.shutdown();
7932 mBatteryStatsService.shutdown();
7933
7934 return timedout;
7935 }
7936
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007937 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007938 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007939 if (!mGoingToSleep.isHeld()) {
7940 mGoingToSleep.acquire();
7941 if (mLaunchingActivity.isHeld()) {
7942 mLaunchingActivity.release();
7943 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7944 }
7945 }
7946
7947 // If we are not currently pausing an activity, get the current
7948 // one to pause. If we are pausing one, we will just let that stuff
7949 // run and release the wake lock when all done.
7950 if (mPausingActivity == null) {
7951 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7952 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7953 startPausingLocked(false, true);
7954 }
7955 }
7956 }
7957
7958 public void wakingUp() {
7959 synchronized(this) {
7960 if (mGoingToSleep.isHeld()) {
7961 mGoingToSleep.release();
7962 }
7963 mWindowManager.setEventDispatching(true);
7964 mSleeping = false;
7965 resumeTopActivityLocked(null);
7966 }
7967 }
7968
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007969 public void stopAppSwitches() {
7970 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7971 != PackageManager.PERMISSION_GRANTED) {
7972 throw new SecurityException("Requires permission "
7973 + android.Manifest.permission.STOP_APP_SWITCHES);
7974 }
7975
7976 synchronized(this) {
7977 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7978 + APP_SWITCH_DELAY_TIME;
7979 mDidAppSwitch = false;
7980 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7981 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7982 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7983 }
7984 }
7985
7986 public void resumeAppSwitches() {
7987 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7988 != PackageManager.PERMISSION_GRANTED) {
7989 throw new SecurityException("Requires permission "
7990 + android.Manifest.permission.STOP_APP_SWITCHES);
7991 }
7992
7993 synchronized(this) {
7994 // Note that we don't execute any pending app switches... we will
7995 // let those wait until either the timeout, or the next start
7996 // activity request.
7997 mAppSwitchesAllowedTime = 0;
7998 }
7999 }
8000
8001 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8002 String name) {
8003 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8004 return true;
8005 }
8006
8007 final int perm = checkComponentPermission(
8008 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8009 callingUid, -1);
8010 if (perm == PackageManager.PERMISSION_GRANTED) {
8011 return true;
8012 }
8013
8014 Log.w(TAG, name + " request from " + callingUid + " stopped");
8015 return false;
8016 }
8017
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008018 public void setDebugApp(String packageName, boolean waitForDebugger,
8019 boolean persistent) {
8020 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8021 "setDebugApp()");
8022
8023 // Note that this is not really thread safe if there are multiple
8024 // callers into it at the same time, but that's not a situation we
8025 // care about.
8026 if (persistent) {
8027 final ContentResolver resolver = mContext.getContentResolver();
8028 Settings.System.putString(
8029 resolver, Settings.System.DEBUG_APP,
8030 packageName);
8031 Settings.System.putInt(
8032 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8033 waitForDebugger ? 1 : 0);
8034 }
8035
8036 synchronized (this) {
8037 if (!persistent) {
8038 mOrigDebugApp = mDebugApp;
8039 mOrigWaitForDebugger = mWaitForDebugger;
8040 }
8041 mDebugApp = packageName;
8042 mWaitForDebugger = waitForDebugger;
8043 mDebugTransient = !persistent;
8044 if (packageName != null) {
8045 final long origId = Binder.clearCallingIdentity();
8046 uninstallPackageLocked(packageName, -1, false);
8047 Binder.restoreCallingIdentity(origId);
8048 }
8049 }
8050 }
8051
8052 public void setAlwaysFinish(boolean enabled) {
8053 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8054 "setAlwaysFinish()");
8055
8056 Settings.System.putInt(
8057 mContext.getContentResolver(),
8058 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8059
8060 synchronized (this) {
8061 mAlwaysFinishActivities = enabled;
8062 }
8063 }
8064
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008065 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008066 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008067 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008068 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008069 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008070 }
8071 }
8072
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008073 public void registerActivityWatcher(IActivityWatcher watcher) {
8074 mWatchers.register(watcher);
8075 }
8076
8077 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8078 mWatchers.unregister(watcher);
8079 }
8080
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008081 public final void enterSafeMode() {
8082 synchronized(this) {
8083 // It only makes sense to do this before the system is ready
8084 // and started launching other packages.
8085 if (!mSystemReady) {
8086 try {
8087 ActivityThread.getPackageManager().enterSafeMode();
8088 } catch (RemoteException e) {
8089 }
8090
8091 View v = LayoutInflater.from(mContext).inflate(
8092 com.android.internal.R.layout.safe_mode, null);
8093 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8094 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8095 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8096 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8097 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8098 lp.format = v.getBackground().getOpacity();
8099 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8100 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8101 ((WindowManager)mContext.getSystemService(
8102 Context.WINDOW_SERVICE)).addView(v, lp);
8103 }
8104 }
8105 }
8106
8107 public void noteWakeupAlarm(IIntentSender sender) {
8108 if (!(sender instanceof PendingIntentRecord)) {
8109 return;
8110 }
8111 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8112 synchronized (stats) {
8113 if (mBatteryStatsService.isOnBattery()) {
8114 mBatteryStatsService.enforceCallingPermission();
8115 PendingIntentRecord rec = (PendingIntentRecord)sender;
8116 int MY_UID = Binder.getCallingUid();
8117 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8118 BatteryStatsImpl.Uid.Pkg pkg =
8119 stats.getPackageStatsLocked(uid, rec.key.packageName);
8120 pkg.incWakeupsLocked();
8121 }
8122 }
8123 }
8124
8125 public boolean killPidsForMemory(int[] pids) {
8126 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8127 throw new SecurityException("killPidsForMemory only available to the system");
8128 }
8129
8130 // XXX Note: don't acquire main activity lock here, because the window
8131 // manager calls in with its locks held.
8132
8133 boolean killed = false;
8134 synchronized (mPidsSelfLocked) {
8135 int[] types = new int[pids.length];
8136 int worstType = 0;
8137 for (int i=0; i<pids.length; i++) {
8138 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8139 if (proc != null) {
8140 int type = proc.setAdj;
8141 types[i] = type;
8142 if (type > worstType) {
8143 worstType = type;
8144 }
8145 }
8146 }
8147
8148 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8149 // then constrain it so we will kill all hidden procs.
8150 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8151 worstType = HIDDEN_APP_MIN_ADJ;
8152 }
8153 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8154 for (int i=0; i<pids.length; i++) {
8155 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8156 if (proc == null) {
8157 continue;
8158 }
8159 int adj = proc.setAdj;
8160 if (adj >= worstType) {
8161 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8162 + adj + ")");
8163 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
8164 proc.processName, adj);
8165 killed = true;
8166 Process.killProcess(pids[i]);
8167 }
8168 }
8169 }
8170 return killed;
8171 }
8172
8173 public void reportPss(IApplicationThread caller, int pss) {
8174 Watchdog.PssRequestor req;
8175 String name;
8176 ProcessRecord callerApp;
8177 synchronized (this) {
8178 if (caller == null) {
8179 return;
8180 }
8181 callerApp = getRecordForAppLocked(caller);
8182 if (callerApp == null) {
8183 return;
8184 }
8185 callerApp.lastPss = pss;
8186 req = callerApp;
8187 name = callerApp.processName;
8188 }
8189 Watchdog.getInstance().reportPss(req, name, pss);
8190 if (!callerApp.persistent) {
8191 removeRequestedPss(callerApp);
8192 }
8193 }
8194
8195 public void requestPss(Runnable completeCallback) {
8196 ArrayList<ProcessRecord> procs;
8197 synchronized (this) {
8198 mRequestPssCallback = completeCallback;
8199 mRequestPssList.clear();
8200 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8201 ProcessRecord proc = mLRUProcesses.get(i);
8202 if (!proc.persistent) {
8203 mRequestPssList.add(proc);
8204 }
8205 }
8206 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8207 }
8208
8209 int oldPri = Process.getThreadPriority(Process.myTid());
8210 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8211 for (int i=procs.size()-1; i>=0; i--) {
8212 ProcessRecord proc = procs.get(i);
8213 proc.lastPss = 0;
8214 proc.requestPss();
8215 }
8216 Process.setThreadPriority(oldPri);
8217 }
8218
8219 void removeRequestedPss(ProcessRecord proc) {
8220 Runnable callback = null;
8221 synchronized (this) {
8222 if (mRequestPssList.remove(proc)) {
8223 if (mRequestPssList.size() == 0) {
8224 callback = mRequestPssCallback;
8225 mRequestPssCallback = null;
8226 }
8227 }
8228 }
8229
8230 if (callback != null) {
8231 callback.run();
8232 }
8233 }
8234
8235 public void collectPss(Watchdog.PssStats stats) {
8236 stats.mEmptyPss = 0;
8237 stats.mEmptyCount = 0;
8238 stats.mBackgroundPss = 0;
8239 stats.mBackgroundCount = 0;
8240 stats.mServicePss = 0;
8241 stats.mServiceCount = 0;
8242 stats.mVisiblePss = 0;
8243 stats.mVisibleCount = 0;
8244 stats.mForegroundPss = 0;
8245 stats.mForegroundCount = 0;
8246 stats.mNoPssCount = 0;
8247 synchronized (this) {
8248 int i;
8249 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8250 ? mProcDeaths.length : stats.mProcDeaths.length;
8251 int aggr = 0;
8252 for (i=0; i<NPD; i++) {
8253 aggr += mProcDeaths[i];
8254 stats.mProcDeaths[i] = aggr;
8255 }
8256 while (i<stats.mProcDeaths.length) {
8257 stats.mProcDeaths[i] = 0;
8258 i++;
8259 }
8260
8261 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8262 ProcessRecord proc = mLRUProcesses.get(i);
8263 if (proc.persistent) {
8264 continue;
8265 }
8266 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8267 if (proc.lastPss == 0) {
8268 stats.mNoPssCount++;
8269 continue;
8270 }
8271 if (proc.setAdj == EMPTY_APP_ADJ) {
8272 stats.mEmptyPss += proc.lastPss;
8273 stats.mEmptyCount++;
8274 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8275 stats.mEmptyPss += proc.lastPss;
8276 stats.mEmptyCount++;
8277 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8278 stats.mBackgroundPss += proc.lastPss;
8279 stats.mBackgroundCount++;
8280 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8281 stats.mVisiblePss += proc.lastPss;
8282 stats.mVisibleCount++;
8283 } else {
8284 stats.mForegroundPss += proc.lastPss;
8285 stats.mForegroundCount++;
8286 }
8287 }
8288 }
8289 }
8290
8291 public final void startRunning(String pkg, String cls, String action,
8292 String data) {
8293 synchronized(this) {
8294 if (mStartRunning) {
8295 return;
8296 }
8297 mStartRunning = true;
8298 mTopComponent = pkg != null && cls != null
8299 ? new ComponentName(pkg, cls) : null;
8300 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8301 mTopData = data;
8302 if (!mSystemReady) {
8303 return;
8304 }
8305 }
8306
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008307 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008308 }
8309
8310 private void retrieveSettings() {
8311 final ContentResolver resolver = mContext.getContentResolver();
8312 String debugApp = Settings.System.getString(
8313 resolver, Settings.System.DEBUG_APP);
8314 boolean waitForDebugger = Settings.System.getInt(
8315 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8316 boolean alwaysFinishActivities = Settings.System.getInt(
8317 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8318
8319 Configuration configuration = new Configuration();
8320 Settings.System.getConfiguration(resolver, configuration);
8321
8322 synchronized (this) {
8323 mDebugApp = mOrigDebugApp = debugApp;
8324 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8325 mAlwaysFinishActivities = alwaysFinishActivities;
8326 // This happens before any activities are started, so we can
8327 // change mConfiguration in-place.
8328 mConfiguration.updateFrom(configuration);
8329 }
8330 }
8331
8332 public boolean testIsSystemReady() {
8333 // no need to synchronize(this) just to read & return the value
8334 return mSystemReady;
8335 }
8336
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008337 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008338 // In the simulator, startRunning will never have been called, which
8339 // normally sets a few crucial variables. Do it here instead.
8340 if (!Process.supportsProcesses()) {
8341 mStartRunning = true;
8342 mTopAction = Intent.ACTION_MAIN;
8343 }
8344
8345 synchronized(this) {
8346 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008347 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008348 return;
8349 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008350
8351 // Check to see if there are any update receivers to run.
8352 if (!mDidUpdate) {
8353 if (mWaitingUpdate) {
8354 return;
8355 }
8356 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8357 List<ResolveInfo> ris = null;
8358 try {
8359 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8360 intent, null, 0);
8361 } catch (RemoteException e) {
8362 }
8363 if (ris != null) {
8364 for (int i=ris.size()-1; i>=0; i--) {
8365 if ((ris.get(i).activityInfo.applicationInfo.flags
8366 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8367 ris.remove(i);
8368 }
8369 }
8370 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8371 for (int i=0; i<ris.size(); i++) {
8372 ActivityInfo ai = ris.get(i).activityInfo;
8373 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8374 IIntentReceiver finisher = null;
8375 if (i == 0) {
8376 finisher = new IIntentReceiver.Stub() {
8377 public void performReceive(Intent intent, int resultCode,
8378 String data, Bundle extras, boolean ordered)
8379 throws RemoteException {
8380 synchronized (ActivityManagerService.this) {
8381 mDidUpdate = true;
8382 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008383 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008384 }
8385 };
8386 }
8387 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8388 broadcastIntentLocked(null, null, intent, null, finisher,
8389 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8390 if (i == 0) {
8391 mWaitingUpdate = true;
8392 }
8393 }
8394 }
8395 if (mWaitingUpdate) {
8396 return;
8397 }
8398 mDidUpdate = true;
8399 }
8400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008401 mSystemReady = true;
8402 if (!mStartRunning) {
8403 return;
8404 }
8405 }
8406
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008407 ArrayList<ProcessRecord> procsToKill = null;
8408 synchronized(mPidsSelfLocked) {
8409 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8410 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8411 if (!isAllowedWhileBooting(proc.info)){
8412 if (procsToKill == null) {
8413 procsToKill = new ArrayList<ProcessRecord>();
8414 }
8415 procsToKill.add(proc);
8416 }
8417 }
8418 }
8419
8420 if (procsToKill != null) {
8421 synchronized(this) {
8422 for (int i=procsToKill.size()-1; i>=0; i--) {
8423 ProcessRecord proc = procsToKill.get(i);
8424 Log.i(TAG, "Removing system update proc: " + proc);
8425 removeProcessLocked(proc, true);
8426 }
8427 }
8428 }
8429
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008430 Log.i(TAG, "System now ready");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008431 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8432 SystemClock.uptimeMillis());
8433
8434 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008435 // Make sure we have no pre-ready processes sitting around.
8436
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008437 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8438 ResolveInfo ri = mContext.getPackageManager()
8439 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008440 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008441 CharSequence errorMsg = null;
8442 if (ri != null) {
8443 ActivityInfo ai = ri.activityInfo;
8444 ApplicationInfo app = ai.applicationInfo;
8445 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8446 mTopAction = Intent.ACTION_FACTORY_TEST;
8447 mTopData = null;
8448 mTopComponent = new ComponentName(app.packageName,
8449 ai.name);
8450 } else {
8451 errorMsg = mContext.getResources().getText(
8452 com.android.internal.R.string.factorytest_not_system);
8453 }
8454 } else {
8455 errorMsg = mContext.getResources().getText(
8456 com.android.internal.R.string.factorytest_no_action);
8457 }
8458 if (errorMsg != null) {
8459 mTopAction = null;
8460 mTopData = null;
8461 mTopComponent = null;
8462 Message msg = Message.obtain();
8463 msg.what = SHOW_FACTORY_ERROR_MSG;
8464 msg.getData().putCharSequence("msg", errorMsg);
8465 mHandler.sendMessage(msg);
8466 }
8467 }
8468 }
8469
8470 retrieveSettings();
8471
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008472 if (goingCallback != null) goingCallback.run();
8473
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008474 synchronized (this) {
8475 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8476 try {
8477 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008478 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008479 if (apps != null) {
8480 int N = apps.size();
8481 int i;
8482 for (i=0; i<N; i++) {
8483 ApplicationInfo info
8484 = (ApplicationInfo)apps.get(i);
8485 if (info != null &&
8486 !info.packageName.equals("android")) {
8487 addAppLocked(info);
8488 }
8489 }
8490 }
8491 } catch (RemoteException ex) {
8492 // pm is in same process, this will never happen.
8493 }
8494 }
8495
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008496 // Start up initial activity.
8497 mBooting = true;
8498
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008499 try {
8500 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8501 Message msg = Message.obtain();
8502 msg.what = SHOW_UID_ERROR_MSG;
8503 mHandler.sendMessage(msg);
8504 }
8505 } catch (RemoteException e) {
8506 }
8507
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008508 resumeTopActivityLocked(null);
8509 }
8510 }
8511
8512 boolean makeAppCrashingLocked(ProcessRecord app,
8513 String tag, String shortMsg, String longMsg, byte[] crashData) {
8514 app.crashing = true;
8515 app.crashingReport = generateProcessError(app,
8516 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8517 startAppProblemLocked(app);
8518 app.stopFreezingAllLocked();
8519 return handleAppCrashLocked(app);
8520 }
8521
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008522 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Jacek Surazskia2339432009-09-18 15:01:26 +02008523 // check if error reporting is enabled in Gservices
8524 int enabled = Settings.Gservices.getInt(mContext.getContentResolver(),
8525 Settings.Gservices.SEND_ACTION_APP_ERROR, 0);
8526 if (enabled == 0) {
8527 return null;
8528 }
8529
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008530 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008531
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008532 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008533 // look for receiver in the installer package
8534 String candidate = pm.getInstallerPackageName(app.info.packageName);
8535 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8536 if (result != null) {
8537 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008538 }
8539
Jacek Surazski82a73df2009-06-17 14:33:18 +02008540 // if the error app is on the system image, look for system apps
8541 // error receiver
8542 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8543 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8544 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8545 if (result != null) {
8546 return result;
8547 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008548 }
8549
Jacek Surazski82a73df2009-06-17 14:33:18 +02008550 // if there is a default receiver, try that
8551 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8552 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008553 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008554 // should not happen
8555 Log.e(TAG, "error talking to PackageManager", e);
8556 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008557 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008558 }
8559
8560 /**
8561 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8562 *
8563 * @param pm PackageManager isntance
8564 * @param errorPackage package which caused the error
8565 * @param receiverPackage candidate package to receive the error
8566 * @return activity component within receiverPackage which handles
8567 * ACTION_APP_ERROR, or null if not found
8568 */
8569 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8570 String receiverPackage) throws RemoteException {
8571 if (receiverPackage == null || receiverPackage.length() == 0) {
8572 return null;
8573 }
8574
8575 // break the loop if it's the error report receiver package that crashed
8576 if (receiverPackage.equals(errorPackage)) {
8577 return null;
8578 }
8579
8580 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8581 intent.setPackage(receiverPackage);
8582 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8583 if (info == null || info.activityInfo == null) {
8584 return null;
8585 }
8586 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008587 }
8588
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008589 void makeAppNotRespondingLocked(ProcessRecord app,
8590 String tag, String shortMsg, String longMsg, byte[] crashData) {
8591 app.notResponding = true;
8592 app.notRespondingReport = generateProcessError(app,
8593 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8594 crashData);
8595 startAppProblemLocked(app);
8596 app.stopFreezingAllLocked();
8597 }
8598
8599 /**
8600 * Generate a process error record, suitable for attachment to a ProcessRecord.
8601 *
8602 * @param app The ProcessRecord in which the error occurred.
8603 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8604 * ActivityManager.AppErrorStateInfo
8605 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8606 * @param shortMsg Short message describing the crash.
8607 * @param longMsg Long message describing the crash.
8608 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8609 *
8610 * @return Returns a fully-formed AppErrorStateInfo record.
8611 */
8612 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8613 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8614 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8615
8616 report.condition = condition;
8617 report.processName = app.processName;
8618 report.pid = app.pid;
8619 report.uid = app.info.uid;
8620 report.tag = tag;
8621 report.shortMsg = shortMsg;
8622 report.longMsg = longMsg;
8623 report.crashData = crashData;
8624
8625 return report;
8626 }
8627
8628 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8629 boolean crashed) {
8630 synchronized (this) {
8631 app.crashing = false;
8632 app.crashingReport = null;
8633 app.notResponding = false;
8634 app.notRespondingReport = null;
8635 if (app.anrDialog == fromDialog) {
8636 app.anrDialog = null;
8637 }
8638 if (app.waitDialog == fromDialog) {
8639 app.waitDialog = null;
8640 }
8641 if (app.pid > 0 && app.pid != MY_PID) {
8642 if (crashed) {
8643 handleAppCrashLocked(app);
8644 }
8645 Log.i(ActivityManagerService.TAG, "Killing process "
8646 + app.processName
8647 + " (pid=" + app.pid + ") at user's request");
8648 Process.killProcess(app.pid);
8649 }
8650
8651 }
8652 }
8653
8654 boolean handleAppCrashLocked(ProcessRecord app) {
8655 long now = SystemClock.uptimeMillis();
8656
8657 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8658 app.info.uid);
8659 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8660 // This process loses!
8661 Log.w(TAG, "Process " + app.info.processName
8662 + " has crashed too many times: killing!");
8663 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8664 app.info.processName, app.info.uid);
8665 killServicesLocked(app, false);
8666 for (int i=mHistory.size()-1; i>=0; i--) {
8667 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8668 if (r.app == app) {
8669 if (Config.LOGD) Log.d(
8670 TAG, " Force finishing activity "
8671 + r.intent.getComponent().flattenToShortString());
8672 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8673 }
8674 }
8675 if (!app.persistent) {
8676 // We don't want to start this process again until the user
8677 // explicitly does so... but for persistent process, we really
8678 // need to keep it running. If a persistent process is actually
8679 // repeatedly crashing, then badness for everyone.
8680 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8681 app.info.processName);
8682 mBadProcesses.put(app.info.processName, app.info.uid, now);
8683 app.bad = true;
8684 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8685 app.removed = true;
8686 removeProcessLocked(app, false);
8687 return false;
8688 }
8689 }
8690
8691 // Bump up the crash count of any services currently running in the proc.
8692 if (app.services.size() != 0) {
8693 // Any services running in the application need to be placed
8694 // back in the pending list.
8695 Iterator it = app.services.iterator();
8696 while (it.hasNext()) {
8697 ServiceRecord sr = (ServiceRecord)it.next();
8698 sr.crashCount++;
8699 }
8700 }
8701
8702 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8703 return true;
8704 }
8705
8706 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008707 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008708 skipCurrentReceiverLocked(app);
8709 }
8710
8711 void skipCurrentReceiverLocked(ProcessRecord app) {
8712 boolean reschedule = false;
8713 BroadcastRecord r = app.curReceiver;
8714 if (r != null) {
8715 // The current broadcast is waiting for this app's receiver
8716 // to be finished. Looks like that's not going to happen, so
8717 // let the broadcast continue.
8718 logBroadcastReceiverDiscard(r);
8719 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8720 r.resultExtras, r.resultAbort, true);
8721 reschedule = true;
8722 }
8723 r = mPendingBroadcast;
8724 if (r != null && r.curApp == app) {
8725 if (DEBUG_BROADCAST) Log.v(TAG,
8726 "skip & discard pending app " + r);
8727 logBroadcastReceiverDiscard(r);
8728 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8729 r.resultExtras, r.resultAbort, true);
8730 reschedule = true;
8731 }
8732 if (reschedule) {
8733 scheduleBroadcastsLocked();
8734 }
8735 }
8736
8737 public int handleApplicationError(IBinder app, int flags,
8738 String tag, String shortMsg, String longMsg, byte[] crashData) {
8739 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008740 ProcessRecord r = null;
8741 synchronized (this) {
8742 if (app != null) {
8743 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8744 final int NA = apps.size();
8745 for (int ia=0; ia<NA; ia++) {
8746 ProcessRecord p = apps.valueAt(ia);
8747 if (p.thread != null && p.thread.asBinder() == app) {
8748 r = p;
8749 break;
8750 }
8751 }
8752 }
8753 }
8754
8755 if (r != null) {
8756 // The application has crashed. Send the SIGQUIT to the process so
8757 // that it can dump its state.
8758 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8759 //Log.i(TAG, "Current system threads:");
8760 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8761 }
8762
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008763 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008764 try {
8765 String name = r != null ? r.processName : null;
8766 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008767 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008768 shortMsg, longMsg, crashData)) {
8769 Log.w(TAG, "Force-killing crashed app " + name
8770 + " at watcher's request");
8771 Process.killProcess(pid);
8772 return 0;
8773 }
8774 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008775 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008776 }
8777 }
8778
8779 final long origId = Binder.clearCallingIdentity();
8780
8781 // If this process is running instrumentation, finish it.
8782 if (r != null && r.instrumentationClass != null) {
8783 Log.w(TAG, "Error in app " + r.processName
8784 + " running instrumentation " + r.instrumentationClass + ":");
8785 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8786 if (longMsg != null) Log.w(TAG, " " + longMsg);
8787 Bundle info = new Bundle();
8788 info.putString("shortMsg", shortMsg);
8789 info.putString("longMsg", longMsg);
8790 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8791 Binder.restoreCallingIdentity(origId);
8792 return 0;
8793 }
8794
8795 if (r != null) {
8796 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8797 return 0;
8798 }
8799 } else {
8800 Log.w(TAG, "Some application object " + app + " tag " + tag
8801 + " has crashed, but I don't know who it is.");
8802 Log.w(TAG, "ShortMsg:" + shortMsg);
8803 Log.w(TAG, "LongMsg:" + longMsg);
8804 Binder.restoreCallingIdentity(origId);
8805 return 0;
8806 }
8807
8808 Message msg = Message.obtain();
8809 msg.what = SHOW_ERROR_MSG;
8810 HashMap data = new HashMap();
8811 data.put("result", result);
8812 data.put("app", r);
8813 data.put("flags", flags);
8814 data.put("shortMsg", shortMsg);
8815 data.put("longMsg", longMsg);
8816 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8817 // For system processes, submit crash data to the server.
8818 data.put("crashData", crashData);
8819 }
8820 msg.obj = data;
8821 mHandler.sendMessage(msg);
8822
8823 Binder.restoreCallingIdentity(origId);
8824 }
8825
8826 int res = result.get();
8827
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008828 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008829 synchronized (this) {
8830 if (r != null) {
8831 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8832 SystemClock.uptimeMillis());
8833 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008834 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8835 appErrorIntent = createAppErrorIntentLocked(r);
8836 res = AppErrorDialog.FORCE_QUIT;
8837 }
8838 }
8839
8840 if (appErrorIntent != null) {
8841 try {
8842 mContext.startActivity(appErrorIntent);
8843 } catch (ActivityNotFoundException e) {
8844 Log.w(TAG, "bug report receiver dissappeared", e);
8845 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008846 }
8847
8848 return res;
8849 }
8850
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008851 Intent createAppErrorIntentLocked(ProcessRecord r) {
8852 ApplicationErrorReport report = createAppErrorReportLocked(r);
8853 if (report == null) {
8854 return null;
8855 }
8856 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8857 result.setComponent(r.errorReportReceiver);
8858 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8859 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8860 return result;
8861 }
8862
8863 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8864 if (r.errorReportReceiver == null) {
8865 return null;
8866 }
8867
8868 if (!r.crashing && !r.notResponding) {
8869 return null;
8870 }
8871
8872 try {
8873 ApplicationErrorReport report = new ApplicationErrorReport();
8874 report.packageName = r.info.packageName;
8875 report.installerPackageName = r.errorReportReceiver.getPackageName();
8876 report.processName = r.processName;
8877
8878 if (r.crashing) {
8879 report.type = ApplicationErrorReport.TYPE_CRASH;
8880 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8881
8882 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8883 r.crashingReport.crashData);
8884 DataInputStream dataStream = new DataInputStream(byteStream);
8885 CrashData crashData = new CrashData(dataStream);
8886 ThrowableData throwData = crashData.getThrowableData();
8887
8888 report.time = crashData.getTime();
8889 report.crashInfo.stackTrace = throwData.toString();
8890
Jacek Surazskif829a782009-06-11 22:47:02 +02008891 // Extract the source of the exception, useful for report
8892 // clustering. Also extract the "deepest" non-null exception
8893 // message.
8894 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008895 while (throwData.getCause() != null) {
8896 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008897 String msg = throwData.getMessage();
8898 if (msg != null && msg.length() > 0) {
8899 exceptionMessage = msg;
8900 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008901 }
8902 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008903 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008904 report.crashInfo.exceptionClassName = throwData.getType();
8905 report.crashInfo.throwFileName = trace.getFileName();
8906 report.crashInfo.throwClassName = trace.getClassName();
8907 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008908 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008909 } else if (r.notResponding) {
8910 report.type = ApplicationErrorReport.TYPE_ANR;
8911 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8912
8913 report.anrInfo.activity = r.notRespondingReport.tag;
8914 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8915 report.anrInfo.info = r.notRespondingReport.longMsg;
8916 }
8917
8918 return report;
8919 } catch (IOException e) {
8920 // we don't send it
8921 }
8922
8923 return null;
8924 }
8925
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008926 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8927 // assume our apps are happy - lazy create the list
8928 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8929
8930 synchronized (this) {
8931
8932 // iterate across all processes
8933 final int N = mLRUProcesses.size();
8934 for (int i = 0; i < N; i++) {
8935 ProcessRecord app = mLRUProcesses.get(i);
8936 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8937 // This one's in trouble, so we'll generate a report for it
8938 // crashes are higher priority (in case there's a crash *and* an anr)
8939 ActivityManager.ProcessErrorStateInfo report = null;
8940 if (app.crashing) {
8941 report = app.crashingReport;
8942 } else if (app.notResponding) {
8943 report = app.notRespondingReport;
8944 }
8945
8946 if (report != null) {
8947 if (errList == null) {
8948 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8949 }
8950 errList.add(report);
8951 } else {
8952 Log.w(TAG, "Missing app error report, app = " + app.processName +
8953 " crashing = " + app.crashing +
8954 " notResponding = " + app.notResponding);
8955 }
8956 }
8957 }
8958 }
8959
8960 return errList;
8961 }
8962
8963 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8964 // Lazy instantiation of list
8965 List<ActivityManager.RunningAppProcessInfo> runList = null;
8966 synchronized (this) {
8967 // Iterate across all processes
8968 final int N = mLRUProcesses.size();
8969 for (int i = 0; i < N; i++) {
8970 ProcessRecord app = mLRUProcesses.get(i);
8971 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8972 // Generate process state info for running application
8973 ActivityManager.RunningAppProcessInfo currApp =
8974 new ActivityManager.RunningAppProcessInfo(app.processName,
8975 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07008976 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008977 int adj = app.curAdj;
8978 if (adj >= CONTENT_PROVIDER_ADJ) {
8979 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8980 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8981 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008982 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8983 } else if (adj >= HOME_APP_ADJ) {
8984 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8985 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008986 } else if (adj >= SECONDARY_SERVER_ADJ) {
8987 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8988 } else if (adj >= VISIBLE_APP_ADJ) {
8989 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8990 } else {
8991 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8992 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07008993 currApp.importanceReasonCode = app.adjTypeCode;
8994 if (app.adjSource instanceof ProcessRecord) {
8995 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
8996 } else if (app.adjSource instanceof HistoryRecord) {
8997 HistoryRecord r = (HistoryRecord)app.adjSource;
8998 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
8999 }
9000 if (app.adjTarget instanceof ComponentName) {
9001 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9002 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009003 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9004 // + " lru=" + currApp.lru);
9005 if (runList == null) {
9006 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9007 }
9008 runList.add(currApp);
9009 }
9010 }
9011 }
9012 return runList;
9013 }
9014
9015 @Override
9016 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9017 synchronized (this) {
9018 if (checkCallingPermission(android.Manifest.permission.DUMP)
9019 != PackageManager.PERMISSION_GRANTED) {
9020 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9021 + Binder.getCallingPid()
9022 + ", uid=" + Binder.getCallingUid()
9023 + " without permission "
9024 + android.Manifest.permission.DUMP);
9025 return;
9026 }
9027 if (args.length != 0 && "service".equals(args[0])) {
9028 dumpService(fd, pw, args);
9029 return;
9030 }
9031 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009032 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009033 pw.println(" ");
9034 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009035 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009036 if (mWaitingVisibleActivities.size() > 0) {
9037 pw.println(" ");
9038 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009039 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009040 }
9041 if (mStoppingActivities.size() > 0) {
9042 pw.println(" ");
9043 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009044 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009045 }
9046 if (mFinishingActivities.size() > 0) {
9047 pw.println(" ");
9048 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009049 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009050 }
9051
9052 pw.println(" ");
9053 pw.println(" mPausingActivity: " + mPausingActivity);
9054 pw.println(" mResumedActivity: " + mResumedActivity);
9055 pw.println(" mFocusedActivity: " + mFocusedActivity);
9056 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
9057
9058 if (mRecentTasks.size() > 0) {
9059 pw.println(" ");
9060 pw.println("Recent tasks in Current Activity Manager State:");
9061
9062 final int N = mRecentTasks.size();
9063 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009064 TaskRecord tr = mRecentTasks.get(i);
9065 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9066 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009067 mRecentTasks.get(i).dump(pw, " ");
9068 }
9069 }
9070
9071 pw.println(" ");
9072 pw.println(" mCurTask: " + mCurTask);
9073
9074 pw.println(" ");
9075 pw.println("Processes in Current Activity Manager State:");
9076
9077 boolean needSep = false;
9078 int numPers = 0;
9079
9080 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9081 final int NA = procs.size();
9082 for (int ia=0; ia<NA; ia++) {
9083 if (!needSep) {
9084 pw.println(" All known processes:");
9085 needSep = true;
9086 }
9087 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009088 pw.print(r.persistent ? " *PERS*" : " *APP*");
9089 pw.print(" UID "); pw.print(procs.keyAt(ia));
9090 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009091 r.dump(pw, " ");
9092 if (r.persistent) {
9093 numPers++;
9094 }
9095 }
9096 }
9097
9098 if (mLRUProcesses.size() > 0) {
9099 if (needSep) pw.println(" ");
9100 needSep = true;
9101 pw.println(" Running processes (most recent first):");
9102 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009103 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009104 needSep = true;
9105 }
9106
9107 synchronized (mPidsSelfLocked) {
9108 if (mPidsSelfLocked.size() > 0) {
9109 if (needSep) pw.println(" ");
9110 needSep = true;
9111 pw.println(" PID mappings:");
9112 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009113 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9114 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009115 }
9116 }
9117 }
9118
9119 if (mForegroundProcesses.size() > 0) {
9120 if (needSep) pw.println(" ");
9121 needSep = true;
9122 pw.println(" Foreground Processes:");
9123 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009124 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9125 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009126 }
9127 }
9128
9129 if (mPersistentStartingProcesses.size() > 0) {
9130 if (needSep) pw.println(" ");
9131 needSep = true;
9132 pw.println(" Persisent processes that are starting:");
9133 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009134 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009135 }
9136
9137 if (mStartingProcesses.size() > 0) {
9138 if (needSep) pw.println(" ");
9139 needSep = true;
9140 pw.println(" Processes that are starting:");
9141 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009142 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009143 }
9144
9145 if (mRemovedProcesses.size() > 0) {
9146 if (needSep) pw.println(" ");
9147 needSep = true;
9148 pw.println(" Processes that are being removed:");
9149 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009150 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009151 }
9152
9153 if (mProcessesOnHold.size() > 0) {
9154 if (needSep) pw.println(" ");
9155 needSep = true;
9156 pw.println(" Processes that are on old until the system is ready:");
9157 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009158 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009159 }
9160
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009161 if (mProcessesToGc.size() > 0) {
9162 if (needSep) pw.println(" ");
9163 needSep = true;
9164 pw.println(" Processes that are waiting to GC:");
9165 long now = SystemClock.uptimeMillis();
9166 for (int i=0; i<mProcessesToGc.size(); i++) {
9167 ProcessRecord proc = mProcessesToGc.get(i);
9168 pw.print(" Process "); pw.println(proc);
9169 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9170 pw.print(", last gced=");
9171 pw.print(now-proc.lastRequestedGc);
9172 pw.print(" ms ago, last lowMwm=");
9173 pw.print(now-proc.lastLowMemory);
9174 pw.println(" ms ago");
9175
9176 }
9177 }
9178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009179 if (mProcessCrashTimes.getMap().size() > 0) {
9180 if (needSep) pw.println(" ");
9181 needSep = true;
9182 pw.println(" Time since processes crashed:");
9183 long now = SystemClock.uptimeMillis();
9184 for (Map.Entry<String, SparseArray<Long>> procs
9185 : mProcessCrashTimes.getMap().entrySet()) {
9186 SparseArray<Long> uids = procs.getValue();
9187 final int N = uids.size();
9188 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009189 pw.print(" Process "); pw.print(procs.getKey());
9190 pw.print(" uid "); pw.print(uids.keyAt(i));
9191 pw.print(": last crashed ");
9192 pw.print((now-uids.valueAt(i)));
9193 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009194 }
9195 }
9196 }
9197
9198 if (mBadProcesses.getMap().size() > 0) {
9199 if (needSep) pw.println(" ");
9200 needSep = true;
9201 pw.println(" Bad processes:");
9202 for (Map.Entry<String, SparseArray<Long>> procs
9203 : mBadProcesses.getMap().entrySet()) {
9204 SparseArray<Long> uids = procs.getValue();
9205 final int N = uids.size();
9206 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009207 pw.print(" Bad process "); pw.print(procs.getKey());
9208 pw.print(" uid "); pw.print(uids.keyAt(i));
9209 pw.print(": crashed at time ");
9210 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009211 }
9212 }
9213 }
9214
9215 pw.println(" ");
9216 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009217 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009218 pw.println(" mConfiguration: " + mConfiguration);
9219 pw.println(" mStartRunning=" + mStartRunning
9220 + " mSystemReady=" + mSystemReady
9221 + " mBooting=" + mBooting
9222 + " mBooted=" + mBooted
9223 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009224 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009225 pw.println(" mGoingToSleep=" + mGoingToSleep);
9226 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9227 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9228 + " mDebugTransient=" + mDebugTransient
9229 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9230 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009231 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009232 }
9233 }
9234
9235 /**
9236 * There are three ways to call this:
9237 * - no service specified: dump all the services
9238 * - a flattened component name that matched an existing service was specified as the
9239 * first arg: dump that one service
9240 * - the first arg isn't the flattened component name of an existing service:
9241 * dump all services whose component contains the first arg as a substring
9242 */
9243 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9244 String[] newArgs;
9245 String componentNameString;
9246 ServiceRecord r;
9247 if (args.length == 1) {
9248 componentNameString = null;
9249 newArgs = EMPTY_STRING_ARRAY;
9250 r = null;
9251 } else {
9252 componentNameString = args[1];
9253 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9254 r = componentName != null ? mServices.get(componentName) : null;
9255 newArgs = new String[args.length - 2];
9256 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9257 }
9258
9259 if (r != null) {
9260 dumpService(fd, pw, r, newArgs);
9261 } else {
9262 for (ServiceRecord r1 : mServices.values()) {
9263 if (componentNameString == null
9264 || r1.name.flattenToString().contains(componentNameString)) {
9265 dumpService(fd, pw, r1, newArgs);
9266 }
9267 }
9268 }
9269 }
9270
9271 /**
9272 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9273 * there is a thread associated with the service.
9274 */
9275 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9276 pw.println(" Service " + r.name.flattenToString());
9277 if (r.app != null && r.app.thread != null) {
9278 try {
9279 // flush anything that is already in the PrintWriter since the thread is going
9280 // to write to the file descriptor directly
9281 pw.flush();
9282 r.app.thread.dumpService(fd, r, args);
9283 pw.print("\n");
9284 } catch (RemoteException e) {
9285 pw.println("got a RemoteException while dumping the service");
9286 }
9287 }
9288 }
9289
9290 void dumpBroadcasts(PrintWriter pw) {
9291 synchronized (this) {
9292 if (checkCallingPermission(android.Manifest.permission.DUMP)
9293 != PackageManager.PERMISSION_GRANTED) {
9294 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9295 + Binder.getCallingPid()
9296 + ", uid=" + Binder.getCallingUid()
9297 + " without permission "
9298 + android.Manifest.permission.DUMP);
9299 return;
9300 }
9301 pw.println("Broadcasts in Current Activity Manager State:");
9302
9303 if (mRegisteredReceivers.size() > 0) {
9304 pw.println(" ");
9305 pw.println(" Registered Receivers:");
9306 Iterator it = mRegisteredReceivers.values().iterator();
9307 while (it.hasNext()) {
9308 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009309 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009310 r.dump(pw, " ");
9311 }
9312 }
9313
9314 pw.println(" ");
9315 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009316 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009317
9318 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9319 || mPendingBroadcast != null) {
9320 if (mParallelBroadcasts.size() > 0) {
9321 pw.println(" ");
9322 pw.println(" Active broadcasts:");
9323 }
9324 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9325 pw.println(" Broadcast #" + i + ":");
9326 mParallelBroadcasts.get(i).dump(pw, " ");
9327 }
9328 if (mOrderedBroadcasts.size() > 0) {
9329 pw.println(" ");
9330 pw.println(" Active serialized broadcasts:");
9331 }
9332 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9333 pw.println(" Serialized Broadcast #" + i + ":");
9334 mOrderedBroadcasts.get(i).dump(pw, " ");
9335 }
9336 pw.println(" ");
9337 pw.println(" Pending broadcast:");
9338 if (mPendingBroadcast != null) {
9339 mPendingBroadcast.dump(pw, " ");
9340 } else {
9341 pw.println(" (null)");
9342 }
9343 }
9344
9345 pw.println(" ");
9346 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9347 if (mStickyBroadcasts != null) {
9348 pw.println(" ");
9349 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009350 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009351 for (Map.Entry<String, ArrayList<Intent>> ent
9352 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009353 pw.print(" * Sticky action "); pw.print(ent.getKey());
9354 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009355 ArrayList<Intent> intents = ent.getValue();
9356 final int N = intents.size();
9357 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009358 sb.setLength(0);
9359 sb.append(" Intent: ");
9360 intents.get(i).toShortString(sb, true, false);
9361 pw.println(sb.toString());
9362 Bundle bundle = intents.get(i).getExtras();
9363 if (bundle != null) {
9364 pw.print(" ");
9365 pw.println(bundle.toString());
9366 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009367 }
9368 }
9369 }
9370
9371 pw.println(" ");
9372 pw.println(" mHandler:");
9373 mHandler.dump(new PrintWriterPrinter(pw), " ");
9374 }
9375 }
9376
9377 void dumpServices(PrintWriter pw) {
9378 synchronized (this) {
9379 if (checkCallingPermission(android.Manifest.permission.DUMP)
9380 != PackageManager.PERMISSION_GRANTED) {
9381 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9382 + Binder.getCallingPid()
9383 + ", uid=" + Binder.getCallingUid()
9384 + " without permission "
9385 + android.Manifest.permission.DUMP);
9386 return;
9387 }
9388 pw.println("Services in Current Activity Manager State:");
9389
9390 boolean needSep = false;
9391
9392 if (mServices.size() > 0) {
9393 pw.println(" Active services:");
9394 Iterator<ServiceRecord> it = mServices.values().iterator();
9395 while (it.hasNext()) {
9396 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009397 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009398 r.dump(pw, " ");
9399 }
9400 needSep = true;
9401 }
9402
9403 if (mPendingServices.size() > 0) {
9404 if (needSep) pw.println(" ");
9405 pw.println(" Pending services:");
9406 for (int i=0; i<mPendingServices.size(); i++) {
9407 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009408 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009409 r.dump(pw, " ");
9410 }
9411 needSep = true;
9412 }
9413
9414 if (mRestartingServices.size() > 0) {
9415 if (needSep) pw.println(" ");
9416 pw.println(" Restarting services:");
9417 for (int i=0; i<mRestartingServices.size(); i++) {
9418 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009419 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009420 r.dump(pw, " ");
9421 }
9422 needSep = true;
9423 }
9424
9425 if (mStoppingServices.size() > 0) {
9426 if (needSep) pw.println(" ");
9427 pw.println(" Stopping services:");
9428 for (int i=0; i<mStoppingServices.size(); i++) {
9429 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009430 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009431 r.dump(pw, " ");
9432 }
9433 needSep = true;
9434 }
9435
9436 if (mServiceConnections.size() > 0) {
9437 if (needSep) pw.println(" ");
9438 pw.println(" Connection bindings to services:");
9439 Iterator<ConnectionRecord> it
9440 = mServiceConnections.values().iterator();
9441 while (it.hasNext()) {
9442 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009443 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009444 r.dump(pw, " ");
9445 }
9446 }
9447 }
9448 }
9449
9450 void dumpProviders(PrintWriter pw) {
9451 synchronized (this) {
9452 if (checkCallingPermission(android.Manifest.permission.DUMP)
9453 != PackageManager.PERMISSION_GRANTED) {
9454 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9455 + Binder.getCallingPid()
9456 + ", uid=" + Binder.getCallingUid()
9457 + " without permission "
9458 + android.Manifest.permission.DUMP);
9459 return;
9460 }
9461
9462 pw.println("Content Providers in Current Activity Manager State:");
9463
9464 boolean needSep = false;
9465
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009466 if (mProvidersByClass.size() > 0) {
9467 if (needSep) pw.println(" ");
9468 pw.println(" Published content providers (by class):");
9469 Iterator it = mProvidersByClass.entrySet().iterator();
9470 while (it.hasNext()) {
9471 Map.Entry e = (Map.Entry)it.next();
9472 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009473 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009474 r.dump(pw, " ");
9475 }
9476 needSep = true;
9477 }
9478
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009479 if (mProvidersByName.size() > 0) {
9480 pw.println(" ");
9481 pw.println(" Authority to provider mappings:");
9482 Iterator it = mProvidersByName.entrySet().iterator();
9483 while (it.hasNext()) {
9484 Map.Entry e = (Map.Entry)it.next();
9485 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9486 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9487 pw.println(r);
9488 }
9489 needSep = true;
9490 }
9491
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009492 if (mLaunchingProviders.size() > 0) {
9493 if (needSep) pw.println(" ");
9494 pw.println(" Launching content providers:");
9495 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009496 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9497 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009498 }
9499 needSep = true;
9500 }
9501
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009502 if (mGrantedUriPermissions.size() > 0) {
9503 pw.println();
9504 pw.println("Granted Uri Permissions:");
9505 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9506 int uid = mGrantedUriPermissions.keyAt(i);
9507 HashMap<Uri, UriPermission> perms
9508 = mGrantedUriPermissions.valueAt(i);
9509 pw.print(" * UID "); pw.print(uid);
9510 pw.println(" holds:");
9511 for (UriPermission perm : perms.values()) {
9512 pw.print(" "); pw.println(perm);
9513 perm.dump(pw, " ");
9514 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009515 }
9516 }
9517 }
9518 }
9519
9520 void dumpSenders(PrintWriter pw) {
9521 synchronized (this) {
9522 if (checkCallingPermission(android.Manifest.permission.DUMP)
9523 != PackageManager.PERMISSION_GRANTED) {
9524 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9525 + Binder.getCallingPid()
9526 + ", uid=" + Binder.getCallingUid()
9527 + " without permission "
9528 + android.Manifest.permission.DUMP);
9529 return;
9530 }
9531
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009532 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009533
9534 if (this.mIntentSenderRecords.size() > 0) {
9535 Iterator<WeakReference<PendingIntentRecord>> it
9536 = mIntentSenderRecords.values().iterator();
9537 while (it.hasNext()) {
9538 WeakReference<PendingIntentRecord> ref = it.next();
9539 PendingIntentRecord rec = ref != null ? ref.get(): null;
9540 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009541 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009542 rec.dump(pw, " ");
9543 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009544 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009545 }
9546 }
9547 }
9548 }
9549 }
9550
9551 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009552 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009553 TaskRecord lastTask = null;
9554 for (int i=list.size()-1; i>=0; i--) {
9555 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009556 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009557 if (lastTask != r.task) {
9558 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009559 pw.print(prefix);
9560 pw.print(full ? "* " : " ");
9561 pw.println(lastTask);
9562 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009563 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009564 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009565 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009566 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9567 pw.print(" #"); pw.print(i); pw.print(": ");
9568 pw.println(r);
9569 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009570 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009571 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009572 }
9573 }
9574
9575 private static final int dumpProcessList(PrintWriter pw, List list,
9576 String prefix, String normalLabel, String persistentLabel,
9577 boolean inclOomAdj) {
9578 int numPers = 0;
9579 for (int i=list.size()-1; i>=0; i--) {
9580 ProcessRecord r = (ProcessRecord)list.get(i);
9581 if (false) {
9582 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9583 + " #" + i + ":");
9584 r.dump(pw, prefix + " ");
9585 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009586 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009587 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009588 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9589 if (r.adjSource != null || r.adjTarget != null) {
9590 pw.println(prefix + " " + r.adjTarget
9591 + " used by " + r.adjSource);
9592 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009593 } else {
9594 pw.println(String.format("%s%s #%2d: %s",
9595 prefix, (r.persistent ? persistentLabel : normalLabel),
9596 i, r.toString()));
9597 }
9598 if (r.persistent) {
9599 numPers++;
9600 }
9601 }
9602 return numPers;
9603 }
9604
9605 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9606 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009607 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009608 long uptime = SystemClock.uptimeMillis();
9609 long realtime = SystemClock.elapsedRealtime();
9610
9611 if (isCheckinRequest) {
9612 // short checkin version
9613 pw.println(uptime + "," + realtime);
9614 pw.flush();
9615 } else {
9616 pw.println("Applications Memory Usage (kB):");
9617 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9618 }
9619 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9620 ProcessRecord r = (ProcessRecord)list.get(i);
9621 if (r.thread != null) {
9622 if (!isCheckinRequest) {
9623 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9624 pw.flush();
9625 }
9626 try {
9627 r.thread.asBinder().dump(fd, args);
9628 } catch (RemoteException e) {
9629 if (!isCheckinRequest) {
9630 pw.println("Got RemoteException!");
9631 pw.flush();
9632 }
9633 }
9634 }
9635 }
9636 }
9637
9638 /**
9639 * Searches array of arguments for the specified string
9640 * @param args array of argument strings
9641 * @param value value to search for
9642 * @return true if the value is contained in the array
9643 */
9644 private static boolean scanArgs(String[] args, String value) {
9645 if (args != null) {
9646 for (String arg : args) {
9647 if (value.equals(arg)) {
9648 return true;
9649 }
9650 }
9651 }
9652 return false;
9653 }
9654
Dianne Hackborn75b03852009-06-12 15:43:26 -07009655 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009656 int count = mHistory.size();
9657
9658 // convert the token to an entry in the history.
9659 HistoryRecord r = null;
9660 int index = -1;
9661 for (int i=count-1; i>=0; i--) {
9662 Object o = mHistory.get(i);
9663 if (o == token) {
9664 r = (HistoryRecord)o;
9665 index = i;
9666 break;
9667 }
9668 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009669
9670 return index;
9671 }
9672
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009673 private final void killServicesLocked(ProcessRecord app,
9674 boolean allowRestart) {
9675 // Report disconnected services.
9676 if (false) {
9677 // XXX we are letting the client link to the service for
9678 // death notifications.
9679 if (app.services.size() > 0) {
9680 Iterator it = app.services.iterator();
9681 while (it.hasNext()) {
9682 ServiceRecord r = (ServiceRecord)it.next();
9683 if (r.connections.size() > 0) {
9684 Iterator<ConnectionRecord> jt
9685 = r.connections.values().iterator();
9686 while (jt.hasNext()) {
9687 ConnectionRecord c = jt.next();
9688 if (c.binding.client != app) {
9689 try {
9690 //c.conn.connected(r.className, null);
9691 } catch (Exception e) {
9692 // todo: this should be asynchronous!
9693 Log.w(TAG, "Exception thrown disconnected servce "
9694 + r.shortName
9695 + " from app " + app.processName, e);
9696 }
9697 }
9698 }
9699 }
9700 }
9701 }
9702 }
9703
9704 // Clean up any connections this application has to other services.
9705 if (app.connections.size() > 0) {
9706 Iterator<ConnectionRecord> it = app.connections.iterator();
9707 while (it.hasNext()) {
9708 ConnectionRecord r = it.next();
9709 removeConnectionLocked(r, app, null);
9710 }
9711 }
9712 app.connections.clear();
9713
9714 if (app.services.size() != 0) {
9715 // Any services running in the application need to be placed
9716 // back in the pending list.
9717 Iterator it = app.services.iterator();
9718 while (it.hasNext()) {
9719 ServiceRecord sr = (ServiceRecord)it.next();
9720 synchronized (sr.stats.getBatteryStats()) {
9721 sr.stats.stopLaunchedLocked();
9722 }
9723 sr.app = null;
9724 sr.executeNesting = 0;
9725 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009726
9727 boolean hasClients = sr.bindings.size() > 0;
9728 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009729 Iterator<IntentBindRecord> bindings
9730 = sr.bindings.values().iterator();
9731 while (bindings.hasNext()) {
9732 IntentBindRecord b = bindings.next();
9733 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9734 + ": shouldUnbind=" + b.hasBound);
9735 b.binder = null;
9736 b.requested = b.received = b.hasBound = false;
9737 }
9738 }
9739
9740 if (sr.crashCount >= 2) {
9741 Log.w(TAG, "Service crashed " + sr.crashCount
9742 + " times, stopping: " + sr);
9743 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9744 sr.crashCount, sr.shortName, app.pid);
9745 bringDownServiceLocked(sr, true);
9746 } else if (!allowRestart) {
9747 bringDownServiceLocked(sr, true);
9748 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009749 boolean canceled = scheduleServiceRestartLocked(sr, true);
9750
9751 // Should the service remain running? Note that in the
9752 // extreme case of so many attempts to deliver a command
9753 // that it failed, that we also will stop it here.
9754 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9755 if (sr.pendingStarts.size() == 0) {
9756 sr.startRequested = false;
9757 if (!hasClients) {
9758 // Whoops, no reason to restart!
9759 bringDownServiceLocked(sr, true);
9760 }
9761 }
9762 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009763 }
9764 }
9765
9766 if (!allowRestart) {
9767 app.services.clear();
9768 }
9769 }
9770
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009771 // Make sure we have no more records on the stopping list.
9772 int i = mStoppingServices.size();
9773 while (i > 0) {
9774 i--;
9775 ServiceRecord sr = mStoppingServices.get(i);
9776 if (sr.app == app) {
9777 mStoppingServices.remove(i);
9778 }
9779 }
9780
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009781 app.executingServices.clear();
9782 }
9783
9784 private final void removeDyingProviderLocked(ProcessRecord proc,
9785 ContentProviderRecord cpr) {
9786 synchronized (cpr) {
9787 cpr.launchingApp = null;
9788 cpr.notifyAll();
9789 }
9790
9791 mProvidersByClass.remove(cpr.info.name);
9792 String names[] = cpr.info.authority.split(";");
9793 for (int j = 0; j < names.length; j++) {
9794 mProvidersByName.remove(names[j]);
9795 }
9796
9797 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9798 while (cit.hasNext()) {
9799 ProcessRecord capp = cit.next();
9800 if (!capp.persistent && capp.thread != null
9801 && capp.pid != 0
9802 && capp.pid != MY_PID) {
9803 Log.i(TAG, "Killing app " + capp.processName
9804 + " (pid " + capp.pid
9805 + ") because provider " + cpr.info.name
9806 + " is in dying process " + proc.processName);
9807 Process.killProcess(capp.pid);
9808 }
9809 }
9810
9811 mLaunchingProviders.remove(cpr);
9812 }
9813
9814 /**
9815 * Main code for cleaning up a process when it has gone away. This is
9816 * called both as a result of the process dying, or directly when stopping
9817 * a process when running in single process mode.
9818 */
9819 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9820 boolean restarting, int index) {
9821 if (index >= 0) {
9822 mLRUProcesses.remove(index);
9823 }
9824
9825 // Dismiss any open dialogs.
9826 if (app.crashDialog != null) {
9827 app.crashDialog.dismiss();
9828 app.crashDialog = null;
9829 }
9830 if (app.anrDialog != null) {
9831 app.anrDialog.dismiss();
9832 app.anrDialog = null;
9833 }
9834 if (app.waitDialog != null) {
9835 app.waitDialog.dismiss();
9836 app.waitDialog = null;
9837 }
9838
9839 app.crashing = false;
9840 app.notResponding = false;
9841
9842 app.resetPackageList();
9843 app.thread = null;
9844 app.forcingToForeground = null;
9845 app.foregroundServices = false;
9846
9847 killServicesLocked(app, true);
9848
9849 boolean restart = false;
9850
9851 int NL = mLaunchingProviders.size();
9852
9853 // Remove published content providers.
9854 if (!app.pubProviders.isEmpty()) {
9855 Iterator it = app.pubProviders.values().iterator();
9856 while (it.hasNext()) {
9857 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9858 cpr.provider = null;
9859 cpr.app = null;
9860
9861 // See if someone is waiting for this provider... in which
9862 // case we don't remove it, but just let it restart.
9863 int i = 0;
9864 if (!app.bad) {
9865 for (; i<NL; i++) {
9866 if (mLaunchingProviders.get(i) == cpr) {
9867 restart = true;
9868 break;
9869 }
9870 }
9871 } else {
9872 i = NL;
9873 }
9874
9875 if (i >= NL) {
9876 removeDyingProviderLocked(app, cpr);
9877 NL = mLaunchingProviders.size();
9878 }
9879 }
9880 app.pubProviders.clear();
9881 }
9882
9883 // Look through the content providers we are waiting to have launched,
9884 // and if any run in this process then either schedule a restart of
9885 // the process or kill the client waiting for it if this process has
9886 // gone bad.
9887 for (int i=0; i<NL; i++) {
9888 ContentProviderRecord cpr = (ContentProviderRecord)
9889 mLaunchingProviders.get(i);
9890 if (cpr.launchingApp == app) {
9891 if (!app.bad) {
9892 restart = true;
9893 } else {
9894 removeDyingProviderLocked(app, cpr);
9895 NL = mLaunchingProviders.size();
9896 }
9897 }
9898 }
9899
9900 // Unregister from connected content providers.
9901 if (!app.conProviders.isEmpty()) {
9902 Iterator it = app.conProviders.iterator();
9903 while (it.hasNext()) {
9904 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9905 cpr.clients.remove(app);
9906 }
9907 app.conProviders.clear();
9908 }
9909
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009910 // At this point there may be remaining entries in mLaunchingProviders
9911 // where we were the only one waiting, so they are no longer of use.
9912 // Look for these and clean up if found.
9913 // XXX Commented out for now. Trying to figure out a way to reproduce
9914 // the actual situation to identify what is actually going on.
9915 if (false) {
9916 for (int i=0; i<NL; i++) {
9917 ContentProviderRecord cpr = (ContentProviderRecord)
9918 mLaunchingProviders.get(i);
9919 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9920 synchronized (cpr) {
9921 cpr.launchingApp = null;
9922 cpr.notifyAll();
9923 }
9924 }
9925 }
9926 }
9927
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009928 skipCurrentReceiverLocked(app);
9929
9930 // Unregister any receivers.
9931 if (app.receivers.size() > 0) {
9932 Iterator<ReceiverList> it = app.receivers.iterator();
9933 while (it.hasNext()) {
9934 removeReceiverLocked(it.next());
9935 }
9936 app.receivers.clear();
9937 }
9938
Christopher Tate181fafa2009-05-14 11:12:14 -07009939 // If the app is undergoing backup, tell the backup manager about it
9940 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9941 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9942 try {
9943 IBackupManager bm = IBackupManager.Stub.asInterface(
9944 ServiceManager.getService(Context.BACKUP_SERVICE));
9945 bm.agentDisconnected(app.info.packageName);
9946 } catch (RemoteException e) {
9947 // can't happen; backup manager is local
9948 }
9949 }
9950
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009951 // If the caller is restarting this app, then leave it in its
9952 // current lists and let the caller take care of it.
9953 if (restarting) {
9954 return;
9955 }
9956
9957 if (!app.persistent) {
9958 if (DEBUG_PROCESSES) Log.v(TAG,
9959 "Removing non-persistent process during cleanup: " + app);
9960 mProcessNames.remove(app.processName, app.info.uid);
9961 } else if (!app.removed) {
9962 // This app is persistent, so we need to keep its record around.
9963 // If it is not already on the pending app list, add it there
9964 // and start a new process for it.
9965 app.thread = null;
9966 app.forcingToForeground = null;
9967 app.foregroundServices = false;
9968 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9969 mPersistentStartingProcesses.add(app);
9970 restart = true;
9971 }
9972 }
9973 mProcessesOnHold.remove(app);
9974
The Android Open Source Project4df24232009-03-05 14:34:35 -08009975 if (app == mHomeProcess) {
9976 mHomeProcess = null;
9977 }
9978
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009979 if (restart) {
9980 // We have components that still need to be running in the
9981 // process, so re-launch it.
9982 mProcessNames.put(app.processName, app.info.uid, app);
9983 startProcessLocked(app, "restart", app.processName);
9984 } else if (app.pid > 0 && app.pid != MY_PID) {
9985 // Goodbye!
9986 synchronized (mPidsSelfLocked) {
9987 mPidsSelfLocked.remove(app.pid);
9988 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9989 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009990 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009991 }
9992 }
9993
9994 // =========================================================
9995 // SERVICES
9996 // =========================================================
9997
9998 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9999 ActivityManager.RunningServiceInfo info =
10000 new ActivityManager.RunningServiceInfo();
10001 info.service = r.name;
10002 if (r.app != null) {
10003 info.pid = r.app.pid;
10004 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010005 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010006 info.process = r.processName;
10007 info.foreground = r.isForeground;
10008 info.activeSince = r.createTime;
10009 info.started = r.startRequested;
10010 info.clientCount = r.connections.size();
10011 info.crashCount = r.crashCount;
10012 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010013 if (r.isForeground) {
10014 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10015 }
10016 if (r.startRequested) {
10017 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10018 }
10019 if (r.app != null && r.app.pid == Process.myPid()) {
10020 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10021 }
10022 if (r.app != null && r.app.persistent) {
10023 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10024 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010025 for (ConnectionRecord conn : r.connections.values()) {
10026 if (conn.clientLabel != 0) {
10027 info.clientPackage = conn.binding.client.info.packageName;
10028 info.clientLabel = conn.clientLabel;
10029 break;
10030 }
10031 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010032 return info;
10033 }
10034
10035 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10036 int flags) {
10037 synchronized (this) {
10038 ArrayList<ActivityManager.RunningServiceInfo> res
10039 = new ArrayList<ActivityManager.RunningServiceInfo>();
10040
10041 if (mServices.size() > 0) {
10042 Iterator<ServiceRecord> it = mServices.values().iterator();
10043 while (it.hasNext() && res.size() < maxNum) {
10044 res.add(makeRunningServiceInfoLocked(it.next()));
10045 }
10046 }
10047
10048 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10049 ServiceRecord r = mRestartingServices.get(i);
10050 ActivityManager.RunningServiceInfo info =
10051 makeRunningServiceInfoLocked(r);
10052 info.restarting = r.nextRestartTime;
10053 res.add(info);
10054 }
10055
10056 return res;
10057 }
10058 }
10059
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010060 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10061 synchronized (this) {
10062 ServiceRecord r = mServices.get(name);
10063 if (r != null) {
10064 for (ConnectionRecord conn : r.connections.values()) {
10065 if (conn.clientIntent != null) {
10066 return conn.clientIntent;
10067 }
10068 }
10069 }
10070 }
10071 return null;
10072 }
10073
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010074 private final ServiceRecord findServiceLocked(ComponentName name,
10075 IBinder token) {
10076 ServiceRecord r = mServices.get(name);
10077 return r == token ? r : null;
10078 }
10079
10080 private final class ServiceLookupResult {
10081 final ServiceRecord record;
10082 final String permission;
10083
10084 ServiceLookupResult(ServiceRecord _record, String _permission) {
10085 record = _record;
10086 permission = _permission;
10087 }
10088 };
10089
10090 private ServiceLookupResult findServiceLocked(Intent service,
10091 String resolvedType) {
10092 ServiceRecord r = null;
10093 if (service.getComponent() != null) {
10094 r = mServices.get(service.getComponent());
10095 }
10096 if (r == null) {
10097 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10098 r = mServicesByIntent.get(filter);
10099 }
10100
10101 if (r == null) {
10102 try {
10103 ResolveInfo rInfo =
10104 ActivityThread.getPackageManager().resolveService(
10105 service, resolvedType, 0);
10106 ServiceInfo sInfo =
10107 rInfo != null ? rInfo.serviceInfo : null;
10108 if (sInfo == null) {
10109 return null;
10110 }
10111
10112 ComponentName name = new ComponentName(
10113 sInfo.applicationInfo.packageName, sInfo.name);
10114 r = mServices.get(name);
10115 } catch (RemoteException ex) {
10116 // pm is in same process, this will never happen.
10117 }
10118 }
10119 if (r != null) {
10120 int callingPid = Binder.getCallingPid();
10121 int callingUid = Binder.getCallingUid();
10122 if (checkComponentPermission(r.permission,
10123 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10124 != PackageManager.PERMISSION_GRANTED) {
10125 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10126 + " from pid=" + callingPid
10127 + ", uid=" + callingUid
10128 + " requires " + r.permission);
10129 return new ServiceLookupResult(null, r.permission);
10130 }
10131 return new ServiceLookupResult(r, null);
10132 }
10133 return null;
10134 }
10135
10136 private class ServiceRestarter implements Runnable {
10137 private ServiceRecord mService;
10138
10139 void setService(ServiceRecord service) {
10140 mService = service;
10141 }
10142
10143 public void run() {
10144 synchronized(ActivityManagerService.this) {
10145 performServiceRestartLocked(mService);
10146 }
10147 }
10148 }
10149
10150 private ServiceLookupResult retrieveServiceLocked(Intent service,
10151 String resolvedType, int callingPid, int callingUid) {
10152 ServiceRecord r = null;
10153 if (service.getComponent() != null) {
10154 r = mServices.get(service.getComponent());
10155 }
10156 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10157 r = mServicesByIntent.get(filter);
10158 if (r == null) {
10159 try {
10160 ResolveInfo rInfo =
10161 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010162 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010163 ServiceInfo sInfo =
10164 rInfo != null ? rInfo.serviceInfo : null;
10165 if (sInfo == null) {
10166 Log.w(TAG, "Unable to start service " + service +
10167 ": not found");
10168 return null;
10169 }
10170
10171 ComponentName name = new ComponentName(
10172 sInfo.applicationInfo.packageName, sInfo.name);
10173 r = mServices.get(name);
10174 if (r == null) {
10175 filter = new Intent.FilterComparison(service.cloneFilter());
10176 ServiceRestarter res = new ServiceRestarter();
10177 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10178 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10179 synchronized (stats) {
10180 ss = stats.getServiceStatsLocked(
10181 sInfo.applicationInfo.uid, sInfo.packageName,
10182 sInfo.name);
10183 }
10184 r = new ServiceRecord(ss, name, filter, sInfo, res);
10185 res.setService(r);
10186 mServices.put(name, r);
10187 mServicesByIntent.put(filter, r);
10188
10189 // Make sure this component isn't in the pending list.
10190 int N = mPendingServices.size();
10191 for (int i=0; i<N; i++) {
10192 ServiceRecord pr = mPendingServices.get(i);
10193 if (pr.name.equals(name)) {
10194 mPendingServices.remove(i);
10195 i--;
10196 N--;
10197 }
10198 }
10199 }
10200 } catch (RemoteException ex) {
10201 // pm is in same process, this will never happen.
10202 }
10203 }
10204 if (r != null) {
10205 if (checkComponentPermission(r.permission,
10206 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10207 != PackageManager.PERMISSION_GRANTED) {
10208 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10209 + " from pid=" + Binder.getCallingPid()
10210 + ", uid=" + Binder.getCallingUid()
10211 + " requires " + r.permission);
10212 return new ServiceLookupResult(null, r.permission);
10213 }
10214 return new ServiceLookupResult(r, null);
10215 }
10216 return null;
10217 }
10218
10219 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10220 long now = SystemClock.uptimeMillis();
10221 if (r.executeNesting == 0 && r.app != null) {
10222 if (r.app.executingServices.size() == 0) {
10223 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10224 msg.obj = r.app;
10225 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10226 }
10227 r.app.executingServices.add(r);
10228 }
10229 r.executeNesting++;
10230 r.executingStart = now;
10231 }
10232
10233 private final void sendServiceArgsLocked(ServiceRecord r,
10234 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010235 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010236 if (N == 0) {
10237 return;
10238 }
10239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010240 int i = 0;
10241 while (i < N) {
10242 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010243 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010244 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010245 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010246 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010247 // If somehow we got a dummy start at the front, then
10248 // just drop it here.
10249 i++;
10250 continue;
10251 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010252 bumpServiceExecutingLocked(r);
10253 if (!oomAdjusted) {
10254 oomAdjusted = true;
10255 updateOomAdjLocked(r.app);
10256 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010257 int flags = 0;
10258 if (si.deliveryCount > 0) {
10259 flags |= Service.START_FLAG_RETRY;
10260 }
10261 if (si.doneExecutingCount > 0) {
10262 flags |= Service.START_FLAG_REDELIVERY;
10263 }
10264 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10265 si.deliveredTime = SystemClock.uptimeMillis();
10266 r.deliveredStarts.add(si);
10267 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010268 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010269 } catch (RemoteException e) {
10270 // Remote process gone... we'll let the normal cleanup take
10271 // care of this.
10272 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010273 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010274 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010275 break;
10276 }
10277 }
10278 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010279 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010280 } else {
10281 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010282 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010283 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010284 }
10285 }
10286 }
10287
10288 private final boolean requestServiceBindingLocked(ServiceRecord r,
10289 IntentBindRecord i, boolean rebind) {
10290 if (r.app == null || r.app.thread == null) {
10291 // If service is not currently running, can't yet bind.
10292 return false;
10293 }
10294 if ((!i.requested || rebind) && i.apps.size() > 0) {
10295 try {
10296 bumpServiceExecutingLocked(r);
10297 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10298 + ": shouldUnbind=" + i.hasBound);
10299 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10300 if (!rebind) {
10301 i.requested = true;
10302 }
10303 i.hasBound = true;
10304 i.doRebind = false;
10305 } catch (RemoteException e) {
10306 return false;
10307 }
10308 }
10309 return true;
10310 }
10311
10312 private final void requestServiceBindingsLocked(ServiceRecord r) {
10313 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10314 while (bindings.hasNext()) {
10315 IntentBindRecord i = bindings.next();
10316 if (!requestServiceBindingLocked(r, i, false)) {
10317 break;
10318 }
10319 }
10320 }
10321
10322 private final void realStartServiceLocked(ServiceRecord r,
10323 ProcessRecord app) throws RemoteException {
10324 if (app.thread == null) {
10325 throw new RemoteException();
10326 }
10327
10328 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010329 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010330
10331 app.services.add(r);
10332 bumpServiceExecutingLocked(r);
10333 updateLRUListLocked(app, true);
10334
10335 boolean created = false;
10336 try {
10337 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10338 + r.name + " " + r.intent);
10339 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
10340 System.identityHashCode(r), r.shortName,
10341 r.intent.getIntent().toString(), r.app.pid);
10342 synchronized (r.stats.getBatteryStats()) {
10343 r.stats.startLaunchedLocked();
10344 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010345 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010346 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010347 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010348 created = true;
10349 } finally {
10350 if (!created) {
10351 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010352 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010353 }
10354 }
10355
10356 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010357
10358 // If the service is in the started state, and there are no
10359 // pending arguments, then fake up one so its onStartCommand() will
10360 // be called.
10361 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10362 r.lastStartId++;
10363 if (r.lastStartId < 1) {
10364 r.lastStartId = 1;
10365 }
10366 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10367 }
10368
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010369 sendServiceArgsLocked(r, true);
10370 }
10371
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010372 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10373 boolean allowCancel) {
10374 boolean canceled = false;
10375
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010376 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010377 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010378 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010379
10380 // Any delivered but not yet finished starts should be put back
10381 // on the pending list.
10382 final int N = r.deliveredStarts.size();
10383 if (N > 0) {
10384 for (int i=N-1; i>=0; i--) {
10385 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10386 if (si.intent == null) {
10387 // We'll generate this again if needed.
10388 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10389 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10390 r.pendingStarts.add(0, si);
10391 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10392 dur *= 2;
10393 if (minDuration < dur) minDuration = dur;
10394 if (resetTime < dur) resetTime = dur;
10395 } else {
10396 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10397 + r.name);
10398 canceled = true;
10399 }
10400 }
10401 r.deliveredStarts.clear();
10402 }
10403
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010404 r.totalRestartCount++;
10405 if (r.restartDelay == 0) {
10406 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010407 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010408 } else {
10409 // If it has been a "reasonably long time" since the service
10410 // was started, then reset our restart duration back to
10411 // the beginning, so we don't infinitely increase the duration
10412 // on a service that just occasionally gets killed (which is
10413 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010414 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010415 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010416 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010417 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010418 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010419 if (r.restartDelay < minDuration) {
10420 r.restartDelay = minDuration;
10421 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010422 }
10423 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010424
10425 r.nextRestartTime = now + r.restartDelay;
10426
10427 // Make sure that we don't end up restarting a bunch of services
10428 // all at the same time.
10429 boolean repeat;
10430 do {
10431 repeat = false;
10432 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10433 ServiceRecord r2 = mRestartingServices.get(i);
10434 if (r2 != r && r.nextRestartTime
10435 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10436 && r.nextRestartTime
10437 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10438 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10439 r.restartDelay = r.nextRestartTime - now;
10440 repeat = true;
10441 break;
10442 }
10443 }
10444 } while (repeat);
10445
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010446 if (!mRestartingServices.contains(r)) {
10447 mRestartingServices.add(r);
10448 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010449
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010450 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010452 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010453 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010454 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10455 Log.w(TAG, "Scheduling restart of crashed service "
10456 + r.shortName + " in " + r.restartDelay + "ms");
10457 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10458 r.shortName, r.restartDelay);
10459
10460 Message msg = Message.obtain();
10461 msg.what = SERVICE_ERROR_MSG;
10462 msg.obj = r;
10463 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010464
10465 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010466 }
10467
10468 final void performServiceRestartLocked(ServiceRecord r) {
10469 if (!mRestartingServices.contains(r)) {
10470 return;
10471 }
10472 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10473 }
10474
10475 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10476 if (r.restartDelay == 0) {
10477 return false;
10478 }
10479 r.resetRestartCounter();
10480 mRestartingServices.remove(r);
10481 mHandler.removeCallbacks(r.restarter);
10482 return true;
10483 }
10484
10485 private final boolean bringUpServiceLocked(ServiceRecord r,
10486 int intentFlags, boolean whileRestarting) {
10487 //Log.i(TAG, "Bring up service:");
10488 //r.dump(" ");
10489
10490 if (r.app != null) {
10491 sendServiceArgsLocked(r, false);
10492 return true;
10493 }
10494
10495 if (!whileRestarting && r.restartDelay > 0) {
10496 // If waiting for a restart, then do nothing.
10497 return true;
10498 }
10499
10500 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10501 + " " + r.intent);
10502
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010503 // We are now bringing the service up, so no longer in the
10504 // restarting state.
10505 mRestartingServices.remove(r);
10506
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010507 final String appName = r.processName;
10508 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10509 if (app != null && app.thread != null) {
10510 try {
10511 realStartServiceLocked(r, app);
10512 return true;
10513 } catch (RemoteException e) {
10514 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10515 }
10516
10517 // If a dead object exception was thrown -- fall through to
10518 // restart the application.
10519 }
10520
10521 if (!mPendingServices.contains(r)) {
10522 // Not running -- get it started, and enqueue this service record
10523 // to be executed when the app comes up.
10524 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070010525 "service", r.name, false) == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010526 Log.w(TAG, "Unable to launch app "
10527 + r.appInfo.packageName + "/"
10528 + r.appInfo.uid + " for service "
10529 + r.intent.getIntent() + ": process is bad");
10530 bringDownServiceLocked(r, true);
10531 return false;
10532 }
10533 mPendingServices.add(r);
10534 }
10535 return true;
10536 }
10537
10538 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10539 //Log.i(TAG, "Bring down service:");
10540 //r.dump(" ");
10541
10542 // Does it still need to run?
10543 if (!force && r.startRequested) {
10544 return;
10545 }
10546 if (r.connections.size() > 0) {
10547 if (!force) {
10548 // XXX should probably keep a count of the number of auto-create
10549 // connections directly in the service.
10550 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10551 while (it.hasNext()) {
10552 ConnectionRecord cr = it.next();
10553 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10554 return;
10555 }
10556 }
10557 }
10558
10559 // Report to all of the connections that the service is no longer
10560 // available.
10561 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10562 while (it.hasNext()) {
10563 ConnectionRecord c = it.next();
10564 try {
10565 // todo: shouldn't be a synchronous call!
10566 c.conn.connected(r.name, null);
10567 } catch (Exception e) {
10568 Log.w(TAG, "Failure disconnecting service " + r.name +
10569 " to connection " + c.conn.asBinder() +
10570 " (in " + c.binding.client.processName + ")", e);
10571 }
10572 }
10573 }
10574
10575 // Tell the service that it has been unbound.
10576 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10577 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10578 while (it.hasNext()) {
10579 IntentBindRecord ibr = it.next();
10580 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10581 + ": hasBound=" + ibr.hasBound);
10582 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10583 try {
10584 bumpServiceExecutingLocked(r);
10585 updateOomAdjLocked(r.app);
10586 ibr.hasBound = false;
10587 r.app.thread.scheduleUnbindService(r,
10588 ibr.intent.getIntent());
10589 } catch (Exception e) {
10590 Log.w(TAG, "Exception when unbinding service "
10591 + r.shortName, e);
10592 serviceDoneExecutingLocked(r, true);
10593 }
10594 }
10595 }
10596 }
10597
10598 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10599 + " " + r.intent);
10600 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10601 System.identityHashCode(r), r.shortName,
10602 (r.app != null) ? r.app.pid : -1);
10603
10604 mServices.remove(r.name);
10605 mServicesByIntent.remove(r.intent);
10606 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10607 r.totalRestartCount = 0;
10608 unscheduleServiceRestartLocked(r);
10609
10610 // Also make sure it is not on the pending list.
10611 int N = mPendingServices.size();
10612 for (int i=0; i<N; i++) {
10613 if (mPendingServices.get(i) == r) {
10614 mPendingServices.remove(i);
10615 if (DEBUG_SERVICE) Log.v(
10616 TAG, "Removed pending service: " + r.shortName);
10617 i--;
10618 N--;
10619 }
10620 }
10621
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010622 r.cancelNotification();
10623 r.isForeground = false;
10624 r.foregroundId = 0;
10625 r.foregroundNoti = null;
10626
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010627 // Clear start entries.
10628 r.deliveredStarts.clear();
10629 r.pendingStarts.clear();
10630
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010631 if (r.app != null) {
10632 synchronized (r.stats.getBatteryStats()) {
10633 r.stats.stopLaunchedLocked();
10634 }
10635 r.app.services.remove(r);
10636 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010637 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010638 if (DEBUG_SERVICE) Log.v(TAG,
10639 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010640 bumpServiceExecutingLocked(r);
10641 mStoppingServices.add(r);
10642 updateOomAdjLocked(r.app);
10643 r.app.thread.scheduleStopService(r);
10644 } catch (Exception e) {
10645 Log.w(TAG, "Exception when stopping service "
10646 + r.shortName, e);
10647 serviceDoneExecutingLocked(r, true);
10648 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010649 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010650 } else {
10651 if (DEBUG_SERVICE) Log.v(
10652 TAG, "Removed service that has no process: " + r.shortName);
10653 }
10654 } else {
10655 if (DEBUG_SERVICE) Log.v(
10656 TAG, "Removed service that is not running: " + r.shortName);
10657 }
10658 }
10659
10660 ComponentName startServiceLocked(IApplicationThread caller,
10661 Intent service, String resolvedType,
10662 int callingPid, int callingUid) {
10663 synchronized(this) {
10664 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10665 + " type=" + resolvedType + " args=" + service.getExtras());
10666
10667 if (caller != null) {
10668 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10669 if (callerApp == null) {
10670 throw new SecurityException(
10671 "Unable to find app for caller " + caller
10672 + " (pid=" + Binder.getCallingPid()
10673 + ") when starting service " + service);
10674 }
10675 }
10676
10677 ServiceLookupResult res =
10678 retrieveServiceLocked(service, resolvedType,
10679 callingPid, callingUid);
10680 if (res == null) {
10681 return null;
10682 }
10683 if (res.record == null) {
10684 return new ComponentName("!", res.permission != null
10685 ? res.permission : "private to package");
10686 }
10687 ServiceRecord r = res.record;
10688 if (unscheduleServiceRestartLocked(r)) {
10689 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10690 + r.shortName);
10691 }
10692 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010693 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010694 r.lastStartId++;
10695 if (r.lastStartId < 1) {
10696 r.lastStartId = 1;
10697 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010698 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010699 r.lastActivity = SystemClock.uptimeMillis();
10700 synchronized (r.stats.getBatteryStats()) {
10701 r.stats.startRunningLocked();
10702 }
10703 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10704 return new ComponentName("!", "Service process is bad");
10705 }
10706 return r.name;
10707 }
10708 }
10709
10710 public ComponentName startService(IApplicationThread caller, Intent service,
10711 String resolvedType) {
10712 // Refuse possible leaked file descriptors
10713 if (service != null && service.hasFileDescriptors() == true) {
10714 throw new IllegalArgumentException("File descriptors passed in Intent");
10715 }
10716
10717 synchronized(this) {
10718 final int callingPid = Binder.getCallingPid();
10719 final int callingUid = Binder.getCallingUid();
10720 final long origId = Binder.clearCallingIdentity();
10721 ComponentName res = startServiceLocked(caller, service,
10722 resolvedType, callingPid, callingUid);
10723 Binder.restoreCallingIdentity(origId);
10724 return res;
10725 }
10726 }
10727
10728 ComponentName startServiceInPackage(int uid,
10729 Intent service, String resolvedType) {
10730 synchronized(this) {
10731 final long origId = Binder.clearCallingIdentity();
10732 ComponentName res = startServiceLocked(null, service,
10733 resolvedType, -1, uid);
10734 Binder.restoreCallingIdentity(origId);
10735 return res;
10736 }
10737 }
10738
10739 public int stopService(IApplicationThread caller, Intent service,
10740 String resolvedType) {
10741 // Refuse possible leaked file descriptors
10742 if (service != null && service.hasFileDescriptors() == true) {
10743 throw new IllegalArgumentException("File descriptors passed in Intent");
10744 }
10745
10746 synchronized(this) {
10747 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10748 + " type=" + resolvedType);
10749
10750 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10751 if (caller != null && callerApp == null) {
10752 throw new SecurityException(
10753 "Unable to find app for caller " + caller
10754 + " (pid=" + Binder.getCallingPid()
10755 + ") when stopping service " + service);
10756 }
10757
10758 // If this service is active, make sure it is stopped.
10759 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10760 if (r != null) {
10761 if (r.record != null) {
10762 synchronized (r.record.stats.getBatteryStats()) {
10763 r.record.stats.stopRunningLocked();
10764 }
10765 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010766 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010767 final long origId = Binder.clearCallingIdentity();
10768 bringDownServiceLocked(r.record, false);
10769 Binder.restoreCallingIdentity(origId);
10770 return 1;
10771 }
10772 return -1;
10773 }
10774 }
10775
10776 return 0;
10777 }
10778
10779 public IBinder peekService(Intent service, String resolvedType) {
10780 // Refuse possible leaked file descriptors
10781 if (service != null && service.hasFileDescriptors() == true) {
10782 throw new IllegalArgumentException("File descriptors passed in Intent");
10783 }
10784
10785 IBinder ret = null;
10786
10787 synchronized(this) {
10788 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10789
10790 if (r != null) {
10791 // r.record is null if findServiceLocked() failed the caller permission check
10792 if (r.record == null) {
10793 throw new SecurityException(
10794 "Permission Denial: Accessing service " + r.record.name
10795 + " from pid=" + Binder.getCallingPid()
10796 + ", uid=" + Binder.getCallingUid()
10797 + " requires " + r.permission);
10798 }
10799 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10800 if (ib != null) {
10801 ret = ib.binder;
10802 }
10803 }
10804 }
10805
10806 return ret;
10807 }
10808
10809 public boolean stopServiceToken(ComponentName className, IBinder token,
10810 int startId) {
10811 synchronized(this) {
10812 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10813 + " " + token + " startId=" + startId);
10814 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010815 if (r != null) {
10816 if (startId >= 0) {
10817 // Asked to only stop if done with all work. Note that
10818 // to avoid leaks, we will take this as dropping all
10819 // start items up to and including this one.
10820 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10821 if (si != null) {
10822 while (r.deliveredStarts.size() > 0) {
10823 if (r.deliveredStarts.remove(0) == si) {
10824 break;
10825 }
10826 }
10827 }
10828
10829 if (r.lastStartId != startId) {
10830 return false;
10831 }
10832
10833 if (r.deliveredStarts.size() > 0) {
10834 Log.w(TAG, "stopServiceToken startId " + startId
10835 + " is last, but have " + r.deliveredStarts.size()
10836 + " remaining args");
10837 }
10838 }
10839
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010840 synchronized (r.stats.getBatteryStats()) {
10841 r.stats.stopRunningLocked();
10842 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010843 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010844 }
10845 final long origId = Binder.clearCallingIdentity();
10846 bringDownServiceLocked(r, false);
10847 Binder.restoreCallingIdentity(origId);
10848 return true;
10849 }
10850 }
10851 return false;
10852 }
10853
10854 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010855 int id, Notification notification, boolean removeNotification) {
10856 final long origId = Binder.clearCallingIdentity();
10857 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010858 synchronized(this) {
10859 ServiceRecord r = findServiceLocked(className, token);
10860 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010861 if (id != 0) {
10862 if (notification == null) {
10863 throw new IllegalArgumentException("null notification");
10864 }
10865 if (r.foregroundId != id) {
10866 r.cancelNotification();
10867 r.foregroundId = id;
10868 }
10869 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10870 r.foregroundNoti = notification;
10871 r.isForeground = true;
10872 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010873 if (r.app != null) {
10874 updateServiceForegroundLocked(r.app, true);
10875 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010876 } else {
10877 if (r.isForeground) {
10878 r.isForeground = false;
10879 if (r.app != null) {
10880 updateServiceForegroundLocked(r.app, true);
10881 }
10882 }
10883 if (removeNotification) {
10884 r.cancelNotification();
10885 r.foregroundId = 0;
10886 r.foregroundNoti = null;
10887 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010888 }
10889 }
10890 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010891 } finally {
10892 Binder.restoreCallingIdentity(origId);
10893 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010894 }
10895
10896 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10897 boolean anyForeground = false;
10898 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10899 if (sr.isForeground) {
10900 anyForeground = true;
10901 break;
10902 }
10903 }
10904 if (anyForeground != proc.foregroundServices) {
10905 proc.foregroundServices = anyForeground;
10906 if (oomAdj) {
10907 updateOomAdjLocked();
10908 }
10909 }
10910 }
10911
10912 public int bindService(IApplicationThread caller, IBinder token,
10913 Intent service, String resolvedType,
10914 IServiceConnection connection, int flags) {
10915 // Refuse possible leaked file descriptors
10916 if (service != null && service.hasFileDescriptors() == true) {
10917 throw new IllegalArgumentException("File descriptors passed in Intent");
10918 }
10919
10920 synchronized(this) {
10921 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10922 + " type=" + resolvedType + " conn=" + connection.asBinder()
10923 + " flags=0x" + Integer.toHexString(flags));
10924 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10925 if (callerApp == null) {
10926 throw new SecurityException(
10927 "Unable to find app for caller " + caller
10928 + " (pid=" + Binder.getCallingPid()
10929 + ") when binding service " + service);
10930 }
10931
10932 HistoryRecord activity = null;
10933 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010934 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010935 if (aindex < 0) {
10936 Log.w(TAG, "Binding with unknown activity: " + token);
10937 return 0;
10938 }
10939 activity = (HistoryRecord)mHistory.get(aindex);
10940 }
10941
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010942 int clientLabel = 0;
10943 PendingIntent clientIntent = null;
10944
10945 if (callerApp.info.uid == Process.SYSTEM_UID) {
10946 // Hacky kind of thing -- allow system stuff to tell us
10947 // what they are, so we can report this elsewhere for
10948 // others to know why certain services are running.
10949 try {
10950 clientIntent = (PendingIntent)service.getParcelableExtra(
10951 Intent.EXTRA_CLIENT_INTENT);
10952 } catch (RuntimeException e) {
10953 }
10954 if (clientIntent != null) {
10955 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
10956 if (clientLabel != 0) {
10957 // There are no useful extras in the intent, trash them.
10958 // System code calling with this stuff just needs to know
10959 // this will happen.
10960 service = service.cloneFilter();
10961 }
10962 }
10963 }
10964
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010965 ServiceLookupResult res =
10966 retrieveServiceLocked(service, resolvedType,
10967 Binder.getCallingPid(), Binder.getCallingUid());
10968 if (res == null) {
10969 return 0;
10970 }
10971 if (res.record == null) {
10972 return -1;
10973 }
10974 ServiceRecord s = res.record;
10975
10976 final long origId = Binder.clearCallingIdentity();
10977
10978 if (unscheduleServiceRestartLocked(s)) {
10979 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10980 + s.shortName);
10981 }
10982
10983 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10984 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010985 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010986
10987 IBinder binder = connection.asBinder();
10988 s.connections.put(binder, c);
10989 b.connections.add(c);
10990 if (activity != null) {
10991 if (activity.connections == null) {
10992 activity.connections = new HashSet<ConnectionRecord>();
10993 }
10994 activity.connections.add(c);
10995 }
10996 b.client.connections.add(c);
10997 mServiceConnections.put(binder, c);
10998
10999 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11000 s.lastActivity = SystemClock.uptimeMillis();
11001 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11002 return 0;
11003 }
11004 }
11005
11006 if (s.app != null) {
11007 // This could have made the service more important.
11008 updateOomAdjLocked(s.app);
11009 }
11010
11011 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11012 + ": received=" + b.intent.received
11013 + " apps=" + b.intent.apps.size()
11014 + " doRebind=" + b.intent.doRebind);
11015
11016 if (s.app != null && b.intent.received) {
11017 // Service is already running, so we can immediately
11018 // publish the connection.
11019 try {
11020 c.conn.connected(s.name, b.intent.binder);
11021 } catch (Exception e) {
11022 Log.w(TAG, "Failure sending service " + s.shortName
11023 + " to connection " + c.conn.asBinder()
11024 + " (in " + c.binding.client.processName + ")", e);
11025 }
11026
11027 // If this is the first app connected back to this binding,
11028 // and the service had previously asked to be told when
11029 // rebound, then do so.
11030 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11031 requestServiceBindingLocked(s, b.intent, true);
11032 }
11033 } else if (!b.intent.requested) {
11034 requestServiceBindingLocked(s, b.intent, false);
11035 }
11036
11037 Binder.restoreCallingIdentity(origId);
11038 }
11039
11040 return 1;
11041 }
11042
11043 private void removeConnectionLocked(
11044 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11045 IBinder binder = c.conn.asBinder();
11046 AppBindRecord b = c.binding;
11047 ServiceRecord s = b.service;
11048 s.connections.remove(binder);
11049 b.connections.remove(c);
11050 if (c.activity != null && c.activity != skipAct) {
11051 if (c.activity.connections != null) {
11052 c.activity.connections.remove(c);
11053 }
11054 }
11055 if (b.client != skipApp) {
11056 b.client.connections.remove(c);
11057 }
11058 mServiceConnections.remove(binder);
11059
11060 if (b.connections.size() == 0) {
11061 b.intent.apps.remove(b.client);
11062 }
11063
11064 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11065 + ": shouldUnbind=" + b.intent.hasBound);
11066 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11067 && b.intent.hasBound) {
11068 try {
11069 bumpServiceExecutingLocked(s);
11070 updateOomAdjLocked(s.app);
11071 b.intent.hasBound = false;
11072 // Assume the client doesn't want to know about a rebind;
11073 // we will deal with that later if it asks for one.
11074 b.intent.doRebind = false;
11075 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11076 } catch (Exception e) {
11077 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11078 serviceDoneExecutingLocked(s, true);
11079 }
11080 }
11081
11082 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11083 bringDownServiceLocked(s, false);
11084 }
11085 }
11086
11087 public boolean unbindService(IServiceConnection connection) {
11088 synchronized (this) {
11089 IBinder binder = connection.asBinder();
11090 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11091 ConnectionRecord r = mServiceConnections.get(binder);
11092 if (r == null) {
11093 Log.w(TAG, "Unbind failed: could not find connection for "
11094 + connection.asBinder());
11095 return false;
11096 }
11097
11098 final long origId = Binder.clearCallingIdentity();
11099
11100 removeConnectionLocked(r, null, null);
11101
11102 if (r.binding.service.app != null) {
11103 // This could have made the service less important.
11104 updateOomAdjLocked(r.binding.service.app);
11105 }
11106
11107 Binder.restoreCallingIdentity(origId);
11108 }
11109
11110 return true;
11111 }
11112
11113 public void publishService(IBinder token, Intent intent, IBinder service) {
11114 // Refuse possible leaked file descriptors
11115 if (intent != null && intent.hasFileDescriptors() == true) {
11116 throw new IllegalArgumentException("File descriptors passed in Intent");
11117 }
11118
11119 synchronized(this) {
11120 if (!(token instanceof ServiceRecord)) {
11121 throw new IllegalArgumentException("Invalid service token");
11122 }
11123 ServiceRecord r = (ServiceRecord)token;
11124
11125 final long origId = Binder.clearCallingIdentity();
11126
11127 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11128 + " " + intent + ": " + service);
11129 if (r != null) {
11130 Intent.FilterComparison filter
11131 = new Intent.FilterComparison(intent);
11132 IntentBindRecord b = r.bindings.get(filter);
11133 if (b != null && !b.received) {
11134 b.binder = service;
11135 b.requested = true;
11136 b.received = true;
11137 if (r.connections.size() > 0) {
11138 Iterator<ConnectionRecord> it
11139 = r.connections.values().iterator();
11140 while (it.hasNext()) {
11141 ConnectionRecord c = it.next();
11142 if (!filter.equals(c.binding.intent.intent)) {
11143 if (DEBUG_SERVICE) Log.v(
11144 TAG, "Not publishing to: " + c);
11145 if (DEBUG_SERVICE) Log.v(
11146 TAG, "Bound intent: " + c.binding.intent.intent);
11147 if (DEBUG_SERVICE) Log.v(
11148 TAG, "Published intent: " + intent);
11149 continue;
11150 }
11151 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11152 try {
11153 c.conn.connected(r.name, service);
11154 } catch (Exception e) {
11155 Log.w(TAG, "Failure sending service " + r.name +
11156 " to connection " + c.conn.asBinder() +
11157 " (in " + c.binding.client.processName + ")", e);
11158 }
11159 }
11160 }
11161 }
11162
11163 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11164
11165 Binder.restoreCallingIdentity(origId);
11166 }
11167 }
11168 }
11169
11170 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11171 // Refuse possible leaked file descriptors
11172 if (intent != null && intent.hasFileDescriptors() == true) {
11173 throw new IllegalArgumentException("File descriptors passed in Intent");
11174 }
11175
11176 synchronized(this) {
11177 if (!(token instanceof ServiceRecord)) {
11178 throw new IllegalArgumentException("Invalid service token");
11179 }
11180 ServiceRecord r = (ServiceRecord)token;
11181
11182 final long origId = Binder.clearCallingIdentity();
11183
11184 if (r != null) {
11185 Intent.FilterComparison filter
11186 = new Intent.FilterComparison(intent);
11187 IntentBindRecord b = r.bindings.get(filter);
11188 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11189 + " at " + b + ": apps="
11190 + (b != null ? b.apps.size() : 0));
11191 if (b != null) {
11192 if (b.apps.size() > 0) {
11193 // Applications have already bound since the last
11194 // unbind, so just rebind right here.
11195 requestServiceBindingLocked(r, b, true);
11196 } else {
11197 // Note to tell the service the next time there is
11198 // a new client.
11199 b.doRebind = true;
11200 }
11201 }
11202
11203 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11204
11205 Binder.restoreCallingIdentity(origId);
11206 }
11207 }
11208 }
11209
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011210 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011211 synchronized(this) {
11212 if (!(token instanceof ServiceRecord)) {
11213 throw new IllegalArgumentException("Invalid service token");
11214 }
11215 ServiceRecord r = (ServiceRecord)token;
11216 boolean inStopping = mStoppingServices.contains(token);
11217 if (r != null) {
11218 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11219 + ": nesting=" + r.executeNesting
11220 + ", inStopping=" + inStopping);
11221 if (r != token) {
11222 Log.w(TAG, "Done executing service " + r.name
11223 + " with incorrect token: given " + token
11224 + ", expected " + r);
11225 return;
11226 }
11227
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011228 if (type == 1) {
11229 // This is a call from a service start... take care of
11230 // book-keeping.
11231 r.callStart = true;
11232 switch (res) {
11233 case Service.START_STICKY_COMPATIBILITY:
11234 case Service.START_STICKY: {
11235 // We are done with the associated start arguments.
11236 r.findDeliveredStart(startId, true);
11237 // Don't stop if killed.
11238 r.stopIfKilled = false;
11239 break;
11240 }
11241 case Service.START_NOT_STICKY: {
11242 // We are done with the associated start arguments.
11243 r.findDeliveredStart(startId, true);
11244 if (r.lastStartId == startId) {
11245 // There is no more work, and this service
11246 // doesn't want to hang around if killed.
11247 r.stopIfKilled = true;
11248 }
11249 break;
11250 }
11251 case Service.START_REDELIVER_INTENT: {
11252 // We'll keep this item until they explicitly
11253 // call stop for it, but keep track of the fact
11254 // that it was delivered.
11255 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11256 if (si != null) {
11257 si.deliveryCount = 0;
11258 si.doneExecutingCount++;
11259 // Don't stop if killed.
11260 r.stopIfKilled = true;
11261 }
11262 break;
11263 }
11264 default:
11265 throw new IllegalArgumentException(
11266 "Unknown service start result: " + res);
11267 }
11268 if (res == Service.START_STICKY_COMPATIBILITY) {
11269 r.callStart = false;
11270 }
11271 }
11272
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011273 final long origId = Binder.clearCallingIdentity();
11274 serviceDoneExecutingLocked(r, inStopping);
11275 Binder.restoreCallingIdentity(origId);
11276 } else {
11277 Log.w(TAG, "Done executing unknown service " + r.name
11278 + " with token " + token);
11279 }
11280 }
11281 }
11282
11283 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11284 r.executeNesting--;
11285 if (r.executeNesting <= 0 && r.app != null) {
11286 r.app.executingServices.remove(r);
11287 if (r.app.executingServices.size() == 0) {
11288 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11289 }
11290 if (inStopping) {
11291 mStoppingServices.remove(r);
11292 }
11293 updateOomAdjLocked(r.app);
11294 }
11295 }
11296
11297 void serviceTimeout(ProcessRecord proc) {
11298 synchronized(this) {
11299 if (proc.executingServices.size() == 0 || proc.thread == null) {
11300 return;
11301 }
11302 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11303 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11304 ServiceRecord timeout = null;
11305 long nextTime = 0;
11306 while (it.hasNext()) {
11307 ServiceRecord sr = it.next();
11308 if (sr.executingStart < maxTime) {
11309 timeout = sr;
11310 break;
11311 }
11312 if (sr.executingStart > nextTime) {
11313 nextTime = sr.executingStart;
11314 }
11315 }
11316 if (timeout != null && mLRUProcesses.contains(proc)) {
11317 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011318 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011319 + timeout.name);
11320 } else {
11321 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11322 msg.obj = proc;
11323 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11324 }
11325 }
11326 }
11327
11328 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011329 // BACKUP AND RESTORE
11330 // =========================================================
11331
11332 // Cause the target app to be launched if necessary and its backup agent
11333 // instantiated. The backup agent will invoke backupAgentCreated() on the
11334 // activity manager to announce its creation.
11335 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11336 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11337 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11338
11339 synchronized(this) {
11340 // !!! TODO: currently no check here that we're already bound
11341 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11342 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11343 synchronized (stats) {
11344 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11345 }
11346
11347 BackupRecord r = new BackupRecord(ss, app, backupMode);
11348 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11349 // startProcessLocked() returns existing proc's record if it's already running
11350 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011351 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011352 if (proc == null) {
11353 Log.e(TAG, "Unable to start backup agent process " + r);
11354 return false;
11355 }
11356
11357 r.app = proc;
11358 mBackupTarget = r;
11359 mBackupAppName = app.packageName;
11360
Christopher Tate6fa95972009-06-05 18:43:55 -070011361 // Try not to kill the process during backup
11362 updateOomAdjLocked(proc);
11363
Christopher Tate181fafa2009-05-14 11:12:14 -070011364 // If the process is already attached, schedule the creation of the backup agent now.
11365 // If it is not yet live, this will be done when it attaches to the framework.
11366 if (proc.thread != null) {
11367 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11368 try {
11369 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11370 } catch (RemoteException e) {
11371 // !!! TODO: notify the backup manager that we crashed, or rely on
11372 // death notices, or...?
11373 }
11374 } else {
11375 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11376 }
11377 // Invariants: at this point, the target app process exists and the application
11378 // is either already running or in the process of coming up. mBackupTarget and
11379 // mBackupAppName describe the app, so that when it binds back to the AM we
11380 // know that it's scheduled for a backup-agent operation.
11381 }
11382
11383 return true;
11384 }
11385
11386 // A backup agent has just come up
11387 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11388 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11389 + " = " + agent);
11390
11391 synchronized(this) {
11392 if (!agentPackageName.equals(mBackupAppName)) {
11393 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11394 return;
11395 }
11396
Christopher Tate043dadc2009-06-02 16:11:00 -070011397 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011398 try {
11399 IBackupManager bm = IBackupManager.Stub.asInterface(
11400 ServiceManager.getService(Context.BACKUP_SERVICE));
11401 bm.agentConnected(agentPackageName, agent);
11402 } catch (RemoteException e) {
11403 // can't happen; the backup manager service is local
11404 } catch (Exception e) {
11405 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11406 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011407 } finally {
11408 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011409 }
11410 }
11411 }
11412
11413 // done with this agent
11414 public void unbindBackupAgent(ApplicationInfo appInfo) {
11415 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011416 if (appInfo == null) {
11417 Log.w(TAG, "unbind backup agent for null app");
11418 return;
11419 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011420
11421 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011422 if (mBackupAppName == null) {
11423 Log.w(TAG, "Unbinding backup agent with no active backup");
11424 return;
11425 }
11426
Christopher Tate181fafa2009-05-14 11:12:14 -070011427 if (!mBackupAppName.equals(appInfo.packageName)) {
11428 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11429 return;
11430 }
11431
Christopher Tate6fa95972009-06-05 18:43:55 -070011432 ProcessRecord proc = mBackupTarget.app;
11433 mBackupTarget = null;
11434 mBackupAppName = null;
11435
11436 // Not backing this app up any more; reset its OOM adjustment
11437 updateOomAdjLocked(proc);
11438
Christopher Tatec7b31e32009-06-10 15:49:30 -070011439 // If the app crashed during backup, 'thread' will be null here
11440 if (proc.thread != null) {
11441 try {
11442 proc.thread.scheduleDestroyBackupAgent(appInfo);
11443 } catch (Exception e) {
11444 Log.e(TAG, "Exception when unbinding backup agent:");
11445 e.printStackTrace();
11446 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011447 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011448 }
11449 }
11450 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011451 // BROADCASTS
11452 // =========================================================
11453
11454 private final List getStickies(String action, IntentFilter filter,
11455 List cur) {
11456 final ContentResolver resolver = mContext.getContentResolver();
11457 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11458 if (list == null) {
11459 return cur;
11460 }
11461 int N = list.size();
11462 for (int i=0; i<N; i++) {
11463 Intent intent = list.get(i);
11464 if (filter.match(resolver, intent, true, TAG) >= 0) {
11465 if (cur == null) {
11466 cur = new ArrayList<Intent>();
11467 }
11468 cur.add(intent);
11469 }
11470 }
11471 return cur;
11472 }
11473
11474 private final void scheduleBroadcastsLocked() {
11475 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11476 + mBroadcastsScheduled);
11477
11478 if (mBroadcastsScheduled) {
11479 return;
11480 }
11481 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11482 mBroadcastsScheduled = true;
11483 }
11484
11485 public Intent registerReceiver(IApplicationThread caller,
11486 IIntentReceiver receiver, IntentFilter filter, String permission) {
11487 synchronized(this) {
11488 ProcessRecord callerApp = null;
11489 if (caller != null) {
11490 callerApp = getRecordForAppLocked(caller);
11491 if (callerApp == null) {
11492 throw new SecurityException(
11493 "Unable to find app for caller " + caller
11494 + " (pid=" + Binder.getCallingPid()
11495 + ") when registering receiver " + receiver);
11496 }
11497 }
11498
11499 List allSticky = null;
11500
11501 // Look for any matching sticky broadcasts...
11502 Iterator actions = filter.actionsIterator();
11503 if (actions != null) {
11504 while (actions.hasNext()) {
11505 String action = (String)actions.next();
11506 allSticky = getStickies(action, filter, allSticky);
11507 }
11508 } else {
11509 allSticky = getStickies(null, filter, allSticky);
11510 }
11511
11512 // The first sticky in the list is returned directly back to
11513 // the client.
11514 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11515
11516 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11517 + ": " + sticky);
11518
11519 if (receiver == null) {
11520 return sticky;
11521 }
11522
11523 ReceiverList rl
11524 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11525 if (rl == null) {
11526 rl = new ReceiverList(this, callerApp,
11527 Binder.getCallingPid(),
11528 Binder.getCallingUid(), receiver);
11529 if (rl.app != null) {
11530 rl.app.receivers.add(rl);
11531 } else {
11532 try {
11533 receiver.asBinder().linkToDeath(rl, 0);
11534 } catch (RemoteException e) {
11535 return sticky;
11536 }
11537 rl.linkedToDeath = true;
11538 }
11539 mRegisteredReceivers.put(receiver.asBinder(), rl);
11540 }
11541 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11542 rl.add(bf);
11543 if (!bf.debugCheck()) {
11544 Log.w(TAG, "==> For Dynamic broadast");
11545 }
11546 mReceiverResolver.addFilter(bf);
11547
11548 // Enqueue broadcasts for all existing stickies that match
11549 // this filter.
11550 if (allSticky != null) {
11551 ArrayList receivers = new ArrayList();
11552 receivers.add(bf);
11553
11554 int N = allSticky.size();
11555 for (int i=0; i<N; i++) {
11556 Intent intent = (Intent)allSticky.get(i);
11557 BroadcastRecord r = new BroadcastRecord(intent, null,
11558 null, -1, -1, null, receivers, null, 0, null, null,
11559 false);
11560 if (mParallelBroadcasts.size() == 0) {
11561 scheduleBroadcastsLocked();
11562 }
11563 mParallelBroadcasts.add(r);
11564 }
11565 }
11566
11567 return sticky;
11568 }
11569 }
11570
11571 public void unregisterReceiver(IIntentReceiver receiver) {
11572 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11573
11574 boolean doNext = false;
11575
11576 synchronized(this) {
11577 ReceiverList rl
11578 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11579 if (rl != null) {
11580 if (rl.curBroadcast != null) {
11581 BroadcastRecord r = rl.curBroadcast;
11582 doNext = finishReceiverLocked(
11583 receiver.asBinder(), r.resultCode, r.resultData,
11584 r.resultExtras, r.resultAbort, true);
11585 }
11586
11587 if (rl.app != null) {
11588 rl.app.receivers.remove(rl);
11589 }
11590 removeReceiverLocked(rl);
11591 if (rl.linkedToDeath) {
11592 rl.linkedToDeath = false;
11593 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11594 }
11595 }
11596 }
11597
11598 if (!doNext) {
11599 return;
11600 }
11601
11602 final long origId = Binder.clearCallingIdentity();
11603 processNextBroadcast(false);
11604 trimApplications();
11605 Binder.restoreCallingIdentity(origId);
11606 }
11607
11608 void removeReceiverLocked(ReceiverList rl) {
11609 mRegisteredReceivers.remove(rl.receiver.asBinder());
11610 int N = rl.size();
11611 for (int i=0; i<N; i++) {
11612 mReceiverResolver.removeFilter(rl.get(i));
11613 }
11614 }
11615
11616 private final int broadcastIntentLocked(ProcessRecord callerApp,
11617 String callerPackage, Intent intent, String resolvedType,
11618 IIntentReceiver resultTo, int resultCode, String resultData,
11619 Bundle map, String requiredPermission,
11620 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11621 intent = new Intent(intent);
11622
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011623 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011624 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11625 + " ordered=" + ordered);
11626 if ((resultTo != null) && !ordered) {
11627 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11628 }
11629
11630 // Handle special intents: if this broadcast is from the package
11631 // manager about a package being removed, we need to remove all of
11632 // its activities from the history stack.
11633 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11634 intent.getAction());
11635 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11636 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11637 || uidRemoved) {
11638 if (checkComponentPermission(
11639 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11640 callingPid, callingUid, -1)
11641 == PackageManager.PERMISSION_GRANTED) {
11642 if (uidRemoved) {
11643 final Bundle intentExtras = intent.getExtras();
11644 final int uid = intentExtras != null
11645 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11646 if (uid >= 0) {
11647 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11648 synchronized (bs) {
11649 bs.removeUidStatsLocked(uid);
11650 }
11651 }
11652 } else {
11653 Uri data = intent.getData();
11654 String ssp;
11655 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11656 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11657 uninstallPackageLocked(ssp,
11658 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011659 AttributeCache ac = AttributeCache.instance();
11660 if (ac != null) {
11661 ac.removePackage(ssp);
11662 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011663 }
11664 }
11665 }
11666 } else {
11667 String msg = "Permission Denial: " + intent.getAction()
11668 + " broadcast from " + callerPackage + " (pid=" + callingPid
11669 + ", uid=" + callingUid + ")"
11670 + " requires "
11671 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11672 Log.w(TAG, msg);
11673 throw new SecurityException(msg);
11674 }
11675 }
11676
11677 /*
11678 * If this is the time zone changed action, queue up a message that will reset the timezone
11679 * of all currently running processes. This message will get queued up before the broadcast
11680 * happens.
11681 */
11682 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11683 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11684 }
11685
Dianne Hackborn854060af2009-07-09 18:14:31 -070011686 /*
11687 * Prevent non-system code (defined here to be non-persistent
11688 * processes) from sending protected broadcasts.
11689 */
11690 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11691 || callingUid == Process.SHELL_UID || callingUid == 0) {
11692 // Always okay.
11693 } else if (callerApp == null || !callerApp.persistent) {
11694 try {
11695 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11696 intent.getAction())) {
11697 String msg = "Permission Denial: not allowed to send broadcast "
11698 + intent.getAction() + " from pid="
11699 + callingPid + ", uid=" + callingUid;
11700 Log.w(TAG, msg);
11701 throw new SecurityException(msg);
11702 }
11703 } catch (RemoteException e) {
11704 Log.w(TAG, "Remote exception", e);
11705 return BROADCAST_SUCCESS;
11706 }
11707 }
11708
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011709 // Add to the sticky list if requested.
11710 if (sticky) {
11711 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11712 callingPid, callingUid)
11713 != PackageManager.PERMISSION_GRANTED) {
11714 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11715 + callingPid + ", uid=" + callingUid
11716 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11717 Log.w(TAG, msg);
11718 throw new SecurityException(msg);
11719 }
11720 if (requiredPermission != null) {
11721 Log.w(TAG, "Can't broadcast sticky intent " + intent
11722 + " and enforce permission " + requiredPermission);
11723 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11724 }
11725 if (intent.getComponent() != null) {
11726 throw new SecurityException(
11727 "Sticky broadcasts can't target a specific component");
11728 }
11729 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11730 if (list == null) {
11731 list = new ArrayList<Intent>();
11732 mStickyBroadcasts.put(intent.getAction(), list);
11733 }
11734 int N = list.size();
11735 int i;
11736 for (i=0; i<N; i++) {
11737 if (intent.filterEquals(list.get(i))) {
11738 // This sticky already exists, replace it.
11739 list.set(i, new Intent(intent));
11740 break;
11741 }
11742 }
11743 if (i >= N) {
11744 list.add(new Intent(intent));
11745 }
11746 }
11747
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011748 // Figure out who all will receive this broadcast.
11749 List receivers = null;
11750 List<BroadcastFilter> registeredReceivers = null;
11751 try {
11752 if (intent.getComponent() != null) {
11753 // Broadcast is going to one specific receiver class...
11754 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011755 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011756 if (ai != null) {
11757 receivers = new ArrayList();
11758 ResolveInfo ri = new ResolveInfo();
11759 ri.activityInfo = ai;
11760 receivers.add(ri);
11761 }
11762 } else {
11763 // Need to resolve the intent to interested receivers...
11764 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11765 == 0) {
11766 receivers =
11767 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011768 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011769 }
Mihai Preda074edef2009-05-18 17:13:31 +020011770 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011771 }
11772 } catch (RemoteException ex) {
11773 // pm is in same process, this will never happen.
11774 }
11775
11776 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11777 if (!ordered && NR > 0) {
11778 // If we are not serializing this broadcast, then send the
11779 // registered receivers separately so they don't wait for the
11780 // components to be launched.
11781 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11782 callerPackage, callingPid, callingUid, requiredPermission,
11783 registeredReceivers, resultTo, resultCode, resultData, map,
11784 ordered);
11785 if (DEBUG_BROADCAST) Log.v(
11786 TAG, "Enqueueing parallel broadcast " + r
11787 + ": prev had " + mParallelBroadcasts.size());
11788 mParallelBroadcasts.add(r);
11789 scheduleBroadcastsLocked();
11790 registeredReceivers = null;
11791 NR = 0;
11792 }
11793
11794 // Merge into one list.
11795 int ir = 0;
11796 if (receivers != null) {
11797 // A special case for PACKAGE_ADDED: do not allow the package
11798 // being added to see this broadcast. This prevents them from
11799 // using this as a back door to get run as soon as they are
11800 // installed. Maybe in the future we want to have a special install
11801 // broadcast or such for apps, but we'd like to deliberately make
11802 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011803 boolean skip = false;
11804 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011805 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011806 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11807 skip = true;
11808 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11809 skip = true;
11810 }
11811 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011812 ? intent.getData().getSchemeSpecificPart()
11813 : null;
11814 if (skipPackage != null && receivers != null) {
11815 int NT = receivers.size();
11816 for (int it=0; it<NT; it++) {
11817 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11818 if (curt.activityInfo.packageName.equals(skipPackage)) {
11819 receivers.remove(it);
11820 it--;
11821 NT--;
11822 }
11823 }
11824 }
11825
11826 int NT = receivers != null ? receivers.size() : 0;
11827 int it = 0;
11828 ResolveInfo curt = null;
11829 BroadcastFilter curr = null;
11830 while (it < NT && ir < NR) {
11831 if (curt == null) {
11832 curt = (ResolveInfo)receivers.get(it);
11833 }
11834 if (curr == null) {
11835 curr = registeredReceivers.get(ir);
11836 }
11837 if (curr.getPriority() >= curt.priority) {
11838 // Insert this broadcast record into the final list.
11839 receivers.add(it, curr);
11840 ir++;
11841 curr = null;
11842 it++;
11843 NT++;
11844 } else {
11845 // Skip to the next ResolveInfo in the final list.
11846 it++;
11847 curt = null;
11848 }
11849 }
11850 }
11851 while (ir < NR) {
11852 if (receivers == null) {
11853 receivers = new ArrayList();
11854 }
11855 receivers.add(registeredReceivers.get(ir));
11856 ir++;
11857 }
11858
11859 if ((receivers != null && receivers.size() > 0)
11860 || resultTo != null) {
11861 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11862 callerPackage, callingPid, callingUid, requiredPermission,
11863 receivers, resultTo, resultCode, resultData, map, ordered);
11864 if (DEBUG_BROADCAST) Log.v(
11865 TAG, "Enqueueing ordered broadcast " + r
11866 + ": prev had " + mOrderedBroadcasts.size());
11867 if (DEBUG_BROADCAST) {
11868 int seq = r.intent.getIntExtra("seq", -1);
11869 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11870 }
11871 mOrderedBroadcasts.add(r);
11872 scheduleBroadcastsLocked();
11873 }
11874
11875 return BROADCAST_SUCCESS;
11876 }
11877
11878 public final int broadcastIntent(IApplicationThread caller,
11879 Intent intent, String resolvedType, IIntentReceiver resultTo,
11880 int resultCode, String resultData, Bundle map,
11881 String requiredPermission, boolean serialized, boolean sticky) {
11882 // Refuse possible leaked file descriptors
11883 if (intent != null && intent.hasFileDescriptors() == true) {
11884 throw new IllegalArgumentException("File descriptors passed in Intent");
11885 }
11886
11887 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011888 int flags = intent.getFlags();
11889
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011890 if (!mSystemReady) {
11891 // if the caller really truly claims to know what they're doing, go
11892 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011893 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11894 intent = new Intent(intent);
11895 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11896 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11897 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11898 + " before boot completion");
11899 throw new IllegalStateException("Cannot broadcast before boot completed");
11900 }
11901 }
11902
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011903 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
11904 throw new IllegalArgumentException(
11905 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
11906 }
11907
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011908 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11909 final int callingPid = Binder.getCallingPid();
11910 final int callingUid = Binder.getCallingUid();
11911 final long origId = Binder.clearCallingIdentity();
11912 int res = broadcastIntentLocked(callerApp,
11913 callerApp != null ? callerApp.info.packageName : null,
11914 intent, resolvedType, resultTo,
11915 resultCode, resultData, map, requiredPermission, serialized,
11916 sticky, callingPid, callingUid);
11917 Binder.restoreCallingIdentity(origId);
11918 return res;
11919 }
11920 }
11921
11922 int broadcastIntentInPackage(String packageName, int uid,
11923 Intent intent, String resolvedType, IIntentReceiver resultTo,
11924 int resultCode, String resultData, Bundle map,
11925 String requiredPermission, boolean serialized, boolean sticky) {
11926 synchronized(this) {
11927 final long origId = Binder.clearCallingIdentity();
11928 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11929 resultTo, resultCode, resultData, map, requiredPermission,
11930 serialized, sticky, -1, uid);
11931 Binder.restoreCallingIdentity(origId);
11932 return res;
11933 }
11934 }
11935
11936 public final void unbroadcastIntent(IApplicationThread caller,
11937 Intent intent) {
11938 // Refuse possible leaked file descriptors
11939 if (intent != null && intent.hasFileDescriptors() == true) {
11940 throw new IllegalArgumentException("File descriptors passed in Intent");
11941 }
11942
11943 synchronized(this) {
11944 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11945 != PackageManager.PERMISSION_GRANTED) {
11946 String msg = "Permission Denial: unbroadcastIntent() from pid="
11947 + Binder.getCallingPid()
11948 + ", uid=" + Binder.getCallingUid()
11949 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11950 Log.w(TAG, msg);
11951 throw new SecurityException(msg);
11952 }
11953 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11954 if (list != null) {
11955 int N = list.size();
11956 int i;
11957 for (i=0; i<N; i++) {
11958 if (intent.filterEquals(list.get(i))) {
11959 list.remove(i);
11960 break;
11961 }
11962 }
11963 }
11964 }
11965 }
11966
11967 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11968 String resultData, Bundle resultExtras, boolean resultAbort,
11969 boolean explicit) {
11970 if (mOrderedBroadcasts.size() == 0) {
11971 if (explicit) {
11972 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11973 }
11974 return false;
11975 }
11976 BroadcastRecord r = mOrderedBroadcasts.get(0);
11977 if (r.receiver == null) {
11978 if (explicit) {
11979 Log.w(TAG, "finishReceiver called but none active");
11980 }
11981 return false;
11982 }
11983 if (r.receiver != receiver) {
11984 Log.w(TAG, "finishReceiver called but active receiver is different");
11985 return false;
11986 }
11987 int state = r.state;
11988 r.state = r.IDLE;
11989 if (state == r.IDLE) {
11990 if (explicit) {
11991 Log.w(TAG, "finishReceiver called but state is IDLE");
11992 }
11993 }
11994 r.receiver = null;
11995 r.intent.setComponent(null);
11996 if (r.curApp != null) {
11997 r.curApp.curReceiver = null;
11998 }
11999 if (r.curFilter != null) {
12000 r.curFilter.receiverList.curBroadcast = null;
12001 }
12002 r.curFilter = null;
12003 r.curApp = null;
12004 r.curComponent = null;
12005 r.curReceiver = null;
12006 mPendingBroadcast = null;
12007
12008 r.resultCode = resultCode;
12009 r.resultData = resultData;
12010 r.resultExtras = resultExtras;
12011 r.resultAbort = resultAbort;
12012
12013 // We will process the next receiver right now if this is finishing
12014 // an app receiver (which is always asynchronous) or after we have
12015 // come back from calling a receiver.
12016 return state == BroadcastRecord.APP_RECEIVE
12017 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12018 }
12019
12020 public void finishReceiver(IBinder who, int resultCode, String resultData,
12021 Bundle resultExtras, boolean resultAbort) {
12022 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12023
12024 // Refuse possible leaked file descriptors
12025 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12026 throw new IllegalArgumentException("File descriptors passed in Bundle");
12027 }
12028
12029 boolean doNext;
12030
12031 final long origId = Binder.clearCallingIdentity();
12032
12033 synchronized(this) {
12034 doNext = finishReceiverLocked(
12035 who, resultCode, resultData, resultExtras, resultAbort, true);
12036 }
12037
12038 if (doNext) {
12039 processNextBroadcast(false);
12040 }
12041 trimApplications();
12042
12043 Binder.restoreCallingIdentity(origId);
12044 }
12045
12046 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12047 if (r.nextReceiver > 0) {
12048 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12049 if (curReceiver instanceof BroadcastFilter) {
12050 BroadcastFilter bf = (BroadcastFilter) curReceiver;
12051 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
12052 System.identityHashCode(r),
12053 r.intent.getAction(),
12054 r.nextReceiver - 1,
12055 System.identityHashCode(bf));
12056 } else {
12057 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12058 System.identityHashCode(r),
12059 r.intent.getAction(),
12060 r.nextReceiver - 1,
12061 ((ResolveInfo)curReceiver).toString());
12062 }
12063 } else {
12064 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12065 + r);
12066 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12067 System.identityHashCode(r),
12068 r.intent.getAction(),
12069 r.nextReceiver,
12070 "NONE");
12071 }
12072 }
12073
12074 private final void broadcastTimeout() {
12075 synchronized (this) {
12076 if (mOrderedBroadcasts.size() == 0) {
12077 return;
12078 }
12079 long now = SystemClock.uptimeMillis();
12080 BroadcastRecord r = mOrderedBroadcasts.get(0);
12081 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
12082 if (DEBUG_BROADCAST) Log.v(TAG,
12083 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
12084 + (r.startTime + BROADCAST_TIMEOUT));
12085 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12086 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12087 return;
12088 }
12089
12090 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
12091 r.startTime = now;
12092 r.anrCount++;
12093
12094 // Current receiver has passed its expiration date.
12095 if (r.nextReceiver <= 0) {
12096 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12097 return;
12098 }
12099
12100 ProcessRecord app = null;
12101
12102 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12103 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12104 logBroadcastReceiverDiscard(r);
12105 if (curReceiver instanceof BroadcastFilter) {
12106 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12107 if (bf.receiverList.pid != 0
12108 && bf.receiverList.pid != MY_PID) {
12109 synchronized (this.mPidsSelfLocked) {
12110 app = this.mPidsSelfLocked.get(
12111 bf.receiverList.pid);
12112 }
12113 }
12114 } else {
12115 app = r.curApp;
12116 }
12117
12118 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070012119 appNotRespondingLocked(app, null, null,
12120 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012121 }
12122
12123 if (mPendingBroadcast == r) {
12124 mPendingBroadcast = null;
12125 }
12126
12127 // Move on to the next receiver.
12128 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12129 r.resultExtras, r.resultAbort, true);
12130 scheduleBroadcastsLocked();
12131 }
12132 }
12133
12134 private final void processCurBroadcastLocked(BroadcastRecord r,
12135 ProcessRecord app) throws RemoteException {
12136 if (app.thread == null) {
12137 throw new RemoteException();
12138 }
12139 r.receiver = app.thread.asBinder();
12140 r.curApp = app;
12141 app.curReceiver = r;
12142 updateLRUListLocked(app, true);
12143
12144 // Tell the application to launch this receiver.
12145 r.intent.setComponent(r.curComponent);
12146
12147 boolean started = false;
12148 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012149 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012150 "Delivering to component " + r.curComponent
12151 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012152 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012153 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12154 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12155 started = true;
12156 } finally {
12157 if (!started) {
12158 r.receiver = null;
12159 r.curApp = null;
12160 app.curReceiver = null;
12161 }
12162 }
12163
12164 }
12165
12166 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
12167 Intent intent, int resultCode, String data,
12168 Bundle extras, boolean ordered) throws RemoteException {
12169 if (app != null && app.thread != null) {
12170 // If we have an app thread, do the call through that so it is
12171 // correctly ordered with other one-way calls.
12172 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
12173 data, extras, ordered);
12174 } else {
12175 receiver.performReceive(intent, resultCode, data, extras, ordered);
12176 }
12177 }
12178
12179 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12180 BroadcastFilter filter, boolean ordered) {
12181 boolean skip = false;
12182 if (filter.requiredPermission != null) {
12183 int perm = checkComponentPermission(filter.requiredPermission,
12184 r.callingPid, r.callingUid, -1);
12185 if (perm != PackageManager.PERMISSION_GRANTED) {
12186 Log.w(TAG, "Permission Denial: broadcasting "
12187 + r.intent.toString()
12188 + " from " + r.callerPackage + " (pid="
12189 + r.callingPid + ", uid=" + r.callingUid + ")"
12190 + " requires " + filter.requiredPermission
12191 + " due to registered receiver " + filter);
12192 skip = true;
12193 }
12194 }
12195 if (r.requiredPermission != null) {
12196 int perm = checkComponentPermission(r.requiredPermission,
12197 filter.receiverList.pid, filter.receiverList.uid, -1);
12198 if (perm != PackageManager.PERMISSION_GRANTED) {
12199 Log.w(TAG, "Permission Denial: receiving "
12200 + r.intent.toString()
12201 + " to " + filter.receiverList.app
12202 + " (pid=" + filter.receiverList.pid
12203 + ", uid=" + filter.receiverList.uid + ")"
12204 + " requires " + r.requiredPermission
12205 + " due to sender " + r.callerPackage
12206 + " (uid " + r.callingUid + ")");
12207 skip = true;
12208 }
12209 }
12210
12211 if (!skip) {
12212 // If this is not being sent as an ordered broadcast, then we
12213 // don't want to touch the fields that keep track of the current
12214 // state of ordered broadcasts.
12215 if (ordered) {
12216 r.receiver = filter.receiverList.receiver.asBinder();
12217 r.curFilter = filter;
12218 filter.receiverList.curBroadcast = r;
12219 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012220 if (filter.receiverList.app != null) {
12221 // Bump hosting application to no longer be in background
12222 // scheduling class. Note that we can't do that if there
12223 // isn't an app... but we can only be in that case for
12224 // things that directly call the IActivityManager API, which
12225 // are already core system stuff so don't matter for this.
12226 r.curApp = filter.receiverList.app;
12227 filter.receiverList.app.curReceiver = r;
12228 updateOomAdjLocked();
12229 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012230 }
12231 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012232 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012233 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012234 Log.i(TAG, "Delivering to " + filter.receiverList.app
12235 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012236 }
12237 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12238 new Intent(r.intent), r.resultCode,
12239 r.resultData, r.resultExtras, r.ordered);
12240 if (ordered) {
12241 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12242 }
12243 } catch (RemoteException e) {
12244 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12245 if (ordered) {
12246 r.receiver = null;
12247 r.curFilter = null;
12248 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012249 if (filter.receiverList.app != null) {
12250 filter.receiverList.app.curReceiver = null;
12251 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012252 }
12253 }
12254 }
12255 }
12256
12257 private final void processNextBroadcast(boolean fromMsg) {
12258 synchronized(this) {
12259 BroadcastRecord r;
12260
12261 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12262 + mParallelBroadcasts.size() + " broadcasts, "
12263 + mOrderedBroadcasts.size() + " serialized broadcasts");
12264
12265 updateCpuStats();
12266
12267 if (fromMsg) {
12268 mBroadcastsScheduled = false;
12269 }
12270
12271 // First, deliver any non-serialized broadcasts right away.
12272 while (mParallelBroadcasts.size() > 0) {
12273 r = mParallelBroadcasts.remove(0);
12274 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012275 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12276 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012277 for (int i=0; i<N; i++) {
12278 Object target = r.receivers.get(i);
12279 if (DEBUG_BROADCAST) Log.v(TAG,
12280 "Delivering non-serialized to registered "
12281 + target + ": " + r);
12282 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12283 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012284 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12285 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012286 }
12287
12288 // Now take care of the next serialized one...
12289
12290 // If we are waiting for a process to come up to handle the next
12291 // broadcast, then do nothing at this point. Just in case, we
12292 // check that the process we're waiting for still exists.
12293 if (mPendingBroadcast != null) {
12294 Log.i(TAG, "processNextBroadcast: waiting for "
12295 + mPendingBroadcast.curApp);
12296
12297 boolean isDead;
12298 synchronized (mPidsSelfLocked) {
12299 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12300 }
12301 if (!isDead) {
12302 // It's still alive, so keep waiting
12303 return;
12304 } else {
12305 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12306 + " died before responding to broadcast");
12307 mPendingBroadcast = null;
12308 }
12309 }
12310
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012311 boolean looped = false;
12312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012313 do {
12314 if (mOrderedBroadcasts.size() == 0) {
12315 // No more broadcasts pending, so all done!
12316 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012317 if (looped) {
12318 // If we had finished the last ordered broadcast, then
12319 // make sure all processes have correct oom and sched
12320 // adjustments.
12321 updateOomAdjLocked();
12322 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012323 return;
12324 }
12325 r = mOrderedBroadcasts.get(0);
12326 boolean forceReceive = false;
12327
12328 // Ensure that even if something goes awry with the timeout
12329 // detection, we catch "hung" broadcasts here, discard them,
12330 // and continue to make progress.
12331 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12332 long now = SystemClock.uptimeMillis();
12333 if (r.dispatchTime > 0) {
12334 if ((numReceivers > 0) &&
12335 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12336 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12337 + " now=" + now
12338 + " dispatchTime=" + r.dispatchTime
12339 + " startTime=" + r.startTime
12340 + " intent=" + r.intent
12341 + " numReceivers=" + numReceivers
12342 + " nextReceiver=" + r.nextReceiver
12343 + " state=" + r.state);
12344 broadcastTimeout(); // forcibly finish this broadcast
12345 forceReceive = true;
12346 r.state = BroadcastRecord.IDLE;
12347 }
12348 }
12349
12350 if (r.state != BroadcastRecord.IDLE) {
12351 if (DEBUG_BROADCAST) Log.d(TAG,
12352 "processNextBroadcast() called when not idle (state="
12353 + r.state + ")");
12354 return;
12355 }
12356
12357 if (r.receivers == null || r.nextReceiver >= numReceivers
12358 || r.resultAbort || forceReceive) {
12359 // No more receivers for this broadcast! Send the final
12360 // result if requested...
12361 if (r.resultTo != null) {
12362 try {
12363 if (DEBUG_BROADCAST) {
12364 int seq = r.intent.getIntExtra("seq", -1);
12365 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12366 + " seq=" + seq + " app=" + r.callerApp);
12367 }
12368 performReceive(r.callerApp, r.resultTo,
12369 new Intent(r.intent), r.resultCode,
12370 r.resultData, r.resultExtras, false);
12371 } catch (RemoteException e) {
12372 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12373 }
12374 }
12375
12376 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12377 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12378
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012379 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12380 + r);
12381
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012382 // ... and on to the next...
12383 mOrderedBroadcasts.remove(0);
12384 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012385 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012386 continue;
12387 }
12388 } while (r == null);
12389
12390 // Get the next receiver...
12391 int recIdx = r.nextReceiver++;
12392
12393 // Keep track of when this receiver started, and make sure there
12394 // is a timeout message pending to kill it if need be.
12395 r.startTime = SystemClock.uptimeMillis();
12396 if (recIdx == 0) {
12397 r.dispatchTime = r.startTime;
12398
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012399 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12400 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012401 if (DEBUG_BROADCAST) Log.v(TAG,
12402 "Submitting BROADCAST_TIMEOUT_MSG for "
12403 + (r.startTime + BROADCAST_TIMEOUT));
12404 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12405 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12406 }
12407
12408 Object nextReceiver = r.receivers.get(recIdx);
12409 if (nextReceiver instanceof BroadcastFilter) {
12410 // Simple case: this is a registered receiver who gets
12411 // a direct call.
12412 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12413 if (DEBUG_BROADCAST) Log.v(TAG,
12414 "Delivering serialized to registered "
12415 + filter + ": " + r);
12416 deliverToRegisteredReceiver(r, filter, r.ordered);
12417 if (r.receiver == null || !r.ordered) {
12418 // The receiver has already finished, so schedule to
12419 // process the next one.
12420 r.state = BroadcastRecord.IDLE;
12421 scheduleBroadcastsLocked();
12422 }
12423 return;
12424 }
12425
12426 // Hard case: need to instantiate the receiver, possibly
12427 // starting its application process to host it.
12428
12429 ResolveInfo info =
12430 (ResolveInfo)nextReceiver;
12431
12432 boolean skip = false;
12433 int perm = checkComponentPermission(info.activityInfo.permission,
12434 r.callingPid, r.callingUid,
12435 info.activityInfo.exported
12436 ? -1 : info.activityInfo.applicationInfo.uid);
12437 if (perm != PackageManager.PERMISSION_GRANTED) {
12438 Log.w(TAG, "Permission Denial: broadcasting "
12439 + r.intent.toString()
12440 + " from " + r.callerPackage + " (pid=" + r.callingPid
12441 + ", uid=" + r.callingUid + ")"
12442 + " requires " + info.activityInfo.permission
12443 + " due to receiver " + info.activityInfo.packageName
12444 + "/" + info.activityInfo.name);
12445 skip = true;
12446 }
12447 if (r.callingUid != Process.SYSTEM_UID &&
12448 r.requiredPermission != null) {
12449 try {
12450 perm = ActivityThread.getPackageManager().
12451 checkPermission(r.requiredPermission,
12452 info.activityInfo.applicationInfo.packageName);
12453 } catch (RemoteException e) {
12454 perm = PackageManager.PERMISSION_DENIED;
12455 }
12456 if (perm != PackageManager.PERMISSION_GRANTED) {
12457 Log.w(TAG, "Permission Denial: receiving "
12458 + r.intent + " to "
12459 + info.activityInfo.applicationInfo.packageName
12460 + " requires " + r.requiredPermission
12461 + " due to sender " + r.callerPackage
12462 + " (uid " + r.callingUid + ")");
12463 skip = true;
12464 }
12465 }
12466 if (r.curApp != null && r.curApp.crashing) {
12467 // If the target process is crashing, just skip it.
12468 skip = true;
12469 }
12470
12471 if (skip) {
12472 r.receiver = null;
12473 r.curFilter = null;
12474 r.state = BroadcastRecord.IDLE;
12475 scheduleBroadcastsLocked();
12476 return;
12477 }
12478
12479 r.state = BroadcastRecord.APP_RECEIVE;
12480 String targetProcess = info.activityInfo.processName;
12481 r.curComponent = new ComponentName(
12482 info.activityInfo.applicationInfo.packageName,
12483 info.activityInfo.name);
12484 r.curReceiver = info.activityInfo;
12485
12486 // Is this receiver's application already running?
12487 ProcessRecord app = getProcessRecordLocked(targetProcess,
12488 info.activityInfo.applicationInfo.uid);
12489 if (app != null && app.thread != null) {
12490 try {
12491 processCurBroadcastLocked(r, app);
12492 return;
12493 } catch (RemoteException e) {
12494 Log.w(TAG, "Exception when sending broadcast to "
12495 + r.curComponent, e);
12496 }
12497
12498 // If a dead object exception was thrown -- fall through to
12499 // restart the application.
12500 }
12501
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012502 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012503 if ((r.curApp=startProcessLocked(targetProcess,
12504 info.activityInfo.applicationInfo, true,
12505 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012506 "broadcast", r.curComponent,
12507 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12508 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012509 // Ah, this recipient is unavailable. Finish it if necessary,
12510 // and mark the broadcast record as ready for the next.
12511 Log.w(TAG, "Unable to launch app "
12512 + info.activityInfo.applicationInfo.packageName + "/"
12513 + info.activityInfo.applicationInfo.uid + " for broadcast "
12514 + r.intent + ": process is bad");
12515 logBroadcastReceiverDiscard(r);
12516 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12517 r.resultExtras, r.resultAbort, true);
12518 scheduleBroadcastsLocked();
12519 r.state = BroadcastRecord.IDLE;
12520 return;
12521 }
12522
12523 mPendingBroadcast = r;
12524 }
12525 }
12526
12527 // =========================================================
12528 // INSTRUMENTATION
12529 // =========================================================
12530
12531 public boolean startInstrumentation(ComponentName className,
12532 String profileFile, int flags, Bundle arguments,
12533 IInstrumentationWatcher watcher) {
12534 // Refuse possible leaked file descriptors
12535 if (arguments != null && arguments.hasFileDescriptors()) {
12536 throw new IllegalArgumentException("File descriptors passed in Bundle");
12537 }
12538
12539 synchronized(this) {
12540 InstrumentationInfo ii = null;
12541 ApplicationInfo ai = null;
12542 try {
12543 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012544 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012545 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012546 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012547 } catch (PackageManager.NameNotFoundException e) {
12548 }
12549 if (ii == null) {
12550 reportStartInstrumentationFailure(watcher, className,
12551 "Unable to find instrumentation info for: " + className);
12552 return false;
12553 }
12554 if (ai == null) {
12555 reportStartInstrumentationFailure(watcher, className,
12556 "Unable to find instrumentation target package: " + ii.targetPackage);
12557 return false;
12558 }
12559
12560 int match = mContext.getPackageManager().checkSignatures(
12561 ii.targetPackage, ii.packageName);
12562 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12563 String msg = "Permission Denial: starting instrumentation "
12564 + className + " from pid="
12565 + Binder.getCallingPid()
12566 + ", uid=" + Binder.getCallingPid()
12567 + " not allowed because package " + ii.packageName
12568 + " does not have a signature matching the target "
12569 + ii.targetPackage;
12570 reportStartInstrumentationFailure(watcher, className, msg);
12571 throw new SecurityException(msg);
12572 }
12573
12574 final long origId = Binder.clearCallingIdentity();
12575 uninstallPackageLocked(ii.targetPackage, -1, true);
12576 ProcessRecord app = addAppLocked(ai);
12577 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012578 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012579 app.instrumentationProfileFile = profileFile;
12580 app.instrumentationArguments = arguments;
12581 app.instrumentationWatcher = watcher;
12582 app.instrumentationResultClass = className;
12583 Binder.restoreCallingIdentity(origId);
12584 }
12585
12586 return true;
12587 }
12588
12589 /**
12590 * Report errors that occur while attempting to start Instrumentation. Always writes the
12591 * error to the logs, but if somebody is watching, send the report there too. This enables
12592 * the "am" command to report errors with more information.
12593 *
12594 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12595 * @param cn The component name of the instrumentation.
12596 * @param report The error report.
12597 */
12598 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12599 ComponentName cn, String report) {
12600 Log.w(TAG, report);
12601 try {
12602 if (watcher != null) {
12603 Bundle results = new Bundle();
12604 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12605 results.putString("Error", report);
12606 watcher.instrumentationStatus(cn, -1, results);
12607 }
12608 } catch (RemoteException e) {
12609 Log.w(TAG, e);
12610 }
12611 }
12612
12613 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12614 if (app.instrumentationWatcher != null) {
12615 try {
12616 // NOTE: IInstrumentationWatcher *must* be oneway here
12617 app.instrumentationWatcher.instrumentationFinished(
12618 app.instrumentationClass,
12619 resultCode,
12620 results);
12621 } catch (RemoteException e) {
12622 }
12623 }
12624 app.instrumentationWatcher = null;
12625 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012626 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012627 app.instrumentationProfileFile = null;
12628 app.instrumentationArguments = null;
12629
12630 uninstallPackageLocked(app.processName, -1, false);
12631 }
12632
12633 public void finishInstrumentation(IApplicationThread target,
12634 int resultCode, Bundle results) {
12635 // Refuse possible leaked file descriptors
12636 if (results != null && results.hasFileDescriptors()) {
12637 throw new IllegalArgumentException("File descriptors passed in Intent");
12638 }
12639
12640 synchronized(this) {
12641 ProcessRecord app = getRecordForAppLocked(target);
12642 if (app == null) {
12643 Log.w(TAG, "finishInstrumentation: no app for " + target);
12644 return;
12645 }
12646 final long origId = Binder.clearCallingIdentity();
12647 finishInstrumentationLocked(app, resultCode, results);
12648 Binder.restoreCallingIdentity(origId);
12649 }
12650 }
12651
12652 // =========================================================
12653 // CONFIGURATION
12654 // =========================================================
12655
12656 public ConfigurationInfo getDeviceConfigurationInfo() {
12657 ConfigurationInfo config = new ConfigurationInfo();
12658 synchronized (this) {
12659 config.reqTouchScreen = mConfiguration.touchscreen;
12660 config.reqKeyboardType = mConfiguration.keyboard;
12661 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012662 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12663 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012664 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12665 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012666 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12667 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012668 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12669 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012670 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012671 }
12672 return config;
12673 }
12674
12675 public Configuration getConfiguration() {
12676 Configuration ci;
12677 synchronized(this) {
12678 ci = new Configuration(mConfiguration);
12679 }
12680 return ci;
12681 }
12682
12683 public void updateConfiguration(Configuration values) {
12684 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12685 "updateConfiguration()");
12686
12687 synchronized(this) {
12688 if (values == null && mWindowManager != null) {
12689 // sentinel: fetch the current configuration from the window manager
12690 values = mWindowManager.computeNewConfiguration();
12691 }
12692
12693 final long origId = Binder.clearCallingIdentity();
12694 updateConfigurationLocked(values, null);
12695 Binder.restoreCallingIdentity(origId);
12696 }
12697 }
12698
12699 /**
12700 * Do either or both things: (1) change the current configuration, and (2)
12701 * make sure the given activity is running with the (now) current
12702 * configuration. Returns true if the activity has been left running, or
12703 * false if <var>starting</var> is being destroyed to match the new
12704 * configuration.
12705 */
12706 public boolean updateConfigurationLocked(Configuration values,
12707 HistoryRecord starting) {
12708 int changes = 0;
12709
12710 boolean kept = true;
12711
12712 if (values != null) {
12713 Configuration newConfig = new Configuration(mConfiguration);
12714 changes = newConfig.updateFrom(values);
12715 if (changes != 0) {
12716 if (DEBUG_SWITCH) {
12717 Log.i(TAG, "Updating configuration to: " + values);
12718 }
12719
12720 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12721
12722 if (values.locale != null) {
12723 saveLocaleLocked(values.locale,
12724 !values.locale.equals(mConfiguration.locale),
12725 values.userSetLocale);
12726 }
12727
12728 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012729 Log.i(TAG, "Config changed: " + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012730
12731 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12732 msg.obj = new Configuration(mConfiguration);
12733 mHandler.sendMessage(msg);
12734
12735 final int N = mLRUProcesses.size();
12736 for (int i=0; i<N; i++) {
12737 ProcessRecord app = mLRUProcesses.get(i);
12738 try {
12739 if (app.thread != null) {
12740 app.thread.scheduleConfigurationChanged(mConfiguration);
12741 }
12742 } catch (Exception e) {
12743 }
12744 }
12745 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12746 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12747 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012748
12749 AttributeCache ac = AttributeCache.instance();
12750 if (ac != null) {
12751 ac.updateConfiguration(mConfiguration);
12752 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012753 }
12754 }
12755
12756 if (changes != 0 && starting == null) {
12757 // If the configuration changed, and the caller is not already
12758 // in the process of starting an activity, then find the top
12759 // activity to check if its configuration needs to change.
12760 starting = topRunningActivityLocked(null);
12761 }
12762
12763 if (starting != null) {
12764 kept = ensureActivityConfigurationLocked(starting, changes);
12765 if (kept) {
12766 // If this didn't result in the starting activity being
12767 // destroyed, then we need to make sure at this point that all
12768 // other activities are made visible.
12769 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12770 + ", ensuring others are correct.");
12771 ensureActivitiesVisibleLocked(starting, changes);
12772 }
12773 }
12774
12775 return kept;
12776 }
12777
12778 private final boolean relaunchActivityLocked(HistoryRecord r,
12779 int changes, boolean andResume) {
12780 List<ResultInfo> results = null;
12781 List<Intent> newIntents = null;
12782 if (andResume) {
12783 results = r.results;
12784 newIntents = r.newIntents;
12785 }
12786 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12787 + " with results=" + results + " newIntents=" + newIntents
12788 + " andResume=" + andResume);
12789 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12790 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12791 r.task.taskId, r.shortComponentName);
12792
12793 r.startFreezingScreenLocked(r.app, 0);
12794
12795 try {
12796 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12797 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12798 changes, !andResume);
12799 // Note: don't need to call pauseIfSleepingLocked() here, because
12800 // the caller will only pass in 'andResume' if this activity is
12801 // currently resumed, which implies we aren't sleeping.
12802 } catch (RemoteException e) {
12803 return false;
12804 }
12805
12806 if (andResume) {
12807 r.results = null;
12808 r.newIntents = null;
12809 }
12810
12811 return true;
12812 }
12813
12814 /**
12815 * Make sure the given activity matches the current configuration. Returns
12816 * false if the activity had to be destroyed. Returns true if the
12817 * configuration is the same, or the activity will remain running as-is
12818 * for whatever reason. Ensures the HistoryRecord is updated with the
12819 * correct configuration and all other bookkeeping is handled.
12820 */
12821 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12822 int globalChanges) {
12823 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12824
12825 // Short circuit: if the two configurations are the exact same
12826 // object (the common case), then there is nothing to do.
12827 Configuration newConfig = mConfiguration;
12828 if (r.configuration == newConfig) {
12829 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12830 return true;
12831 }
12832
12833 // We don't worry about activities that are finishing.
12834 if (r.finishing) {
12835 if (DEBUG_SWITCH) Log.i(TAG,
12836 "Configuration doesn't matter in finishing " + r);
12837 r.stopFreezingScreenLocked(false);
12838 return true;
12839 }
12840
12841 // Okay we now are going to make this activity have the new config.
12842 // But then we need to figure out how it needs to deal with that.
12843 Configuration oldConfig = r.configuration;
12844 r.configuration = newConfig;
12845
12846 // If the activity isn't currently running, just leave the new
12847 // configuration and it will pick that up next time it starts.
12848 if (r.app == null || r.app.thread == null) {
12849 if (DEBUG_SWITCH) Log.i(TAG,
12850 "Configuration doesn't matter not running " + r);
12851 r.stopFreezingScreenLocked(false);
12852 return true;
12853 }
12854
12855 // If the activity isn't persistent, there is a chance we will
12856 // need to restart it.
12857 if (!r.persistent) {
12858
12859 // Figure out what has changed between the two configurations.
12860 int changes = oldConfig.diff(newConfig);
12861 if (DEBUG_SWITCH) {
12862 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12863 + Integer.toHexString(changes) + ", handles=0x"
12864 + Integer.toHexString(r.info.configChanges));
12865 }
12866 if ((changes&(~r.info.configChanges)) != 0) {
12867 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12868 r.configChangeFlags |= changes;
12869 r.startFreezingScreenLocked(r.app, globalChanges);
12870 if (r.app == null || r.app.thread == null) {
12871 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12872 destroyActivityLocked(r, true);
12873 } else if (r.state == ActivityState.PAUSING) {
12874 // A little annoying: we are waiting for this activity to
12875 // finish pausing. Let's not do anything now, but just
12876 // flag that it needs to be restarted when done pausing.
12877 r.configDestroy = true;
12878 return true;
12879 } else if (r.state == ActivityState.RESUMED) {
12880 // Try to optimize this case: the configuration is changing
12881 // and we need to restart the top, resumed activity.
12882 // Instead of doing the normal handshaking, just say
12883 // "restart!".
12884 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12885 relaunchActivityLocked(r, r.configChangeFlags, true);
12886 r.configChangeFlags = 0;
12887 } else {
12888 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12889 relaunchActivityLocked(r, r.configChangeFlags, false);
12890 r.configChangeFlags = 0;
12891 }
12892
12893 // All done... tell the caller we weren't able to keep this
12894 // activity around.
12895 return false;
12896 }
12897 }
12898
12899 // Default case: the activity can handle this new configuration, so
12900 // hand it over. Note that we don't need to give it the new
12901 // configuration, since we always send configuration changes to all
12902 // process when they happen so it can just use whatever configuration
12903 // it last got.
12904 if (r.app != null && r.app.thread != null) {
12905 try {
12906 r.app.thread.scheduleActivityConfigurationChanged(r);
12907 } catch (RemoteException e) {
12908 // If process died, whatever.
12909 }
12910 }
12911 r.stopFreezingScreenLocked(false);
12912
12913 return true;
12914 }
12915
12916 /**
12917 * Save the locale. You must be inside a synchronized (this) block.
12918 */
12919 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12920 if(isDiff) {
12921 SystemProperties.set("user.language", l.getLanguage());
12922 SystemProperties.set("user.region", l.getCountry());
12923 }
12924
12925 if(isPersist) {
12926 SystemProperties.set("persist.sys.language", l.getLanguage());
12927 SystemProperties.set("persist.sys.country", l.getCountry());
12928 SystemProperties.set("persist.sys.localevar", l.getVariant());
12929 }
12930 }
12931
12932 // =========================================================
12933 // LIFETIME MANAGEMENT
12934 // =========================================================
12935
12936 private final int computeOomAdjLocked(
12937 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12938 if (mAdjSeq == app.adjSeq) {
12939 // This adjustment has already been computed.
12940 return app.curAdj;
12941 }
12942
12943 if (app.thread == null) {
12944 app.adjSeq = mAdjSeq;
12945 return (app.curAdj=EMPTY_APP_ADJ);
12946 }
12947
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012948 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
12949 // The max adjustment doesn't allow this app to be anything
12950 // below foreground, so it is not worth doing work for it.
12951 app.adjType = "fixed";
12952 app.adjSeq = mAdjSeq;
12953 app.curRawAdj = app.maxAdj;
12954 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
12955 return (app.curAdj=app.maxAdj);
12956 }
12957
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070012958 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012959 app.adjSource = null;
12960 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012961
The Android Open Source Project4df24232009-03-05 14:34:35 -080012962 // Determine the importance of the process, starting with most
12963 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012964 int adj;
12965 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012966 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012967 // The last app on the list is the foreground app.
12968 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012969 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012970 } else if (app.instrumentationClass != null) {
12971 // Don't want to kill running instrumentation.
12972 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012973 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012974 } else if (app.persistentActivities > 0) {
12975 // Special persistent activities... shouldn't be used these days.
12976 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012977 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012978 } else if (app.curReceiver != null ||
12979 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12980 // An app that is currently receiving a broadcast also
12981 // counts as being in the foreground.
12982 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012983 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012984 } else if (app.executingServices.size() > 0) {
12985 // An app that is currently executing a service callback also
12986 // counts as being in the foreground.
12987 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012988 app.adjType = "exec-service";
12989 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012990 // The user is aware of this app, so make it visible.
12991 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012992 app.adjType = "foreground-service";
12993 } else if (app.forcingToForeground != null) {
12994 // The user is aware of this app, so make it visible.
12995 adj = VISIBLE_APP_ADJ;
12996 app.adjType = "force-foreground";
12997 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012998 } else if (app == mHomeProcess) {
12999 // This process is hosting what we currently consider to be the
13000 // home app, so we don't want to let it go into the background.
13001 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013002 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013003 } else if ((N=app.activities.size()) != 0) {
13004 // This app is in the background with paused activities.
13005 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013006 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013007 for (int j=0; j<N; j++) {
13008 if (((HistoryRecord)app.activities.get(j)).visible) {
13009 // This app has a visible activity!
13010 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013011 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013012 break;
13013 }
13014 }
13015 } else {
13016 // A very not-needed process.
13017 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013018 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013019 }
13020
The Android Open Source Project4df24232009-03-05 14:34:35 -080013021 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013022 // there are applications dependent on our services or providers, but
13023 // this gives us a baseline and makes sure we don't get into an
13024 // infinite recursion.
13025 app.adjSeq = mAdjSeq;
13026 app.curRawAdj = adj;
13027 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
13028
Christopher Tate6fa95972009-06-05 18:43:55 -070013029 if (mBackupTarget != null && app == mBackupTarget.app) {
13030 // If possible we want to avoid killing apps while they're being backed up
13031 if (adj > BACKUP_APP_ADJ) {
13032 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13033 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013034 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070013035 }
13036 }
13037
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013038 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013039 final long now = SystemClock.uptimeMillis();
13040 // This process is more important if the top activity is
13041 // bound to the service.
13042 Iterator jt = app.services.iterator();
13043 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13044 ServiceRecord s = (ServiceRecord)jt.next();
13045 if (s.startRequested) {
13046 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13047 // This service has seen some activity within
13048 // recent memory, so we will keep its process ahead
13049 // of the background processes.
13050 if (adj > SECONDARY_SERVER_ADJ) {
13051 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013052 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013053 }
13054 }
13055 }
13056 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
13057 Iterator<ConnectionRecord> kt
13058 = s.connections.values().iterator();
13059 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13060 // XXX should compute this based on the max of
13061 // all connected clients.
13062 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013063 if (cr.binding.client == app) {
13064 // Binding to ourself is not interesting.
13065 continue;
13066 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013067 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13068 ProcessRecord client = cr.binding.client;
13069 int myHiddenAdj = hiddenAdj;
13070 if (myHiddenAdj > client.hiddenAdj) {
13071 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13072 myHiddenAdj = client.hiddenAdj;
13073 } else {
13074 myHiddenAdj = VISIBLE_APP_ADJ;
13075 }
13076 }
13077 int clientAdj = computeOomAdjLocked(
13078 client, myHiddenAdj, TOP_APP);
13079 if (adj > clientAdj) {
13080 adj = clientAdj > VISIBLE_APP_ADJ
13081 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013082 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013083 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13084 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013085 app.adjSource = cr.binding.client;
13086 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013087 }
13088 }
13089 HistoryRecord a = cr.activity;
13090 //if (a != null) {
13091 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13092 //}
13093 if (a != null && adj > FOREGROUND_APP_ADJ &&
13094 (a.state == ActivityState.RESUMED
13095 || a.state == ActivityState.PAUSING)) {
13096 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013097 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013098 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13099 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013100 app.adjSource = a;
13101 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013102 }
13103 }
13104 }
13105 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013106
13107 // Finally, f this process has active services running in it, we
13108 // would like to avoid killing it unless it would prevent the current
13109 // application from running. By default we put the process in
13110 // with the rest of the background processes; as we scan through
13111 // its services we may bump it up from there.
13112 if (adj > hiddenAdj) {
13113 adj = hiddenAdj;
13114 app.adjType = "bg-services";
13115 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013116 }
13117
13118 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013119 Iterator jt = app.pubProviders.values().iterator();
13120 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13121 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13122 if (cpr.clients.size() != 0) {
13123 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13124 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13125 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013126 if (client == app) {
13127 // Being our own client is not interesting.
13128 continue;
13129 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013130 int myHiddenAdj = hiddenAdj;
13131 if (myHiddenAdj > client.hiddenAdj) {
13132 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13133 myHiddenAdj = client.hiddenAdj;
13134 } else {
13135 myHiddenAdj = FOREGROUND_APP_ADJ;
13136 }
13137 }
13138 int clientAdj = computeOomAdjLocked(
13139 client, myHiddenAdj, TOP_APP);
13140 if (adj > clientAdj) {
13141 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013142 ? clientAdj : FOREGROUND_APP_ADJ;
13143 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013144 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13145 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013146 app.adjSource = client;
13147 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013148 }
13149 }
13150 }
13151 // If the provider has external (non-framework) process
13152 // dependencies, ensure that its adjustment is at least
13153 // FOREGROUND_APP_ADJ.
13154 if (cpr.externals != 0) {
13155 if (adj > FOREGROUND_APP_ADJ) {
13156 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013157 app.adjType = "provider";
13158 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013159 }
13160 }
13161 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013162
13163 // Finally, if this process has published any content providers,
13164 // then its adjustment makes it at least as important as any of the
13165 // processes using those providers, and no less important than
13166 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
13167 if (adj > CONTENT_PROVIDER_ADJ) {
13168 adj = CONTENT_PROVIDER_ADJ;
13169 app.adjType = "pub-providers";
13170 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013171 }
13172
13173 app.curRawAdj = adj;
13174
13175 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13176 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13177 if (adj > app.maxAdj) {
13178 adj = app.maxAdj;
13179 }
13180
13181 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013182 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013183 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
13184 : Process.THREAD_GROUP_DEFAULT;
13185
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013186 return adj;
13187 }
13188
13189 /**
13190 * Ask a given process to GC right now.
13191 */
13192 final void performAppGcLocked(ProcessRecord app) {
13193 try {
13194 app.lastRequestedGc = SystemClock.uptimeMillis();
13195 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013196 if (app.reportLowMemory) {
13197 app.reportLowMemory = false;
13198 app.thread.scheduleLowMemory();
13199 } else {
13200 app.thread.processInBackground();
13201 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013202 }
13203 } catch (Exception e) {
13204 // whatever.
13205 }
13206 }
13207
13208 /**
13209 * Returns true if things are idle enough to perform GCs.
13210 */
13211 private final boolean canGcNow() {
13212 return mParallelBroadcasts.size() == 0
13213 && mOrderedBroadcasts.size() == 0
13214 && (mSleeping || (mResumedActivity != null &&
13215 mResumedActivity.idle));
13216 }
13217
13218 /**
13219 * Perform GCs on all processes that are waiting for it, but only
13220 * if things are idle.
13221 */
13222 final void performAppGcsLocked() {
13223 final int N = mProcessesToGc.size();
13224 if (N <= 0) {
13225 return;
13226 }
13227 if (canGcNow()) {
13228 while (mProcessesToGc.size() > 0) {
13229 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013230 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13231 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13232 <= SystemClock.uptimeMillis()) {
13233 // To avoid spamming the system, we will GC processes one
13234 // at a time, waiting a few seconds between each.
13235 performAppGcLocked(proc);
13236 scheduleAppGcsLocked();
13237 return;
13238 } else {
13239 // It hasn't been long enough since we last GCed this
13240 // process... put it in the list to wait for its time.
13241 addProcessToGcListLocked(proc);
13242 break;
13243 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013244 }
13245 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013246
13247 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013248 }
13249 }
13250
13251 /**
13252 * If all looks good, perform GCs on all processes waiting for them.
13253 */
13254 final void performAppGcsIfAppropriateLocked() {
13255 if (canGcNow()) {
13256 performAppGcsLocked();
13257 return;
13258 }
13259 // Still not idle, wait some more.
13260 scheduleAppGcsLocked();
13261 }
13262
13263 /**
13264 * Schedule the execution of all pending app GCs.
13265 */
13266 final void scheduleAppGcsLocked() {
13267 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013268
13269 if (mProcessesToGc.size() > 0) {
13270 // Schedule a GC for the time to the next process.
13271 ProcessRecord proc = mProcessesToGc.get(0);
13272 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13273
13274 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13275 long now = SystemClock.uptimeMillis();
13276 if (when < (now+GC_TIMEOUT)) {
13277 when = now + GC_TIMEOUT;
13278 }
13279 mHandler.sendMessageAtTime(msg, when);
13280 }
13281 }
13282
13283 /**
13284 * Add a process to the array of processes waiting to be GCed. Keeps the
13285 * list in sorted order by the last GC time. The process can't already be
13286 * on the list.
13287 */
13288 final void addProcessToGcListLocked(ProcessRecord proc) {
13289 boolean added = false;
13290 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13291 if (mProcessesToGc.get(i).lastRequestedGc <
13292 proc.lastRequestedGc) {
13293 added = true;
13294 mProcessesToGc.add(i+1, proc);
13295 break;
13296 }
13297 }
13298 if (!added) {
13299 mProcessesToGc.add(0, proc);
13300 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013301 }
13302
13303 /**
13304 * Set up to ask a process to GC itself. This will either do it
13305 * immediately, or put it on the list of processes to gc the next
13306 * time things are idle.
13307 */
13308 final void scheduleAppGcLocked(ProcessRecord app) {
13309 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013310 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013311 return;
13312 }
13313 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013314 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013315 scheduleAppGcsLocked();
13316 }
13317 }
13318
13319 private final boolean updateOomAdjLocked(
13320 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13321 app.hiddenAdj = hiddenAdj;
13322
13323 if (app.thread == null) {
13324 return true;
13325 }
13326
13327 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
13328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013329 if (app.pid != 0 && app.pid != MY_PID) {
13330 if (app.curRawAdj != app.setRawAdj) {
13331 if (app.curRawAdj > FOREGROUND_APP_ADJ
13332 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13333 // If this app is transitioning from foreground to
13334 // non-foreground, have it do a gc.
13335 scheduleAppGcLocked(app);
13336 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13337 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13338 // Likewise do a gc when an app is moving in to the
13339 // background (such as a service stopping).
13340 scheduleAppGcLocked(app);
13341 }
13342 app.setRawAdj = app.curRawAdj;
13343 }
13344 if (adj != app.setAdj) {
13345 if (Process.setOomAdj(app.pid, adj)) {
13346 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13347 TAG, "Set app " + app.processName +
13348 " oom adj to " + adj);
13349 app.setAdj = adj;
13350 } else {
13351 return false;
13352 }
13353 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013354 if (app.setSchedGroup != app.curSchedGroup) {
13355 app.setSchedGroup = app.curSchedGroup;
13356 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13357 "Setting process group of " + app.processName
13358 + " to " + app.curSchedGroup);
13359 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013360 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013361 try {
13362 Process.setProcessGroup(app.pid, app.curSchedGroup);
13363 } catch (Exception e) {
13364 Log.w(TAG, "Failed setting process group of " + app.pid
13365 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013366 e.printStackTrace();
13367 } finally {
13368 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013369 }
13370 }
13371 if (false) {
13372 if (app.thread != null) {
13373 try {
13374 app.thread.setSchedulingGroup(app.curSchedGroup);
13375 } catch (RemoteException e) {
13376 }
13377 }
13378 }
13379 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013380 }
13381
13382 return true;
13383 }
13384
13385 private final HistoryRecord resumedAppLocked() {
13386 HistoryRecord resumedActivity = mResumedActivity;
13387 if (resumedActivity == null || resumedActivity.app == null) {
13388 resumedActivity = mPausingActivity;
13389 if (resumedActivity == null || resumedActivity.app == null) {
13390 resumedActivity = topRunningActivityLocked(null);
13391 }
13392 }
13393 return resumedActivity;
13394 }
13395
13396 private final boolean updateOomAdjLocked(ProcessRecord app) {
13397 final HistoryRecord TOP_ACT = resumedAppLocked();
13398 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13399 int curAdj = app.curAdj;
13400 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13401 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13402
13403 mAdjSeq++;
13404
13405 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13406 if (res) {
13407 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13408 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13409 if (nowHidden != wasHidden) {
13410 // Changed to/from hidden state, so apps after it in the LRU
13411 // list may also be changed.
13412 updateOomAdjLocked();
13413 }
13414 }
13415 return res;
13416 }
13417
13418 private final boolean updateOomAdjLocked() {
13419 boolean didOomAdj = true;
13420 final HistoryRecord TOP_ACT = resumedAppLocked();
13421 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13422
13423 if (false) {
13424 RuntimeException e = new RuntimeException();
13425 e.fillInStackTrace();
13426 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13427 }
13428
13429 mAdjSeq++;
13430
13431 // First try updating the OOM adjustment for each of the
13432 // application processes based on their current state.
13433 int i = mLRUProcesses.size();
13434 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13435 while (i > 0) {
13436 i--;
13437 ProcessRecord app = mLRUProcesses.get(i);
13438 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13439 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13440 && app.curAdj == curHiddenAdj) {
13441 curHiddenAdj++;
13442 }
13443 } else {
13444 didOomAdj = false;
13445 }
13446 }
13447
13448 // todo: for now pretend like OOM ADJ didn't work, because things
13449 // aren't behaving as expected on Linux -- it's not killing processes.
13450 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13451 }
13452
13453 private final void trimApplications() {
13454 synchronized (this) {
13455 int i;
13456
13457 // First remove any unused application processes whose package
13458 // has been removed.
13459 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13460 final ProcessRecord app = mRemovedProcesses.get(i);
13461 if (app.activities.size() == 0
13462 && app.curReceiver == null && app.services.size() == 0) {
13463 Log.i(
13464 TAG, "Exiting empty application process "
13465 + app.processName + " ("
13466 + (app.thread != null ? app.thread.asBinder() : null)
13467 + ")\n");
13468 if (app.pid > 0 && app.pid != MY_PID) {
13469 Process.killProcess(app.pid);
13470 } else {
13471 try {
13472 app.thread.scheduleExit();
13473 } catch (Exception e) {
13474 // Ignore exceptions.
13475 }
13476 }
13477 cleanUpApplicationRecordLocked(app, false, -1);
13478 mRemovedProcesses.remove(i);
13479
13480 if (app.persistent) {
13481 if (app.persistent) {
13482 addAppLocked(app.info);
13483 }
13484 }
13485 }
13486 }
13487
13488 // Now try updating the OOM adjustment for each of the
13489 // application processes based on their current state.
13490 // If the setOomAdj() API is not supported, then go with our
13491 // back-up plan...
13492 if (!updateOomAdjLocked()) {
13493
13494 // Count how many processes are running services.
13495 int numServiceProcs = 0;
13496 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13497 final ProcessRecord app = mLRUProcesses.get(i);
13498
13499 if (app.persistent || app.services.size() != 0
13500 || app.curReceiver != null
13501 || app.persistentActivities > 0) {
13502 // Don't count processes holding services against our
13503 // maximum process count.
13504 if (localLOGV) Log.v(
13505 TAG, "Not trimming app " + app + " with services: "
13506 + app.services);
13507 numServiceProcs++;
13508 }
13509 }
13510
13511 int curMaxProcs = mProcessLimit;
13512 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13513 if (mAlwaysFinishActivities) {
13514 curMaxProcs = 1;
13515 }
13516 curMaxProcs += numServiceProcs;
13517
13518 // Quit as many processes as we can to get down to the desired
13519 // process count. First remove any processes that no longer
13520 // have activites running in them.
13521 for ( i=0;
13522 i<mLRUProcesses.size()
13523 && mLRUProcesses.size() > curMaxProcs;
13524 i++) {
13525 final ProcessRecord app = mLRUProcesses.get(i);
13526 // Quit an application only if it is not currently
13527 // running any activities.
13528 if (!app.persistent && app.activities.size() == 0
13529 && app.curReceiver == null && app.services.size() == 0) {
13530 Log.i(
13531 TAG, "Exiting empty application process "
13532 + app.processName + " ("
13533 + (app.thread != null ? app.thread.asBinder() : null)
13534 + ")\n");
13535 if (app.pid > 0 && app.pid != MY_PID) {
13536 Process.killProcess(app.pid);
13537 } else {
13538 try {
13539 app.thread.scheduleExit();
13540 } catch (Exception e) {
13541 // Ignore exceptions.
13542 }
13543 }
13544 // todo: For now we assume the application is not buggy
13545 // or evil, and will quit as a result of our request.
13546 // Eventually we need to drive this off of the death
13547 // notification, and kill the process if it takes too long.
13548 cleanUpApplicationRecordLocked(app, false, i);
13549 i--;
13550 }
13551 }
13552
13553 // If we still have too many processes, now from the least
13554 // recently used process we start finishing activities.
13555 if (Config.LOGV) Log.v(
13556 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13557 " of " + curMaxProcs + " processes");
13558 for ( i=0;
13559 i<mLRUProcesses.size()
13560 && mLRUProcesses.size() > curMaxProcs;
13561 i++) {
13562 final ProcessRecord app = mLRUProcesses.get(i);
13563 // Quit the application only if we have a state saved for
13564 // all of its activities.
13565 boolean canQuit = !app.persistent && app.curReceiver == null
13566 && app.services.size() == 0
13567 && app.persistentActivities == 0;
13568 int NUMA = app.activities.size();
13569 int j;
13570 if (Config.LOGV) Log.v(
13571 TAG, "Looking to quit " + app.processName);
13572 for (j=0; j<NUMA && canQuit; j++) {
13573 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13574 if (Config.LOGV) Log.v(
13575 TAG, " " + r.intent.getComponent().flattenToShortString()
13576 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13577 canQuit = (r.haveState || !r.stateNotNeeded)
13578 && !r.visible && r.stopped;
13579 }
13580 if (canQuit) {
13581 // Finish all of the activities, and then the app itself.
13582 for (j=0; j<NUMA; j++) {
13583 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13584 if (!r.finishing) {
13585 destroyActivityLocked(r, false);
13586 }
13587 r.resultTo = null;
13588 }
13589 Log.i(TAG, "Exiting application process "
13590 + app.processName + " ("
13591 + (app.thread != null ? app.thread.asBinder() : null)
13592 + ")\n");
13593 if (app.pid > 0 && app.pid != MY_PID) {
13594 Process.killProcess(app.pid);
13595 } else {
13596 try {
13597 app.thread.scheduleExit();
13598 } catch (Exception e) {
13599 // Ignore exceptions.
13600 }
13601 }
13602 // todo: For now we assume the application is not buggy
13603 // or evil, and will quit as a result of our request.
13604 // Eventually we need to drive this off of the death
13605 // notification, and kill the process if it takes too long.
13606 cleanUpApplicationRecordLocked(app, false, i);
13607 i--;
13608 //dump();
13609 }
13610 }
13611
13612 }
13613
13614 int curMaxActivities = MAX_ACTIVITIES;
13615 if (mAlwaysFinishActivities) {
13616 curMaxActivities = 1;
13617 }
13618
13619 // Finally, if there are too many activities now running, try to
13620 // finish as many as we can to get back down to the limit.
13621 for ( i=0;
13622 i<mLRUActivities.size()
13623 && mLRUActivities.size() > curMaxActivities;
13624 i++) {
13625 final HistoryRecord r
13626 = (HistoryRecord)mLRUActivities.get(i);
13627
13628 // We can finish this one if we have its icicle saved and
13629 // it is not persistent.
13630 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13631 && r.stopped && !r.persistent && !r.finishing) {
13632 final int origSize = mLRUActivities.size();
13633 destroyActivityLocked(r, true);
13634
13635 // This will remove it from the LRU list, so keep
13636 // our index at the same value. Note that this check to
13637 // see if the size changes is just paranoia -- if
13638 // something unexpected happens, we don't want to end up
13639 // in an infinite loop.
13640 if (origSize > mLRUActivities.size()) {
13641 i--;
13642 }
13643 }
13644 }
13645 }
13646 }
13647
13648 /** This method sends the specified signal to each of the persistent apps */
13649 public void signalPersistentProcesses(int sig) throws RemoteException {
13650 if (sig != Process.SIGNAL_USR1) {
13651 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13652 }
13653
13654 synchronized (this) {
13655 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13656 != PackageManager.PERMISSION_GRANTED) {
13657 throw new SecurityException("Requires permission "
13658 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13659 }
13660
13661 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13662 ProcessRecord r = mLRUProcesses.get(i);
13663 if (r.thread != null && r.persistent) {
13664 Process.sendSignal(r.pid, sig);
13665 }
13666 }
13667 }
13668 }
13669
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013670 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013671 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013672
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013673 try {
13674 synchronized (this) {
13675 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13676 // its own permission.
13677 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13678 != PackageManager.PERMISSION_GRANTED) {
13679 throw new SecurityException("Requires permission "
13680 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013681 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013682
13683 if (start && fd == null) {
13684 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013685 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013686
13687 ProcessRecord proc = null;
13688 try {
13689 int pid = Integer.parseInt(process);
13690 synchronized (mPidsSelfLocked) {
13691 proc = mPidsSelfLocked.get(pid);
13692 }
13693 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013694 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013695
13696 if (proc == null) {
13697 HashMap<String, SparseArray<ProcessRecord>> all
13698 = mProcessNames.getMap();
13699 SparseArray<ProcessRecord> procs = all.get(process);
13700 if (procs != null && procs.size() > 0) {
13701 proc = procs.valueAt(0);
13702 }
13703 }
13704
13705 if (proc == null || proc.thread == null) {
13706 throw new IllegalArgumentException("Unknown process: " + process);
13707 }
13708
13709 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13710 if (isSecure) {
13711 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13712 throw new SecurityException("Process not debuggable: " + proc);
13713 }
13714 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013715
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013716 proc.thread.profilerControl(start, path, fd);
13717 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013718 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013719 }
13720 } catch (RemoteException e) {
13721 throw new IllegalStateException("Process disappeared");
13722 } finally {
13723 if (fd != null) {
13724 try {
13725 fd.close();
13726 } catch (IOException e) {
13727 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013728 }
13729 }
13730 }
13731
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013732 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13733 public void monitor() {
13734 synchronized (this) { }
13735 }
13736}