blob: 82664eba49b42d71bedc4a1760ffc3ecbc52abbb [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);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001224 synchronized (mSelf) {
1225 ProcessRecord app = mSelf.newProcessRecordLocked(
1226 mSystemThread.getApplicationThread(), info,
1227 info.processName);
1228 app.persistent = true;
1229 app.pid = Process.myPid();
1230 app.maxAdj = SYSTEM_ADJ;
1231 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1232 synchronized (mSelf.mPidsSelfLocked) {
1233 mSelf.mPidsSelfLocked.put(app.pid, app);
1234 }
1235 mSelf.updateLRUListLocked(app, true);
1236 }
1237 } catch (PackageManager.NameNotFoundException e) {
1238 throw new RuntimeException(
1239 "Unable to find android system package", e);
1240 }
1241 }
1242
1243 public void setWindowManager(WindowManagerService wm) {
1244 mWindowManager = wm;
1245 }
1246
1247 public static final Context main(int factoryTest) {
1248 AThread thr = new AThread();
1249 thr.start();
1250
1251 synchronized (thr) {
1252 while (thr.mService == null) {
1253 try {
1254 thr.wait();
1255 } catch (InterruptedException e) {
1256 }
1257 }
1258 }
1259
1260 ActivityManagerService m = thr.mService;
1261 mSelf = m;
1262 ActivityThread at = ActivityThread.systemMain();
1263 mSystemThread = at;
1264 Context context = at.getSystemContext();
1265 m.mContext = context;
1266 m.mFactoryTest = factoryTest;
1267 PowerManager pm =
1268 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1269 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1270 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1271 m.mLaunchingActivity.setReferenceCounted(false);
1272
1273 m.mBatteryStatsService.publish(context);
1274 m.mUsageStatsService.publish(context);
1275
1276 synchronized (thr) {
1277 thr.mReady = true;
1278 thr.notifyAll();
1279 }
1280
1281 m.startRunning(null, null, null, null);
1282
1283 return context;
1284 }
1285
1286 public static ActivityManagerService self() {
1287 return mSelf;
1288 }
1289
1290 static class AThread extends Thread {
1291 ActivityManagerService mService;
1292 boolean mReady = false;
1293
1294 public AThread() {
1295 super("ActivityManager");
1296 }
1297
1298 public void run() {
1299 Looper.prepare();
1300
1301 android.os.Process.setThreadPriority(
1302 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1303
1304 ActivityManagerService m = new ActivityManagerService();
1305
1306 synchronized (this) {
1307 mService = m;
1308 notifyAll();
1309 }
1310
1311 synchronized (this) {
1312 while (!mReady) {
1313 try {
1314 wait();
1315 } catch (InterruptedException e) {
1316 }
1317 }
1318 }
1319
1320 Looper.loop();
1321 }
1322 }
1323
1324 static class BroadcastsBinder extends Binder {
1325 ActivityManagerService mActivityManagerService;
1326 BroadcastsBinder(ActivityManagerService activityManagerService) {
1327 mActivityManagerService = activityManagerService;
1328 }
1329
1330 @Override
1331 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1332 mActivityManagerService.dumpBroadcasts(pw);
1333 }
1334 }
1335
1336 static class ServicesBinder extends Binder {
1337 ActivityManagerService mActivityManagerService;
1338 ServicesBinder(ActivityManagerService activityManagerService) {
1339 mActivityManagerService = activityManagerService;
1340 }
1341
1342 @Override
1343 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1344 mActivityManagerService.dumpServices(pw);
1345 }
1346 }
1347
1348 static class SendersBinder extends Binder {
1349 ActivityManagerService mActivityManagerService;
1350 SendersBinder(ActivityManagerService activityManagerService) {
1351 mActivityManagerService = activityManagerService;
1352 }
1353
1354 @Override
1355 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1356 mActivityManagerService.dumpSenders(pw);
1357 }
1358 }
1359
1360 static class ProvidersBinder extends Binder {
1361 ActivityManagerService mActivityManagerService;
1362 ProvidersBinder(ActivityManagerService activityManagerService) {
1363 mActivityManagerService = activityManagerService;
1364 }
1365
1366 @Override
1367 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1368 mActivityManagerService.dumpProviders(pw);
1369 }
1370 }
1371
1372 static class MemBinder extends Binder {
1373 ActivityManagerService mActivityManagerService;
1374 MemBinder(ActivityManagerService activityManagerService) {
1375 mActivityManagerService = activityManagerService;
1376 }
1377
1378 @Override
1379 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1380 ActivityManagerService service = mActivityManagerService;
1381 ArrayList<ProcessRecord> procs;
1382 synchronized (mActivityManagerService) {
1383 if (args != null && args.length > 0
1384 && args[0].charAt(0) != '-') {
1385 procs = new ArrayList<ProcessRecord>();
1386 int pid = -1;
1387 try {
1388 pid = Integer.parseInt(args[0]);
1389 } catch (NumberFormatException e) {
1390
1391 }
1392 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1393 ProcessRecord proc = service.mLRUProcesses.get(i);
1394 if (proc.pid == pid) {
1395 procs.add(proc);
1396 } else if (proc.processName.equals(args[0])) {
1397 procs.add(proc);
1398 }
1399 }
1400 if (procs.size() <= 0) {
1401 pw.println("No process found for: " + args[0]);
1402 return;
1403 }
1404 } else {
1405 procs = service.mLRUProcesses;
1406 }
1407 }
1408 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1409 }
1410 }
1411
1412 static class CpuBinder extends Binder {
1413 ActivityManagerService mActivityManagerService;
1414 CpuBinder(ActivityManagerService activityManagerService) {
1415 mActivityManagerService = activityManagerService;
1416 }
1417
1418 @Override
1419 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1420 synchronized (mActivityManagerService.mProcessStatsThread) {
1421 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1422 }
1423 }
1424 }
1425
1426 private ActivityManagerService() {
1427 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1428 if (v != null && Integer.getInteger(v) != 0) {
1429 mSimpleProcessManagement = true;
1430 }
1431 v = System.getenv("ANDROID_DEBUG_APP");
1432 if (v != null) {
1433 mSimpleProcessManagement = true;
1434 }
1435
1436 MY_PID = Process.myPid();
1437
1438 File dataDir = Environment.getDataDirectory();
1439 File systemDir = new File(dataDir, "system");
1440 systemDir.mkdirs();
1441 mBatteryStatsService = new BatteryStatsService(new File(
1442 systemDir, "batterystats.bin").toString());
1443 mBatteryStatsService.getActiveStatistics().readLocked();
1444 mBatteryStatsService.getActiveStatistics().writeLocked();
1445
1446 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001447 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448
Jack Palevichb90d28c2009-07-22 15:35:24 -07001449 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1450 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001452 mConfiguration.makeDefault();
1453 mProcessStats.init();
1454
1455 // Add ourself to the Watchdog monitors.
1456 Watchdog.getInstance().addMonitor(this);
1457
1458 // These values are set in system/rootdir/init.rc on startup.
1459 FOREGROUND_APP_ADJ =
1460 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1461 VISIBLE_APP_ADJ =
1462 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1463 SECONDARY_SERVER_ADJ =
1464 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001465 BACKUP_APP_ADJ =
1466 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001467 HOME_APP_ADJ =
1468 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001469 HIDDEN_APP_MIN_ADJ =
1470 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1471 CONTENT_PROVIDER_ADJ =
1472 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1473 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1474 EMPTY_APP_ADJ =
1475 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1476 FOREGROUND_APP_MEM =
1477 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1478 VISIBLE_APP_MEM =
1479 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1480 SECONDARY_SERVER_MEM =
1481 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001482 BACKUP_APP_MEM =
1483 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001484 HOME_APP_MEM =
1485 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486 HIDDEN_APP_MEM =
1487 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1488 EMPTY_APP_MEM =
1489 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1490
1491 mProcessStatsThread = new Thread("ProcessStats") {
1492 public void run() {
1493 while (true) {
1494 try {
1495 try {
1496 synchronized(this) {
1497 final long now = SystemClock.uptimeMillis();
1498 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1499 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1500 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1501 // + ", write delay=" + nextWriteDelay);
1502 if (nextWriteDelay < nextCpuDelay) {
1503 nextCpuDelay = nextWriteDelay;
1504 }
1505 if (nextCpuDelay > 0) {
1506 this.wait(nextCpuDelay);
1507 }
1508 }
1509 } catch (InterruptedException e) {
1510 }
1511
1512 updateCpuStatsNow();
1513 } catch (Exception e) {
1514 Log.e(TAG, "Unexpected exception collecting process stats", e);
1515 }
1516 }
1517 }
1518 };
1519 mProcessStatsThread.start();
1520 }
1521
1522 @Override
1523 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1524 throws RemoteException {
1525 try {
1526 return super.onTransact(code, data, reply, flags);
1527 } catch (RuntimeException e) {
1528 // The activity manager only throws security exceptions, so let's
1529 // log all others.
1530 if (!(e instanceof SecurityException)) {
1531 Log.e(TAG, "Activity Manager Crash", e);
1532 }
1533 throw e;
1534 }
1535 }
1536
1537 void updateCpuStats() {
1538 synchronized (mProcessStatsThread) {
1539 final long now = SystemClock.uptimeMillis();
1540 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1541 mProcessStatsThread.notify();
1542 }
1543 }
1544 }
1545
1546 void updateCpuStatsNow() {
1547 synchronized (mProcessStatsThread) {
1548 final long now = SystemClock.uptimeMillis();
1549 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001550
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001551 if (MONITOR_CPU_USAGE &&
1552 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1553 mLastCpuTime = now;
1554 haveNewCpuStats = true;
1555 mProcessStats.update();
1556 //Log.i(TAG, mProcessStats.printCurrentState());
1557 //Log.i(TAG, "Total CPU usage: "
1558 // + mProcessStats.getTotalCpuPercent() + "%");
1559
1560 // Log the cpu usage if the property is set.
1561 if ("true".equals(SystemProperties.get("events.cpu"))) {
1562 int user = mProcessStats.getLastUserTime();
1563 int system = mProcessStats.getLastSystemTime();
1564 int iowait = mProcessStats.getLastIoWaitTime();
1565 int irq = mProcessStats.getLastIrqTime();
1566 int softIrq = mProcessStats.getLastSoftIrqTime();
1567 int idle = mProcessStats.getLastIdleTime();
1568
1569 int total = user + system + iowait + irq + softIrq + idle;
1570 if (total == 0) total = 1;
1571
1572 EventLog.writeEvent(LOG_CPU,
1573 ((user+system+iowait+irq+softIrq) * 100) / total,
1574 (user * 100) / total,
1575 (system * 100) / total,
1576 (iowait * 100) / total,
1577 (irq * 100) / total,
1578 (softIrq * 100) / total);
1579 }
1580 }
1581
Amith Yamasanie43530a2009-08-21 13:11:37 -07001582 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001583 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001584 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585 synchronized(mPidsSelfLocked) {
1586 if (haveNewCpuStats) {
1587 if (mBatteryStatsService.isOnBattery()) {
1588 final int N = mProcessStats.countWorkingStats();
1589 for (int i=0; i<N; i++) {
1590 ProcessStats.Stats st
1591 = mProcessStats.getWorkingStats(i);
1592 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1593 if (pr != null) {
1594 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1595 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001596 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001597 } else {
1598 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001599 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001600 if (ps != null) {
1601 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001602 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001603 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604 }
1605 }
1606 }
1607 }
1608 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001609
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001610 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1611 mLastWriteTime = now;
1612 mBatteryStatsService.getActiveStatistics().writeLocked();
1613 }
1614 }
1615 }
1616 }
1617
1618 /**
1619 * Initialize the application bind args. These are passed to each
1620 * process when the bindApplication() IPC is sent to the process. They're
1621 * lazily setup to make sure the services are running when they're asked for.
1622 */
1623 private HashMap<String, IBinder> getCommonServicesLocked() {
1624 if (mAppBindArgs == null) {
1625 mAppBindArgs = new HashMap<String, IBinder>();
1626
1627 // Setup the application init args
1628 mAppBindArgs.put("package", ServiceManager.getService("package"));
1629 mAppBindArgs.put("window", ServiceManager.getService("window"));
1630 mAppBindArgs.put(Context.ALARM_SERVICE,
1631 ServiceManager.getService(Context.ALARM_SERVICE));
1632 }
1633 return mAppBindArgs;
1634 }
1635
1636 private final void setFocusedActivityLocked(HistoryRecord r) {
1637 if (mFocusedActivity != r) {
1638 mFocusedActivity = r;
1639 mWindowManager.setFocusedApp(r, true);
1640 }
1641 }
1642
1643 private final void updateLRUListLocked(ProcessRecord app,
1644 boolean oomAdj) {
1645 // put it on the LRU to keep track of when it should be exited.
1646 int lrui = mLRUProcesses.indexOf(app);
1647 if (lrui >= 0) mLRUProcesses.remove(lrui);
1648 mLRUProcesses.add(app);
1649 //Log.i(TAG, "Putting proc to front: " + app.processName);
1650 if (oomAdj) {
1651 updateOomAdjLocked();
1652 }
1653 }
1654
1655 private final boolean updateLRUListLocked(HistoryRecord r) {
1656 final boolean hadit = mLRUActivities.remove(r);
1657 mLRUActivities.add(r);
1658 return hadit;
1659 }
1660
1661 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1662 int i = mHistory.size()-1;
1663 while (i >= 0) {
1664 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1665 if (!r.finishing && r != notTop) {
1666 return r;
1667 }
1668 i--;
1669 }
1670 return null;
1671 }
1672
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001673 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1674 int i = mHistory.size()-1;
1675 while (i >= 0) {
1676 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1677 if (!r.finishing && !r.delayedResume && r != notTop) {
1678 return r;
1679 }
1680 i--;
1681 }
1682 return null;
1683 }
1684
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001685 /**
1686 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001687 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001688 *
1689 * @param token If non-null, any history records matching this token will be skipped.
1690 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1691 *
1692 * @return Returns the HistoryRecord of the next activity on the stack.
1693 */
1694 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1695 int i = mHistory.size()-1;
1696 while (i >= 0) {
1697 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1698 // Note: the taskId check depends on real taskId fields being non-zero
1699 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1700 return r;
1701 }
1702 i--;
1703 }
1704 return null;
1705 }
1706
1707 private final ProcessRecord getProcessRecordLocked(
1708 String processName, int uid) {
1709 if (uid == Process.SYSTEM_UID) {
1710 // The system gets to run in any process. If there are multiple
1711 // processes with the same uid, just pick the first (this
1712 // should never happen).
1713 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1714 processName);
1715 return procs != null ? procs.valueAt(0) : null;
1716 }
1717 ProcessRecord proc = mProcessNames.get(processName, uid);
1718 return proc;
1719 }
1720
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001721 private void ensurePackageDexOpt(String packageName) {
1722 IPackageManager pm = ActivityThread.getPackageManager();
1723 try {
1724 if (pm.performDexOpt(packageName)) {
1725 mDidDexOpt = true;
1726 }
1727 } catch (RemoteException e) {
1728 }
1729 }
1730
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001731 private boolean isNextTransitionForward() {
1732 int transit = mWindowManager.getPendingAppTransition();
1733 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1734 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1735 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1736 }
1737
1738 private final boolean realStartActivityLocked(HistoryRecord r,
1739 ProcessRecord app, boolean andResume, boolean checkConfig)
1740 throws RemoteException {
1741
1742 r.startFreezingScreenLocked(app, 0);
1743 mWindowManager.setAppVisibility(r, true);
1744
1745 // Have the window manager re-evaluate the orientation of
1746 // the screen based on the new activity order. Note that
1747 // as a result of this, it can call back into the activity
1748 // manager with a new orientation. We don't care about that,
1749 // because the activity is not currently running so we are
1750 // just restarting it anyway.
1751 if (checkConfig) {
1752 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001753 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001754 r.mayFreezeScreenLocked(app) ? r : null);
1755 updateConfigurationLocked(config, r);
1756 }
1757
1758 r.app = app;
1759
1760 if (localLOGV) Log.v(TAG, "Launching: " + r);
1761
1762 int idx = app.activities.indexOf(r);
1763 if (idx < 0) {
1764 app.activities.add(r);
1765 }
1766 updateLRUListLocked(app, true);
1767
1768 try {
1769 if (app.thread == null) {
1770 throw new RemoteException();
1771 }
1772 List<ResultInfo> results = null;
1773 List<Intent> newIntents = null;
1774 if (andResume) {
1775 results = r.results;
1776 newIntents = r.newIntents;
1777 }
1778 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1779 + " icicle=" + r.icicle
1780 + " with results=" + results + " newIntents=" + newIntents
1781 + " andResume=" + andResume);
1782 if (andResume) {
1783 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1784 System.identityHashCode(r),
1785 r.task.taskId, r.shortComponentName);
1786 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001787 if (r.isHomeActivity) {
1788 mHomeProcess = app;
1789 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001790 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001791 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001792 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001793 r.info, r.icicle, results, newIntents, !andResume,
1794 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001795 } catch (RemoteException e) {
1796 if (r.launchFailed) {
1797 // This is the second time we failed -- finish activity
1798 // and give up.
1799 Log.e(TAG, "Second failure launching "
1800 + r.intent.getComponent().flattenToShortString()
1801 + ", giving up", e);
1802 appDiedLocked(app, app.pid, app.thread);
1803 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1804 "2nd-crash");
1805 return false;
1806 }
1807
1808 // This is the first time we failed -- restart process and
1809 // retry.
1810 app.activities.remove(r);
1811 throw e;
1812 }
1813
1814 r.launchFailed = false;
1815 if (updateLRUListLocked(r)) {
1816 Log.w(TAG, "Activity " + r
1817 + " being launched, but already in LRU list");
1818 }
1819
1820 if (andResume) {
1821 // As part of the process of launching, ActivityThread also performs
1822 // a resume.
1823 r.state = ActivityState.RESUMED;
1824 r.icicle = null;
1825 r.haveState = false;
1826 r.stopped = false;
1827 mResumedActivity = r;
1828 r.task.touchActiveTime();
1829 completeResumeLocked(r);
1830 pauseIfSleepingLocked();
1831 } else {
1832 // This activity is not starting in the resumed state... which
1833 // should look like we asked it to pause+stop (but remain visible),
1834 // and it has done so and reported back the current icicle and
1835 // other state.
1836 r.state = ActivityState.STOPPED;
1837 r.stopped = true;
1838 }
1839
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001840 // Launch the new version setup screen if needed. We do this -after-
1841 // launching the initial activity (that is, home), so that it can have
1842 // a chance to initialize itself while in the background, making the
1843 // switch back to it faster and look better.
1844 startSetupActivityLocked();
1845
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001846 return true;
1847 }
1848
1849 private final void startSpecificActivityLocked(HistoryRecord r,
1850 boolean andResume, boolean checkConfig) {
1851 // Is this activity's application already running?
1852 ProcessRecord app = getProcessRecordLocked(r.processName,
1853 r.info.applicationInfo.uid);
1854
1855 if (r.startTime == 0) {
1856 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001857 if (mInitialStartTime == 0) {
1858 mInitialStartTime = r.startTime;
1859 }
1860 } else if (mInitialStartTime == 0) {
1861 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001862 }
1863
1864 if (app != null && app.thread != null) {
1865 try {
1866 realStartActivityLocked(r, app, andResume, checkConfig);
1867 return;
1868 } catch (RemoteException e) {
1869 Log.w(TAG, "Exception when starting activity "
1870 + r.intent.getComponent().flattenToShortString(), e);
1871 }
1872
1873 // If a dead object exception was thrown -- fall through to
1874 // restart the application.
1875 }
1876
1877 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001878 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001879 }
1880
1881 private final ProcessRecord startProcessLocked(String processName,
1882 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001883 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001884 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1885 // We don't have to do anything more if:
1886 // (1) There is an existing application record; and
1887 // (2) The caller doesn't think it is dead, OR there is no thread
1888 // object attached to it so we know it couldn't have crashed; and
1889 // (3) There is a pid assigned to it, so it is either starting or
1890 // already running.
1891 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1892 + " app=" + app + " knownToBeDead=" + knownToBeDead
1893 + " thread=" + (app != null ? app.thread : null)
1894 + " pid=" + (app != null ? app.pid : -1));
1895 if (app != null &&
1896 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1897 return app;
1898 }
1899
1900 String hostingNameStr = hostingName != null
1901 ? hostingName.flattenToShortString() : null;
1902
1903 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1904 // If we are in the background, then check to see if this process
1905 // is bad. If so, we will just silently fail.
1906 if (mBadProcesses.get(info.processName, info.uid) != null) {
1907 return null;
1908 }
1909 } else {
1910 // When the user is explicitly starting a process, then clear its
1911 // crash count so that we won't make it bad until they see at
1912 // least one crash dialog again, and make the process good again
1913 // if it had been bad.
1914 mProcessCrashTimes.remove(info.processName, info.uid);
1915 if (mBadProcesses.get(info.processName, info.uid) != null) {
1916 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1917 info.processName);
1918 mBadProcesses.remove(info.processName, info.uid);
1919 if (app != null) {
1920 app.bad = false;
1921 }
1922 }
1923 }
1924
1925 if (app == null) {
1926 app = newProcessRecordLocked(null, info, processName);
1927 mProcessNames.put(processName, info.uid, app);
1928 } else {
1929 // If this is a new package in the process, add the package to the list
1930 app.addPackage(info.packageName);
1931 }
1932
1933 // If the system is not ready yet, then hold off on starting this
1934 // process until it is.
1935 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001936 && !isAllowedWhileBooting(info)
1937 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001938 if (!mProcessesOnHold.contains(app)) {
1939 mProcessesOnHold.add(app);
1940 }
1941 return app;
1942 }
1943
1944 startProcessLocked(app, hostingType, hostingNameStr);
1945 return (app.pid != 0) ? app : null;
1946 }
1947
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001948 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1949 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1950 }
1951
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001952 private final void startProcessLocked(ProcessRecord app,
1953 String hostingType, String hostingNameStr) {
1954 if (app.pid > 0 && app.pid != MY_PID) {
1955 synchronized (mPidsSelfLocked) {
1956 mPidsSelfLocked.remove(app.pid);
1957 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1958 }
1959 app.pid = 0;
1960 }
1961
1962 mProcessesOnHold.remove(app);
1963
1964 updateCpuStats();
1965
1966 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1967 mProcDeaths[0] = 0;
1968
1969 try {
1970 int uid = app.info.uid;
1971 int[] gids = null;
1972 try {
1973 gids = mContext.getPackageManager().getPackageGids(
1974 app.info.packageName);
1975 } catch (PackageManager.NameNotFoundException e) {
1976 Log.w(TAG, "Unable to retrieve gids", e);
1977 }
1978 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1979 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1980 && mTopComponent != null
1981 && app.processName.equals(mTopComponent.getPackageName())) {
1982 uid = 0;
1983 }
1984 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1985 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1986 uid = 0;
1987 }
1988 }
1989 int debugFlags = 0;
1990 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1991 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1992 }
1993 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1994 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1995 }
1996 if ("1".equals(SystemProperties.get("debug.assert"))) {
1997 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1998 }
1999 int pid = Process.start("android.app.ActivityThread",
2000 mSimpleProcessManagement ? app.processName : null, uid, uid,
2001 gids, debugFlags, null);
2002 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
2003 synchronized (bs) {
2004 if (bs.isOnBattery()) {
2005 app.batteryStats.incStartsLocked();
2006 }
2007 }
2008
2009 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
2010 app.processName, hostingType,
2011 hostingNameStr != null ? hostingNameStr : "");
2012
2013 if (app.persistent) {
2014 Watchdog.getInstance().processStarted(app, app.processName, pid);
2015 }
2016
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07002017 StringBuilder buf = mStringBuilder;
2018 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002019 buf.append("Start proc ");
2020 buf.append(app.processName);
2021 buf.append(" for ");
2022 buf.append(hostingType);
2023 if (hostingNameStr != null) {
2024 buf.append(" ");
2025 buf.append(hostingNameStr);
2026 }
2027 buf.append(": pid=");
2028 buf.append(pid);
2029 buf.append(" uid=");
2030 buf.append(uid);
2031 buf.append(" gids={");
2032 if (gids != null) {
2033 for (int gi=0; gi<gids.length; gi++) {
2034 if (gi != 0) buf.append(", ");
2035 buf.append(gids[gi]);
2036
2037 }
2038 }
2039 buf.append("}");
2040 Log.i(TAG, buf.toString());
2041 if (pid == 0 || pid == MY_PID) {
2042 // Processes are being emulated with threads.
2043 app.pid = MY_PID;
2044 app.removed = false;
2045 mStartingProcesses.add(app);
2046 } else if (pid > 0) {
2047 app.pid = pid;
2048 app.removed = false;
2049 synchronized (mPidsSelfLocked) {
2050 this.mPidsSelfLocked.put(pid, app);
2051 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2052 msg.obj = app;
2053 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2054 }
2055 } else {
2056 app.pid = 0;
2057 RuntimeException e = new RuntimeException(
2058 "Failure starting process " + app.processName
2059 + ": returned pid=" + pid);
2060 Log.e(TAG, e.getMessage(), e);
2061 }
2062 } catch (RuntimeException e) {
2063 // XXX do better error recovery.
2064 app.pid = 0;
2065 Log.e(TAG, "Failure starting process " + app.processName, e);
2066 }
2067 }
2068
2069 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2070 if (mPausingActivity != null) {
2071 RuntimeException e = new RuntimeException();
2072 Log.e(TAG, "Trying to pause when pause is already pending for "
2073 + mPausingActivity, e);
2074 }
2075 HistoryRecord prev = mResumedActivity;
2076 if (prev == null) {
2077 RuntimeException e = new RuntimeException();
2078 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2079 resumeTopActivityLocked(null);
2080 return;
2081 }
2082 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2083 mResumedActivity = null;
2084 mPausingActivity = prev;
2085 mLastPausedActivity = prev;
2086 prev.state = ActivityState.PAUSING;
2087 prev.task.touchActiveTime();
2088
2089 updateCpuStats();
2090
2091 if (prev.app != null && prev.app.thread != null) {
2092 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2093 try {
2094 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2095 System.identityHashCode(prev),
2096 prev.shortComponentName);
2097 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2098 prev.configChangeFlags);
2099 updateUsageStats(prev, false);
2100 } catch (Exception e) {
2101 // Ignore exception, if process died other code will cleanup.
2102 Log.w(TAG, "Exception thrown during pause", e);
2103 mPausingActivity = null;
2104 mLastPausedActivity = null;
2105 }
2106 } else {
2107 mPausingActivity = null;
2108 mLastPausedActivity = null;
2109 }
2110
2111 // If we are not going to sleep, we want to ensure the device is
2112 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002113 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002114 mLaunchingActivity.acquire();
2115 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2116 // To be safe, don't allow the wake lock to be held for too long.
2117 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2118 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2119 }
2120 }
2121
2122
2123 if (mPausingActivity != null) {
2124 // Have the window manager pause its key dispatching until the new
2125 // activity has started. If we're pausing the activity just because
2126 // the screen is being turned off and the UI is sleeping, don't interrupt
2127 // key dispatch; the same activity will pick it up again on wakeup.
2128 if (!uiSleeping) {
2129 prev.pauseKeyDispatchingLocked();
2130 } else {
2131 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2132 }
2133
2134 // Schedule a pause timeout in case the app doesn't respond.
2135 // We don't give it much time because this directly impacts the
2136 // responsiveness seen by the user.
2137 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2138 msg.obj = prev;
2139 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2140 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2141 } else {
2142 // This activity failed to schedule the
2143 // pause, so just treat it as being paused now.
2144 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2145 resumeTopActivityLocked(null);
2146 }
2147 }
2148
2149 private final void completePauseLocked() {
2150 HistoryRecord prev = mPausingActivity;
2151 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2152
2153 if (prev != null) {
2154 if (prev.finishing) {
2155 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2156 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2157 } else if (prev.app != null) {
2158 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2159 if (prev.waitingVisible) {
2160 prev.waitingVisible = false;
2161 mWaitingVisibleActivities.remove(prev);
2162 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2163 TAG, "Complete pause, no longer waiting: " + prev);
2164 }
2165 if (prev.configDestroy) {
2166 // The previous is being paused because the configuration
2167 // is changing, which means it is actually stopping...
2168 // To juggle the fact that we are also starting a new
2169 // instance right now, we need to first completely stop
2170 // the current instance before starting the new one.
2171 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2172 destroyActivityLocked(prev, true);
2173 } else {
2174 mStoppingActivities.add(prev);
2175 if (mStoppingActivities.size() > 3) {
2176 // If we already have a few activities waiting to stop,
2177 // then give up on things going idle and start clearing
2178 // them out.
2179 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2180 Message msg = Message.obtain();
2181 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2182 mHandler.sendMessage(msg);
2183 }
2184 }
2185 } else {
2186 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2187 prev = null;
2188 }
2189 mPausingActivity = null;
2190 }
2191
Dianne Hackborn55280a92009-05-07 15:53:46 -07002192 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002193 resumeTopActivityLocked(prev);
2194 } else {
2195 if (mGoingToSleep.isHeld()) {
2196 mGoingToSleep.release();
2197 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002198 if (mShuttingDown) {
2199 notifyAll();
2200 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002201 }
2202
2203 if (prev != null) {
2204 prev.resumeKeyDispatchingLocked();
2205 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002206
2207 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2208 long diff = 0;
2209 synchronized (mProcessStatsThread) {
2210 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2211 }
2212 if (diff > 0) {
2213 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2214 synchronized (bsi) {
2215 BatteryStatsImpl.Uid.Proc ps =
2216 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2217 prev.info.packageName);
2218 if (ps != null) {
2219 ps.addForegroundTimeLocked(diff);
2220 }
2221 }
2222 }
2223 }
2224 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002225 }
2226
2227 /**
2228 * Once we know that we have asked an application to put an activity in
2229 * the resumed state (either by launching it or explicitly telling it),
2230 * this function updates the rest of our state to match that fact.
2231 */
2232 private final void completeResumeLocked(HistoryRecord next) {
2233 next.idle = false;
2234 next.results = null;
2235 next.newIntents = null;
2236
2237 // schedule an idle timeout in case the app doesn't do it for us.
2238 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2239 msg.obj = next;
2240 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2241
2242 if (false) {
2243 // The activity was never told to pause, so just keep
2244 // things going as-is. To maintain our own state,
2245 // we need to emulate it coming back and saying it is
2246 // idle.
2247 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2248 msg.obj = next;
2249 mHandler.sendMessage(msg);
2250 }
2251
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002252 reportResumedActivity(next);
2253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002254 next.thumbnail = null;
2255 setFocusedActivityLocked(next);
2256 next.resumeKeyDispatchingLocked();
2257 ensureActivitiesVisibleLocked(null, 0);
2258 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002259 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002260
2261 // Mark the point when the activity is resuming
2262 // TODO: To be more accurate, the mark should be before the onCreate,
2263 // not after the onResume. But for subsequent starts, onResume is fine.
2264 if (next.app != null) {
2265 synchronized (mProcessStatsThread) {
2266 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2267 }
2268 } else {
2269 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2270 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002271 }
2272
2273 /**
2274 * Make sure that all activities that need to be visible (that is, they
2275 * currently can be seen by the user) actually are.
2276 */
2277 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2278 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2279 if (DEBUG_VISBILITY) Log.v(
2280 TAG, "ensureActivitiesVisible behind " + top
2281 + " configChanges=0x" + Integer.toHexString(configChanges));
2282
2283 // If the top activity is not fullscreen, then we need to
2284 // make sure any activities under it are now visible.
2285 final int count = mHistory.size();
2286 int i = count-1;
2287 while (mHistory.get(i) != top) {
2288 i--;
2289 }
2290 HistoryRecord r;
2291 boolean behindFullscreen = false;
2292 for (; i>=0; i--) {
2293 r = (HistoryRecord)mHistory.get(i);
2294 if (DEBUG_VISBILITY) Log.v(
2295 TAG, "Make visible? " + r + " finishing=" + r.finishing
2296 + " state=" + r.state);
2297 if (r.finishing) {
2298 continue;
2299 }
2300
2301 final boolean doThisProcess = onlyThisProcess == null
2302 || onlyThisProcess.equals(r.processName);
2303
2304 // First: if this is not the current activity being started, make
2305 // sure it matches the current configuration.
2306 if (r != starting && doThisProcess) {
2307 ensureActivityConfigurationLocked(r, 0);
2308 }
2309
2310 if (r.app == null || r.app.thread == null) {
2311 if (onlyThisProcess == null
2312 || onlyThisProcess.equals(r.processName)) {
2313 // This activity needs to be visible, but isn't even
2314 // running... get it started, but don't resume it
2315 // at this point.
2316 if (DEBUG_VISBILITY) Log.v(
2317 TAG, "Start and freeze screen for " + r);
2318 if (r != starting) {
2319 r.startFreezingScreenLocked(r.app, configChanges);
2320 }
2321 if (!r.visible) {
2322 if (DEBUG_VISBILITY) Log.v(
2323 TAG, "Starting and making visible: " + r);
2324 mWindowManager.setAppVisibility(r, true);
2325 }
2326 if (r != starting) {
2327 startSpecificActivityLocked(r, false, false);
2328 }
2329 }
2330
2331 } else if (r.visible) {
2332 // If this activity is already visible, then there is nothing
2333 // else to do here.
2334 if (DEBUG_VISBILITY) Log.v(
2335 TAG, "Skipping: already visible at " + r);
2336 r.stopFreezingScreenLocked(false);
2337
2338 } else if (onlyThisProcess == null) {
2339 // This activity is not currently visible, but is running.
2340 // Tell it to become visible.
2341 r.visible = true;
2342 if (r.state != ActivityState.RESUMED && r != starting) {
2343 // If this activity is paused, tell it
2344 // to now show its window.
2345 if (DEBUG_VISBILITY) Log.v(
2346 TAG, "Making visible and scheduling visibility: " + r);
2347 try {
2348 mWindowManager.setAppVisibility(r, true);
2349 r.app.thread.scheduleWindowVisibility(r, true);
2350 r.stopFreezingScreenLocked(false);
2351 } catch (Exception e) {
2352 // Just skip on any failure; we'll make it
2353 // visible when it next restarts.
2354 Log.w(TAG, "Exception thrown making visibile: "
2355 + r.intent.getComponent(), e);
2356 }
2357 }
2358 }
2359
2360 // Aggregate current change flags.
2361 configChanges |= r.configChangeFlags;
2362
2363 if (r.fullscreen) {
2364 // At this point, nothing else needs to be shown
2365 if (DEBUG_VISBILITY) Log.v(
2366 TAG, "Stopping: fullscreen at " + r);
2367 behindFullscreen = true;
2368 i--;
2369 break;
2370 }
2371 }
2372
2373 // Now for any activities that aren't visible to the user, make
2374 // sure they no longer are keeping the screen frozen.
2375 while (i >= 0) {
2376 r = (HistoryRecord)mHistory.get(i);
2377 if (DEBUG_VISBILITY) Log.v(
2378 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2379 + " state=" + r.state
2380 + " behindFullscreen=" + behindFullscreen);
2381 if (!r.finishing) {
2382 if (behindFullscreen) {
2383 if (r.visible) {
2384 if (DEBUG_VISBILITY) Log.v(
2385 TAG, "Making invisible: " + r);
2386 r.visible = false;
2387 try {
2388 mWindowManager.setAppVisibility(r, false);
2389 if ((r.state == ActivityState.STOPPING
2390 || r.state == ActivityState.STOPPED)
2391 && r.app != null && r.app.thread != null) {
2392 if (DEBUG_VISBILITY) Log.v(
2393 TAG, "Scheduling invisibility: " + r);
2394 r.app.thread.scheduleWindowVisibility(r, false);
2395 }
2396 } catch (Exception e) {
2397 // Just skip on any failure; we'll make it
2398 // visible when it next restarts.
2399 Log.w(TAG, "Exception thrown making hidden: "
2400 + r.intent.getComponent(), e);
2401 }
2402 } else {
2403 if (DEBUG_VISBILITY) Log.v(
2404 TAG, "Already invisible: " + r);
2405 }
2406 } else if (r.fullscreen) {
2407 if (DEBUG_VISBILITY) Log.v(
2408 TAG, "Now behindFullscreen: " + r);
2409 behindFullscreen = true;
2410 }
2411 }
2412 i--;
2413 }
2414 }
2415
2416 /**
2417 * Version of ensureActivitiesVisible that can easily be called anywhere.
2418 */
2419 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2420 int configChanges) {
2421 HistoryRecord r = topRunningActivityLocked(null);
2422 if (r != null) {
2423 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2424 }
2425 }
2426
2427 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2428 if (resumed) {
2429 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2430 } else {
2431 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2432 }
2433 }
2434
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002435 private boolean startHomeActivityLocked() {
2436 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2437 && mTopAction == null) {
2438 // We are running in factory test mode, but unable to find
2439 // the factory test app, so just sit around displaying the
2440 // error message and don't try to start anything.
2441 return false;
2442 }
2443 Intent intent = new Intent(
2444 mTopAction,
2445 mTopData != null ? Uri.parse(mTopData) : null);
2446 intent.setComponent(mTopComponent);
2447 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2448 intent.addCategory(Intent.CATEGORY_HOME);
2449 }
2450 ActivityInfo aInfo =
2451 intent.resolveActivityInfo(mContext.getPackageManager(),
2452 STOCK_PM_FLAGS);
2453 if (aInfo != null) {
2454 intent.setComponent(new ComponentName(
2455 aInfo.applicationInfo.packageName, aInfo.name));
2456 // Don't do this if the home app is currently being
2457 // instrumented.
2458 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2459 aInfo.applicationInfo.uid);
2460 if (app == null || app.instrumentationClass == null) {
2461 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2462 startActivityLocked(null, intent, null, null, 0, aInfo,
2463 null, null, 0, 0, 0, false, false);
2464 }
2465 }
2466
2467
2468 return true;
2469 }
2470
2471 /**
2472 * Starts the "new version setup screen" if appropriate.
2473 */
2474 private void startSetupActivityLocked() {
2475 // Only do this once per boot.
2476 if (mCheckedForSetup) {
2477 return;
2478 }
2479
2480 // We will show this screen if the current one is a different
2481 // version than the last one shown, and we are not running in
2482 // low-level factory test mode.
2483 final ContentResolver resolver = mContext.getContentResolver();
2484 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2485 Settings.Secure.getInt(resolver,
2486 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2487 mCheckedForSetup = true;
2488
2489 // See if we should be showing the platform update setup UI.
2490 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2491 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2492 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2493
2494 // We don't allow third party apps to replace this.
2495 ResolveInfo ri = null;
2496 for (int i=0; ris != null && i<ris.size(); i++) {
2497 if ((ris.get(i).activityInfo.applicationInfo.flags
2498 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2499 ri = ris.get(i);
2500 break;
2501 }
2502 }
2503
2504 if (ri != null) {
2505 String vers = ri.activityInfo.metaData != null
2506 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2507 : null;
2508 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2509 vers = ri.activityInfo.applicationInfo.metaData.getString(
2510 Intent.METADATA_SETUP_VERSION);
2511 }
2512 String lastVers = Settings.Secure.getString(
2513 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2514 if (vers != null && !vers.equals(lastVers)) {
2515 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2516 intent.setComponent(new ComponentName(
2517 ri.activityInfo.packageName, ri.activityInfo.name));
2518 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2519 null, null, 0, 0, 0, false, false);
2520 }
2521 }
2522 }
2523 }
2524
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002525 private void reportResumedActivity(HistoryRecord r) {
2526 //Log.i(TAG, "**** REPORT RESUME: " + r);
2527
2528 final int identHash = System.identityHashCode(r);
2529 updateUsageStats(r, true);
2530
2531 int i = mWatchers.beginBroadcast();
2532 while (i > 0) {
2533 i--;
2534 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2535 if (w != null) {
2536 try {
2537 w.activityResuming(identHash);
2538 } catch (RemoteException e) {
2539 }
2540 }
2541 }
2542 mWatchers.finishBroadcast();
2543 }
2544
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002545 /**
2546 * Ensure that the top activity in the stack is resumed.
2547 *
2548 * @param prev The previously resumed activity, for when in the process
2549 * of pausing; can be null to call from elsewhere.
2550 *
2551 * @return Returns true if something is being resumed, or false if
2552 * nothing happened.
2553 */
2554 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2555 // Find the first activity that is not finishing.
2556 HistoryRecord next = topRunningActivityLocked(null);
2557
2558 // Remember how we'll process this pause/resume situation, and ensure
2559 // that the state is reset however we wind up proceeding.
2560 final boolean userLeaving = mUserLeaving;
2561 mUserLeaving = false;
2562
2563 if (next == null) {
2564 // There are no more activities! Let's just start up the
2565 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002566 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002567 }
2568
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002569 next.delayedResume = false;
2570
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002571 // If the top activity is the resumed one, nothing to do.
2572 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2573 // Make sure we have executed any pending transitions, since there
2574 // should be nothing left to do at this point.
2575 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002576 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002577 return false;
2578 }
2579
2580 // If we are sleeping, and there is no resumed activity, and the top
2581 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002582 if ((mSleeping || mShuttingDown)
2583 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002584 // Make sure we have executed any pending transitions, since there
2585 // should be nothing left to do at this point.
2586 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002587 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002588 return false;
2589 }
2590
2591 // The activity may be waiting for stop, but that is no longer
2592 // appropriate for it.
2593 mStoppingActivities.remove(next);
2594 mWaitingVisibleActivities.remove(next);
2595
2596 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2597
2598 // If we are currently pausing an activity, then don't do anything
2599 // until that is done.
2600 if (mPausingActivity != null) {
2601 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2602 return false;
2603 }
2604
2605 // We need to start pausing the current activity so the top one
2606 // can be resumed...
2607 if (mResumedActivity != null) {
2608 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2609 startPausingLocked(userLeaving, false);
2610 return true;
2611 }
2612
2613 if (prev != null && prev != next) {
2614 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2615 prev.waitingVisible = true;
2616 mWaitingVisibleActivities.add(prev);
2617 if (DEBUG_SWITCH) Log.v(
2618 TAG, "Resuming top, waiting visible to hide: " + prev);
2619 } else {
2620 // The next activity is already visible, so hide the previous
2621 // activity's windows right now so we can show the new one ASAP.
2622 // We only do this if the previous is finishing, which should mean
2623 // it is on top of the one being resumed so hiding it quickly
2624 // is good. Otherwise, we want to do the normal route of allowing
2625 // the resumed activity to be shown so we can decide if the
2626 // previous should actually be hidden depending on whether the
2627 // new one is found to be full-screen or not.
2628 if (prev.finishing) {
2629 mWindowManager.setAppVisibility(prev, false);
2630 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2631 + prev + ", waitingVisible="
2632 + (prev != null ? prev.waitingVisible : null)
2633 + ", nowVisible=" + next.nowVisible);
2634 } else {
2635 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2636 + prev + ", waitingVisible="
2637 + (prev != null ? prev.waitingVisible : null)
2638 + ", nowVisible=" + next.nowVisible);
2639 }
2640 }
2641 }
2642
2643 // We are starting up the next activity, so tell the window manager
2644 // that the previous one will be hidden soon. This way it can know
2645 // to ignore it when computing the desired screen orientation.
2646 if (prev != null) {
2647 if (prev.finishing) {
2648 if (DEBUG_TRANSITION) Log.v(TAG,
2649 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002650 if (mNoAnimActivities.contains(prev)) {
2651 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2652 } else {
2653 mWindowManager.prepareAppTransition(prev.task == next.task
2654 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2655 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2656 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002657 mWindowManager.setAppWillBeHidden(prev);
2658 mWindowManager.setAppVisibility(prev, false);
2659 } else {
2660 if (DEBUG_TRANSITION) Log.v(TAG,
2661 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002662 if (mNoAnimActivities.contains(next)) {
2663 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2664 } else {
2665 mWindowManager.prepareAppTransition(prev.task == next.task
2666 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2667 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2668 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002669 }
2670 if (false) {
2671 mWindowManager.setAppWillBeHidden(prev);
2672 mWindowManager.setAppVisibility(prev, false);
2673 }
2674 } else if (mHistory.size() > 1) {
2675 if (DEBUG_TRANSITION) Log.v(TAG,
2676 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002677 if (mNoAnimActivities.contains(next)) {
2678 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2679 } else {
2680 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2681 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002682 }
2683
2684 if (next.app != null && next.app.thread != null) {
2685 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2686
2687 // This activity is now becoming visible.
2688 mWindowManager.setAppVisibility(next, true);
2689
2690 HistoryRecord lastResumedActivity = mResumedActivity;
2691 ActivityState lastState = next.state;
2692
2693 updateCpuStats();
2694
2695 next.state = ActivityState.RESUMED;
2696 mResumedActivity = next;
2697 next.task.touchActiveTime();
2698 updateLRUListLocked(next.app, true);
2699 updateLRUListLocked(next);
2700
2701 // Have the window manager re-evaluate the orientation of
2702 // the screen based on the new activity order.
2703 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002704 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002705 next.mayFreezeScreenLocked(next.app) ? next : null);
2706 if (config != null) {
2707 next.frozenBeforeDestroy = true;
2708 }
2709 if (!updateConfigurationLocked(config, next)) {
2710 // The configuration update wasn't able to keep the existing
2711 // instance of the activity, and instead started a new one.
2712 // We should be all done, but let's just make sure our activity
2713 // is still at the top and schedule another run if something
2714 // weird happened.
2715 HistoryRecord nextNext = topRunningActivityLocked(null);
2716 if (DEBUG_SWITCH) Log.i(TAG,
2717 "Activity config changed during resume: " + next
2718 + ", new next: " + nextNext);
2719 if (nextNext != next) {
2720 // Do over!
2721 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2722 }
2723 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002724 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002725 return true;
2726 }
2727
2728 try {
2729 // Deliver all pending results.
2730 ArrayList a = next.results;
2731 if (a != null) {
2732 final int N = a.size();
2733 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002734 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002735 TAG, "Delivering results to " + next
2736 + ": " + a);
2737 next.app.thread.scheduleSendResult(next, a);
2738 }
2739 }
2740
2741 if (next.newIntents != null) {
2742 next.app.thread.scheduleNewIntent(next.newIntents, next);
2743 }
2744
2745 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2746 System.identityHashCode(next),
2747 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002748
2749 next.app.thread.scheduleResumeActivity(next,
2750 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002751
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002752 pauseIfSleepingLocked();
2753
2754 } catch (Exception e) {
2755 // Whoops, need to restart this activity!
2756 next.state = lastState;
2757 mResumedActivity = lastResumedActivity;
2758 if (Config.LOGD) Log.d(TAG,
2759 "Restarting because process died: " + next);
2760 if (!next.hasBeenLaunched) {
2761 next.hasBeenLaunched = true;
2762 } else {
2763 if (SHOW_APP_STARTING_ICON) {
2764 mWindowManager.setAppStartingWindow(
2765 next, next.packageName, next.theme,
2766 next.nonLocalizedLabel,
2767 next.labelRes, next.icon, null, true);
2768 }
2769 }
2770 startSpecificActivityLocked(next, true, false);
2771 return true;
2772 }
2773
2774 // From this point on, if something goes wrong there is no way
2775 // to recover the activity.
2776 try {
2777 next.visible = true;
2778 completeResumeLocked(next);
2779 } catch (Exception e) {
2780 // If any exception gets thrown, toss away this
2781 // activity and try the next one.
2782 Log.w(TAG, "Exception thrown during resume of " + next, e);
2783 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2784 "resume-exception");
2785 return true;
2786 }
2787
2788 // Didn't need to use the icicle, and it is now out of date.
2789 next.icicle = null;
2790 next.haveState = false;
2791 next.stopped = false;
2792
2793 } else {
2794 // Whoops, need to restart this activity!
2795 if (!next.hasBeenLaunched) {
2796 next.hasBeenLaunched = true;
2797 } else {
2798 if (SHOW_APP_STARTING_ICON) {
2799 mWindowManager.setAppStartingWindow(
2800 next, next.packageName, next.theme,
2801 next.nonLocalizedLabel,
2802 next.labelRes, next.icon, null, true);
2803 }
2804 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2805 }
2806 startSpecificActivityLocked(next, true, true);
2807 }
2808
2809 return true;
2810 }
2811
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002812 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2813 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002814 final int NH = mHistory.size();
2815
2816 int addPos = -1;
2817
2818 if (!newTask) {
2819 // If starting in an existing task, find where that is...
2820 HistoryRecord next = null;
2821 boolean startIt = true;
2822 for (int i = NH-1; i >= 0; i--) {
2823 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2824 if (p.finishing) {
2825 continue;
2826 }
2827 if (p.task == r.task) {
2828 // Here it is! Now, if this is not yet visible to the
2829 // user, then just add it without starting; it will
2830 // get started when the user navigates back to it.
2831 addPos = i+1;
2832 if (!startIt) {
2833 mHistory.add(addPos, r);
2834 r.inHistory = true;
2835 r.task.numActivities++;
2836 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2837 r.info.screenOrientation, r.fullscreen);
2838 if (VALIDATE_TOKENS) {
2839 mWindowManager.validateAppTokens(mHistory);
2840 }
2841 return;
2842 }
2843 break;
2844 }
2845 if (p.fullscreen) {
2846 startIt = false;
2847 }
2848 next = p;
2849 }
2850 }
2851
2852 // Place a new activity at top of stack, so it is next to interact
2853 // with the user.
2854 if (addPos < 0) {
2855 addPos = mHistory.size();
2856 }
2857
2858 // If we are not placing the new activity frontmost, we do not want
2859 // to deliver the onUserLeaving callback to the actual frontmost
2860 // activity
2861 if (addPos < NH) {
2862 mUserLeaving = false;
2863 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2864 }
2865
2866 // Slot the activity into the history stack and proceed
2867 mHistory.add(addPos, r);
2868 r.inHistory = true;
2869 r.frontOfTask = newTask;
2870 r.task.numActivities++;
2871 if (NH > 0) {
2872 // We want to show the starting preview window if we are
2873 // switching to a new task, or the next activity's process is
2874 // not currently running.
2875 boolean showStartingIcon = newTask;
2876 ProcessRecord proc = r.app;
2877 if (proc == null) {
2878 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2879 }
2880 if (proc == null || proc.thread == null) {
2881 showStartingIcon = true;
2882 }
2883 if (DEBUG_TRANSITION) Log.v(TAG,
2884 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002885 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2886 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2887 mNoAnimActivities.add(r);
2888 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2889 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2890 mNoAnimActivities.remove(r);
2891 } else {
2892 mWindowManager.prepareAppTransition(newTask
2893 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2894 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2895 mNoAnimActivities.remove(r);
2896 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002897 mWindowManager.addAppToken(
2898 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2899 boolean doShow = true;
2900 if (newTask) {
2901 // Even though this activity is starting fresh, we still need
2902 // to reset it to make sure we apply affinities to move any
2903 // existing activities from other tasks in to it.
2904 // If the caller has requested that the target task be
2905 // reset, then do so.
2906 if ((r.intent.getFlags()
2907 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2908 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002909 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002910 }
2911 }
2912 if (SHOW_APP_STARTING_ICON && doShow) {
2913 // Figure out if we are transitioning from another activity that is
2914 // "has the same starting icon" as the next one. This allows the
2915 // window manager to keep the previous window it had previously
2916 // created, if it still had one.
2917 HistoryRecord prev = mResumedActivity;
2918 if (prev != null) {
2919 // We don't want to reuse the previous starting preview if:
2920 // (1) The current activity is in a different task.
2921 if (prev.task != r.task) prev = null;
2922 // (2) The current activity is already displayed.
2923 else if (prev.nowVisible) prev = null;
2924 }
2925 mWindowManager.setAppStartingWindow(
2926 r, r.packageName, r.theme, r.nonLocalizedLabel,
2927 r.labelRes, r.icon, prev, showStartingIcon);
2928 }
2929 } else {
2930 // If this is the first activity, don't do any fancy animations,
2931 // because there is nothing for it to animate on top of.
2932 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2933 r.info.screenOrientation, r.fullscreen);
2934 }
2935 if (VALIDATE_TOKENS) {
2936 mWindowManager.validateAppTokens(mHistory);
2937 }
2938
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002939 if (doResume) {
2940 resumeTopActivityLocked(null);
2941 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002942 }
2943
2944 /**
2945 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002946 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2947 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002948 * an instance of that activity in the stack and, if found, finish all
2949 * activities on top of it and return the instance.
2950 *
2951 * @param newR Description of the new activity being started.
2952 * @return Returns the old activity that should be continue to be used,
2953 * or null if none was found.
2954 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002955 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002956 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002957 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002958
2959 // First find the requested task.
2960 while (i > 0) {
2961 i--;
2962 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2963 if (r.task.taskId == taskId) {
2964 i++;
2965 break;
2966 }
2967 }
2968
2969 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002970 while (i > 0) {
2971 i--;
2972 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2973 if (r.finishing) {
2974 continue;
2975 }
2976 if (r.task.taskId != taskId) {
2977 return null;
2978 }
2979 if (r.realActivity.equals(newR.realActivity)) {
2980 // Here it is! Now finish everything in front...
2981 HistoryRecord ret = r;
2982 if (doClear) {
2983 while (i < (mHistory.size()-1)) {
2984 i++;
2985 r = (HistoryRecord)mHistory.get(i);
2986 if (r.finishing) {
2987 continue;
2988 }
2989 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2990 null, "clear")) {
2991 i--;
2992 }
2993 }
2994 }
2995
2996 // Finally, if this is a normal launch mode (that is, not
2997 // expecting onNewIntent()), then we will finish the current
2998 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002999 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
3000 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003001 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003002 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003003 if (index >= 0) {
3004 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
3005 null, "clear");
3006 }
3007 return null;
3008 }
3009 }
3010
3011 return ret;
3012 }
3013 }
3014
3015 return null;
3016 }
3017
3018 /**
3019 * Find the activity in the history stack within the given task. Returns
3020 * the index within the history at which it's found, or < 0 if not found.
3021 */
3022 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3023 int i = mHistory.size();
3024 while (i > 0) {
3025 i--;
3026 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3027 if (candidate.task.taskId != task) {
3028 break;
3029 }
3030 if (candidate.realActivity.equals(r.realActivity)) {
3031 return i;
3032 }
3033 }
3034
3035 return -1;
3036 }
3037
3038 /**
3039 * Reorder the history stack so that the activity at the given index is
3040 * brought to the front.
3041 */
3042 private final HistoryRecord moveActivityToFrontLocked(int where) {
3043 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3044 int top = mHistory.size();
3045 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3046 mHistory.add(top, newTop);
3047 oldTop.frontOfTask = false;
3048 newTop.frontOfTask = true;
3049 return newTop;
3050 }
3051
3052 /**
3053 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3054 * method will be called at the proper time.
3055 */
3056 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3057 boolean sent = false;
3058 if (r.state == ActivityState.RESUMED
3059 && r.app != null && r.app.thread != null) {
3060 try {
3061 ArrayList<Intent> ar = new ArrayList<Intent>();
3062 ar.add(new Intent(intent));
3063 r.app.thread.scheduleNewIntent(ar, r);
3064 sent = true;
3065 } catch (Exception e) {
3066 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3067 }
3068 }
3069 if (!sent) {
3070 r.addNewIntentLocked(new Intent(intent));
3071 }
3072 }
3073
3074 private final void logStartActivity(int tag, HistoryRecord r,
3075 TaskRecord task) {
3076 EventLog.writeEvent(tag,
3077 System.identityHashCode(r), task.taskId,
3078 r.shortComponentName, r.intent.getAction(),
3079 r.intent.getType(), r.intent.getDataString(),
3080 r.intent.getFlags());
3081 }
3082
3083 private final int startActivityLocked(IApplicationThread caller,
3084 Intent intent, String resolvedType,
3085 Uri[] grantedUriPermissions,
3086 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3087 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003088 int callingPid, int callingUid, boolean onlyIfNeeded,
3089 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003090 Log.i(TAG, "Starting activity: " + intent);
3091
3092 HistoryRecord sourceRecord = null;
3093 HistoryRecord resultRecord = null;
3094 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003095 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003096 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003097 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3098 if (index >= 0) {
3099 sourceRecord = (HistoryRecord)mHistory.get(index);
3100 if (requestCode >= 0 && !sourceRecord.finishing) {
3101 resultRecord = sourceRecord;
3102 }
3103 }
3104 }
3105
3106 int launchFlags = intent.getFlags();
3107
3108 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3109 && sourceRecord != null) {
3110 // Transfer the result target from the source activity to the new
3111 // one being started, including any failures.
3112 if (requestCode >= 0) {
3113 return START_FORWARD_AND_REQUEST_CONFLICT;
3114 }
3115 resultRecord = sourceRecord.resultTo;
3116 resultWho = sourceRecord.resultWho;
3117 requestCode = sourceRecord.requestCode;
3118 sourceRecord.resultTo = null;
3119 if (resultRecord != null) {
3120 resultRecord.removeResultsLocked(
3121 sourceRecord, resultWho, requestCode);
3122 }
3123 }
3124
3125 int err = START_SUCCESS;
3126
3127 if (intent.getComponent() == null) {
3128 // We couldn't find a class that can handle the given Intent.
3129 // That's the end of that!
3130 err = START_INTENT_NOT_RESOLVED;
3131 }
3132
3133 if (err == START_SUCCESS && aInfo == null) {
3134 // We couldn't find the specific class specified in the Intent.
3135 // Also the end of the line.
3136 err = START_CLASS_NOT_FOUND;
3137 }
3138
3139 ProcessRecord callerApp = null;
3140 if (err == START_SUCCESS && caller != null) {
3141 callerApp = getRecordForAppLocked(caller);
3142 if (callerApp != null) {
3143 callingPid = callerApp.pid;
3144 callingUid = callerApp.info.uid;
3145 } else {
3146 Log.w(TAG, "Unable to find app for caller " + caller
3147 + " (pid=" + callingPid + ") when starting: "
3148 + intent.toString());
3149 err = START_PERMISSION_DENIED;
3150 }
3151 }
3152
3153 if (err != START_SUCCESS) {
3154 if (resultRecord != null) {
3155 sendActivityResultLocked(-1,
3156 resultRecord, resultWho, requestCode,
3157 Activity.RESULT_CANCELED, null);
3158 }
3159 return err;
3160 }
3161
3162 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3163 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3164 if (perm != PackageManager.PERMISSION_GRANTED) {
3165 if (resultRecord != null) {
3166 sendActivityResultLocked(-1,
3167 resultRecord, resultWho, requestCode,
3168 Activity.RESULT_CANCELED, null);
3169 }
3170 String msg = "Permission Denial: starting " + intent.toString()
3171 + " from " + callerApp + " (pid=" + callingPid
3172 + ", uid=" + callingUid + ")"
3173 + " requires " + aInfo.permission;
3174 Log.w(TAG, msg);
3175 throw new SecurityException(msg);
3176 }
3177
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003178 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003179 boolean abort = false;
3180 try {
3181 // The Intent we give to the watcher has the extra data
3182 // stripped off, since it can contain private information.
3183 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003184 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003185 aInfo.applicationInfo.packageName);
3186 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003187 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003188 }
3189
3190 if (abort) {
3191 if (resultRecord != null) {
3192 sendActivityResultLocked(-1,
3193 resultRecord, resultWho, requestCode,
3194 Activity.RESULT_CANCELED, null);
3195 }
3196 // We pretend to the caller that it was really started, but
3197 // they will just get a cancel result.
3198 return START_SUCCESS;
3199 }
3200 }
3201
3202 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3203 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003204 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003205
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003206 if (mResumedActivity == null
3207 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3208 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3209 PendingActivityLaunch pal = new PendingActivityLaunch();
3210 pal.r = r;
3211 pal.sourceRecord = sourceRecord;
3212 pal.grantedUriPermissions = grantedUriPermissions;
3213 pal.grantedMode = grantedMode;
3214 pal.onlyIfNeeded = onlyIfNeeded;
3215 mPendingActivityLaunches.add(pal);
3216 return START_SWITCHES_CANCELED;
3217 }
3218 }
3219
3220 if (mDidAppSwitch) {
3221 // This is the second allowed switch since we stopped switches,
3222 // so now just generally allow switches. Use case: user presses
3223 // home (switches disabled, switch to home, mDidAppSwitch now true);
3224 // user taps a home icon (coming from home so allowed, we hit here
3225 // and now allow anyone to switch again).
3226 mAppSwitchesAllowedTime = 0;
3227 } else {
3228 mDidAppSwitch = true;
3229 }
3230
3231 doPendingActivityLaunchesLocked(false);
3232
3233 return startActivityUncheckedLocked(r, sourceRecord,
3234 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3235 }
3236
3237 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3238 final int N = mPendingActivityLaunches.size();
3239 if (N <= 0) {
3240 return;
3241 }
3242 for (int i=0; i<N; i++) {
3243 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3244 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3245 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3246 doResume && i == (N-1));
3247 }
3248 mPendingActivityLaunches.clear();
3249 }
3250
3251 private final int startActivityUncheckedLocked(HistoryRecord r,
3252 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3253 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3254 final Intent intent = r.intent;
3255 final int callingUid = r.launchedFromUid;
3256
3257 int launchFlags = intent.getFlags();
3258
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003259 // We'll invoke onUserLeaving before onPause only if the launching
3260 // activity did not explicitly state that this is an automated launch.
3261 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3262 if (DEBUG_USER_LEAVING) Log.v(TAG,
3263 "startActivity() => mUserLeaving=" + mUserLeaving);
3264
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003265 // If the caller has asked not to resume at this point, we make note
3266 // of this in the record so that we can skip it when trying to find
3267 // the top running activity.
3268 if (!doResume) {
3269 r.delayedResume = true;
3270 }
3271
3272 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3273 != 0 ? r : null;
3274
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003275 // If the onlyIfNeeded flag is set, then we can do this if the activity
3276 // being launched is the same as the one making the call... or, as
3277 // a special case, if we do not know the caller then we count the
3278 // current top activity as the caller.
3279 if (onlyIfNeeded) {
3280 HistoryRecord checkedCaller = sourceRecord;
3281 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003282 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003283 }
3284 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3285 // Caller is not the same as launcher, so always needed.
3286 onlyIfNeeded = false;
3287 }
3288 }
3289
3290 if (grantedUriPermissions != null && callingUid > 0) {
3291 for (int i=0; i<grantedUriPermissions.length; i++) {
3292 grantUriPermissionLocked(callingUid, r.packageName,
3293 grantedUriPermissions[i], grantedMode, r);
3294 }
3295 }
3296
3297 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3298 intent, r);
3299
3300 if (sourceRecord == null) {
3301 // This activity is not being started from another... in this
3302 // case we -always- start a new task.
3303 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3304 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3305 + intent);
3306 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3307 }
3308 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3309 // The original activity who is starting us is running as a single
3310 // instance... this new activity it is starting must go on its
3311 // own task.
3312 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3313 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3314 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3315 // The activity being started is a single instance... it always
3316 // gets launched into its own task.
3317 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3318 }
3319
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003320 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003321 // For whatever reason this activity is being launched into a new
3322 // task... yet the caller has requested a result back. Well, that
3323 // is pretty messed up, so instead immediately send back a cancel
3324 // and let the new task continue launched as normal without a
3325 // dependency on its originator.
3326 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3327 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003328 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003329 Activity.RESULT_CANCELED, null);
3330 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003331 }
3332
3333 boolean addingToTask = false;
3334 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3335 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3336 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3337 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3338 // If bring to front is requested, and no result is requested, and
3339 // we can find a task that was started with this same
3340 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003341 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003342 // See if there is a task to bring to the front. If this is
3343 // a SINGLE_INSTANCE activity, there can be one and only one
3344 // instance of it in the history, and it is always in its own
3345 // unique task, so we do a special search.
3346 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3347 ? findTaskLocked(intent, r.info)
3348 : findActivityLocked(intent, r.info);
3349 if (taskTop != null) {
3350 if (taskTop.task.intent == null) {
3351 // This task was started because of movement of
3352 // the activity based on affinity... now that we
3353 // are actually launching it, we can assign the
3354 // base intent.
3355 taskTop.task.setIntent(intent, r.info);
3356 }
3357 // If the target task is not in the front, then we need
3358 // to bring it to the front... except... well, with
3359 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3360 // to have the same behavior as if a new instance was
3361 // being started, which means not bringing it to the front
3362 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003363 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003364 if (curTop.task != taskTop.task) {
3365 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3366 boolean callerAtFront = sourceRecord == null
3367 || curTop.task == sourceRecord.task;
3368 if (callerAtFront) {
3369 // We really do want to push this one into the
3370 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003371 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003372 }
3373 }
3374 // If the caller has requested that the target task be
3375 // reset, then do so.
3376 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3377 taskTop = resetTaskIfNeededLocked(taskTop, r);
3378 }
3379 if (onlyIfNeeded) {
3380 // We don't need to start a new activity, and
3381 // the client said not to do anything if that
3382 // is the case, so this is it! And for paranoia, make
3383 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003384 if (doResume) {
3385 resumeTopActivityLocked(null);
3386 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003387 return START_RETURN_INTENT_TO_CALLER;
3388 }
3389 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3390 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3391 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3392 // In this situation we want to remove all activities
3393 // from the task up to the one being started. In most
3394 // cases this means we are resetting the task to its
3395 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003396 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003397 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003398 if (top != null) {
3399 if (top.frontOfTask) {
3400 // Activity aliases may mean we use different
3401 // intents for the top activity, so make sure
3402 // the task now has the identity of the new
3403 // intent.
3404 top.task.setIntent(r.intent, r.info);
3405 }
3406 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3407 deliverNewIntentLocked(top, r.intent);
3408 } else {
3409 // A special case: we need to
3410 // start the activity because it is not currently
3411 // running, and the caller has asked to clear the
3412 // current task to have this activity at the top.
3413 addingToTask = true;
3414 // Now pretend like this activity is being started
3415 // by the top of its task, so it is put in the
3416 // right place.
3417 sourceRecord = taskTop;
3418 }
3419 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3420 // In this case the top activity on the task is the
3421 // same as the one being launched, so we take that
3422 // as a request to bring the task to the foreground.
3423 // If the top activity in the task is the root
3424 // activity, deliver this new intent to it if it
3425 // desires.
3426 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3427 && taskTop.realActivity.equals(r.realActivity)) {
3428 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3429 if (taskTop.frontOfTask) {
3430 taskTop.task.setIntent(r.intent, r.info);
3431 }
3432 deliverNewIntentLocked(taskTop, r.intent);
3433 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3434 // In this case we are launching the root activity
3435 // of the task, but with a different intent. We
3436 // should start a new instance on top.
3437 addingToTask = true;
3438 sourceRecord = taskTop;
3439 }
3440 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3441 // In this case an activity is being launched in to an
3442 // existing task, without resetting that task. This
3443 // is typically the situation of launching an activity
3444 // from a notification or shortcut. We want to place
3445 // the new activity on top of the current task.
3446 addingToTask = true;
3447 sourceRecord = taskTop;
3448 } else if (!taskTop.task.rootWasReset) {
3449 // In this case we are launching in to an existing task
3450 // that has not yet been started from its front door.
3451 // The current task has been brought to the front.
3452 // Ideally, we'd probably like to place this new task
3453 // at the bottom of its stack, but that's a little hard
3454 // to do with the current organization of the code so
3455 // for now we'll just drop it.
3456 taskTop.task.setIntent(r.intent, r.info);
3457 }
3458 if (!addingToTask) {
3459 // We didn't do anything... but it was needed (a.k.a., client
3460 // don't use that intent!) And for paranoia, make
3461 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003462 if (doResume) {
3463 resumeTopActivityLocked(null);
3464 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003465 return START_TASK_TO_FRONT;
3466 }
3467 }
3468 }
3469 }
3470
3471 //String uri = r.intent.toURI();
3472 //Intent intent2 = new Intent(uri);
3473 //Log.i(TAG, "Given intent: " + r.intent);
3474 //Log.i(TAG, "URI is: " + uri);
3475 //Log.i(TAG, "To intent: " + intent2);
3476
3477 if (r.packageName != null) {
3478 // If the activity being launched is the same as the one currently
3479 // at the top, then we need to check if it should only be launched
3480 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003481 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3482 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003483 if (top.realActivity.equals(r.realActivity)) {
3484 if (top.app != null && top.app.thread != null) {
3485 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3486 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3487 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3488 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3489 // For paranoia, make sure we have correctly
3490 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003491 if (doResume) {
3492 resumeTopActivityLocked(null);
3493 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003494 if (onlyIfNeeded) {
3495 // We don't need to start a new activity, and
3496 // the client said not to do anything if that
3497 // is the case, so this is it!
3498 return START_RETURN_INTENT_TO_CALLER;
3499 }
3500 deliverNewIntentLocked(top, r.intent);
3501 return START_DELIVERED_TO_TOP;
3502 }
3503 }
3504 }
3505 }
3506
3507 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003508 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003509 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003510 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003511 Activity.RESULT_CANCELED, null);
3512 }
3513 return START_CLASS_NOT_FOUND;
3514 }
3515
3516 boolean newTask = false;
3517
3518 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003519 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003520 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3521 // todo: should do better management of integers.
3522 mCurTask++;
3523 if (mCurTask <= 0) {
3524 mCurTask = 1;
3525 }
3526 r.task = new TaskRecord(mCurTask, r.info, intent,
3527 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3528 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3529 + " in new task " + r.task);
3530 newTask = true;
3531 addRecentTask(r.task);
3532
3533 } else if (sourceRecord != null) {
3534 if (!addingToTask &&
3535 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3536 // In this case, we are adding the activity to an existing
3537 // task, but the caller has asked to clear that task if the
3538 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003539 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003540 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003541 if (top != null) {
3542 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3543 deliverNewIntentLocked(top, r.intent);
3544 // For paranoia, make sure we have correctly
3545 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003546 if (doResume) {
3547 resumeTopActivityLocked(null);
3548 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003549 return START_DELIVERED_TO_TOP;
3550 }
3551 } else if (!addingToTask &&
3552 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3553 // In this case, we are launching an activity in our own task
3554 // that may already be running somewhere in the history, and
3555 // we want to shuffle it to the front of the stack if so.
3556 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3557 if (where >= 0) {
3558 HistoryRecord top = moveActivityToFrontLocked(where);
3559 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3560 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003561 if (doResume) {
3562 resumeTopActivityLocked(null);
3563 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003564 return START_DELIVERED_TO_TOP;
3565 }
3566 }
3567 // An existing activity is starting this new activity, so we want
3568 // to keep the new one in the same task as the one that is starting
3569 // it.
3570 r.task = sourceRecord.task;
3571 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3572 + " in existing task " + r.task);
3573
3574 } else {
3575 // This not being started from an existing activity, and not part
3576 // of a new task... just put it in the top task, though these days
3577 // this case should never happen.
3578 final int N = mHistory.size();
3579 HistoryRecord prev =
3580 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3581 r.task = prev != null
3582 ? prev.task
3583 : new TaskRecord(mCurTask, r.info, intent,
3584 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3585 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3586 + " in new guessed " + r.task);
3587 }
3588 if (newTask) {
3589 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3590 }
3591 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003592 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003593 return START_SUCCESS;
3594 }
3595
3596 public final int startActivity(IApplicationThread caller,
3597 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3598 int grantedMode, IBinder resultTo,
3599 String resultWho, int requestCode, boolean onlyIfNeeded,
3600 boolean debug) {
3601 // Refuse possible leaked file descriptors
3602 if (intent != null && intent.hasFileDescriptors()) {
3603 throw new IllegalArgumentException("File descriptors passed in Intent");
3604 }
3605
The Android Open Source Project4df24232009-03-05 14:34:35 -08003606 final boolean componentSpecified = intent.getComponent() != null;
3607
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003608 // Don't modify the client's object!
3609 intent = new Intent(intent);
3610
3611 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003612 ActivityInfo aInfo;
3613 try {
3614 ResolveInfo rInfo =
3615 ActivityThread.getPackageManager().resolveIntent(
3616 intent, resolvedType,
3617 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003618 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003619 aInfo = rInfo != null ? rInfo.activityInfo : null;
3620 } catch (RemoteException e) {
3621 aInfo = null;
3622 }
3623
3624 if (aInfo != null) {
3625 // Store the found target back into the intent, because now that
3626 // we have it we never want to do this again. For example, if the
3627 // user navigates back to this point in the history, we should
3628 // always restart the exact same activity.
3629 intent.setComponent(new ComponentName(
3630 aInfo.applicationInfo.packageName, aInfo.name));
3631
3632 // Don't debug things in the system process
3633 if (debug) {
3634 if (!aInfo.processName.equals("system")) {
3635 setDebugApp(aInfo.processName, true, false);
3636 }
3637 }
3638 }
3639
3640 synchronized(this) {
3641 final long origId = Binder.clearCallingIdentity();
3642 int res = startActivityLocked(caller, intent, resolvedType,
3643 grantedUriPermissions, grantedMode, aInfo,
3644 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003645 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003646 Binder.restoreCallingIdentity(origId);
3647 return res;
3648 }
3649 }
3650
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003651 public int startActivityIntentSender(IApplicationThread caller,
3652 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003653 IBinder resultTo, String resultWho, int requestCode,
3654 int flagsMask, int flagsValues) {
3655 // Refuse possible leaked file descriptors
3656 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3657 throw new IllegalArgumentException("File descriptors passed in Intent");
3658 }
3659
3660 IIntentSender sender = intent.getTarget();
3661 if (!(sender instanceof PendingIntentRecord)) {
3662 throw new IllegalArgumentException("Bad PendingIntent object");
3663 }
3664
3665 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003666
3667 synchronized (this) {
3668 // If this is coming from the currently resumed activity, it is
3669 // effectively saying that app switches are allowed at this point.
3670 if (mResumedActivity != null
3671 && mResumedActivity.info.applicationInfo.uid ==
3672 Binder.getCallingUid()) {
3673 mAppSwitchesAllowedTime = 0;
3674 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003675 }
3676
3677 return pir.sendInner(0, fillInIntent, resolvedType,
3678 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3679 }
3680
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003681 public boolean startNextMatchingActivity(IBinder callingActivity,
3682 Intent intent) {
3683 // Refuse possible leaked file descriptors
3684 if (intent != null && intent.hasFileDescriptors() == true) {
3685 throw new IllegalArgumentException("File descriptors passed in Intent");
3686 }
3687
3688 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003689 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003690 if (index < 0) {
3691 return false;
3692 }
3693 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3694 if (r.app == null || r.app.thread == null) {
3695 // The caller is not running... d'oh!
3696 return false;
3697 }
3698 intent = new Intent(intent);
3699 // The caller is not allowed to change the data.
3700 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3701 // And we are resetting to find the next component...
3702 intent.setComponent(null);
3703
3704 ActivityInfo aInfo = null;
3705 try {
3706 List<ResolveInfo> resolves =
3707 ActivityThread.getPackageManager().queryIntentActivities(
3708 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003709 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003710
3711 // Look for the original activity in the list...
3712 final int N = resolves != null ? resolves.size() : 0;
3713 for (int i=0; i<N; i++) {
3714 ResolveInfo rInfo = resolves.get(i);
3715 if (rInfo.activityInfo.packageName.equals(r.packageName)
3716 && rInfo.activityInfo.name.equals(r.info.name)) {
3717 // We found the current one... the next matching is
3718 // after it.
3719 i++;
3720 if (i<N) {
3721 aInfo = resolves.get(i).activityInfo;
3722 }
3723 break;
3724 }
3725 }
3726 } catch (RemoteException e) {
3727 }
3728
3729 if (aInfo == null) {
3730 // Nobody who is next!
3731 return false;
3732 }
3733
3734 intent.setComponent(new ComponentName(
3735 aInfo.applicationInfo.packageName, aInfo.name));
3736 intent.setFlags(intent.getFlags()&~(
3737 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3738 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3739 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3740 Intent.FLAG_ACTIVITY_NEW_TASK));
3741
3742 // Okay now we need to start the new activity, replacing the
3743 // currently running activity. This is a little tricky because
3744 // we want to start the new one as if the current one is finished,
3745 // but not finish the current one first so that there is no flicker.
3746 // And thus...
3747 final boolean wasFinishing = r.finishing;
3748 r.finishing = true;
3749
3750 // Propagate reply information over to the new activity.
3751 final HistoryRecord resultTo = r.resultTo;
3752 final String resultWho = r.resultWho;
3753 final int requestCode = r.requestCode;
3754 r.resultTo = null;
3755 if (resultTo != null) {
3756 resultTo.removeResultsLocked(r, resultWho, requestCode);
3757 }
3758
3759 final long origId = Binder.clearCallingIdentity();
3760 // XXX we are not dealing with propagating grantedUriPermissions...
3761 // those are not yet exposed to user code, so there is no need.
3762 int res = startActivityLocked(r.app.thread, intent,
3763 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003764 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003765 Binder.restoreCallingIdentity(origId);
3766
3767 r.finishing = wasFinishing;
3768 if (res != START_SUCCESS) {
3769 return false;
3770 }
3771 return true;
3772 }
3773 }
3774
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003775 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003776 Intent intent, String resolvedType, IBinder resultTo,
3777 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003778
3779 // This is so super not safe, that only the system (or okay root)
3780 // can do it.
3781 final int callingUid = Binder.getCallingUid();
3782 if (callingUid != 0 && callingUid != Process.myUid()) {
3783 throw new SecurityException(
3784 "startActivityInPackage only available to the system");
3785 }
3786
The Android Open Source Project4df24232009-03-05 14:34:35 -08003787 final boolean componentSpecified = intent.getComponent() != null;
3788
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003789 // Don't modify the client's object!
3790 intent = new Intent(intent);
3791
3792 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003793 ActivityInfo aInfo;
3794 try {
3795 ResolveInfo rInfo =
3796 ActivityThread.getPackageManager().resolveIntent(
3797 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003798 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003799 aInfo = rInfo != null ? rInfo.activityInfo : null;
3800 } catch (RemoteException e) {
3801 aInfo = null;
3802 }
3803
3804 if (aInfo != null) {
3805 // Store the found target back into the intent, because now that
3806 // we have it we never want to do this again. For example, if the
3807 // user navigates back to this point in the history, we should
3808 // always restart the exact same activity.
3809 intent.setComponent(new ComponentName(
3810 aInfo.applicationInfo.packageName, aInfo.name));
3811 }
3812
3813 synchronized(this) {
3814 return startActivityLocked(null, intent, resolvedType,
3815 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003816 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003817 }
3818 }
3819
3820 private final void addRecentTask(TaskRecord task) {
3821 // Remove any existing entries that are the same kind of task.
3822 int N = mRecentTasks.size();
3823 for (int i=0; i<N; i++) {
3824 TaskRecord tr = mRecentTasks.get(i);
3825 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3826 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3827 mRecentTasks.remove(i);
3828 i--;
3829 N--;
3830 if (task.intent == null) {
3831 // If the new recent task we are adding is not fully
3832 // specified, then replace it with the existing recent task.
3833 task = tr;
3834 }
3835 }
3836 }
3837 if (N >= MAX_RECENT_TASKS) {
3838 mRecentTasks.remove(N-1);
3839 }
3840 mRecentTasks.add(0, task);
3841 }
3842
3843 public void setRequestedOrientation(IBinder token,
3844 int requestedOrientation) {
3845 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003846 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003847 if (index < 0) {
3848 return;
3849 }
3850 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3851 final long origId = Binder.clearCallingIdentity();
3852 mWindowManager.setAppOrientation(r, requestedOrientation);
3853 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003854 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003855 r.mayFreezeScreenLocked(r.app) ? r : null);
3856 if (config != null) {
3857 r.frozenBeforeDestroy = true;
3858 if (!updateConfigurationLocked(config, r)) {
3859 resumeTopActivityLocked(null);
3860 }
3861 }
3862 Binder.restoreCallingIdentity(origId);
3863 }
3864 }
3865
3866 public int getRequestedOrientation(IBinder token) {
3867 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003868 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003869 if (index < 0) {
3870 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3871 }
3872 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3873 return mWindowManager.getAppOrientation(r);
3874 }
3875 }
3876
3877 private final void stopActivityLocked(HistoryRecord r) {
3878 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3879 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3880 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3881 if (!r.finishing) {
3882 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3883 "no-history");
3884 }
3885 } else if (r.app != null && r.app.thread != null) {
3886 if (mFocusedActivity == r) {
3887 setFocusedActivityLocked(topRunningActivityLocked(null));
3888 }
3889 r.resumeKeyDispatchingLocked();
3890 try {
3891 r.stopped = false;
3892 r.state = ActivityState.STOPPING;
3893 if (DEBUG_VISBILITY) Log.v(
3894 TAG, "Stopping visible=" + r.visible + " for " + r);
3895 if (!r.visible) {
3896 mWindowManager.setAppVisibility(r, false);
3897 }
3898 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3899 } catch (Exception e) {
3900 // Maybe just ignore exceptions here... if the process
3901 // has crashed, our death notification will clean things
3902 // up.
3903 Log.w(TAG, "Exception thrown during pause", e);
3904 // Just in case, assume it to be stopped.
3905 r.stopped = true;
3906 r.state = ActivityState.STOPPED;
3907 if (r.configDestroy) {
3908 destroyActivityLocked(r, true);
3909 }
3910 }
3911 }
3912 }
3913
3914 /**
3915 * @return Returns true if the activity is being finished, false if for
3916 * some reason it is being left as-is.
3917 */
3918 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3919 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003920 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003921 TAG, "Finishing activity: token=" + token
3922 + ", result=" + resultCode + ", data=" + resultData);
3923
Dianne Hackborn75b03852009-06-12 15:43:26 -07003924 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003925 if (index < 0) {
3926 return false;
3927 }
3928 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3929
3930 // Is this the last activity left?
3931 boolean lastActivity = true;
3932 for (int i=mHistory.size()-1; i>=0; i--) {
3933 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3934 if (!p.finishing && p != r) {
3935 lastActivity = false;
3936 break;
3937 }
3938 }
3939
3940 // If this is the last activity, but it is the home activity, then
3941 // just don't finish it.
3942 if (lastActivity) {
3943 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3944 return false;
3945 }
3946 }
3947
3948 finishActivityLocked(r, index, resultCode, resultData, reason);
3949 return true;
3950 }
3951
3952 /**
3953 * @return Returns true if this activity has been removed from the history
3954 * list, or false if it is still in the list and will be removed later.
3955 */
3956 private final boolean finishActivityLocked(HistoryRecord r, int index,
3957 int resultCode, Intent resultData, String reason) {
3958 if (r.finishing) {
3959 Log.w(TAG, "Duplicate finish request for " + r);
3960 return false;
3961 }
3962
3963 r.finishing = true;
3964 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3965 System.identityHashCode(r),
3966 r.task.taskId, r.shortComponentName, reason);
3967 r.task.numActivities--;
3968 if (r.frontOfTask && index < (mHistory.size()-1)) {
3969 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3970 if (next.task == r.task) {
3971 next.frontOfTask = true;
3972 }
3973 }
3974
3975 r.pauseKeyDispatchingLocked();
3976 if (mFocusedActivity == r) {
3977 setFocusedActivityLocked(topRunningActivityLocked(null));
3978 }
3979
3980 // send the result
3981 HistoryRecord resultTo = r.resultTo;
3982 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003983 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3984 + " who=" + r.resultWho + " req=" + r.requestCode
3985 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003986 if (r.info.applicationInfo.uid > 0) {
3987 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3988 r.packageName, resultData, r);
3989 }
3990 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3991 resultData);
3992 r.resultTo = null;
3993 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003994 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003995
3996 // Make sure this HistoryRecord is not holding on to other resources,
3997 // because clients have remote IPC references to this object so we
3998 // can't assume that will go away and want to avoid circular IPC refs.
3999 r.results = null;
4000 r.pendingResults = null;
4001 r.newIntents = null;
4002 r.icicle = null;
4003
4004 if (mPendingThumbnails.size() > 0) {
4005 // There are clients waiting to receive thumbnails so, in case
4006 // this is an activity that someone is waiting for, add it
4007 // to the pending list so we can correctly update the clients.
4008 mCancelledThumbnails.add(r);
4009 }
4010
4011 if (mResumedActivity == r) {
4012 boolean endTask = index <= 0
4013 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
4014 if (DEBUG_TRANSITION) Log.v(TAG,
4015 "Prepare close transition: finishing " + r);
4016 mWindowManager.prepareAppTransition(endTask
4017 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
4018 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
4019
4020 // Tell window manager to prepare for this one to be removed.
4021 mWindowManager.setAppVisibility(r, false);
4022
4023 if (mPausingActivity == null) {
4024 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4025 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4026 startPausingLocked(false, false);
4027 }
4028
4029 } else if (r.state != ActivityState.PAUSING) {
4030 // If the activity is PAUSING, we will complete the finish once
4031 // it is done pausing; else we can just directly finish it here.
4032 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4033 return finishCurrentActivityLocked(r, index,
4034 FINISH_AFTER_PAUSE) == null;
4035 } else {
4036 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4037 }
4038
4039 return false;
4040 }
4041
4042 private static final int FINISH_IMMEDIATELY = 0;
4043 private static final int FINISH_AFTER_PAUSE = 1;
4044 private static final int FINISH_AFTER_VISIBLE = 2;
4045
4046 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4047 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004048 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004049 if (index < 0) {
4050 return null;
4051 }
4052
4053 return finishCurrentActivityLocked(r, index, mode);
4054 }
4055
4056 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4057 int index, int mode) {
4058 // First things first: if this activity is currently visible,
4059 // and the resumed activity is not yet visible, then hold off on
4060 // finishing until the resumed one becomes visible.
4061 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4062 if (!mStoppingActivities.contains(r)) {
4063 mStoppingActivities.add(r);
4064 if (mStoppingActivities.size() > 3) {
4065 // If we already have a few activities waiting to stop,
4066 // then give up on things going idle and start clearing
4067 // them out.
4068 Message msg = Message.obtain();
4069 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4070 mHandler.sendMessage(msg);
4071 }
4072 }
4073 r.state = ActivityState.STOPPING;
4074 updateOomAdjLocked();
4075 return r;
4076 }
4077
4078 // make sure the record is cleaned out of other places.
4079 mStoppingActivities.remove(r);
4080 mWaitingVisibleActivities.remove(r);
4081 if (mResumedActivity == r) {
4082 mResumedActivity = null;
4083 }
4084 final ActivityState prevState = r.state;
4085 r.state = ActivityState.FINISHING;
4086
4087 if (mode == FINISH_IMMEDIATELY
4088 || prevState == ActivityState.STOPPED
4089 || prevState == ActivityState.INITIALIZING) {
4090 // If this activity is already stopped, we can just finish
4091 // it right now.
4092 return destroyActivityLocked(r, true) ? null : r;
4093 } else {
4094 // Need to go through the full pause cycle to get this
4095 // activity into the stopped state and then finish it.
4096 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4097 mFinishingActivities.add(r);
4098 resumeTopActivityLocked(null);
4099 }
4100 return r;
4101 }
4102
4103 /**
4104 * This is the internal entry point for handling Activity.finish().
4105 *
4106 * @param token The Binder token referencing the Activity we want to finish.
4107 * @param resultCode Result code, if any, from this Activity.
4108 * @param resultData Result data (Intent), if any, from this Activity.
4109 *
4110 * @result Returns true if the activity successfully finished, or false if it is still running.
4111 */
4112 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4113 // Refuse possible leaked file descriptors
4114 if (resultData != null && resultData.hasFileDescriptors() == true) {
4115 throw new IllegalArgumentException("File descriptors passed in Intent");
4116 }
4117
4118 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004119 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004120 // Find the first activity that is not finishing.
4121 HistoryRecord next = topRunningActivityLocked(token, 0);
4122 if (next != null) {
4123 // ask watcher if this is allowed
4124 boolean resumeOK = true;
4125 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004126 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004127 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004128 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004129 }
4130
4131 if (!resumeOK) {
4132 return false;
4133 }
4134 }
4135 }
4136 final long origId = Binder.clearCallingIdentity();
4137 boolean res = requestFinishActivityLocked(token, resultCode,
4138 resultData, "app-request");
4139 Binder.restoreCallingIdentity(origId);
4140 return res;
4141 }
4142 }
4143
4144 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4145 String resultWho, int requestCode, int resultCode, Intent data) {
4146
4147 if (callingUid > 0) {
4148 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4149 data, r);
4150 }
4151
The Android Open Source Project10592532009-03-18 17:39:46 -07004152 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4153 + " : who=" + resultWho + " req=" + requestCode
4154 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004155 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4156 try {
4157 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4158 list.add(new ResultInfo(resultWho, requestCode,
4159 resultCode, data));
4160 r.app.thread.scheduleSendResult(r, list);
4161 return;
4162 } catch (Exception e) {
4163 Log.w(TAG, "Exception thrown sending result to " + r, e);
4164 }
4165 }
4166
4167 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4168 }
4169
4170 public final void finishSubActivity(IBinder token, String resultWho,
4171 int requestCode) {
4172 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004173 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004174 if (index < 0) {
4175 return;
4176 }
4177 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4178
4179 final long origId = Binder.clearCallingIdentity();
4180
4181 int i;
4182 for (i=mHistory.size()-1; i>=0; i--) {
4183 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4184 if (r.resultTo == self && r.requestCode == requestCode) {
4185 if ((r.resultWho == null && resultWho == null) ||
4186 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4187 finishActivityLocked(r, i,
4188 Activity.RESULT_CANCELED, null, "request-sub");
4189 }
4190 }
4191 }
4192
4193 Binder.restoreCallingIdentity(origId);
4194 }
4195 }
4196
4197 /**
4198 * Perform clean-up of service connections in an activity record.
4199 */
4200 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4201 // Throw away any services that have been bound by this activity.
4202 if (r.connections != null) {
4203 Iterator<ConnectionRecord> it = r.connections.iterator();
4204 while (it.hasNext()) {
4205 ConnectionRecord c = it.next();
4206 removeConnectionLocked(c, null, r);
4207 }
4208 r.connections = null;
4209 }
4210 }
4211
4212 /**
4213 * Perform the common clean-up of an activity record. This is called both
4214 * as part of destroyActivityLocked() (when destroying the client-side
4215 * representation) and cleaning things up as a result of its hosting
4216 * processing going away, in which case there is no remaining client-side
4217 * state to destroy so only the cleanup here is needed.
4218 */
4219 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4220 if (mResumedActivity == r) {
4221 mResumedActivity = null;
4222 }
4223 if (mFocusedActivity == r) {
4224 mFocusedActivity = null;
4225 }
4226
4227 r.configDestroy = false;
4228 r.frozenBeforeDestroy = false;
4229
4230 // Make sure this record is no longer in the pending finishes list.
4231 // This could happen, for example, if we are trimming activities
4232 // down to the max limit while they are still waiting to finish.
4233 mFinishingActivities.remove(r);
4234 mWaitingVisibleActivities.remove(r);
4235
4236 // Remove any pending results.
4237 if (r.finishing && r.pendingResults != null) {
4238 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4239 PendingIntentRecord rec = apr.get();
4240 if (rec != null) {
4241 cancelIntentSenderLocked(rec, false);
4242 }
4243 }
4244 r.pendingResults = null;
4245 }
4246
4247 if (cleanServices) {
4248 cleanUpActivityServicesLocked(r);
4249 }
4250
4251 if (mPendingThumbnails.size() > 0) {
4252 // There are clients waiting to receive thumbnails so, in case
4253 // this is an activity that someone is waiting for, add it
4254 // to the pending list so we can correctly update the clients.
4255 mCancelledThumbnails.add(r);
4256 }
4257
4258 // Get rid of any pending idle timeouts.
4259 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4260 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4261 }
4262
4263 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4264 if (r.state != ActivityState.DESTROYED) {
4265 mHistory.remove(r);
4266 r.inHistory = false;
4267 r.state = ActivityState.DESTROYED;
4268 mWindowManager.removeAppToken(r);
4269 if (VALIDATE_TOKENS) {
4270 mWindowManager.validateAppTokens(mHistory);
4271 }
4272 cleanUpActivityServicesLocked(r);
4273 removeActivityUriPermissionsLocked(r);
4274 }
4275 }
4276
4277 /**
4278 * Destroy the current CLIENT SIDE instance of an activity. This may be
4279 * called both when actually finishing an activity, or when performing
4280 * a configuration switch where we destroy the current client-side object
4281 * but then create a new client-side object for this same HistoryRecord.
4282 */
4283 private final boolean destroyActivityLocked(HistoryRecord r,
4284 boolean removeFromApp) {
4285 if (DEBUG_SWITCH) Log.v(
4286 TAG, "Removing activity: token=" + r
4287 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4288 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4289 System.identityHashCode(r),
4290 r.task.taskId, r.shortComponentName);
4291
4292 boolean removedFromHistory = false;
4293
4294 cleanUpActivityLocked(r, false);
4295
4296 if (r.app != null) {
4297 if (removeFromApp) {
4298 int idx = r.app.activities.indexOf(r);
4299 if (idx >= 0) {
4300 r.app.activities.remove(idx);
4301 }
4302 if (r.persistent) {
4303 decPersistentCountLocked(r.app);
4304 }
4305 }
4306
4307 boolean skipDestroy = false;
4308
4309 try {
4310 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4311 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4312 r.configChangeFlags);
4313 } catch (Exception e) {
4314 // We can just ignore exceptions here... if the process
4315 // has crashed, our death notification will clean things
4316 // up.
4317 //Log.w(TAG, "Exception thrown during finish", e);
4318 if (r.finishing) {
4319 removeActivityFromHistoryLocked(r);
4320 removedFromHistory = true;
4321 skipDestroy = true;
4322 }
4323 }
4324
4325 r.app = null;
4326 r.nowVisible = false;
4327
4328 if (r.finishing && !skipDestroy) {
4329 r.state = ActivityState.DESTROYING;
4330 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4331 msg.obj = r;
4332 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4333 } else {
4334 r.state = ActivityState.DESTROYED;
4335 }
4336 } else {
4337 // remove this record from the history.
4338 if (r.finishing) {
4339 removeActivityFromHistoryLocked(r);
4340 removedFromHistory = true;
4341 } else {
4342 r.state = ActivityState.DESTROYED;
4343 }
4344 }
4345
4346 r.configChangeFlags = 0;
4347
4348 if (!mLRUActivities.remove(r)) {
4349 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4350 }
4351
4352 return removedFromHistory;
4353 }
4354
4355 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4356 ProcessRecord app)
4357 {
4358 int i = list.size();
4359 if (localLOGV) Log.v(
4360 TAG, "Removing app " + app + " from list " + list
4361 + " with " + i + " entries");
4362 while (i > 0) {
4363 i--;
4364 HistoryRecord r = (HistoryRecord)list.get(i);
4365 if (localLOGV) Log.v(
4366 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4367 if (r.app == app) {
4368 if (localLOGV) Log.v(TAG, "Removing this entry!");
4369 list.remove(i);
4370 }
4371 }
4372 }
4373
4374 /**
4375 * Main function for removing an existing process from the activity manager
4376 * as a result of that process going away. Clears out all connections
4377 * to the process.
4378 */
4379 private final void handleAppDiedLocked(ProcessRecord app,
4380 boolean restarting) {
4381 cleanUpApplicationRecordLocked(app, restarting, -1);
4382 if (!restarting) {
4383 mLRUProcesses.remove(app);
4384 }
4385
4386 // Just in case...
4387 if (mPausingActivity != null && mPausingActivity.app == app) {
4388 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4389 mPausingActivity = null;
4390 }
4391 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4392 mLastPausedActivity = null;
4393 }
4394
4395 // Remove this application's activities from active lists.
4396 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4397 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4398 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4399 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4400
4401 boolean atTop = true;
4402 boolean hasVisibleActivities = false;
4403
4404 // Clean out the history list.
4405 int i = mHistory.size();
4406 if (localLOGV) Log.v(
4407 TAG, "Removing app " + app + " from history with " + i + " entries");
4408 while (i > 0) {
4409 i--;
4410 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4411 if (localLOGV) Log.v(
4412 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4413 if (r.app == app) {
4414 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4415 if (localLOGV) Log.v(
4416 TAG, "Removing this entry! frozen=" + r.haveState
4417 + " finishing=" + r.finishing);
4418 mHistory.remove(i);
4419
4420 r.inHistory = false;
4421 mWindowManager.removeAppToken(r);
4422 if (VALIDATE_TOKENS) {
4423 mWindowManager.validateAppTokens(mHistory);
4424 }
4425 removeActivityUriPermissionsLocked(r);
4426
4427 } else {
4428 // We have the current state for this activity, so
4429 // it can be restarted later when needed.
4430 if (localLOGV) Log.v(
4431 TAG, "Keeping entry, setting app to null");
4432 if (r.visible) {
4433 hasVisibleActivities = true;
4434 }
4435 r.app = null;
4436 r.nowVisible = false;
4437 if (!r.haveState) {
4438 r.icicle = null;
4439 }
4440 }
4441
4442 cleanUpActivityLocked(r, true);
4443 r.state = ActivityState.STOPPED;
4444 }
4445 atTop = false;
4446 }
4447
4448 app.activities.clear();
4449
4450 if (app.instrumentationClass != null) {
4451 Log.w(TAG, "Crash of app " + app.processName
4452 + " running instrumentation " + app.instrumentationClass);
4453 Bundle info = new Bundle();
4454 info.putString("shortMsg", "Process crashed.");
4455 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4456 }
4457
4458 if (!restarting) {
4459 if (!resumeTopActivityLocked(null)) {
4460 // If there was nothing to resume, and we are not already
4461 // restarting this process, but there is a visible activity that
4462 // is hosted by the process... then make sure all visible
4463 // activities are running, taking care of restarting this
4464 // process.
4465 if (hasVisibleActivities) {
4466 ensureActivitiesVisibleLocked(null, 0);
4467 }
4468 }
4469 }
4470 }
4471
4472 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4473 IBinder threadBinder = thread.asBinder();
4474
4475 // Find the application record.
4476 int count = mLRUProcesses.size();
4477 int i;
4478 for (i=0; i<count; i++) {
4479 ProcessRecord rec = mLRUProcesses.get(i);
4480 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4481 return i;
4482 }
4483 }
4484 return -1;
4485 }
4486
4487 private final ProcessRecord getRecordForAppLocked(
4488 IApplicationThread thread) {
4489 if (thread == null) {
4490 return null;
4491 }
4492
4493 int appIndex = getLRURecordIndexForAppLocked(thread);
4494 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4495 }
4496
4497 private final void appDiedLocked(ProcessRecord app, int pid,
4498 IApplicationThread thread) {
4499
4500 mProcDeaths[0]++;
4501
4502 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4503 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4504 + ") has died.");
4505 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4506 if (localLOGV) Log.v(
4507 TAG, "Dying app: " + app + ", pid: " + pid
4508 + ", thread: " + thread.asBinder());
4509 boolean doLowMem = app.instrumentationClass == null;
4510 handleAppDiedLocked(app, false);
4511
4512 if (doLowMem) {
4513 // If there are no longer any background processes running,
4514 // and the app that died was not running instrumentation,
4515 // then tell everyone we are now low on memory.
4516 boolean haveBg = false;
4517 int count = mLRUProcesses.size();
4518 int i;
4519 for (i=0; i<count; i++) {
4520 ProcessRecord rec = mLRUProcesses.get(i);
4521 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4522 haveBg = true;
4523 break;
4524 }
4525 }
4526
4527 if (!haveBg) {
4528 Log.i(TAG, "Low Memory: No more background processes.");
4529 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004530 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004531 for (i=0; i<count; i++) {
4532 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004533 if (rec.thread != null &&
4534 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4535 // The low memory report is overriding any current
4536 // state for a GC request. Make sure to do
4537 // visible/foreground processes first.
4538 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4539 rec.lastRequestedGc = 0;
4540 } else {
4541 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004542 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004543 rec.reportLowMemory = true;
4544 rec.lastLowMemory = now;
4545 mProcessesToGc.remove(rec);
4546 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004547 }
4548 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004549 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004550 }
4551 }
4552 } else if (Config.LOGD) {
4553 Log.d(TAG, "Received spurious death notification for thread "
4554 + thread.asBinder());
4555 }
4556 }
4557
4558 final String readFile(String filename) {
4559 try {
4560 FileInputStream fs = new FileInputStream(filename);
4561 byte[] inp = new byte[8192];
4562 int size = fs.read(inp);
4563 fs.close();
4564 return new String(inp, 0, 0, size);
4565 } catch (java.io.IOException e) {
4566 }
4567 return "";
4568 }
4569
4570 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004571 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004572 if (app.notResponding || app.crashing) {
4573 return;
4574 }
4575
4576 // Log the ANR to the event log.
4577 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4578
4579 // If we are on a secure build and the application is not interesting to the user (it is
4580 // not visible or in the background), just kill it instead of displaying a dialog.
4581 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4582 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4583 Process.killProcess(app.pid);
4584 return;
4585 }
4586
4587 // DeviceMonitor.start();
4588
4589 String processInfo = null;
4590 if (MONITOR_CPU_USAGE) {
4591 updateCpuStatsNow();
4592 synchronized (mProcessStatsThread) {
4593 processInfo = mProcessStats.printCurrentState();
4594 }
4595 }
4596
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004597 StringBuilder info = mStringBuilder;
4598 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004599 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004600 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004601 if (reportedActivity != null && reportedActivity.app != null) {
4602 info.append(" (last in ");
4603 info.append(reportedActivity.app.processName);
4604 info.append(")");
4605 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004606 if (annotation != null) {
4607 info.append("\nAnnotation: ");
4608 info.append(annotation);
4609 }
4610 if (MONITOR_CPU_USAGE) {
4611 info.append("\nCPU usage:\n");
4612 info.append(processInfo);
4613 }
4614 Log.i(TAG, info.toString());
4615
4616 // The application is not responding. Dump as many thread traces as we can.
4617 boolean fileDump = prepareTraceFile(true);
4618 if (!fileDump) {
4619 // Dumping traces to the log, just dump the process that isn't responding so
4620 // we don't overflow the log
4621 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4622 } else {
4623 // Dumping traces to a file so dump all active processes we know about
4624 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004625 // First, these are the most important processes.
4626 final int[] imppids = new int[3];
4627 int i=0;
4628 imppids[0] = app.pid;
4629 i++;
4630 if (reportedActivity != null && reportedActivity.app != null
4631 && reportedActivity.app.thread != null
4632 && reportedActivity.app.pid != app.pid) {
4633 imppids[i] = reportedActivity.app.pid;
4634 i++;
4635 }
4636 imppids[i] = Process.myPid();
4637 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4638 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4639 synchronized (this) {
4640 try {
4641 wait(200);
4642 } catch (InterruptedException e) {
4643 }
4644 }
4645 }
4646 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004647 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004648 boolean done = false;
4649 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4650 if (imppids[j] == r.pid) {
4651 done = true;
4652 break;
4653 }
4654 }
4655 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004656 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004657 synchronized (this) {
4658 try {
4659 wait(200);
4660 } catch (InterruptedException e) {
4661 }
4662 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004663 }
4664 }
4665 }
4666 }
4667
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004668 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004669 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004670 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004671 app.pid, info.toString());
4672 if (res != 0) {
4673 if (res < 0) {
4674 // wait until the SIGQUIT has had a chance to process before killing the
4675 // process.
4676 try {
4677 wait(2000);
4678 } catch (InterruptedException e) {
4679 }
4680
4681 Process.killProcess(app.pid);
4682 return;
4683 }
4684 }
4685 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004686 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004687 }
4688 }
4689
4690 makeAppNotRespondingLocked(app,
4691 activity != null ? activity.shortComponentName : null,
4692 annotation != null ? "ANR " + annotation : "ANR",
4693 info.toString(), null);
4694 Message msg = Message.obtain();
4695 HashMap map = new HashMap();
4696 msg.what = SHOW_NOT_RESPONDING_MSG;
4697 msg.obj = map;
4698 map.put("app", app);
4699 if (activity != null) {
4700 map.put("activity", activity);
4701 }
4702
4703 mHandler.sendMessage(msg);
4704 return;
4705 }
4706
4707 /**
4708 * If a stack trace file has been configured, prepare the filesystem
4709 * by creating the directory if it doesn't exist and optionally
4710 * removing the old trace file.
4711 *
4712 * @param removeExisting If set, the existing trace file will be removed.
4713 * @return Returns true if the trace file preparations succeeded
4714 */
4715 public static boolean prepareTraceFile(boolean removeExisting) {
4716 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4717 boolean fileReady = false;
4718 if (!TextUtils.isEmpty(tracesPath)) {
4719 File f = new File(tracesPath);
4720 if (!f.exists()) {
4721 // Ensure the enclosing directory exists
4722 File dir = f.getParentFile();
4723 if (!dir.exists()) {
4724 fileReady = dir.mkdirs();
4725 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004726 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004727 } else if (dir.isDirectory()) {
4728 fileReady = true;
4729 }
4730 } else if (removeExisting) {
4731 // Remove the previous traces file, so we don't fill the disk.
4732 // The VM will recreate it
4733 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4734 fileReady = f.delete();
4735 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004736
4737 if (removeExisting) {
4738 try {
4739 f.createNewFile();
4740 FileUtils.setPermissions(f.getAbsolutePath(),
4741 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4742 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4743 fileReady = true;
4744 } catch (IOException e) {
4745 Log.w(TAG, "Unable to make ANR traces file", e);
4746 }
4747 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004748 }
4749
4750 return fileReady;
4751 }
4752
4753
4754 private final void decPersistentCountLocked(ProcessRecord app)
4755 {
4756 app.persistentActivities--;
4757 if (app.persistentActivities > 0) {
4758 // Still more of 'em...
4759 return;
4760 }
4761 if (app.persistent) {
4762 // Ah, but the application itself is persistent. Whatever!
4763 return;
4764 }
4765
4766 // App is no longer persistent... make sure it and the ones
4767 // following it in the LRU list have the correc oom_adj.
4768 updateOomAdjLocked();
4769 }
4770
4771 public void setPersistent(IBinder token, boolean isPersistent) {
4772 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4773 != PackageManager.PERMISSION_GRANTED) {
4774 String msg = "Permission Denial: setPersistent() from pid="
4775 + Binder.getCallingPid()
4776 + ", uid=" + Binder.getCallingUid()
4777 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4778 Log.w(TAG, msg);
4779 throw new SecurityException(msg);
4780 }
4781
4782 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004783 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004784 if (index < 0) {
4785 return;
4786 }
4787 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4788 ProcessRecord app = r.app;
4789
4790 if (localLOGV) Log.v(
4791 TAG, "Setting persistence " + isPersistent + ": " + r);
4792
4793 if (isPersistent) {
4794 if (r.persistent) {
4795 // Okay okay, I heard you already!
4796 if (localLOGV) Log.v(TAG, "Already persistent!");
4797 return;
4798 }
4799 r.persistent = true;
4800 app.persistentActivities++;
4801 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4802 if (app.persistentActivities > 1) {
4803 // We aren't the first...
4804 if (localLOGV) Log.v(TAG, "Not the first!");
4805 return;
4806 }
4807 if (app.persistent) {
4808 // This would be redundant.
4809 if (localLOGV) Log.v(TAG, "App is persistent!");
4810 return;
4811 }
4812
4813 // App is now persistent... make sure it and the ones
4814 // following it now have the correct oom_adj.
4815 final long origId = Binder.clearCallingIdentity();
4816 updateOomAdjLocked();
4817 Binder.restoreCallingIdentity(origId);
4818
4819 } else {
4820 if (!r.persistent) {
4821 // Okay okay, I heard you already!
4822 return;
4823 }
4824 r.persistent = false;
4825 final long origId = Binder.clearCallingIdentity();
4826 decPersistentCountLocked(app);
4827 Binder.restoreCallingIdentity(origId);
4828
4829 }
4830 }
4831 }
4832
4833 public boolean clearApplicationUserData(final String packageName,
4834 final IPackageDataObserver observer) {
4835 int uid = Binder.getCallingUid();
4836 int pid = Binder.getCallingPid();
4837 long callingId = Binder.clearCallingIdentity();
4838 try {
4839 IPackageManager pm = ActivityThread.getPackageManager();
4840 int pkgUid = -1;
4841 synchronized(this) {
4842 try {
4843 pkgUid = pm.getPackageUid(packageName);
4844 } catch (RemoteException e) {
4845 }
4846 if (pkgUid == -1) {
4847 Log.w(TAG, "Invalid packageName:" + packageName);
4848 return false;
4849 }
4850 if (uid == pkgUid || checkComponentPermission(
4851 android.Manifest.permission.CLEAR_APP_USER_DATA,
4852 pid, uid, -1)
4853 == PackageManager.PERMISSION_GRANTED) {
4854 restartPackageLocked(packageName, pkgUid);
4855 } else {
4856 throw new SecurityException(pid+" does not have permission:"+
4857 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4858 "for process:"+packageName);
4859 }
4860 }
4861
4862 try {
4863 //clear application user data
4864 pm.clearApplicationUserData(packageName, observer);
4865 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4866 Uri.fromParts("package", packageName, null));
4867 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4868 broadcastIntentLocked(null, null, intent,
4869 null, null, 0, null, null, null,
4870 false, false, MY_PID, Process.SYSTEM_UID);
4871 } catch (RemoteException e) {
4872 }
4873 } finally {
4874 Binder.restoreCallingIdentity(callingId);
4875 }
4876 return true;
4877 }
4878
4879 public void restartPackage(final String packageName) {
4880 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4881 != PackageManager.PERMISSION_GRANTED) {
4882 String msg = "Permission Denial: restartPackage() from pid="
4883 + Binder.getCallingPid()
4884 + ", uid=" + Binder.getCallingUid()
4885 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4886 Log.w(TAG, msg);
4887 throw new SecurityException(msg);
4888 }
4889
4890 long callingId = Binder.clearCallingIdentity();
4891 try {
4892 IPackageManager pm = ActivityThread.getPackageManager();
4893 int pkgUid = -1;
4894 synchronized(this) {
4895 try {
4896 pkgUid = pm.getPackageUid(packageName);
4897 } catch (RemoteException e) {
4898 }
4899 if (pkgUid == -1) {
4900 Log.w(TAG, "Invalid packageName: " + packageName);
4901 return;
4902 }
4903 restartPackageLocked(packageName, pkgUid);
4904 }
4905 } finally {
4906 Binder.restoreCallingIdentity(callingId);
4907 }
4908 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004909
4910 /*
4911 * The pkg name and uid have to be specified.
4912 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4913 */
4914 public void killApplicationWithUid(String pkg, int uid) {
4915 if (pkg == null) {
4916 return;
4917 }
4918 // Make sure the uid is valid.
4919 if (uid < 0) {
4920 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4921 return;
4922 }
4923 int callerUid = Binder.getCallingUid();
4924 // Only the system server can kill an application
4925 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004926 // Post an aysnc message to kill the application
4927 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4928 msg.arg1 = uid;
4929 msg.arg2 = 0;
4930 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004931 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004932 } else {
4933 throw new SecurityException(callerUid + " cannot kill pkg: " +
4934 pkg);
4935 }
4936 }
4937
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004938 public void closeSystemDialogs(String reason) {
4939 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4940 if (reason != null) {
4941 intent.putExtra("reason", reason);
4942 }
4943
4944 final int uid = Binder.getCallingUid();
4945 final long origId = Binder.clearCallingIdentity();
4946 synchronized (this) {
4947 int i = mWatchers.beginBroadcast();
4948 while (i > 0) {
4949 i--;
4950 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4951 if (w != null) {
4952 try {
4953 w.closingSystemDialogs(reason);
4954 } catch (RemoteException e) {
4955 }
4956 }
4957 }
4958 mWatchers.finishBroadcast();
4959
4960 broadcastIntentLocked(null, null, intent, null,
4961 null, 0, null, null, null, false, false, -1, uid);
4962 }
4963 Binder.restoreCallingIdentity(origId);
4964 }
4965
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004966 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004967 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004968 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
4969 for (int i=pids.length-1; i>=0; i--) {
4970 infos[i] = new Debug.MemoryInfo();
4971 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004972 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004973 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004974 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07004975
4976 public void killApplicationProcess(String processName, int uid) {
4977 if (processName == null) {
4978 return;
4979 }
4980
4981 int callerUid = Binder.getCallingUid();
4982 // Only the system server can kill an application
4983 if (callerUid == Process.SYSTEM_UID) {
4984 synchronized (this) {
4985 ProcessRecord app = getProcessRecordLocked(processName, uid);
4986 if (app != null) {
4987 try {
4988 app.thread.scheduleSuicide();
4989 } catch (RemoteException e) {
4990 // If the other end already died, then our work here is done.
4991 }
4992 } else {
4993 Log.w(TAG, "Process/uid not found attempting kill of "
4994 + processName + " / " + uid);
4995 }
4996 }
4997 } else {
4998 throw new SecurityException(callerUid + " cannot kill app process: " +
4999 processName);
5000 }
5001 }
5002
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005003 private void restartPackageLocked(final String packageName, int uid) {
5004 uninstallPackageLocked(packageName, uid, false);
5005 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5006 Uri.fromParts("package", packageName, null));
5007 intent.putExtra(Intent.EXTRA_UID, uid);
5008 broadcastIntentLocked(null, null, intent,
5009 null, null, 0, null, null, null,
5010 false, false, MY_PID, Process.SYSTEM_UID);
5011 }
5012
5013 private final void uninstallPackageLocked(String name, int uid,
5014 boolean callerWillRestart) {
5015 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
5016
5017 int i, N;
5018
5019 final String procNamePrefix = name + ":";
5020 if (uid < 0) {
5021 try {
5022 uid = ActivityThread.getPackageManager().getPackageUid(name);
5023 } catch (RemoteException e) {
5024 }
5025 }
5026
5027 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5028 while (badApps.hasNext()) {
5029 SparseArray<Long> ba = badApps.next();
5030 if (ba.get(uid) != null) {
5031 badApps.remove();
5032 }
5033 }
5034
5035 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
5036
5037 // Remove all processes this package may have touched: all with the
5038 // same UID (except for the system or root user), and all whose name
5039 // matches the package name.
5040 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5041 final int NA = apps.size();
5042 for (int ia=0; ia<NA; ia++) {
5043 ProcessRecord app = apps.valueAt(ia);
5044 if (app.removed) {
5045 procs.add(app);
5046 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5047 || app.processName.equals(name)
5048 || app.processName.startsWith(procNamePrefix)) {
5049 app.removed = true;
5050 procs.add(app);
5051 }
5052 }
5053 }
5054
5055 N = procs.size();
5056 for (i=0; i<N; i++) {
5057 removeProcessLocked(procs.get(i), callerWillRestart);
5058 }
5059
5060 for (i=mHistory.size()-1; i>=0; i--) {
5061 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5062 if (r.packageName.equals(name)) {
5063 if (Config.LOGD) Log.d(
5064 TAG, " Force finishing activity "
5065 + r.intent.getComponent().flattenToShortString());
5066 if (r.app != null) {
5067 r.app.removed = true;
5068 }
5069 r.app = null;
5070 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5071 }
5072 }
5073
5074 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5075 for (ServiceRecord service : mServices.values()) {
5076 if (service.packageName.equals(name)) {
5077 if (service.app != null) {
5078 service.app.removed = true;
5079 }
5080 service.app = null;
5081 services.add(service);
5082 }
5083 }
5084
5085 N = services.size();
5086 for (i=0; i<N; i++) {
5087 bringDownServiceLocked(services.get(i), true);
5088 }
5089
5090 resumeTopActivityLocked(null);
5091 }
5092
5093 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5094 final String name = app.processName;
5095 final int uid = app.info.uid;
5096 if (Config.LOGD) Log.d(
5097 TAG, "Force removing process " + app + " (" + name
5098 + "/" + uid + ")");
5099
5100 mProcessNames.remove(name, uid);
5101 boolean needRestart = false;
5102 if (app.pid > 0 && app.pid != MY_PID) {
5103 int pid = app.pid;
5104 synchronized (mPidsSelfLocked) {
5105 mPidsSelfLocked.remove(pid);
5106 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5107 }
5108 handleAppDiedLocked(app, true);
5109 mLRUProcesses.remove(app);
5110 Process.killProcess(pid);
5111
5112 if (app.persistent) {
5113 if (!callerWillRestart) {
5114 addAppLocked(app.info);
5115 } else {
5116 needRestart = true;
5117 }
5118 }
5119 } else {
5120 mRemovedProcesses.add(app);
5121 }
5122
5123 return needRestart;
5124 }
5125
5126 private final void processStartTimedOutLocked(ProcessRecord app) {
5127 final int pid = app.pid;
5128 boolean gone = false;
5129 synchronized (mPidsSelfLocked) {
5130 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5131 if (knownApp != null && knownApp.thread == null) {
5132 mPidsSelfLocked.remove(pid);
5133 gone = true;
5134 }
5135 }
5136
5137 if (gone) {
5138 Log.w(TAG, "Process " + app + " failed to attach");
5139 mProcessNames.remove(app.processName, app.info.uid);
5140 Process.killProcess(pid);
5141 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5142 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5143 mPendingBroadcast = null;
5144 scheduleBroadcastsLocked();
5145 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005146 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5147 Log.w(TAG, "Unattached app died before backup, skipping");
5148 try {
5149 IBackupManager bm = IBackupManager.Stub.asInterface(
5150 ServiceManager.getService(Context.BACKUP_SERVICE));
5151 bm.agentDisconnected(app.info.packageName);
5152 } catch (RemoteException e) {
5153 // Can't happen; the backup manager is local
5154 }
5155 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005156 } else {
5157 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5158 }
5159 }
5160
5161 private final boolean attachApplicationLocked(IApplicationThread thread,
5162 int pid) {
5163
5164 // Find the application record that is being attached... either via
5165 // the pid if we are running in multiple processes, or just pull the
5166 // next app record if we are emulating process with anonymous threads.
5167 ProcessRecord app;
5168 if (pid != MY_PID && pid >= 0) {
5169 synchronized (mPidsSelfLocked) {
5170 app = mPidsSelfLocked.get(pid);
5171 }
5172 } else if (mStartingProcesses.size() > 0) {
5173 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005174 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005175 } else {
5176 app = null;
5177 }
5178
5179 if (app == null) {
5180 Log.w(TAG, "No pending application record for pid " + pid
5181 + " (IApplicationThread " + thread + "); dropping process");
5182 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5183 if (pid > 0 && pid != MY_PID) {
5184 Process.killProcess(pid);
5185 } else {
5186 try {
5187 thread.scheduleExit();
5188 } catch (Exception e) {
5189 // Ignore exceptions.
5190 }
5191 }
5192 return false;
5193 }
5194
5195 // If this application record is still attached to a previous
5196 // process, clean it up now.
5197 if (app.thread != null) {
5198 handleAppDiedLocked(app, true);
5199 }
5200
5201 // Tell the process all about itself.
5202
5203 if (localLOGV) Log.v(
5204 TAG, "Binding process pid " + pid + " to record " + app);
5205
5206 String processName = app.processName;
5207 try {
5208 thread.asBinder().linkToDeath(new AppDeathRecipient(
5209 app, pid, thread), 0);
5210 } catch (RemoteException e) {
5211 app.resetPackageList();
5212 startProcessLocked(app, "link fail", processName);
5213 return false;
5214 }
5215
5216 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5217
5218 app.thread = thread;
5219 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005220 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005221 app.forcingToForeground = null;
5222 app.foregroundServices = false;
5223 app.debugging = false;
5224
5225 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5226
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005227 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5228 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005229
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005230 if (!normalMode) {
5231 Log.i(TAG, "Launching preboot mode app: " + app);
5232 }
5233
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005234 if (localLOGV) Log.v(
5235 TAG, "New app record " + app
5236 + " thread=" + thread.asBinder() + " pid=" + pid);
5237 try {
5238 int testMode = IApplicationThread.DEBUG_OFF;
5239 if (mDebugApp != null && mDebugApp.equals(processName)) {
5240 testMode = mWaitForDebugger
5241 ? IApplicationThread.DEBUG_WAIT
5242 : IApplicationThread.DEBUG_ON;
5243 app.debugging = true;
5244 if (mDebugTransient) {
5245 mDebugApp = mOrigDebugApp;
5246 mWaitForDebugger = mOrigWaitForDebugger;
5247 }
5248 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005249
Christopher Tate181fafa2009-05-14 11:12:14 -07005250 // If the app is being launched for restore or full backup, set it up specially
5251 boolean isRestrictedBackupMode = false;
5252 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5253 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5254 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5255 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005256
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005257 ensurePackageDexOpt(app.instrumentationInfo != null
5258 ? app.instrumentationInfo.packageName
5259 : app.info.packageName);
5260 if (app.instrumentationClass != null) {
5261 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005262 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07005263 thread.bindApplication(processName, app.instrumentationInfo != null
5264 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005265 app.instrumentationClass, app.instrumentationProfileFile,
5266 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005267 isRestrictedBackupMode || !normalMode,
5268 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005269 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005270 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005271 } catch (Exception e) {
5272 // todo: Yikes! What should we do? For now we will try to
5273 // start another process, but that could easily get us in
5274 // an infinite loop of restarting processes...
5275 Log.w(TAG, "Exception thrown during bind!", e);
5276
5277 app.resetPackageList();
5278 startProcessLocked(app, "bind fail", processName);
5279 return false;
5280 }
5281
5282 // Remove this record from the list of starting applications.
5283 mPersistentStartingProcesses.remove(app);
5284 mProcessesOnHold.remove(app);
5285
5286 boolean badApp = false;
5287 boolean didSomething = false;
5288
5289 // See if the top visible activity is waiting to run in this process...
5290 HistoryRecord hr = topRunningActivityLocked(null);
5291 if (hr != null) {
5292 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5293 && processName.equals(hr.processName)) {
5294 try {
5295 if (realStartActivityLocked(hr, app, true, true)) {
5296 didSomething = true;
5297 }
5298 } catch (Exception e) {
5299 Log.w(TAG, "Exception in new application when starting activity "
5300 + hr.intent.getComponent().flattenToShortString(), e);
5301 badApp = true;
5302 }
5303 } else {
5304 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5305 }
5306 }
5307
5308 // Find any services that should be running in this process...
5309 if (!badApp && mPendingServices.size() > 0) {
5310 ServiceRecord sr = null;
5311 try {
5312 for (int i=0; i<mPendingServices.size(); i++) {
5313 sr = mPendingServices.get(i);
5314 if (app.info.uid != sr.appInfo.uid
5315 || !processName.equals(sr.processName)) {
5316 continue;
5317 }
5318
5319 mPendingServices.remove(i);
5320 i--;
5321 realStartServiceLocked(sr, app);
5322 didSomething = true;
5323 }
5324 } catch (Exception e) {
5325 Log.w(TAG, "Exception in new application when starting service "
5326 + sr.shortName, e);
5327 badApp = true;
5328 }
5329 }
5330
5331 // Check if the next broadcast receiver is in this process...
5332 BroadcastRecord br = mPendingBroadcast;
5333 if (!badApp && br != null && br.curApp == app) {
5334 try {
5335 mPendingBroadcast = null;
5336 processCurBroadcastLocked(br, app);
5337 didSomething = true;
5338 } catch (Exception e) {
5339 Log.w(TAG, "Exception in new application when starting receiver "
5340 + br.curComponent.flattenToShortString(), e);
5341 badApp = true;
5342 logBroadcastReceiverDiscard(br);
5343 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5344 br.resultExtras, br.resultAbort, true);
5345 scheduleBroadcastsLocked();
5346 }
5347 }
5348
Christopher Tate181fafa2009-05-14 11:12:14 -07005349 // Check whether the next backup agent is in this process...
5350 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5351 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005352 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005353 try {
5354 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5355 } catch (Exception e) {
5356 Log.w(TAG, "Exception scheduling backup agent creation: ");
5357 e.printStackTrace();
5358 }
5359 }
5360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005361 if (badApp) {
5362 // todo: Also need to kill application to deal with all
5363 // kinds of exceptions.
5364 handleAppDiedLocked(app, false);
5365 return false;
5366 }
5367
5368 if (!didSomething) {
5369 updateOomAdjLocked();
5370 }
5371
5372 return true;
5373 }
5374
5375 public final void attachApplication(IApplicationThread thread) {
5376 synchronized (this) {
5377 int callingPid = Binder.getCallingPid();
5378 final long origId = Binder.clearCallingIdentity();
5379 attachApplicationLocked(thread, callingPid);
5380 Binder.restoreCallingIdentity(origId);
5381 }
5382 }
5383
5384 public final void activityIdle(IBinder token) {
5385 final long origId = Binder.clearCallingIdentity();
5386 activityIdleInternal(token, false);
5387 Binder.restoreCallingIdentity(origId);
5388 }
5389
5390 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5391 boolean remove) {
5392 int N = mStoppingActivities.size();
5393 if (N <= 0) return null;
5394
5395 ArrayList<HistoryRecord> stops = null;
5396
5397 final boolean nowVisible = mResumedActivity != null
5398 && mResumedActivity.nowVisible
5399 && !mResumedActivity.waitingVisible;
5400 for (int i=0; i<N; i++) {
5401 HistoryRecord s = mStoppingActivities.get(i);
5402 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5403 + nowVisible + " waitingVisible=" + s.waitingVisible
5404 + " finishing=" + s.finishing);
5405 if (s.waitingVisible && nowVisible) {
5406 mWaitingVisibleActivities.remove(s);
5407 s.waitingVisible = false;
5408 if (s.finishing) {
5409 // If this activity is finishing, it is sitting on top of
5410 // everyone else but we now know it is no longer needed...
5411 // so get rid of it. Otherwise, we need to go through the
5412 // normal flow and hide it once we determine that it is
5413 // hidden by the activities in front of it.
5414 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5415 mWindowManager.setAppVisibility(s, false);
5416 }
5417 }
5418 if (!s.waitingVisible && remove) {
5419 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5420 if (stops == null) {
5421 stops = new ArrayList<HistoryRecord>();
5422 }
5423 stops.add(s);
5424 mStoppingActivities.remove(i);
5425 N--;
5426 i--;
5427 }
5428 }
5429
5430 return stops;
5431 }
5432
5433 void enableScreenAfterBoot() {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005434 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5435 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005436 mWindowManager.enableScreenAfterBoot();
5437 }
5438
5439 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5440 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5441
5442 ArrayList<HistoryRecord> stops = null;
5443 ArrayList<HistoryRecord> finishes = null;
5444 ArrayList<HistoryRecord> thumbnails = null;
5445 int NS = 0;
5446 int NF = 0;
5447 int NT = 0;
5448 IApplicationThread sendThumbnail = null;
5449 boolean booting = false;
5450 boolean enableScreen = false;
5451
5452 synchronized (this) {
5453 if (token != null) {
5454 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5455 }
5456
5457 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005458 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005459 if (index >= 0) {
5460 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5461
5462 // No longer need to keep the device awake.
5463 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5464 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5465 mLaunchingActivity.release();
5466 }
5467
5468 // We are now idle. If someone is waiting for a thumbnail from
5469 // us, we can now deliver.
5470 r.idle = true;
5471 scheduleAppGcsLocked();
5472 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5473 sendThumbnail = r.app.thread;
5474 r.thumbnailNeeded = false;
5475 }
5476
5477 // If this activity is fullscreen, set up to hide those under it.
5478
5479 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5480 ensureActivitiesVisibleLocked(null, 0);
5481
5482 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5483 if (!mBooted && !fromTimeout) {
5484 mBooted = true;
5485 enableScreen = true;
5486 }
5487 }
5488
5489 // Atomically retrieve all of the other things to do.
5490 stops = processStoppingActivitiesLocked(true);
5491 NS = stops != null ? stops.size() : 0;
5492 if ((NF=mFinishingActivities.size()) > 0) {
5493 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5494 mFinishingActivities.clear();
5495 }
5496 if ((NT=mCancelledThumbnails.size()) > 0) {
5497 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5498 mCancelledThumbnails.clear();
5499 }
5500
5501 booting = mBooting;
5502 mBooting = false;
5503 }
5504
5505 int i;
5506
5507 // Send thumbnail if requested.
5508 if (sendThumbnail != null) {
5509 try {
5510 sendThumbnail.requestThumbnail(token);
5511 } catch (Exception e) {
5512 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5513 sendPendingThumbnail(null, token, null, null, true);
5514 }
5515 }
5516
5517 // Stop any activities that are scheduled to do so but have been
5518 // waiting for the next one to start.
5519 for (i=0; i<NS; i++) {
5520 HistoryRecord r = (HistoryRecord)stops.get(i);
5521 synchronized (this) {
5522 if (r.finishing) {
5523 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5524 } else {
5525 stopActivityLocked(r);
5526 }
5527 }
5528 }
5529
5530 // Finish any activities that are scheduled to do so but have been
5531 // waiting for the next one to start.
5532 for (i=0; i<NF; i++) {
5533 HistoryRecord r = (HistoryRecord)finishes.get(i);
5534 synchronized (this) {
5535 destroyActivityLocked(r, true);
5536 }
5537 }
5538
5539 // Report back to any thumbnail receivers.
5540 for (i=0; i<NT; i++) {
5541 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5542 sendPendingThumbnail(r, null, null, null, true);
5543 }
5544
5545 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005546 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005547 }
5548
5549 trimApplications();
5550 //dump();
5551 //mWindowManager.dump();
5552
5553 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005554 enableScreenAfterBoot();
5555 }
5556 }
5557
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005558 final void finishBooting() {
5559 // Ensure that any processes we had put on hold are now started
5560 // up.
5561 final int NP = mProcessesOnHold.size();
5562 if (NP > 0) {
5563 ArrayList<ProcessRecord> procs =
5564 new ArrayList<ProcessRecord>(mProcessesOnHold);
5565 for (int ip=0; ip<NP; ip++) {
5566 this.startProcessLocked(procs.get(ip), "on-hold", null);
5567 }
5568 }
5569 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5570 // Tell anyone interested that we are done booting!
5571 synchronized (this) {
5572 broadcastIntentLocked(null, null,
5573 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5574 null, null, 0, null, null,
5575 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5576 false, false, MY_PID, Process.SYSTEM_UID);
5577 }
5578 }
5579 }
5580
5581 final void ensureBootCompleted() {
5582 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005583 boolean enableScreen;
5584 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005585 booting = mBooting;
5586 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005587 enableScreen = !mBooted;
5588 mBooted = true;
5589 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005590
5591 if (booting) {
5592 finishBooting();
5593 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005594
5595 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005596 enableScreenAfterBoot();
5597 }
5598 }
5599
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005600 public final void activityPaused(IBinder token, Bundle icicle) {
5601 // Refuse possible leaked file descriptors
5602 if (icicle != null && icicle.hasFileDescriptors()) {
5603 throw new IllegalArgumentException("File descriptors passed in Bundle");
5604 }
5605
5606 final long origId = Binder.clearCallingIdentity();
5607 activityPaused(token, icicle, false);
5608 Binder.restoreCallingIdentity(origId);
5609 }
5610
5611 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5612 if (DEBUG_PAUSE) Log.v(
5613 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5614 + ", timeout=" + timeout);
5615
5616 HistoryRecord r = null;
5617
5618 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005619 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005620 if (index >= 0) {
5621 r = (HistoryRecord)mHistory.get(index);
5622 if (!timeout) {
5623 r.icicle = icicle;
5624 r.haveState = true;
5625 }
5626 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5627 if (mPausingActivity == r) {
5628 r.state = ActivityState.PAUSED;
5629 completePauseLocked();
5630 } else {
5631 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5632 System.identityHashCode(r), r.shortComponentName,
5633 mPausingActivity != null
5634 ? mPausingActivity.shortComponentName : "(none)");
5635 }
5636 }
5637 }
5638 }
5639
5640 public final void activityStopped(IBinder token, Bitmap thumbnail,
5641 CharSequence description) {
5642 if (localLOGV) Log.v(
5643 TAG, "Activity stopped: token=" + token);
5644
5645 HistoryRecord r = null;
5646
5647 final long origId = Binder.clearCallingIdentity();
5648
5649 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005650 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005651 if (index >= 0) {
5652 r = (HistoryRecord)mHistory.get(index);
5653 r.thumbnail = thumbnail;
5654 r.description = description;
5655 r.stopped = true;
5656 r.state = ActivityState.STOPPED;
5657 if (!r.finishing) {
5658 if (r.configDestroy) {
5659 destroyActivityLocked(r, true);
5660 resumeTopActivityLocked(null);
5661 }
5662 }
5663 }
5664 }
5665
5666 if (r != null) {
5667 sendPendingThumbnail(r, null, null, null, false);
5668 }
5669
5670 trimApplications();
5671
5672 Binder.restoreCallingIdentity(origId);
5673 }
5674
5675 public final void activityDestroyed(IBinder token) {
5676 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5677 synchronized (this) {
5678 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5679
Dianne Hackborn75b03852009-06-12 15:43:26 -07005680 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005681 if (index >= 0) {
5682 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5683 if (r.state == ActivityState.DESTROYING) {
5684 final long origId = Binder.clearCallingIdentity();
5685 removeActivityFromHistoryLocked(r);
5686 Binder.restoreCallingIdentity(origId);
5687 }
5688 }
5689 }
5690 }
5691
5692 public String getCallingPackage(IBinder token) {
5693 synchronized (this) {
5694 HistoryRecord r = getCallingRecordLocked(token);
5695 return r != null && r.app != null ? r.app.processName : null;
5696 }
5697 }
5698
5699 public ComponentName getCallingActivity(IBinder token) {
5700 synchronized (this) {
5701 HistoryRecord r = getCallingRecordLocked(token);
5702 return r != null ? r.intent.getComponent() : null;
5703 }
5704 }
5705
5706 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005707 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005708 if (index >= 0) {
5709 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5710 if (r != null) {
5711 return r.resultTo;
5712 }
5713 }
5714 return null;
5715 }
5716
5717 public ComponentName getActivityClassForToken(IBinder token) {
5718 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005719 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005720 if (index >= 0) {
5721 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5722 return r.intent.getComponent();
5723 }
5724 return null;
5725 }
5726 }
5727
5728 public String getPackageForToken(IBinder token) {
5729 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005730 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005731 if (index >= 0) {
5732 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5733 return r.packageName;
5734 }
5735 return null;
5736 }
5737 }
5738
5739 public IIntentSender getIntentSender(int type,
5740 String packageName, IBinder token, String resultWho,
5741 int requestCode, Intent intent, String resolvedType, int flags) {
5742 // Refuse possible leaked file descriptors
5743 if (intent != null && intent.hasFileDescriptors() == true) {
5744 throw new IllegalArgumentException("File descriptors passed in Intent");
5745 }
5746
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005747 if (type == INTENT_SENDER_BROADCAST) {
5748 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5749 throw new IllegalArgumentException(
5750 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5751 }
5752 }
5753
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005754 synchronized(this) {
5755 int callingUid = Binder.getCallingUid();
5756 try {
5757 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5758 Process.supportsProcesses()) {
5759 int uid = ActivityThread.getPackageManager()
5760 .getPackageUid(packageName);
5761 if (uid != Binder.getCallingUid()) {
5762 String msg = "Permission Denial: getIntentSender() from pid="
5763 + Binder.getCallingPid()
5764 + ", uid=" + Binder.getCallingUid()
5765 + ", (need uid=" + uid + ")"
5766 + " is not allowed to send as package " + packageName;
5767 Log.w(TAG, msg);
5768 throw new SecurityException(msg);
5769 }
5770 }
5771 } catch (RemoteException e) {
5772 throw new SecurityException(e);
5773 }
5774 HistoryRecord activity = null;
5775 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005776 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005777 if (index < 0) {
5778 return null;
5779 }
5780 activity = (HistoryRecord)mHistory.get(index);
5781 if (activity.finishing) {
5782 return null;
5783 }
5784 }
5785
5786 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5787 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5788 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5789 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5790 |PendingIntent.FLAG_UPDATE_CURRENT);
5791
5792 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5793 type, packageName, activity, resultWho,
5794 requestCode, intent, resolvedType, flags);
5795 WeakReference<PendingIntentRecord> ref;
5796 ref = mIntentSenderRecords.get(key);
5797 PendingIntentRecord rec = ref != null ? ref.get() : null;
5798 if (rec != null) {
5799 if (!cancelCurrent) {
5800 if (updateCurrent) {
5801 rec.key.requestIntent.replaceExtras(intent);
5802 }
5803 return rec;
5804 }
5805 rec.canceled = true;
5806 mIntentSenderRecords.remove(key);
5807 }
5808 if (noCreate) {
5809 return rec;
5810 }
5811 rec = new PendingIntentRecord(this, key, callingUid);
5812 mIntentSenderRecords.put(key, rec.ref);
5813 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5814 if (activity.pendingResults == null) {
5815 activity.pendingResults
5816 = new HashSet<WeakReference<PendingIntentRecord>>();
5817 }
5818 activity.pendingResults.add(rec.ref);
5819 }
5820 return rec;
5821 }
5822 }
5823
5824 public void cancelIntentSender(IIntentSender sender) {
5825 if (!(sender instanceof PendingIntentRecord)) {
5826 return;
5827 }
5828 synchronized(this) {
5829 PendingIntentRecord rec = (PendingIntentRecord)sender;
5830 try {
5831 int uid = ActivityThread.getPackageManager()
5832 .getPackageUid(rec.key.packageName);
5833 if (uid != Binder.getCallingUid()) {
5834 String msg = "Permission Denial: cancelIntentSender() from pid="
5835 + Binder.getCallingPid()
5836 + ", uid=" + Binder.getCallingUid()
5837 + " is not allowed to cancel packges "
5838 + rec.key.packageName;
5839 Log.w(TAG, msg);
5840 throw new SecurityException(msg);
5841 }
5842 } catch (RemoteException e) {
5843 throw new SecurityException(e);
5844 }
5845 cancelIntentSenderLocked(rec, true);
5846 }
5847 }
5848
5849 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5850 rec.canceled = true;
5851 mIntentSenderRecords.remove(rec.key);
5852 if (cleanActivity && rec.key.activity != null) {
5853 rec.key.activity.pendingResults.remove(rec.ref);
5854 }
5855 }
5856
5857 public String getPackageForIntentSender(IIntentSender pendingResult) {
5858 if (!(pendingResult instanceof PendingIntentRecord)) {
5859 return null;
5860 }
5861 synchronized(this) {
5862 try {
5863 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5864 return res.key.packageName;
5865 } catch (ClassCastException e) {
5866 }
5867 }
5868 return null;
5869 }
5870
5871 public void setProcessLimit(int max) {
5872 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5873 "setProcessLimit()");
5874 mProcessLimit = max;
5875 }
5876
5877 public int getProcessLimit() {
5878 return mProcessLimit;
5879 }
5880
5881 void foregroundTokenDied(ForegroundToken token) {
5882 synchronized (ActivityManagerService.this) {
5883 synchronized (mPidsSelfLocked) {
5884 ForegroundToken cur
5885 = mForegroundProcesses.get(token.pid);
5886 if (cur != token) {
5887 return;
5888 }
5889 mForegroundProcesses.remove(token.pid);
5890 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5891 if (pr == null) {
5892 return;
5893 }
5894 pr.forcingToForeground = null;
5895 pr.foregroundServices = false;
5896 }
5897 updateOomAdjLocked();
5898 }
5899 }
5900
5901 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5902 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5903 "setProcessForeground()");
5904 synchronized(this) {
5905 boolean changed = false;
5906
5907 synchronized (mPidsSelfLocked) {
5908 ProcessRecord pr = mPidsSelfLocked.get(pid);
5909 if (pr == null) {
5910 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5911 return;
5912 }
5913 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5914 if (oldToken != null) {
5915 oldToken.token.unlinkToDeath(oldToken, 0);
5916 mForegroundProcesses.remove(pid);
5917 pr.forcingToForeground = null;
5918 changed = true;
5919 }
5920 if (isForeground && token != null) {
5921 ForegroundToken newToken = new ForegroundToken() {
5922 public void binderDied() {
5923 foregroundTokenDied(this);
5924 }
5925 };
5926 newToken.pid = pid;
5927 newToken.token = token;
5928 try {
5929 token.linkToDeath(newToken, 0);
5930 mForegroundProcesses.put(pid, newToken);
5931 pr.forcingToForeground = token;
5932 changed = true;
5933 } catch (RemoteException e) {
5934 // If the process died while doing this, we will later
5935 // do the cleanup with the process death link.
5936 }
5937 }
5938 }
5939
5940 if (changed) {
5941 updateOomAdjLocked();
5942 }
5943 }
5944 }
5945
5946 // =========================================================
5947 // PERMISSIONS
5948 // =========================================================
5949
5950 static class PermissionController extends IPermissionController.Stub {
5951 ActivityManagerService mActivityManagerService;
5952 PermissionController(ActivityManagerService activityManagerService) {
5953 mActivityManagerService = activityManagerService;
5954 }
5955
5956 public boolean checkPermission(String permission, int pid, int uid) {
5957 return mActivityManagerService.checkPermission(permission, pid,
5958 uid) == PackageManager.PERMISSION_GRANTED;
5959 }
5960 }
5961
5962 /**
5963 * This can be called with or without the global lock held.
5964 */
5965 int checkComponentPermission(String permission, int pid, int uid,
5966 int reqUid) {
5967 // We might be performing an operation on behalf of an indirect binder
5968 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5969 // client identity accordingly before proceeding.
5970 Identity tlsIdentity = sCallerIdentity.get();
5971 if (tlsIdentity != null) {
5972 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5973 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5974 uid = tlsIdentity.uid;
5975 pid = tlsIdentity.pid;
5976 }
5977
5978 // Root, system server and our own process get to do everything.
5979 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5980 !Process.supportsProcesses()) {
5981 return PackageManager.PERMISSION_GRANTED;
5982 }
5983 // If the target requires a specific UID, always fail for others.
5984 if (reqUid >= 0 && uid != reqUid) {
5985 return PackageManager.PERMISSION_DENIED;
5986 }
5987 if (permission == null) {
5988 return PackageManager.PERMISSION_GRANTED;
5989 }
5990 try {
5991 return ActivityThread.getPackageManager()
5992 .checkUidPermission(permission, uid);
5993 } catch (RemoteException e) {
5994 // Should never happen, but if it does... deny!
5995 Log.e(TAG, "PackageManager is dead?!?", e);
5996 }
5997 return PackageManager.PERMISSION_DENIED;
5998 }
5999
6000 /**
6001 * As the only public entry point for permissions checking, this method
6002 * can enforce the semantic that requesting a check on a null global
6003 * permission is automatically denied. (Internally a null permission
6004 * string is used when calling {@link #checkComponentPermission} in cases
6005 * when only uid-based security is needed.)
6006 *
6007 * This can be called with or without the global lock held.
6008 */
6009 public int checkPermission(String permission, int pid, int uid) {
6010 if (permission == null) {
6011 return PackageManager.PERMISSION_DENIED;
6012 }
6013 return checkComponentPermission(permission, pid, uid, -1);
6014 }
6015
6016 /**
6017 * Binder IPC calls go through the public entry point.
6018 * This can be called with or without the global lock held.
6019 */
6020 int checkCallingPermission(String permission) {
6021 return checkPermission(permission,
6022 Binder.getCallingPid(),
6023 Binder.getCallingUid());
6024 }
6025
6026 /**
6027 * This can be called with or without the global lock held.
6028 */
6029 void enforceCallingPermission(String permission, String func) {
6030 if (checkCallingPermission(permission)
6031 == PackageManager.PERMISSION_GRANTED) {
6032 return;
6033 }
6034
6035 String msg = "Permission Denial: " + func + " from pid="
6036 + Binder.getCallingPid()
6037 + ", uid=" + Binder.getCallingUid()
6038 + " requires " + permission;
6039 Log.w(TAG, msg);
6040 throw new SecurityException(msg);
6041 }
6042
6043 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6044 ProviderInfo pi, int uid, int modeFlags) {
6045 try {
6046 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6047 if ((pi.readPermission != null) &&
6048 (pm.checkUidPermission(pi.readPermission, uid)
6049 != PackageManager.PERMISSION_GRANTED)) {
6050 return false;
6051 }
6052 }
6053 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6054 if ((pi.writePermission != null) &&
6055 (pm.checkUidPermission(pi.writePermission, uid)
6056 != PackageManager.PERMISSION_GRANTED)) {
6057 return false;
6058 }
6059 }
6060 return true;
6061 } catch (RemoteException e) {
6062 return false;
6063 }
6064 }
6065
6066 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6067 int modeFlags) {
6068 // Root gets to do everything.
6069 if (uid == 0 || !Process.supportsProcesses()) {
6070 return true;
6071 }
6072 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6073 if (perms == null) return false;
6074 UriPermission perm = perms.get(uri);
6075 if (perm == null) return false;
6076 return (modeFlags&perm.modeFlags) == modeFlags;
6077 }
6078
6079 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6080 // Another redirected-binder-call permissions check as in
6081 // {@link checkComponentPermission}.
6082 Identity tlsIdentity = sCallerIdentity.get();
6083 if (tlsIdentity != null) {
6084 uid = tlsIdentity.uid;
6085 pid = tlsIdentity.pid;
6086 }
6087
6088 // Our own process gets to do everything.
6089 if (pid == MY_PID) {
6090 return PackageManager.PERMISSION_GRANTED;
6091 }
6092 synchronized(this) {
6093 return checkUriPermissionLocked(uri, uid, modeFlags)
6094 ? PackageManager.PERMISSION_GRANTED
6095 : PackageManager.PERMISSION_DENIED;
6096 }
6097 }
6098
6099 private void grantUriPermissionLocked(int callingUid,
6100 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6101 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6102 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6103 if (modeFlags == 0) {
6104 return;
6105 }
6106
6107 final IPackageManager pm = ActivityThread.getPackageManager();
6108
6109 // If this is not a content: uri, we can't do anything with it.
6110 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6111 return;
6112 }
6113
6114 String name = uri.getAuthority();
6115 ProviderInfo pi = null;
6116 ContentProviderRecord cpr
6117 = (ContentProviderRecord)mProvidersByName.get(name);
6118 if (cpr != null) {
6119 pi = cpr.info;
6120 } else {
6121 try {
6122 pi = pm.resolveContentProvider(name,
6123 PackageManager.GET_URI_PERMISSION_PATTERNS);
6124 } catch (RemoteException ex) {
6125 }
6126 }
6127 if (pi == null) {
6128 Log.w(TAG, "No content provider found for: " + name);
6129 return;
6130 }
6131
6132 int targetUid;
6133 try {
6134 targetUid = pm.getPackageUid(targetPkg);
6135 if (targetUid < 0) {
6136 return;
6137 }
6138 } catch (RemoteException ex) {
6139 return;
6140 }
6141
6142 // First... does the target actually need this permission?
6143 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6144 // No need to grant the target this permission.
6145 return;
6146 }
6147
6148 // Second... maybe someone else has already granted the
6149 // permission?
6150 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6151 // No need to grant the target this permission.
6152 return;
6153 }
6154
6155 // Third... is the provider allowing granting of URI permissions?
6156 if (!pi.grantUriPermissions) {
6157 throw new SecurityException("Provider " + pi.packageName
6158 + "/" + pi.name
6159 + " does not allow granting of Uri permissions (uri "
6160 + uri + ")");
6161 }
6162 if (pi.uriPermissionPatterns != null) {
6163 final int N = pi.uriPermissionPatterns.length;
6164 boolean allowed = false;
6165 for (int i=0; i<N; i++) {
6166 if (pi.uriPermissionPatterns[i] != null
6167 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6168 allowed = true;
6169 break;
6170 }
6171 }
6172 if (!allowed) {
6173 throw new SecurityException("Provider " + pi.packageName
6174 + "/" + pi.name
6175 + " does not allow granting of permission to path of Uri "
6176 + uri);
6177 }
6178 }
6179
6180 // Fourth... does the caller itself have permission to access
6181 // this uri?
6182 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6183 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6184 throw new SecurityException("Uid " + callingUid
6185 + " does not have permission to uri " + uri);
6186 }
6187 }
6188
6189 // Okay! So here we are: the caller has the assumed permission
6190 // to the uri, and the target doesn't. Let's now give this to
6191 // the target.
6192
6193 HashMap<Uri, UriPermission> targetUris
6194 = mGrantedUriPermissions.get(targetUid);
6195 if (targetUris == null) {
6196 targetUris = new HashMap<Uri, UriPermission>();
6197 mGrantedUriPermissions.put(targetUid, targetUris);
6198 }
6199
6200 UriPermission perm = targetUris.get(uri);
6201 if (perm == null) {
6202 perm = new UriPermission(targetUid, uri);
6203 targetUris.put(uri, perm);
6204
6205 }
6206 perm.modeFlags |= modeFlags;
6207 if (activity == null) {
6208 perm.globalModeFlags |= modeFlags;
6209 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6210 perm.readActivities.add(activity);
6211 if (activity.readUriPermissions == null) {
6212 activity.readUriPermissions = new HashSet<UriPermission>();
6213 }
6214 activity.readUriPermissions.add(perm);
6215 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6216 perm.writeActivities.add(activity);
6217 if (activity.writeUriPermissions == null) {
6218 activity.writeUriPermissions = new HashSet<UriPermission>();
6219 }
6220 activity.writeUriPermissions.add(perm);
6221 }
6222 }
6223
6224 private void grantUriPermissionFromIntentLocked(int callingUid,
6225 String targetPkg, Intent intent, HistoryRecord activity) {
6226 if (intent == null) {
6227 return;
6228 }
6229 Uri data = intent.getData();
6230 if (data == null) {
6231 return;
6232 }
6233 grantUriPermissionLocked(callingUid, targetPkg, data,
6234 intent.getFlags(), activity);
6235 }
6236
6237 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6238 Uri uri, int modeFlags) {
6239 synchronized(this) {
6240 final ProcessRecord r = getRecordForAppLocked(caller);
6241 if (r == null) {
6242 throw new SecurityException("Unable to find app for caller "
6243 + caller
6244 + " when granting permission to uri " + uri);
6245 }
6246 if (targetPkg == null) {
6247 Log.w(TAG, "grantUriPermission: null target");
6248 return;
6249 }
6250 if (uri == null) {
6251 Log.w(TAG, "grantUriPermission: null uri");
6252 return;
6253 }
6254
6255 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6256 null);
6257 }
6258 }
6259
6260 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6261 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6262 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6263 HashMap<Uri, UriPermission> perms
6264 = mGrantedUriPermissions.get(perm.uid);
6265 if (perms != null) {
6266 perms.remove(perm.uri);
6267 if (perms.size() == 0) {
6268 mGrantedUriPermissions.remove(perm.uid);
6269 }
6270 }
6271 }
6272 }
6273
6274 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6275 if (activity.readUriPermissions != null) {
6276 for (UriPermission perm : activity.readUriPermissions) {
6277 perm.readActivities.remove(activity);
6278 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6279 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6280 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6281 removeUriPermissionIfNeededLocked(perm);
6282 }
6283 }
6284 }
6285 if (activity.writeUriPermissions != null) {
6286 for (UriPermission perm : activity.writeUriPermissions) {
6287 perm.writeActivities.remove(activity);
6288 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6289 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6290 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6291 removeUriPermissionIfNeededLocked(perm);
6292 }
6293 }
6294 }
6295 }
6296
6297 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6298 int modeFlags) {
6299 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6300 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6301 if (modeFlags == 0) {
6302 return;
6303 }
6304
6305 final IPackageManager pm = ActivityThread.getPackageManager();
6306
6307 final String authority = uri.getAuthority();
6308 ProviderInfo pi = null;
6309 ContentProviderRecord cpr
6310 = (ContentProviderRecord)mProvidersByName.get(authority);
6311 if (cpr != null) {
6312 pi = cpr.info;
6313 } else {
6314 try {
6315 pi = pm.resolveContentProvider(authority,
6316 PackageManager.GET_URI_PERMISSION_PATTERNS);
6317 } catch (RemoteException ex) {
6318 }
6319 }
6320 if (pi == null) {
6321 Log.w(TAG, "No content provider found for: " + authority);
6322 return;
6323 }
6324
6325 // Does the caller have this permission on the URI?
6326 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6327 // Right now, if you are not the original owner of the permission,
6328 // you are not allowed to revoke it.
6329 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6330 throw new SecurityException("Uid " + callingUid
6331 + " does not have permission to uri " + uri);
6332 //}
6333 }
6334
6335 // Go through all of the permissions and remove any that match.
6336 final List<String> SEGMENTS = uri.getPathSegments();
6337 if (SEGMENTS != null) {
6338 final int NS = SEGMENTS.size();
6339 int N = mGrantedUriPermissions.size();
6340 for (int i=0; i<N; i++) {
6341 HashMap<Uri, UriPermission> perms
6342 = mGrantedUriPermissions.valueAt(i);
6343 Iterator<UriPermission> it = perms.values().iterator();
6344 toploop:
6345 while (it.hasNext()) {
6346 UriPermission perm = it.next();
6347 Uri targetUri = perm.uri;
6348 if (!authority.equals(targetUri.getAuthority())) {
6349 continue;
6350 }
6351 List<String> targetSegments = targetUri.getPathSegments();
6352 if (targetSegments == null) {
6353 continue;
6354 }
6355 if (targetSegments.size() < NS) {
6356 continue;
6357 }
6358 for (int j=0; j<NS; j++) {
6359 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6360 continue toploop;
6361 }
6362 }
6363 perm.clearModes(modeFlags);
6364 if (perm.modeFlags == 0) {
6365 it.remove();
6366 }
6367 }
6368 if (perms.size() == 0) {
6369 mGrantedUriPermissions.remove(
6370 mGrantedUriPermissions.keyAt(i));
6371 N--;
6372 i--;
6373 }
6374 }
6375 }
6376 }
6377
6378 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6379 int modeFlags) {
6380 synchronized(this) {
6381 final ProcessRecord r = getRecordForAppLocked(caller);
6382 if (r == null) {
6383 throw new SecurityException("Unable to find app for caller "
6384 + caller
6385 + " when revoking permission to uri " + uri);
6386 }
6387 if (uri == null) {
6388 Log.w(TAG, "revokeUriPermission: null uri");
6389 return;
6390 }
6391
6392 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6393 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6394 if (modeFlags == 0) {
6395 return;
6396 }
6397
6398 final IPackageManager pm = ActivityThread.getPackageManager();
6399
6400 final String authority = uri.getAuthority();
6401 ProviderInfo pi = null;
6402 ContentProviderRecord cpr
6403 = (ContentProviderRecord)mProvidersByName.get(authority);
6404 if (cpr != null) {
6405 pi = cpr.info;
6406 } else {
6407 try {
6408 pi = pm.resolveContentProvider(authority,
6409 PackageManager.GET_URI_PERMISSION_PATTERNS);
6410 } catch (RemoteException ex) {
6411 }
6412 }
6413 if (pi == null) {
6414 Log.w(TAG, "No content provider found for: " + authority);
6415 return;
6416 }
6417
6418 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6419 }
6420 }
6421
6422 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6423 synchronized (this) {
6424 ProcessRecord app =
6425 who != null ? getRecordForAppLocked(who) : null;
6426 if (app == null) return;
6427
6428 Message msg = Message.obtain();
6429 msg.what = WAIT_FOR_DEBUGGER_MSG;
6430 msg.obj = app;
6431 msg.arg1 = waiting ? 1 : 0;
6432 mHandler.sendMessage(msg);
6433 }
6434 }
6435
6436 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6437 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006438 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006439 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006440 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006441 }
6442
6443 // =========================================================
6444 // TASK MANAGEMENT
6445 // =========================================================
6446
6447 public List getTasks(int maxNum, int flags,
6448 IThumbnailReceiver receiver) {
6449 ArrayList list = new ArrayList();
6450
6451 PendingThumbnailsRecord pending = null;
6452 IApplicationThread topThumbnail = null;
6453 HistoryRecord topRecord = null;
6454
6455 synchronized(this) {
6456 if (localLOGV) Log.v(
6457 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6458 + ", receiver=" + receiver);
6459
6460 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6461 != PackageManager.PERMISSION_GRANTED) {
6462 if (receiver != null) {
6463 // If the caller wants to wait for pending thumbnails,
6464 // it ain't gonna get them.
6465 try {
6466 receiver.finished();
6467 } catch (RemoteException ex) {
6468 }
6469 }
6470 String msg = "Permission Denial: getTasks() from pid="
6471 + Binder.getCallingPid()
6472 + ", uid=" + Binder.getCallingUid()
6473 + " requires " + android.Manifest.permission.GET_TASKS;
6474 Log.w(TAG, msg);
6475 throw new SecurityException(msg);
6476 }
6477
6478 int pos = mHistory.size()-1;
6479 HistoryRecord next =
6480 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6481 HistoryRecord top = null;
6482 CharSequence topDescription = null;
6483 TaskRecord curTask = null;
6484 int numActivities = 0;
6485 int numRunning = 0;
6486 while (pos >= 0 && maxNum > 0) {
6487 final HistoryRecord r = next;
6488 pos--;
6489 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6490
6491 // Initialize state for next task if needed.
6492 if (top == null ||
6493 (top.state == ActivityState.INITIALIZING
6494 && top.task == r.task)) {
6495 top = r;
6496 topDescription = r.description;
6497 curTask = r.task;
6498 numActivities = numRunning = 0;
6499 }
6500
6501 // Add 'r' into the current task.
6502 numActivities++;
6503 if (r.app != null && r.app.thread != null) {
6504 numRunning++;
6505 }
6506 if (topDescription == null) {
6507 topDescription = r.description;
6508 }
6509
6510 if (localLOGV) Log.v(
6511 TAG, r.intent.getComponent().flattenToShortString()
6512 + ": task=" + r.task);
6513
6514 // If the next one is a different task, generate a new
6515 // TaskInfo entry for what we have.
6516 if (next == null || next.task != curTask) {
6517 ActivityManager.RunningTaskInfo ci
6518 = new ActivityManager.RunningTaskInfo();
6519 ci.id = curTask.taskId;
6520 ci.baseActivity = r.intent.getComponent();
6521 ci.topActivity = top.intent.getComponent();
6522 ci.thumbnail = top.thumbnail;
6523 ci.description = topDescription;
6524 ci.numActivities = numActivities;
6525 ci.numRunning = numRunning;
6526 //System.out.println(
6527 // "#" + maxNum + ": " + " descr=" + ci.description);
6528 if (ci.thumbnail == null && receiver != null) {
6529 if (localLOGV) Log.v(
6530 TAG, "State=" + top.state + "Idle=" + top.idle
6531 + " app=" + top.app
6532 + " thr=" + (top.app != null ? top.app.thread : null));
6533 if (top.state == ActivityState.RESUMED
6534 || top.state == ActivityState.PAUSING) {
6535 if (top.idle && top.app != null
6536 && top.app.thread != null) {
6537 topRecord = top;
6538 topThumbnail = top.app.thread;
6539 } else {
6540 top.thumbnailNeeded = true;
6541 }
6542 }
6543 if (pending == null) {
6544 pending = new PendingThumbnailsRecord(receiver);
6545 }
6546 pending.pendingRecords.add(top);
6547 }
6548 list.add(ci);
6549 maxNum--;
6550 top = null;
6551 }
6552 }
6553
6554 if (pending != null) {
6555 mPendingThumbnails.add(pending);
6556 }
6557 }
6558
6559 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6560
6561 if (topThumbnail != null) {
6562 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6563 try {
6564 topThumbnail.requestThumbnail(topRecord);
6565 } catch (Exception e) {
6566 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6567 sendPendingThumbnail(null, topRecord, null, null, true);
6568 }
6569 }
6570
6571 if (pending == null && receiver != null) {
6572 // In this case all thumbnails were available and the client
6573 // is being asked to be told when the remaining ones come in...
6574 // which is unusually, since the top-most currently running
6575 // activity should never have a canned thumbnail! Oh well.
6576 try {
6577 receiver.finished();
6578 } catch (RemoteException ex) {
6579 }
6580 }
6581
6582 return list;
6583 }
6584
6585 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6586 int flags) {
6587 synchronized (this) {
6588 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6589 "getRecentTasks()");
6590
6591 final int N = mRecentTasks.size();
6592 ArrayList<ActivityManager.RecentTaskInfo> res
6593 = new ArrayList<ActivityManager.RecentTaskInfo>(
6594 maxNum < N ? maxNum : N);
6595 for (int i=0; i<N && maxNum > 0; i++) {
6596 TaskRecord tr = mRecentTasks.get(i);
6597 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6598 || (tr.intent == null)
6599 || ((tr.intent.getFlags()
6600 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6601 ActivityManager.RecentTaskInfo rti
6602 = new ActivityManager.RecentTaskInfo();
6603 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6604 rti.baseIntent = new Intent(
6605 tr.intent != null ? tr.intent : tr.affinityIntent);
6606 rti.origActivity = tr.origActivity;
6607 res.add(rti);
6608 maxNum--;
6609 }
6610 }
6611 return res;
6612 }
6613 }
6614
6615 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6616 int j;
6617 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6618 TaskRecord jt = startTask;
6619
6620 // First look backwards
6621 for (j=startIndex-1; j>=0; j--) {
6622 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6623 if (r.task != jt) {
6624 jt = r.task;
6625 if (affinity.equals(jt.affinity)) {
6626 return j;
6627 }
6628 }
6629 }
6630
6631 // Now look forwards
6632 final int N = mHistory.size();
6633 jt = startTask;
6634 for (j=startIndex+1; j<N; j++) {
6635 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6636 if (r.task != jt) {
6637 if (affinity.equals(jt.affinity)) {
6638 return j;
6639 }
6640 jt = r.task;
6641 }
6642 }
6643
6644 // Might it be at the top?
6645 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6646 return N-1;
6647 }
6648
6649 return -1;
6650 }
6651
6652 /**
6653 * Perform a reset of the given task, if needed as part of launching it.
6654 * Returns the new HistoryRecord at the top of the task.
6655 */
6656 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6657 HistoryRecord newActivity) {
6658 boolean forceReset = (newActivity.info.flags
6659 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6660 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6661 if ((newActivity.info.flags
6662 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6663 forceReset = true;
6664 }
6665 }
6666
6667 final TaskRecord task = taskTop.task;
6668
6669 // We are going to move through the history list so that we can look
6670 // at each activity 'target' with 'below' either the interesting
6671 // activity immediately below it in the stack or null.
6672 HistoryRecord target = null;
6673 int targetI = 0;
6674 int taskTopI = -1;
6675 int replyChainEnd = -1;
6676 int lastReparentPos = -1;
6677 for (int i=mHistory.size()-1; i>=-1; i--) {
6678 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6679
6680 if (below != null && below.finishing) {
6681 continue;
6682 }
6683 if (target == null) {
6684 target = below;
6685 targetI = i;
6686 // If we were in the middle of a reply chain before this
6687 // task, it doesn't appear like the root of the chain wants
6688 // anything interesting, so drop it.
6689 replyChainEnd = -1;
6690 continue;
6691 }
6692
6693 final int flags = target.info.flags;
6694
6695 final boolean finishOnTaskLaunch =
6696 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6697 final boolean allowTaskReparenting =
6698 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6699
6700 if (target.task == task) {
6701 // We are inside of the task being reset... we'll either
6702 // finish this activity, push it out for another task,
6703 // or leave it as-is. We only do this
6704 // for activities that are not the root of the task (since
6705 // if we finish the root, we may no longer have the task!).
6706 if (taskTopI < 0) {
6707 taskTopI = targetI;
6708 }
6709 if (below != null && below.task == task) {
6710 final boolean clearWhenTaskReset =
6711 (target.intent.getFlags()
6712 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006713 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006714 // If this activity is sending a reply to a previous
6715 // activity, we can't do anything with it now until
6716 // we reach the start of the reply chain.
6717 // XXX note that we are assuming the result is always
6718 // to the previous activity, which is almost always
6719 // the case but we really shouldn't count on.
6720 if (replyChainEnd < 0) {
6721 replyChainEnd = targetI;
6722 }
Ed Heyl73798232009-03-24 21:32:21 -07006723 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006724 && target.taskAffinity != null
6725 && !target.taskAffinity.equals(task.affinity)) {
6726 // If this activity has an affinity for another
6727 // task, then we need to move it out of here. We will
6728 // move it as far out of the way as possible, to the
6729 // bottom of the activity stack. This also keeps it
6730 // correctly ordered with any activities we previously
6731 // moved.
6732 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6733 if (target.taskAffinity != null
6734 && target.taskAffinity.equals(p.task.affinity)) {
6735 // If the activity currently at the bottom has the
6736 // same task affinity as the one we are moving,
6737 // then merge it into the same task.
6738 target.task = p.task;
6739 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6740 + " out to bottom task " + p.task);
6741 } else {
6742 mCurTask++;
6743 if (mCurTask <= 0) {
6744 mCurTask = 1;
6745 }
6746 target.task = new TaskRecord(mCurTask, target.info, null,
6747 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6748 target.task.affinityIntent = target.intent;
6749 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6750 + " out to new task " + target.task);
6751 }
6752 mWindowManager.setAppGroupId(target, task.taskId);
6753 if (replyChainEnd < 0) {
6754 replyChainEnd = targetI;
6755 }
6756 int dstPos = 0;
6757 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6758 p = (HistoryRecord)mHistory.get(srcPos);
6759 if (p.finishing) {
6760 continue;
6761 }
6762 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6763 + " out to target's task " + target.task);
6764 task.numActivities--;
6765 p.task = target.task;
6766 target.task.numActivities++;
6767 mHistory.remove(srcPos);
6768 mHistory.add(dstPos, p);
6769 mWindowManager.moveAppToken(dstPos, p);
6770 mWindowManager.setAppGroupId(p, p.task.taskId);
6771 dstPos++;
6772 if (VALIDATE_TOKENS) {
6773 mWindowManager.validateAppTokens(mHistory);
6774 }
6775 i++;
6776 }
6777 if (taskTop == p) {
6778 taskTop = below;
6779 }
6780 if (taskTopI == replyChainEnd) {
6781 taskTopI = -1;
6782 }
6783 replyChainEnd = -1;
6784 addRecentTask(target.task);
6785 } else if (forceReset || finishOnTaskLaunch
6786 || clearWhenTaskReset) {
6787 // If the activity should just be removed -- either
6788 // because it asks for it, or the task should be
6789 // cleared -- then finish it and anything that is
6790 // part of its reply chain.
6791 if (clearWhenTaskReset) {
6792 // In this case, we want to finish this activity
6793 // and everything above it, so be sneaky and pretend
6794 // like these are all in the reply chain.
6795 replyChainEnd = targetI+1;
6796 while (replyChainEnd < mHistory.size() &&
6797 ((HistoryRecord)mHistory.get(
6798 replyChainEnd)).task == task) {
6799 replyChainEnd++;
6800 }
6801 replyChainEnd--;
6802 } else if (replyChainEnd < 0) {
6803 replyChainEnd = targetI;
6804 }
6805 HistoryRecord p = null;
6806 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6807 p = (HistoryRecord)mHistory.get(srcPos);
6808 if (p.finishing) {
6809 continue;
6810 }
6811 if (finishActivityLocked(p, srcPos,
6812 Activity.RESULT_CANCELED, null, "reset")) {
6813 replyChainEnd--;
6814 srcPos--;
6815 }
6816 }
6817 if (taskTop == p) {
6818 taskTop = below;
6819 }
6820 if (taskTopI == replyChainEnd) {
6821 taskTopI = -1;
6822 }
6823 replyChainEnd = -1;
6824 } else {
6825 // If we were in the middle of a chain, well the
6826 // activity that started it all doesn't want anything
6827 // special, so leave it all as-is.
6828 replyChainEnd = -1;
6829 }
6830 } else {
6831 // Reached the bottom of the task -- any reply chain
6832 // should be left as-is.
6833 replyChainEnd = -1;
6834 }
6835
6836 } else if (target.resultTo != null) {
6837 // If this activity is sending a reply to a previous
6838 // activity, we can't do anything with it now until
6839 // we reach the start of the reply chain.
6840 // XXX note that we are assuming the result is always
6841 // to the previous activity, which is almost always
6842 // the case but we really shouldn't count on.
6843 if (replyChainEnd < 0) {
6844 replyChainEnd = targetI;
6845 }
6846
6847 } else if (taskTopI >= 0 && allowTaskReparenting
6848 && task.affinity != null
6849 && task.affinity.equals(target.taskAffinity)) {
6850 // We are inside of another task... if this activity has
6851 // an affinity for our task, then either remove it if we are
6852 // clearing or move it over to our task. Note that
6853 // we currently punt on the case where we are resetting a
6854 // task that is not at the top but who has activities above
6855 // with an affinity to it... this is really not a normal
6856 // case, and we will need to later pull that task to the front
6857 // and usually at that point we will do the reset and pick
6858 // up those remaining activities. (This only happens if
6859 // someone starts an activity in a new task from an activity
6860 // in a task that is not currently on top.)
6861 if (forceReset || finishOnTaskLaunch) {
6862 if (replyChainEnd < 0) {
6863 replyChainEnd = targetI;
6864 }
6865 HistoryRecord p = null;
6866 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6867 p = (HistoryRecord)mHistory.get(srcPos);
6868 if (p.finishing) {
6869 continue;
6870 }
6871 if (finishActivityLocked(p, srcPos,
6872 Activity.RESULT_CANCELED, null, "reset")) {
6873 taskTopI--;
6874 lastReparentPos--;
6875 replyChainEnd--;
6876 srcPos--;
6877 }
6878 }
6879 replyChainEnd = -1;
6880 } else {
6881 if (replyChainEnd < 0) {
6882 replyChainEnd = targetI;
6883 }
6884 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6885 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6886 if (p.finishing) {
6887 continue;
6888 }
6889 if (lastReparentPos < 0) {
6890 lastReparentPos = taskTopI;
6891 taskTop = p;
6892 } else {
6893 lastReparentPos--;
6894 }
6895 mHistory.remove(srcPos);
6896 p.task.numActivities--;
6897 p.task = task;
6898 mHistory.add(lastReparentPos, p);
6899 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6900 + " in to resetting task " + task);
6901 task.numActivities++;
6902 mWindowManager.moveAppToken(lastReparentPos, p);
6903 mWindowManager.setAppGroupId(p, p.task.taskId);
6904 if (VALIDATE_TOKENS) {
6905 mWindowManager.validateAppTokens(mHistory);
6906 }
6907 }
6908 replyChainEnd = -1;
6909
6910 // Now we've moved it in to place... but what if this is
6911 // a singleTop activity and we have put it on top of another
6912 // instance of the same activity? Then we drop the instance
6913 // below so it remains singleTop.
6914 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6915 for (int j=lastReparentPos-1; j>=0; j--) {
6916 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6917 if (p.finishing) {
6918 continue;
6919 }
6920 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6921 if (finishActivityLocked(p, j,
6922 Activity.RESULT_CANCELED, null, "replace")) {
6923 taskTopI--;
6924 lastReparentPos--;
6925 }
6926 }
6927 }
6928 }
6929 }
6930 }
6931
6932 target = below;
6933 targetI = i;
6934 }
6935
6936 return taskTop;
6937 }
6938
6939 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006940 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006941 */
6942 public void moveTaskToFront(int task) {
6943 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6944 "moveTaskToFront()");
6945
6946 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006947 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6948 Binder.getCallingUid(), "Task to front")) {
6949 return;
6950 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006951 final long origId = Binder.clearCallingIdentity();
6952 try {
6953 int N = mRecentTasks.size();
6954 for (int i=0; i<N; i++) {
6955 TaskRecord tr = mRecentTasks.get(i);
6956 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07006957 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006958 return;
6959 }
6960 }
6961 for (int i=mHistory.size()-1; i>=0; i--) {
6962 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6963 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07006964 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006965 return;
6966 }
6967 }
6968 } finally {
6969 Binder.restoreCallingIdentity(origId);
6970 }
6971 }
6972 }
6973
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07006974 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006975 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6976
6977 final int task = tr.taskId;
6978 int top = mHistory.size()-1;
6979
6980 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6981 // nothing to do!
6982 return;
6983 }
6984
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006985 ArrayList moved = new ArrayList();
6986
6987 // Applying the affinities may have removed entries from the history,
6988 // so get the size again.
6989 top = mHistory.size()-1;
6990 int pos = top;
6991
6992 // Shift all activities with this task up to the top
6993 // of the stack, keeping them in the same internal order.
6994 while (pos >= 0) {
6995 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6996 if (localLOGV) Log.v(
6997 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6998 boolean first = true;
6999 if (r.task.taskId == task) {
7000 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7001 mHistory.remove(pos);
7002 mHistory.add(top, r);
7003 moved.add(0, r);
7004 top--;
7005 if (first) {
7006 addRecentTask(r.task);
7007 first = false;
7008 }
7009 }
7010 pos--;
7011 }
7012
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007013 if (DEBUG_TRANSITION) Log.v(TAG,
7014 "Prepare to front transition: task=" + tr);
7015 if (reason != null &&
7016 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7017 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7018 HistoryRecord r = topRunningActivityLocked(null);
7019 if (r != null) {
7020 mNoAnimActivities.add(r);
7021 }
7022 } else {
7023 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7024 }
7025
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007026 mWindowManager.moveAppTokensToTop(moved);
7027 if (VALIDATE_TOKENS) {
7028 mWindowManager.validateAppTokens(mHistory);
7029 }
7030
7031 finishTaskMove(task);
7032 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
7033 }
7034
7035 private final void finishTaskMove(int task) {
7036 resumeTopActivityLocked(null);
7037 }
7038
7039 public void moveTaskToBack(int task) {
7040 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7041 "moveTaskToBack()");
7042
7043 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007044 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7045 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7046 Binder.getCallingUid(), "Task to back")) {
7047 return;
7048 }
7049 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007050 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007051 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007052 Binder.restoreCallingIdentity(origId);
7053 }
7054 }
7055
7056 /**
7057 * Moves an activity, and all of the other activities within the same task, to the bottom
7058 * of the history stack. The activity's order within the task is unchanged.
7059 *
7060 * @param token A reference to the activity we wish to move
7061 * @param nonRoot If false then this only works if the activity is the root
7062 * of a task; if true it will work for any activity in a task.
7063 * @return Returns true if the move completed, false if not.
7064 */
7065 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7066 synchronized(this) {
7067 final long origId = Binder.clearCallingIdentity();
7068 int taskId = getTaskForActivityLocked(token, !nonRoot);
7069 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007070 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007071 }
7072 Binder.restoreCallingIdentity(origId);
7073 }
7074 return false;
7075 }
7076
7077 /**
7078 * Worker method for rearranging history stack. Implements the function of moving all
7079 * activities for a specific task (gathering them if disjoint) into a single group at the
7080 * bottom of the stack.
7081 *
7082 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7083 * to premeptively cancel the move.
7084 *
7085 * @param task The taskId to collect and move to the bottom.
7086 * @return Returns true if the move completed, false if not.
7087 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007088 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007089 Log.i(TAG, "moveTaskToBack: " + task);
7090
7091 // If we have a watcher, preflight the move before committing to it. First check
7092 // for *other* available tasks, but if none are available, then try again allowing the
7093 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007094 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007095 HistoryRecord next = topRunningActivityLocked(null, task);
7096 if (next == null) {
7097 next = topRunningActivityLocked(null, 0);
7098 }
7099 if (next != null) {
7100 // ask watcher if this is allowed
7101 boolean moveOK = true;
7102 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007103 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007104 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007105 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007106 }
7107 if (!moveOK) {
7108 return false;
7109 }
7110 }
7111 }
7112
7113 ArrayList moved = new ArrayList();
7114
7115 if (DEBUG_TRANSITION) Log.v(TAG,
7116 "Prepare to back transition: task=" + task);
7117 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
7118
7119 final int N = mHistory.size();
7120 int bottom = 0;
7121 int pos = 0;
7122
7123 // Shift all activities with this task down to the bottom
7124 // of the stack, keeping them in the same internal order.
7125 while (pos < N) {
7126 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7127 if (localLOGV) Log.v(
7128 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7129 if (r.task.taskId == task) {
7130 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7131 mHistory.remove(pos);
7132 mHistory.add(bottom, r);
7133 moved.add(r);
7134 bottom++;
7135 }
7136 pos++;
7137 }
7138
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007139 if (reason != null &&
7140 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7141 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7142 HistoryRecord r = topRunningActivityLocked(null);
7143 if (r != null) {
7144 mNoAnimActivities.add(r);
7145 }
7146 } else {
7147 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7148 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007149 mWindowManager.moveAppTokensToBottom(moved);
7150 if (VALIDATE_TOKENS) {
7151 mWindowManager.validateAppTokens(mHistory);
7152 }
7153
7154 finishTaskMove(task);
7155 return true;
7156 }
7157
7158 public void moveTaskBackwards(int task) {
7159 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7160 "moveTaskBackwards()");
7161
7162 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007163 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7164 Binder.getCallingUid(), "Task backwards")) {
7165 return;
7166 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007167 final long origId = Binder.clearCallingIdentity();
7168 moveTaskBackwardsLocked(task);
7169 Binder.restoreCallingIdentity(origId);
7170 }
7171 }
7172
7173 private final void moveTaskBackwardsLocked(int task) {
7174 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7175 }
7176
7177 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7178 synchronized(this) {
7179 return getTaskForActivityLocked(token, onlyRoot);
7180 }
7181 }
7182
7183 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7184 final int N = mHistory.size();
7185 TaskRecord lastTask = null;
7186 for (int i=0; i<N; i++) {
7187 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7188 if (r == token) {
7189 if (!onlyRoot || lastTask != r.task) {
7190 return r.task.taskId;
7191 }
7192 return -1;
7193 }
7194 lastTask = r.task;
7195 }
7196
7197 return -1;
7198 }
7199
7200 /**
7201 * Returns the top activity in any existing task matching the given
7202 * Intent. Returns null if no such task is found.
7203 */
7204 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7205 ComponentName cls = intent.getComponent();
7206 if (info.targetActivity != null) {
7207 cls = new ComponentName(info.packageName, info.targetActivity);
7208 }
7209
7210 TaskRecord cp = null;
7211
7212 final int N = mHistory.size();
7213 for (int i=(N-1); i>=0; i--) {
7214 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7215 if (!r.finishing && r.task != cp
7216 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7217 cp = r.task;
7218 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7219 // + "/aff=" + r.task.affinity + " to new cls="
7220 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7221 if (r.task.affinity != null) {
7222 if (r.task.affinity.equals(info.taskAffinity)) {
7223 //Log.i(TAG, "Found matching affinity!");
7224 return r;
7225 }
7226 } else if (r.task.intent != null
7227 && r.task.intent.getComponent().equals(cls)) {
7228 //Log.i(TAG, "Found matching class!");
7229 //dump();
7230 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7231 return r;
7232 } else if (r.task.affinityIntent != null
7233 && r.task.affinityIntent.getComponent().equals(cls)) {
7234 //Log.i(TAG, "Found matching class!");
7235 //dump();
7236 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7237 return r;
7238 }
7239 }
7240 }
7241
7242 return null;
7243 }
7244
7245 /**
7246 * Returns the first activity (starting from the top of the stack) that
7247 * is the same as the given activity. Returns null if no such activity
7248 * is found.
7249 */
7250 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7251 ComponentName cls = intent.getComponent();
7252 if (info.targetActivity != null) {
7253 cls = new ComponentName(info.packageName, info.targetActivity);
7254 }
7255
7256 final int N = mHistory.size();
7257 for (int i=(N-1); i>=0; i--) {
7258 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7259 if (!r.finishing) {
7260 if (r.intent.getComponent().equals(cls)) {
7261 //Log.i(TAG, "Found matching class!");
7262 //dump();
7263 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7264 return r;
7265 }
7266 }
7267 }
7268
7269 return null;
7270 }
7271
7272 public void finishOtherInstances(IBinder token, ComponentName className) {
7273 synchronized(this) {
7274 final long origId = Binder.clearCallingIdentity();
7275
7276 int N = mHistory.size();
7277 TaskRecord lastTask = null;
7278 for (int i=0; i<N; i++) {
7279 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7280 if (r.realActivity.equals(className)
7281 && r != token && lastTask != r.task) {
7282 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7283 null, "others")) {
7284 i--;
7285 N--;
7286 }
7287 }
7288 lastTask = r.task;
7289 }
7290
7291 Binder.restoreCallingIdentity(origId);
7292 }
7293 }
7294
7295 // =========================================================
7296 // THUMBNAILS
7297 // =========================================================
7298
7299 public void reportThumbnail(IBinder token,
7300 Bitmap thumbnail, CharSequence description) {
7301 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7302 final long origId = Binder.clearCallingIdentity();
7303 sendPendingThumbnail(null, token, thumbnail, description, true);
7304 Binder.restoreCallingIdentity(origId);
7305 }
7306
7307 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7308 Bitmap thumbnail, CharSequence description, boolean always) {
7309 TaskRecord task = null;
7310 ArrayList receivers = null;
7311
7312 //System.out.println("Send pending thumbnail: " + r);
7313
7314 synchronized(this) {
7315 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007316 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007317 if (index < 0) {
7318 return;
7319 }
7320 r = (HistoryRecord)mHistory.get(index);
7321 }
7322 if (thumbnail == null) {
7323 thumbnail = r.thumbnail;
7324 description = r.description;
7325 }
7326 if (thumbnail == null && !always) {
7327 // If there is no thumbnail, and this entry is not actually
7328 // going away, then abort for now and pick up the next
7329 // thumbnail we get.
7330 return;
7331 }
7332 task = r.task;
7333
7334 int N = mPendingThumbnails.size();
7335 int i=0;
7336 while (i<N) {
7337 PendingThumbnailsRecord pr =
7338 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7339 //System.out.println("Looking in " + pr.pendingRecords);
7340 if (pr.pendingRecords.remove(r)) {
7341 if (receivers == null) {
7342 receivers = new ArrayList();
7343 }
7344 receivers.add(pr);
7345 if (pr.pendingRecords.size() == 0) {
7346 pr.finished = true;
7347 mPendingThumbnails.remove(i);
7348 N--;
7349 continue;
7350 }
7351 }
7352 i++;
7353 }
7354 }
7355
7356 if (receivers != null) {
7357 final int N = receivers.size();
7358 for (int i=0; i<N; i++) {
7359 try {
7360 PendingThumbnailsRecord pr =
7361 (PendingThumbnailsRecord)receivers.get(i);
7362 pr.receiver.newThumbnail(
7363 task != null ? task.taskId : -1, thumbnail, description);
7364 if (pr.finished) {
7365 pr.receiver.finished();
7366 }
7367 } catch (Exception e) {
7368 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7369 }
7370 }
7371 }
7372 }
7373
7374 // =========================================================
7375 // CONTENT PROVIDERS
7376 // =========================================================
7377
7378 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7379 List providers = null;
7380 try {
7381 providers = ActivityThread.getPackageManager().
7382 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007383 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007384 } catch (RemoteException ex) {
7385 }
7386 if (providers != null) {
7387 final int N = providers.size();
7388 for (int i=0; i<N; i++) {
7389 ProviderInfo cpi =
7390 (ProviderInfo)providers.get(i);
7391 ContentProviderRecord cpr =
7392 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7393 if (cpr == null) {
7394 cpr = new ContentProviderRecord(cpi, app.info);
7395 mProvidersByClass.put(cpi.name, cpr);
7396 }
7397 app.pubProviders.put(cpi.name, cpr);
7398 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007399 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007400 }
7401 }
7402 return providers;
7403 }
7404
7405 private final String checkContentProviderPermissionLocked(
7406 ProviderInfo cpi, ProcessRecord r, int mode) {
7407 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7408 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7409 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7410 cpi.exported ? -1 : cpi.applicationInfo.uid)
7411 == PackageManager.PERMISSION_GRANTED
7412 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7413 return null;
7414 }
7415 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7416 cpi.exported ? -1 : cpi.applicationInfo.uid)
7417 == PackageManager.PERMISSION_GRANTED) {
7418 return null;
7419 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007420
7421 PathPermission[] pps = cpi.pathPermissions;
7422 if (pps != null) {
7423 int i = pps.length;
7424 while (i > 0) {
7425 i--;
7426 PathPermission pp = pps[i];
7427 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7428 cpi.exported ? -1 : cpi.applicationInfo.uid)
7429 == PackageManager.PERMISSION_GRANTED
7430 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7431 return null;
7432 }
7433 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7434 cpi.exported ? -1 : cpi.applicationInfo.uid)
7435 == PackageManager.PERMISSION_GRANTED) {
7436 return null;
7437 }
7438 }
7439 }
7440
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007441 String msg = "Permission Denial: opening provider " + cpi.name
7442 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7443 + ", uid=" + callingUid + ") requires "
7444 + cpi.readPermission + " or " + cpi.writePermission;
7445 Log.w(TAG, msg);
7446 return msg;
7447 }
7448
7449 private final ContentProviderHolder getContentProviderImpl(
7450 IApplicationThread caller, String name) {
7451 ContentProviderRecord cpr;
7452 ProviderInfo cpi = null;
7453
7454 synchronized(this) {
7455 ProcessRecord r = null;
7456 if (caller != null) {
7457 r = getRecordForAppLocked(caller);
7458 if (r == null) {
7459 throw new SecurityException(
7460 "Unable to find app for caller " + caller
7461 + " (pid=" + Binder.getCallingPid()
7462 + ") when getting content provider " + name);
7463 }
7464 }
7465
7466 // First check if this content provider has been published...
7467 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7468 if (cpr != null) {
7469 cpi = cpr.info;
7470 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7471 return new ContentProviderHolder(cpi,
7472 cpi.readPermission != null
7473 ? cpi.readPermission : cpi.writePermission);
7474 }
7475
7476 if (r != null && cpr.canRunHere(r)) {
7477 // This provider has been published or is in the process
7478 // of being published... but it is also allowed to run
7479 // in the caller's process, so don't make a connection
7480 // and just let the caller instantiate its own instance.
7481 if (cpr.provider != null) {
7482 // don't give caller the provider object, it needs
7483 // to make its own.
7484 cpr = new ContentProviderRecord(cpr);
7485 }
7486 return cpr;
7487 }
7488
7489 final long origId = Binder.clearCallingIdentity();
7490
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007491 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007492 // return it right away.
7493 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007494 if (DEBUG_PROVIDER) Log.v(TAG,
7495 "Adding provider requested by "
7496 + r.processName + " from process "
7497 + cpr.info.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007498 r.conProviders.add(cpr);
7499 cpr.clients.add(r);
7500 } else {
7501 cpr.externals++;
7502 }
7503
7504 if (cpr.app != null) {
7505 updateOomAdjLocked(cpr.app);
7506 }
7507
7508 Binder.restoreCallingIdentity(origId);
7509
7510 } else {
7511 try {
7512 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007513 resolveContentProvider(name,
7514 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007515 } catch (RemoteException ex) {
7516 }
7517 if (cpi == null) {
7518 return null;
7519 }
7520
7521 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7522 return new ContentProviderHolder(cpi,
7523 cpi.readPermission != null
7524 ? cpi.readPermission : cpi.writePermission);
7525 }
7526
7527 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7528 final boolean firstClass = cpr == null;
7529 if (firstClass) {
7530 try {
7531 ApplicationInfo ai =
7532 ActivityThread.getPackageManager().
7533 getApplicationInfo(
7534 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007535 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007536 if (ai == null) {
7537 Log.w(TAG, "No package info for content provider "
7538 + cpi.name);
7539 return null;
7540 }
7541 cpr = new ContentProviderRecord(cpi, ai);
7542 } catch (RemoteException ex) {
7543 // pm is in same process, this will never happen.
7544 }
7545 }
7546
7547 if (r != null && cpr.canRunHere(r)) {
7548 // If this is a multiprocess provider, then just return its
7549 // info and allow the caller to instantiate it. Only do
7550 // this if the provider is the same user as the caller's
7551 // process, or can run as root (so can be in any process).
7552 return cpr;
7553 }
7554
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007555 if (DEBUG_PROVIDER) {
7556 RuntimeException e = new RuntimeException("here");
7557 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7558 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007559 }
7560
7561 // This is single process, and our app is now connecting to it.
7562 // See if we are already in the process of launching this
7563 // provider.
7564 final int N = mLaunchingProviders.size();
7565 int i;
7566 for (i=0; i<N; i++) {
7567 if (mLaunchingProviders.get(i) == cpr) {
7568 break;
7569 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007570 }
7571
7572 // If the provider is not already being launched, then get it
7573 // started.
7574 if (i >= N) {
7575 final long origId = Binder.clearCallingIdentity();
7576 ProcessRecord proc = startProcessLocked(cpi.processName,
7577 cpr.appInfo, false, 0, "content provider",
7578 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007579 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007580 if (proc == null) {
7581 Log.w(TAG, "Unable to launch app "
7582 + cpi.applicationInfo.packageName + "/"
7583 + cpi.applicationInfo.uid + " for provider "
7584 + name + ": process is bad");
7585 return null;
7586 }
7587 cpr.launchingApp = proc;
7588 mLaunchingProviders.add(cpr);
7589 Binder.restoreCallingIdentity(origId);
7590 }
7591
7592 // Make sure the provider is published (the same provider class
7593 // may be published under multiple names).
7594 if (firstClass) {
7595 mProvidersByClass.put(cpi.name, cpr);
7596 }
7597 mProvidersByName.put(name, cpr);
7598
7599 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007600 if (DEBUG_PROVIDER) Log.v(TAG,
7601 "Adding provider requested by "
7602 + r.processName + " from process "
7603 + cpr.info.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007604 r.conProviders.add(cpr);
7605 cpr.clients.add(r);
7606 } else {
7607 cpr.externals++;
7608 }
7609 }
7610 }
7611
7612 // Wait for the provider to be published...
7613 synchronized (cpr) {
7614 while (cpr.provider == null) {
7615 if (cpr.launchingApp == null) {
7616 Log.w(TAG, "Unable to launch app "
7617 + cpi.applicationInfo.packageName + "/"
7618 + cpi.applicationInfo.uid + " for provider "
7619 + name + ": launching app became null");
7620 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7621 cpi.applicationInfo.packageName,
7622 cpi.applicationInfo.uid, name);
7623 return null;
7624 }
7625 try {
7626 cpr.wait();
7627 } catch (InterruptedException ex) {
7628 }
7629 }
7630 }
7631 return cpr;
7632 }
7633
7634 public final ContentProviderHolder getContentProvider(
7635 IApplicationThread caller, String name) {
7636 if (caller == null) {
7637 String msg = "null IApplicationThread when getting content provider "
7638 + name;
7639 Log.w(TAG, msg);
7640 throw new SecurityException(msg);
7641 }
7642
7643 return getContentProviderImpl(caller, name);
7644 }
7645
7646 private ContentProviderHolder getContentProviderExternal(String name) {
7647 return getContentProviderImpl(null, name);
7648 }
7649
7650 /**
7651 * Drop a content provider from a ProcessRecord's bookkeeping
7652 * @param cpr
7653 */
7654 public void removeContentProvider(IApplicationThread caller, String name) {
7655 synchronized (this) {
7656 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7657 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007658 // remove from mProvidersByClass
7659 if (DEBUG_PROVIDER) Log.v(TAG, name +
7660 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007661 return;
7662 }
7663 final ProcessRecord r = getRecordForAppLocked(caller);
7664 if (r == null) {
7665 throw new SecurityException(
7666 "Unable to find app for caller " + caller +
7667 " when removing content provider " + name);
7668 }
7669 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007670 ContentProviderRecord localCpr = (ContentProviderRecord)
7671 mProvidersByClass.get(cpr.info.name);
7672 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7673 + r.info.processName + " from process "
7674 + localCpr.appInfo.processName);
7675 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007676 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007677 Log.w(TAG, "removeContentProvider called on local provider: "
7678 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007679 return;
7680 } else {
7681 localCpr.clients.remove(r);
7682 r.conProviders.remove(localCpr);
7683 }
7684 updateOomAdjLocked();
7685 }
7686 }
7687
7688 private void removeContentProviderExternal(String name) {
7689 synchronized (this) {
7690 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7691 if(cpr == null) {
7692 //remove from mProvidersByClass
7693 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7694 return;
7695 }
7696
7697 //update content provider record entry info
7698 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7699 localCpr.externals--;
7700 if (localCpr.externals < 0) {
7701 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7702 }
7703 updateOomAdjLocked();
7704 }
7705 }
7706
7707 public final void publishContentProviders(IApplicationThread caller,
7708 List<ContentProviderHolder> providers) {
7709 if (providers == null) {
7710 return;
7711 }
7712
7713 synchronized(this) {
7714 final ProcessRecord r = getRecordForAppLocked(caller);
7715 if (r == null) {
7716 throw new SecurityException(
7717 "Unable to find app for caller " + caller
7718 + " (pid=" + Binder.getCallingPid()
7719 + ") when publishing content providers");
7720 }
7721
7722 final long origId = Binder.clearCallingIdentity();
7723
7724 final int N = providers.size();
7725 for (int i=0; i<N; i++) {
7726 ContentProviderHolder src = providers.get(i);
7727 if (src == null || src.info == null || src.provider == null) {
7728 continue;
7729 }
7730 ContentProviderRecord dst =
7731 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7732 if (dst != null) {
7733 mProvidersByClass.put(dst.info.name, dst);
7734 String names[] = dst.info.authority.split(";");
7735 for (int j = 0; j < names.length; j++) {
7736 mProvidersByName.put(names[j], dst);
7737 }
7738
7739 int NL = mLaunchingProviders.size();
7740 int j;
7741 for (j=0; j<NL; j++) {
7742 if (mLaunchingProviders.get(j) == dst) {
7743 mLaunchingProviders.remove(j);
7744 j--;
7745 NL--;
7746 }
7747 }
7748 synchronized (dst) {
7749 dst.provider = src.provider;
7750 dst.app = r;
7751 dst.notifyAll();
7752 }
7753 updateOomAdjLocked(r);
7754 }
7755 }
7756
7757 Binder.restoreCallingIdentity(origId);
7758 }
7759 }
7760
7761 public static final void installSystemProviders() {
7762 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7763 List providers = mSelf.generateApplicationProvidersLocked(app);
7764 mSystemThread.installSystemProviders(providers);
7765 }
7766
7767 // =========================================================
7768 // GLOBAL MANAGEMENT
7769 // =========================================================
7770
7771 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7772 ApplicationInfo info, String customProcess) {
7773 String proc = customProcess != null ? customProcess : info.processName;
7774 BatteryStatsImpl.Uid.Proc ps = null;
7775 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7776 synchronized (stats) {
7777 ps = stats.getProcessStatsLocked(info.uid, proc);
7778 }
7779 return new ProcessRecord(ps, thread, info, proc);
7780 }
7781
7782 final ProcessRecord addAppLocked(ApplicationInfo info) {
7783 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7784
7785 if (app == null) {
7786 app = newProcessRecordLocked(null, info, null);
7787 mProcessNames.put(info.processName, info.uid, app);
7788 updateLRUListLocked(app, true);
7789 }
7790
7791 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7792 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7793 app.persistent = true;
7794 app.maxAdj = CORE_SERVER_ADJ;
7795 }
7796 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7797 mPersistentStartingProcesses.add(app);
7798 startProcessLocked(app, "added application", app.processName);
7799 }
7800
7801 return app;
7802 }
7803
7804 public void unhandledBack() {
7805 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7806 "unhandledBack()");
7807
7808 synchronized(this) {
7809 int count = mHistory.size();
7810 if (Config.LOGD) Log.d(
7811 TAG, "Performing unhandledBack(): stack size = " + count);
7812 if (count > 1) {
7813 final long origId = Binder.clearCallingIdentity();
7814 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7815 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7816 Binder.restoreCallingIdentity(origId);
7817 }
7818 }
7819 }
7820
7821 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7822 String name = uri.getAuthority();
7823 ContentProviderHolder cph = getContentProviderExternal(name);
7824 ParcelFileDescriptor pfd = null;
7825 if (cph != null) {
7826 // We record the binder invoker's uid in thread-local storage before
7827 // going to the content provider to open the file. Later, in the code
7828 // that handles all permissions checks, we look for this uid and use
7829 // that rather than the Activity Manager's own uid. The effect is that
7830 // we do the check against the caller's permissions even though it looks
7831 // to the content provider like the Activity Manager itself is making
7832 // the request.
7833 sCallerIdentity.set(new Identity(
7834 Binder.getCallingPid(), Binder.getCallingUid()));
7835 try {
7836 pfd = cph.provider.openFile(uri, "r");
7837 } catch (FileNotFoundException e) {
7838 // do nothing; pfd will be returned null
7839 } finally {
7840 // Ensure that whatever happens, we clean up the identity state
7841 sCallerIdentity.remove();
7842 }
7843
7844 // We've got the fd now, so we're done with the provider.
7845 removeContentProviderExternal(name);
7846 } else {
7847 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7848 }
7849 return pfd;
7850 }
7851
7852 public void goingToSleep() {
7853 synchronized(this) {
7854 mSleeping = true;
7855 mWindowManager.setEventDispatching(false);
7856
7857 if (mResumedActivity != null) {
7858 pauseIfSleepingLocked();
7859 } else {
7860 Log.w(TAG, "goingToSleep with no resumed activity!");
7861 }
7862 }
7863 }
7864
Dianne Hackborn55280a92009-05-07 15:53:46 -07007865 public boolean shutdown(int timeout) {
7866 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7867 != PackageManager.PERMISSION_GRANTED) {
7868 throw new SecurityException("Requires permission "
7869 + android.Manifest.permission.SHUTDOWN);
7870 }
7871
7872 boolean timedout = false;
7873
7874 synchronized(this) {
7875 mShuttingDown = true;
7876 mWindowManager.setEventDispatching(false);
7877
7878 if (mResumedActivity != null) {
7879 pauseIfSleepingLocked();
7880 final long endTime = System.currentTimeMillis() + timeout;
7881 while (mResumedActivity != null || mPausingActivity != null) {
7882 long delay = endTime - System.currentTimeMillis();
7883 if (delay <= 0) {
7884 Log.w(TAG, "Activity manager shutdown timed out");
7885 timedout = true;
7886 break;
7887 }
7888 try {
7889 this.wait();
7890 } catch (InterruptedException e) {
7891 }
7892 }
7893 }
7894 }
7895
7896 mUsageStatsService.shutdown();
7897 mBatteryStatsService.shutdown();
7898
7899 return timedout;
7900 }
7901
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007902 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007903 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007904 if (!mGoingToSleep.isHeld()) {
7905 mGoingToSleep.acquire();
7906 if (mLaunchingActivity.isHeld()) {
7907 mLaunchingActivity.release();
7908 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7909 }
7910 }
7911
7912 // If we are not currently pausing an activity, get the current
7913 // one to pause. If we are pausing one, we will just let that stuff
7914 // run and release the wake lock when all done.
7915 if (mPausingActivity == null) {
7916 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7917 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7918 startPausingLocked(false, true);
7919 }
7920 }
7921 }
7922
7923 public void wakingUp() {
7924 synchronized(this) {
7925 if (mGoingToSleep.isHeld()) {
7926 mGoingToSleep.release();
7927 }
7928 mWindowManager.setEventDispatching(true);
7929 mSleeping = false;
7930 resumeTopActivityLocked(null);
7931 }
7932 }
7933
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007934 public void stopAppSwitches() {
7935 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7936 != PackageManager.PERMISSION_GRANTED) {
7937 throw new SecurityException("Requires permission "
7938 + android.Manifest.permission.STOP_APP_SWITCHES);
7939 }
7940
7941 synchronized(this) {
7942 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7943 + APP_SWITCH_DELAY_TIME;
7944 mDidAppSwitch = false;
7945 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7946 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7947 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7948 }
7949 }
7950
7951 public void resumeAppSwitches() {
7952 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7953 != PackageManager.PERMISSION_GRANTED) {
7954 throw new SecurityException("Requires permission "
7955 + android.Manifest.permission.STOP_APP_SWITCHES);
7956 }
7957
7958 synchronized(this) {
7959 // Note that we don't execute any pending app switches... we will
7960 // let those wait until either the timeout, or the next start
7961 // activity request.
7962 mAppSwitchesAllowedTime = 0;
7963 }
7964 }
7965
7966 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7967 String name) {
7968 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7969 return true;
7970 }
7971
7972 final int perm = checkComponentPermission(
7973 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7974 callingUid, -1);
7975 if (perm == PackageManager.PERMISSION_GRANTED) {
7976 return true;
7977 }
7978
7979 Log.w(TAG, name + " request from " + callingUid + " stopped");
7980 return false;
7981 }
7982
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007983 public void setDebugApp(String packageName, boolean waitForDebugger,
7984 boolean persistent) {
7985 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7986 "setDebugApp()");
7987
7988 // Note that this is not really thread safe if there are multiple
7989 // callers into it at the same time, but that's not a situation we
7990 // care about.
7991 if (persistent) {
7992 final ContentResolver resolver = mContext.getContentResolver();
7993 Settings.System.putString(
7994 resolver, Settings.System.DEBUG_APP,
7995 packageName);
7996 Settings.System.putInt(
7997 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7998 waitForDebugger ? 1 : 0);
7999 }
8000
8001 synchronized (this) {
8002 if (!persistent) {
8003 mOrigDebugApp = mDebugApp;
8004 mOrigWaitForDebugger = mWaitForDebugger;
8005 }
8006 mDebugApp = packageName;
8007 mWaitForDebugger = waitForDebugger;
8008 mDebugTransient = !persistent;
8009 if (packageName != null) {
8010 final long origId = Binder.clearCallingIdentity();
8011 uninstallPackageLocked(packageName, -1, false);
8012 Binder.restoreCallingIdentity(origId);
8013 }
8014 }
8015 }
8016
8017 public void setAlwaysFinish(boolean enabled) {
8018 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8019 "setAlwaysFinish()");
8020
8021 Settings.System.putInt(
8022 mContext.getContentResolver(),
8023 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8024
8025 synchronized (this) {
8026 mAlwaysFinishActivities = enabled;
8027 }
8028 }
8029
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008030 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008031 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008032 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008033 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008034 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008035 }
8036 }
8037
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008038 public void registerActivityWatcher(IActivityWatcher watcher) {
8039 mWatchers.register(watcher);
8040 }
8041
8042 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8043 mWatchers.unregister(watcher);
8044 }
8045
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008046 public final void enterSafeMode() {
8047 synchronized(this) {
8048 // It only makes sense to do this before the system is ready
8049 // and started launching other packages.
8050 if (!mSystemReady) {
8051 try {
8052 ActivityThread.getPackageManager().enterSafeMode();
8053 } catch (RemoteException e) {
8054 }
8055
8056 View v = LayoutInflater.from(mContext).inflate(
8057 com.android.internal.R.layout.safe_mode, null);
8058 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8059 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8060 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8061 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8062 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8063 lp.format = v.getBackground().getOpacity();
8064 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8065 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8066 ((WindowManager)mContext.getSystemService(
8067 Context.WINDOW_SERVICE)).addView(v, lp);
8068 }
8069 }
8070 }
8071
8072 public void noteWakeupAlarm(IIntentSender sender) {
8073 if (!(sender instanceof PendingIntentRecord)) {
8074 return;
8075 }
8076 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8077 synchronized (stats) {
8078 if (mBatteryStatsService.isOnBattery()) {
8079 mBatteryStatsService.enforceCallingPermission();
8080 PendingIntentRecord rec = (PendingIntentRecord)sender;
8081 int MY_UID = Binder.getCallingUid();
8082 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8083 BatteryStatsImpl.Uid.Pkg pkg =
8084 stats.getPackageStatsLocked(uid, rec.key.packageName);
8085 pkg.incWakeupsLocked();
8086 }
8087 }
8088 }
8089
8090 public boolean killPidsForMemory(int[] pids) {
8091 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8092 throw new SecurityException("killPidsForMemory only available to the system");
8093 }
8094
8095 // XXX Note: don't acquire main activity lock here, because the window
8096 // manager calls in with its locks held.
8097
8098 boolean killed = false;
8099 synchronized (mPidsSelfLocked) {
8100 int[] types = new int[pids.length];
8101 int worstType = 0;
8102 for (int i=0; i<pids.length; i++) {
8103 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8104 if (proc != null) {
8105 int type = proc.setAdj;
8106 types[i] = type;
8107 if (type > worstType) {
8108 worstType = type;
8109 }
8110 }
8111 }
8112
8113 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8114 // then constrain it so we will kill all hidden procs.
8115 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8116 worstType = HIDDEN_APP_MIN_ADJ;
8117 }
8118 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8119 for (int i=0; i<pids.length; i++) {
8120 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8121 if (proc == null) {
8122 continue;
8123 }
8124 int adj = proc.setAdj;
8125 if (adj >= worstType) {
8126 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8127 + adj + ")");
8128 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
8129 proc.processName, adj);
8130 killed = true;
8131 Process.killProcess(pids[i]);
8132 }
8133 }
8134 }
8135 return killed;
8136 }
8137
8138 public void reportPss(IApplicationThread caller, int pss) {
8139 Watchdog.PssRequestor req;
8140 String name;
8141 ProcessRecord callerApp;
8142 synchronized (this) {
8143 if (caller == null) {
8144 return;
8145 }
8146 callerApp = getRecordForAppLocked(caller);
8147 if (callerApp == null) {
8148 return;
8149 }
8150 callerApp.lastPss = pss;
8151 req = callerApp;
8152 name = callerApp.processName;
8153 }
8154 Watchdog.getInstance().reportPss(req, name, pss);
8155 if (!callerApp.persistent) {
8156 removeRequestedPss(callerApp);
8157 }
8158 }
8159
8160 public void requestPss(Runnable completeCallback) {
8161 ArrayList<ProcessRecord> procs;
8162 synchronized (this) {
8163 mRequestPssCallback = completeCallback;
8164 mRequestPssList.clear();
8165 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8166 ProcessRecord proc = mLRUProcesses.get(i);
8167 if (!proc.persistent) {
8168 mRequestPssList.add(proc);
8169 }
8170 }
8171 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8172 }
8173
8174 int oldPri = Process.getThreadPriority(Process.myTid());
8175 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8176 for (int i=procs.size()-1; i>=0; i--) {
8177 ProcessRecord proc = procs.get(i);
8178 proc.lastPss = 0;
8179 proc.requestPss();
8180 }
8181 Process.setThreadPriority(oldPri);
8182 }
8183
8184 void removeRequestedPss(ProcessRecord proc) {
8185 Runnable callback = null;
8186 synchronized (this) {
8187 if (mRequestPssList.remove(proc)) {
8188 if (mRequestPssList.size() == 0) {
8189 callback = mRequestPssCallback;
8190 mRequestPssCallback = null;
8191 }
8192 }
8193 }
8194
8195 if (callback != null) {
8196 callback.run();
8197 }
8198 }
8199
8200 public void collectPss(Watchdog.PssStats stats) {
8201 stats.mEmptyPss = 0;
8202 stats.mEmptyCount = 0;
8203 stats.mBackgroundPss = 0;
8204 stats.mBackgroundCount = 0;
8205 stats.mServicePss = 0;
8206 stats.mServiceCount = 0;
8207 stats.mVisiblePss = 0;
8208 stats.mVisibleCount = 0;
8209 stats.mForegroundPss = 0;
8210 stats.mForegroundCount = 0;
8211 stats.mNoPssCount = 0;
8212 synchronized (this) {
8213 int i;
8214 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8215 ? mProcDeaths.length : stats.mProcDeaths.length;
8216 int aggr = 0;
8217 for (i=0; i<NPD; i++) {
8218 aggr += mProcDeaths[i];
8219 stats.mProcDeaths[i] = aggr;
8220 }
8221 while (i<stats.mProcDeaths.length) {
8222 stats.mProcDeaths[i] = 0;
8223 i++;
8224 }
8225
8226 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8227 ProcessRecord proc = mLRUProcesses.get(i);
8228 if (proc.persistent) {
8229 continue;
8230 }
8231 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8232 if (proc.lastPss == 0) {
8233 stats.mNoPssCount++;
8234 continue;
8235 }
8236 if (proc.setAdj == EMPTY_APP_ADJ) {
8237 stats.mEmptyPss += proc.lastPss;
8238 stats.mEmptyCount++;
8239 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8240 stats.mEmptyPss += proc.lastPss;
8241 stats.mEmptyCount++;
8242 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8243 stats.mBackgroundPss += proc.lastPss;
8244 stats.mBackgroundCount++;
8245 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8246 stats.mVisiblePss += proc.lastPss;
8247 stats.mVisibleCount++;
8248 } else {
8249 stats.mForegroundPss += proc.lastPss;
8250 stats.mForegroundCount++;
8251 }
8252 }
8253 }
8254 }
8255
8256 public final void startRunning(String pkg, String cls, String action,
8257 String data) {
8258 synchronized(this) {
8259 if (mStartRunning) {
8260 return;
8261 }
8262 mStartRunning = true;
8263 mTopComponent = pkg != null && cls != null
8264 ? new ComponentName(pkg, cls) : null;
8265 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8266 mTopData = data;
8267 if (!mSystemReady) {
8268 return;
8269 }
8270 }
8271
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008272 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008273 }
8274
8275 private void retrieveSettings() {
8276 final ContentResolver resolver = mContext.getContentResolver();
8277 String debugApp = Settings.System.getString(
8278 resolver, Settings.System.DEBUG_APP);
8279 boolean waitForDebugger = Settings.System.getInt(
8280 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8281 boolean alwaysFinishActivities = Settings.System.getInt(
8282 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8283
8284 Configuration configuration = new Configuration();
8285 Settings.System.getConfiguration(resolver, configuration);
8286
8287 synchronized (this) {
8288 mDebugApp = mOrigDebugApp = debugApp;
8289 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8290 mAlwaysFinishActivities = alwaysFinishActivities;
8291 // This happens before any activities are started, so we can
8292 // change mConfiguration in-place.
8293 mConfiguration.updateFrom(configuration);
8294 }
8295 }
8296
8297 public boolean testIsSystemReady() {
8298 // no need to synchronize(this) just to read & return the value
8299 return mSystemReady;
8300 }
8301
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008302 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008303 // In the simulator, startRunning will never have been called, which
8304 // normally sets a few crucial variables. Do it here instead.
8305 if (!Process.supportsProcesses()) {
8306 mStartRunning = true;
8307 mTopAction = Intent.ACTION_MAIN;
8308 }
8309
8310 synchronized(this) {
8311 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008312 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008313 return;
8314 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008315
8316 // Check to see if there are any update receivers to run.
8317 if (!mDidUpdate) {
8318 if (mWaitingUpdate) {
8319 return;
8320 }
8321 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8322 List<ResolveInfo> ris = null;
8323 try {
8324 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8325 intent, null, 0);
8326 } catch (RemoteException e) {
8327 }
8328 if (ris != null) {
8329 for (int i=ris.size()-1; i>=0; i--) {
8330 if ((ris.get(i).activityInfo.applicationInfo.flags
8331 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8332 ris.remove(i);
8333 }
8334 }
8335 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8336 for (int i=0; i<ris.size(); i++) {
8337 ActivityInfo ai = ris.get(i).activityInfo;
8338 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8339 IIntentReceiver finisher = null;
8340 if (i == 0) {
8341 finisher = new IIntentReceiver.Stub() {
8342 public void performReceive(Intent intent, int resultCode,
8343 String data, Bundle extras, boolean ordered)
8344 throws RemoteException {
8345 synchronized (ActivityManagerService.this) {
8346 mDidUpdate = true;
8347 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008348 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008349 }
8350 };
8351 }
8352 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8353 broadcastIntentLocked(null, null, intent, null, finisher,
8354 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8355 if (i == 0) {
8356 mWaitingUpdate = true;
8357 }
8358 }
8359 }
8360 if (mWaitingUpdate) {
8361 return;
8362 }
8363 mDidUpdate = true;
8364 }
8365
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008366 mSystemReady = true;
8367 if (!mStartRunning) {
8368 return;
8369 }
8370 }
8371
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008372 ArrayList<ProcessRecord> procsToKill = null;
8373 synchronized(mPidsSelfLocked) {
8374 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8375 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8376 if (!isAllowedWhileBooting(proc.info)){
8377 if (procsToKill == null) {
8378 procsToKill = new ArrayList<ProcessRecord>();
8379 }
8380 procsToKill.add(proc);
8381 }
8382 }
8383 }
8384
8385 if (procsToKill != null) {
8386 synchronized(this) {
8387 for (int i=procsToKill.size()-1; i>=0; i--) {
8388 ProcessRecord proc = procsToKill.get(i);
8389 Log.i(TAG, "Removing system update proc: " + proc);
8390 removeProcessLocked(proc, true);
8391 }
8392 }
8393 }
8394
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008395 Log.i(TAG, "System now ready");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008396 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8397 SystemClock.uptimeMillis());
8398
8399 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008400 // Make sure we have no pre-ready processes sitting around.
8401
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008402 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8403 ResolveInfo ri = mContext.getPackageManager()
8404 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008405 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008406 CharSequence errorMsg = null;
8407 if (ri != null) {
8408 ActivityInfo ai = ri.activityInfo;
8409 ApplicationInfo app = ai.applicationInfo;
8410 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8411 mTopAction = Intent.ACTION_FACTORY_TEST;
8412 mTopData = null;
8413 mTopComponent = new ComponentName(app.packageName,
8414 ai.name);
8415 } else {
8416 errorMsg = mContext.getResources().getText(
8417 com.android.internal.R.string.factorytest_not_system);
8418 }
8419 } else {
8420 errorMsg = mContext.getResources().getText(
8421 com.android.internal.R.string.factorytest_no_action);
8422 }
8423 if (errorMsg != null) {
8424 mTopAction = null;
8425 mTopData = null;
8426 mTopComponent = null;
8427 Message msg = Message.obtain();
8428 msg.what = SHOW_FACTORY_ERROR_MSG;
8429 msg.getData().putCharSequence("msg", errorMsg);
8430 mHandler.sendMessage(msg);
8431 }
8432 }
8433 }
8434
8435 retrieveSettings();
8436
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008437 if (goingCallback != null) goingCallback.run();
8438
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008439 synchronized (this) {
8440 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8441 try {
8442 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008443 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008444 if (apps != null) {
8445 int N = apps.size();
8446 int i;
8447 for (i=0; i<N; i++) {
8448 ApplicationInfo info
8449 = (ApplicationInfo)apps.get(i);
8450 if (info != null &&
8451 !info.packageName.equals("android")) {
8452 addAppLocked(info);
8453 }
8454 }
8455 }
8456 } catch (RemoteException ex) {
8457 // pm is in same process, this will never happen.
8458 }
8459 }
8460
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008461 // Start up initial activity.
8462 mBooting = true;
8463
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008464 try {
8465 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8466 Message msg = Message.obtain();
8467 msg.what = SHOW_UID_ERROR_MSG;
8468 mHandler.sendMessage(msg);
8469 }
8470 } catch (RemoteException e) {
8471 }
8472
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008473 resumeTopActivityLocked(null);
8474 }
8475 }
8476
8477 boolean makeAppCrashingLocked(ProcessRecord app,
8478 String tag, String shortMsg, String longMsg, byte[] crashData) {
8479 app.crashing = true;
8480 app.crashingReport = generateProcessError(app,
8481 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8482 startAppProblemLocked(app);
8483 app.stopFreezingAllLocked();
8484 return handleAppCrashLocked(app);
8485 }
8486
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008487 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Jacek Surazskia2339432009-09-18 15:01:26 +02008488 // check if error reporting is enabled in Gservices
8489 int enabled = Settings.Gservices.getInt(mContext.getContentResolver(),
8490 Settings.Gservices.SEND_ACTION_APP_ERROR, 0);
8491 if (enabled == 0) {
8492 return null;
8493 }
8494
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008495 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008496
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008497 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008498 // look for receiver in the installer package
8499 String candidate = pm.getInstallerPackageName(app.info.packageName);
8500 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8501 if (result != null) {
8502 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008503 }
8504
Jacek Surazski82a73df2009-06-17 14:33:18 +02008505 // if the error app is on the system image, look for system apps
8506 // error receiver
8507 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8508 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8509 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8510 if (result != null) {
8511 return result;
8512 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008513 }
8514
Jacek Surazski82a73df2009-06-17 14:33:18 +02008515 // if there is a default receiver, try that
8516 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8517 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008518 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008519 // should not happen
8520 Log.e(TAG, "error talking to PackageManager", e);
8521 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008522 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008523 }
8524
8525 /**
8526 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8527 *
8528 * @param pm PackageManager isntance
8529 * @param errorPackage package which caused the error
8530 * @param receiverPackage candidate package to receive the error
8531 * @return activity component within receiverPackage which handles
8532 * ACTION_APP_ERROR, or null if not found
8533 */
8534 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8535 String receiverPackage) throws RemoteException {
8536 if (receiverPackage == null || receiverPackage.length() == 0) {
8537 return null;
8538 }
8539
8540 // break the loop if it's the error report receiver package that crashed
8541 if (receiverPackage.equals(errorPackage)) {
8542 return null;
8543 }
8544
8545 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8546 intent.setPackage(receiverPackage);
8547 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8548 if (info == null || info.activityInfo == null) {
8549 return null;
8550 }
8551 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008552 }
8553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008554 void makeAppNotRespondingLocked(ProcessRecord app,
8555 String tag, String shortMsg, String longMsg, byte[] crashData) {
8556 app.notResponding = true;
8557 app.notRespondingReport = generateProcessError(app,
8558 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8559 crashData);
8560 startAppProblemLocked(app);
8561 app.stopFreezingAllLocked();
8562 }
8563
8564 /**
8565 * Generate a process error record, suitable for attachment to a ProcessRecord.
8566 *
8567 * @param app The ProcessRecord in which the error occurred.
8568 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8569 * ActivityManager.AppErrorStateInfo
8570 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8571 * @param shortMsg Short message describing the crash.
8572 * @param longMsg Long message describing the crash.
8573 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8574 *
8575 * @return Returns a fully-formed AppErrorStateInfo record.
8576 */
8577 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8578 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8579 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8580
8581 report.condition = condition;
8582 report.processName = app.processName;
8583 report.pid = app.pid;
8584 report.uid = app.info.uid;
8585 report.tag = tag;
8586 report.shortMsg = shortMsg;
8587 report.longMsg = longMsg;
8588 report.crashData = crashData;
8589
8590 return report;
8591 }
8592
8593 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8594 boolean crashed) {
8595 synchronized (this) {
8596 app.crashing = false;
8597 app.crashingReport = null;
8598 app.notResponding = false;
8599 app.notRespondingReport = null;
8600 if (app.anrDialog == fromDialog) {
8601 app.anrDialog = null;
8602 }
8603 if (app.waitDialog == fromDialog) {
8604 app.waitDialog = null;
8605 }
8606 if (app.pid > 0 && app.pid != MY_PID) {
8607 if (crashed) {
8608 handleAppCrashLocked(app);
8609 }
8610 Log.i(ActivityManagerService.TAG, "Killing process "
8611 + app.processName
8612 + " (pid=" + app.pid + ") at user's request");
8613 Process.killProcess(app.pid);
8614 }
8615
8616 }
8617 }
8618
8619 boolean handleAppCrashLocked(ProcessRecord app) {
8620 long now = SystemClock.uptimeMillis();
8621
8622 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8623 app.info.uid);
8624 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8625 // This process loses!
8626 Log.w(TAG, "Process " + app.info.processName
8627 + " has crashed too many times: killing!");
8628 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8629 app.info.processName, app.info.uid);
8630 killServicesLocked(app, false);
8631 for (int i=mHistory.size()-1; i>=0; i--) {
8632 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8633 if (r.app == app) {
8634 if (Config.LOGD) Log.d(
8635 TAG, " Force finishing activity "
8636 + r.intent.getComponent().flattenToShortString());
8637 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8638 }
8639 }
8640 if (!app.persistent) {
8641 // We don't want to start this process again until the user
8642 // explicitly does so... but for persistent process, we really
8643 // need to keep it running. If a persistent process is actually
8644 // repeatedly crashing, then badness for everyone.
8645 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8646 app.info.processName);
8647 mBadProcesses.put(app.info.processName, app.info.uid, now);
8648 app.bad = true;
8649 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8650 app.removed = true;
8651 removeProcessLocked(app, false);
8652 return false;
8653 }
8654 }
8655
8656 // Bump up the crash count of any services currently running in the proc.
8657 if (app.services.size() != 0) {
8658 // Any services running in the application need to be placed
8659 // back in the pending list.
8660 Iterator it = app.services.iterator();
8661 while (it.hasNext()) {
8662 ServiceRecord sr = (ServiceRecord)it.next();
8663 sr.crashCount++;
8664 }
8665 }
8666
8667 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8668 return true;
8669 }
8670
8671 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008672 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008673 skipCurrentReceiverLocked(app);
8674 }
8675
8676 void skipCurrentReceiverLocked(ProcessRecord app) {
8677 boolean reschedule = false;
8678 BroadcastRecord r = app.curReceiver;
8679 if (r != null) {
8680 // The current broadcast is waiting for this app's receiver
8681 // to be finished. Looks like that's not going to happen, so
8682 // let the broadcast continue.
8683 logBroadcastReceiverDiscard(r);
8684 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8685 r.resultExtras, r.resultAbort, true);
8686 reschedule = true;
8687 }
8688 r = mPendingBroadcast;
8689 if (r != null && r.curApp == app) {
8690 if (DEBUG_BROADCAST) Log.v(TAG,
8691 "skip & discard pending app " + r);
8692 logBroadcastReceiverDiscard(r);
8693 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8694 r.resultExtras, r.resultAbort, true);
8695 reschedule = true;
8696 }
8697 if (reschedule) {
8698 scheduleBroadcastsLocked();
8699 }
8700 }
8701
8702 public int handleApplicationError(IBinder app, int flags,
8703 String tag, String shortMsg, String longMsg, byte[] crashData) {
8704 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008705 ProcessRecord r = null;
8706 synchronized (this) {
8707 if (app != null) {
8708 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8709 final int NA = apps.size();
8710 for (int ia=0; ia<NA; ia++) {
8711 ProcessRecord p = apps.valueAt(ia);
8712 if (p.thread != null && p.thread.asBinder() == app) {
8713 r = p;
8714 break;
8715 }
8716 }
8717 }
8718 }
8719
8720 if (r != null) {
8721 // The application has crashed. Send the SIGQUIT to the process so
8722 // that it can dump its state.
8723 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8724 //Log.i(TAG, "Current system threads:");
8725 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8726 }
8727
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008728 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008729 try {
8730 String name = r != null ? r.processName : null;
8731 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008732 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008733 shortMsg, longMsg, crashData)) {
8734 Log.w(TAG, "Force-killing crashed app " + name
8735 + " at watcher's request");
8736 Process.killProcess(pid);
8737 return 0;
8738 }
8739 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008740 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008741 }
8742 }
8743
8744 final long origId = Binder.clearCallingIdentity();
8745
8746 // If this process is running instrumentation, finish it.
8747 if (r != null && r.instrumentationClass != null) {
8748 Log.w(TAG, "Error in app " + r.processName
8749 + " running instrumentation " + r.instrumentationClass + ":");
8750 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8751 if (longMsg != null) Log.w(TAG, " " + longMsg);
8752 Bundle info = new Bundle();
8753 info.putString("shortMsg", shortMsg);
8754 info.putString("longMsg", longMsg);
8755 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8756 Binder.restoreCallingIdentity(origId);
8757 return 0;
8758 }
8759
8760 if (r != null) {
8761 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8762 return 0;
8763 }
8764 } else {
8765 Log.w(TAG, "Some application object " + app + " tag " + tag
8766 + " has crashed, but I don't know who it is.");
8767 Log.w(TAG, "ShortMsg:" + shortMsg);
8768 Log.w(TAG, "LongMsg:" + longMsg);
8769 Binder.restoreCallingIdentity(origId);
8770 return 0;
8771 }
8772
8773 Message msg = Message.obtain();
8774 msg.what = SHOW_ERROR_MSG;
8775 HashMap data = new HashMap();
8776 data.put("result", result);
8777 data.put("app", r);
8778 data.put("flags", flags);
8779 data.put("shortMsg", shortMsg);
8780 data.put("longMsg", longMsg);
8781 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8782 // For system processes, submit crash data to the server.
8783 data.put("crashData", crashData);
8784 }
8785 msg.obj = data;
8786 mHandler.sendMessage(msg);
8787
8788 Binder.restoreCallingIdentity(origId);
8789 }
8790
8791 int res = result.get();
8792
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008793 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008794 synchronized (this) {
8795 if (r != null) {
8796 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8797 SystemClock.uptimeMillis());
8798 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008799 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8800 appErrorIntent = createAppErrorIntentLocked(r);
8801 res = AppErrorDialog.FORCE_QUIT;
8802 }
8803 }
8804
8805 if (appErrorIntent != null) {
8806 try {
8807 mContext.startActivity(appErrorIntent);
8808 } catch (ActivityNotFoundException e) {
8809 Log.w(TAG, "bug report receiver dissappeared", e);
8810 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008811 }
8812
8813 return res;
8814 }
8815
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008816 Intent createAppErrorIntentLocked(ProcessRecord r) {
8817 ApplicationErrorReport report = createAppErrorReportLocked(r);
8818 if (report == null) {
8819 return null;
8820 }
8821 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8822 result.setComponent(r.errorReportReceiver);
8823 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8824 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8825 return result;
8826 }
8827
8828 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8829 if (r.errorReportReceiver == null) {
8830 return null;
8831 }
8832
8833 if (!r.crashing && !r.notResponding) {
8834 return null;
8835 }
8836
8837 try {
8838 ApplicationErrorReport report = new ApplicationErrorReport();
8839 report.packageName = r.info.packageName;
8840 report.installerPackageName = r.errorReportReceiver.getPackageName();
8841 report.processName = r.processName;
8842
8843 if (r.crashing) {
8844 report.type = ApplicationErrorReport.TYPE_CRASH;
8845 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8846
8847 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8848 r.crashingReport.crashData);
8849 DataInputStream dataStream = new DataInputStream(byteStream);
8850 CrashData crashData = new CrashData(dataStream);
8851 ThrowableData throwData = crashData.getThrowableData();
8852
8853 report.time = crashData.getTime();
8854 report.crashInfo.stackTrace = throwData.toString();
8855
Jacek Surazskif829a782009-06-11 22:47:02 +02008856 // Extract the source of the exception, useful for report
8857 // clustering. Also extract the "deepest" non-null exception
8858 // message.
8859 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008860 while (throwData.getCause() != null) {
8861 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008862 String msg = throwData.getMessage();
8863 if (msg != null && msg.length() > 0) {
8864 exceptionMessage = msg;
8865 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008866 }
8867 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008868 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008869 report.crashInfo.exceptionClassName = throwData.getType();
8870 report.crashInfo.throwFileName = trace.getFileName();
8871 report.crashInfo.throwClassName = trace.getClassName();
8872 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008873 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008874 } else if (r.notResponding) {
8875 report.type = ApplicationErrorReport.TYPE_ANR;
8876 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8877
8878 report.anrInfo.activity = r.notRespondingReport.tag;
8879 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8880 report.anrInfo.info = r.notRespondingReport.longMsg;
8881 }
8882
8883 return report;
8884 } catch (IOException e) {
8885 // we don't send it
8886 }
8887
8888 return null;
8889 }
8890
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008891 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8892 // assume our apps are happy - lazy create the list
8893 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8894
8895 synchronized (this) {
8896
8897 // iterate across all processes
8898 final int N = mLRUProcesses.size();
8899 for (int i = 0; i < N; i++) {
8900 ProcessRecord app = mLRUProcesses.get(i);
8901 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8902 // This one's in trouble, so we'll generate a report for it
8903 // crashes are higher priority (in case there's a crash *and* an anr)
8904 ActivityManager.ProcessErrorStateInfo report = null;
8905 if (app.crashing) {
8906 report = app.crashingReport;
8907 } else if (app.notResponding) {
8908 report = app.notRespondingReport;
8909 }
8910
8911 if (report != null) {
8912 if (errList == null) {
8913 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8914 }
8915 errList.add(report);
8916 } else {
8917 Log.w(TAG, "Missing app error report, app = " + app.processName +
8918 " crashing = " + app.crashing +
8919 " notResponding = " + app.notResponding);
8920 }
8921 }
8922 }
8923 }
8924
8925 return errList;
8926 }
8927
8928 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8929 // Lazy instantiation of list
8930 List<ActivityManager.RunningAppProcessInfo> runList = null;
8931 synchronized (this) {
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 // Generate process state info for running application
8938 ActivityManager.RunningAppProcessInfo currApp =
8939 new ActivityManager.RunningAppProcessInfo(app.processName,
8940 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07008941 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008942 int adj = app.curAdj;
8943 if (adj >= CONTENT_PROVIDER_ADJ) {
8944 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8945 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8946 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008947 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8948 } else if (adj >= HOME_APP_ADJ) {
8949 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8950 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008951 } else if (adj >= SECONDARY_SERVER_ADJ) {
8952 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8953 } else if (adj >= VISIBLE_APP_ADJ) {
8954 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8955 } else {
8956 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8957 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07008958 currApp.importanceReasonCode = app.adjTypeCode;
8959 if (app.adjSource instanceof ProcessRecord) {
8960 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
8961 } else if (app.adjSource instanceof HistoryRecord) {
8962 HistoryRecord r = (HistoryRecord)app.adjSource;
8963 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
8964 }
8965 if (app.adjTarget instanceof ComponentName) {
8966 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
8967 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008968 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8969 // + " lru=" + currApp.lru);
8970 if (runList == null) {
8971 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8972 }
8973 runList.add(currApp);
8974 }
8975 }
8976 }
8977 return runList;
8978 }
8979
8980 @Override
8981 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8982 synchronized (this) {
8983 if (checkCallingPermission(android.Manifest.permission.DUMP)
8984 != PackageManager.PERMISSION_GRANTED) {
8985 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8986 + Binder.getCallingPid()
8987 + ", uid=" + Binder.getCallingUid()
8988 + " without permission "
8989 + android.Manifest.permission.DUMP);
8990 return;
8991 }
8992 if (args.length != 0 && "service".equals(args[0])) {
8993 dumpService(fd, pw, args);
8994 return;
8995 }
8996 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008997 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008998 pw.println(" ");
8999 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009000 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009001 if (mWaitingVisibleActivities.size() > 0) {
9002 pw.println(" ");
9003 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009004 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009005 }
9006 if (mStoppingActivities.size() > 0) {
9007 pw.println(" ");
9008 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009009 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009010 }
9011 if (mFinishingActivities.size() > 0) {
9012 pw.println(" ");
9013 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009014 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009015 }
9016
9017 pw.println(" ");
9018 pw.println(" mPausingActivity: " + mPausingActivity);
9019 pw.println(" mResumedActivity: " + mResumedActivity);
9020 pw.println(" mFocusedActivity: " + mFocusedActivity);
9021 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
9022
9023 if (mRecentTasks.size() > 0) {
9024 pw.println(" ");
9025 pw.println("Recent tasks in Current Activity Manager State:");
9026
9027 final int N = mRecentTasks.size();
9028 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009029 TaskRecord tr = mRecentTasks.get(i);
9030 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9031 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009032 mRecentTasks.get(i).dump(pw, " ");
9033 }
9034 }
9035
9036 pw.println(" ");
9037 pw.println(" mCurTask: " + mCurTask);
9038
9039 pw.println(" ");
9040 pw.println("Processes in Current Activity Manager State:");
9041
9042 boolean needSep = false;
9043 int numPers = 0;
9044
9045 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9046 final int NA = procs.size();
9047 for (int ia=0; ia<NA; ia++) {
9048 if (!needSep) {
9049 pw.println(" All known processes:");
9050 needSep = true;
9051 }
9052 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009053 pw.print(r.persistent ? " *PERS*" : " *APP*");
9054 pw.print(" UID "); pw.print(procs.keyAt(ia));
9055 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009056 r.dump(pw, " ");
9057 if (r.persistent) {
9058 numPers++;
9059 }
9060 }
9061 }
9062
9063 if (mLRUProcesses.size() > 0) {
9064 if (needSep) pw.println(" ");
9065 needSep = true;
9066 pw.println(" Running processes (most recent first):");
9067 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009068 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009069 needSep = true;
9070 }
9071
9072 synchronized (mPidsSelfLocked) {
9073 if (mPidsSelfLocked.size() > 0) {
9074 if (needSep) pw.println(" ");
9075 needSep = true;
9076 pw.println(" PID mappings:");
9077 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009078 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9079 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009080 }
9081 }
9082 }
9083
9084 if (mForegroundProcesses.size() > 0) {
9085 if (needSep) pw.println(" ");
9086 needSep = true;
9087 pw.println(" Foreground Processes:");
9088 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009089 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9090 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009091 }
9092 }
9093
9094 if (mPersistentStartingProcesses.size() > 0) {
9095 if (needSep) pw.println(" ");
9096 needSep = true;
9097 pw.println(" Persisent processes that are starting:");
9098 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009099 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009100 }
9101
9102 if (mStartingProcesses.size() > 0) {
9103 if (needSep) pw.println(" ");
9104 needSep = true;
9105 pw.println(" Processes that are starting:");
9106 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009107 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009108 }
9109
9110 if (mRemovedProcesses.size() > 0) {
9111 if (needSep) pw.println(" ");
9112 needSep = true;
9113 pw.println(" Processes that are being removed:");
9114 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009115 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009116 }
9117
9118 if (mProcessesOnHold.size() > 0) {
9119 if (needSep) pw.println(" ");
9120 needSep = true;
9121 pw.println(" Processes that are on old until the system is ready:");
9122 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009123 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009124 }
9125
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009126 if (mProcessesToGc.size() > 0) {
9127 if (needSep) pw.println(" ");
9128 needSep = true;
9129 pw.println(" Processes that are waiting to GC:");
9130 long now = SystemClock.uptimeMillis();
9131 for (int i=0; i<mProcessesToGc.size(); i++) {
9132 ProcessRecord proc = mProcessesToGc.get(i);
9133 pw.print(" Process "); pw.println(proc);
9134 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9135 pw.print(", last gced=");
9136 pw.print(now-proc.lastRequestedGc);
9137 pw.print(" ms ago, last lowMwm=");
9138 pw.print(now-proc.lastLowMemory);
9139 pw.println(" ms ago");
9140
9141 }
9142 }
9143
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009144 if (mProcessCrashTimes.getMap().size() > 0) {
9145 if (needSep) pw.println(" ");
9146 needSep = true;
9147 pw.println(" Time since processes crashed:");
9148 long now = SystemClock.uptimeMillis();
9149 for (Map.Entry<String, SparseArray<Long>> procs
9150 : mProcessCrashTimes.getMap().entrySet()) {
9151 SparseArray<Long> uids = procs.getValue();
9152 final int N = uids.size();
9153 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009154 pw.print(" Process "); pw.print(procs.getKey());
9155 pw.print(" uid "); pw.print(uids.keyAt(i));
9156 pw.print(": last crashed ");
9157 pw.print((now-uids.valueAt(i)));
9158 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009159 }
9160 }
9161 }
9162
9163 if (mBadProcesses.getMap().size() > 0) {
9164 if (needSep) pw.println(" ");
9165 needSep = true;
9166 pw.println(" Bad processes:");
9167 for (Map.Entry<String, SparseArray<Long>> procs
9168 : mBadProcesses.getMap().entrySet()) {
9169 SparseArray<Long> uids = procs.getValue();
9170 final int N = uids.size();
9171 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009172 pw.print(" Bad process "); pw.print(procs.getKey());
9173 pw.print(" uid "); pw.print(uids.keyAt(i));
9174 pw.print(": crashed at time ");
9175 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009176 }
9177 }
9178 }
9179
9180 pw.println(" ");
9181 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009182 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009183 pw.println(" mConfiguration: " + mConfiguration);
9184 pw.println(" mStartRunning=" + mStartRunning
9185 + " mSystemReady=" + mSystemReady
9186 + " mBooting=" + mBooting
9187 + " mBooted=" + mBooted
9188 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009189 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009190 pw.println(" mGoingToSleep=" + mGoingToSleep);
9191 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9192 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9193 + " mDebugTransient=" + mDebugTransient
9194 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9195 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009196 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009197 }
9198 }
9199
9200 /**
9201 * There are three ways to call this:
9202 * - no service specified: dump all the services
9203 * - a flattened component name that matched an existing service was specified as the
9204 * first arg: dump that one service
9205 * - the first arg isn't the flattened component name of an existing service:
9206 * dump all services whose component contains the first arg as a substring
9207 */
9208 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9209 String[] newArgs;
9210 String componentNameString;
9211 ServiceRecord r;
9212 if (args.length == 1) {
9213 componentNameString = null;
9214 newArgs = EMPTY_STRING_ARRAY;
9215 r = null;
9216 } else {
9217 componentNameString = args[1];
9218 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9219 r = componentName != null ? mServices.get(componentName) : null;
9220 newArgs = new String[args.length - 2];
9221 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9222 }
9223
9224 if (r != null) {
9225 dumpService(fd, pw, r, newArgs);
9226 } else {
9227 for (ServiceRecord r1 : mServices.values()) {
9228 if (componentNameString == null
9229 || r1.name.flattenToString().contains(componentNameString)) {
9230 dumpService(fd, pw, r1, newArgs);
9231 }
9232 }
9233 }
9234 }
9235
9236 /**
9237 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9238 * there is a thread associated with the service.
9239 */
9240 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9241 pw.println(" Service " + r.name.flattenToString());
9242 if (r.app != null && r.app.thread != null) {
9243 try {
9244 // flush anything that is already in the PrintWriter since the thread is going
9245 // to write to the file descriptor directly
9246 pw.flush();
9247 r.app.thread.dumpService(fd, r, args);
9248 pw.print("\n");
9249 } catch (RemoteException e) {
9250 pw.println("got a RemoteException while dumping the service");
9251 }
9252 }
9253 }
9254
9255 void dumpBroadcasts(PrintWriter pw) {
9256 synchronized (this) {
9257 if (checkCallingPermission(android.Manifest.permission.DUMP)
9258 != PackageManager.PERMISSION_GRANTED) {
9259 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9260 + Binder.getCallingPid()
9261 + ", uid=" + Binder.getCallingUid()
9262 + " without permission "
9263 + android.Manifest.permission.DUMP);
9264 return;
9265 }
9266 pw.println("Broadcasts in Current Activity Manager State:");
9267
9268 if (mRegisteredReceivers.size() > 0) {
9269 pw.println(" ");
9270 pw.println(" Registered Receivers:");
9271 Iterator it = mRegisteredReceivers.values().iterator();
9272 while (it.hasNext()) {
9273 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009274 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009275 r.dump(pw, " ");
9276 }
9277 }
9278
9279 pw.println(" ");
9280 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009281 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009282
9283 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9284 || mPendingBroadcast != null) {
9285 if (mParallelBroadcasts.size() > 0) {
9286 pw.println(" ");
9287 pw.println(" Active broadcasts:");
9288 }
9289 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9290 pw.println(" Broadcast #" + i + ":");
9291 mParallelBroadcasts.get(i).dump(pw, " ");
9292 }
9293 if (mOrderedBroadcasts.size() > 0) {
9294 pw.println(" ");
9295 pw.println(" Active serialized broadcasts:");
9296 }
9297 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9298 pw.println(" Serialized Broadcast #" + i + ":");
9299 mOrderedBroadcasts.get(i).dump(pw, " ");
9300 }
9301 pw.println(" ");
9302 pw.println(" Pending broadcast:");
9303 if (mPendingBroadcast != null) {
9304 mPendingBroadcast.dump(pw, " ");
9305 } else {
9306 pw.println(" (null)");
9307 }
9308 }
9309
9310 pw.println(" ");
9311 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9312 if (mStickyBroadcasts != null) {
9313 pw.println(" ");
9314 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009315 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009316 for (Map.Entry<String, ArrayList<Intent>> ent
9317 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009318 pw.print(" * Sticky action "); pw.print(ent.getKey());
9319 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009320 ArrayList<Intent> intents = ent.getValue();
9321 final int N = intents.size();
9322 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009323 sb.setLength(0);
9324 sb.append(" Intent: ");
9325 intents.get(i).toShortString(sb, true, false);
9326 pw.println(sb.toString());
9327 Bundle bundle = intents.get(i).getExtras();
9328 if (bundle != null) {
9329 pw.print(" ");
9330 pw.println(bundle.toString());
9331 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009332 }
9333 }
9334 }
9335
9336 pw.println(" ");
9337 pw.println(" mHandler:");
9338 mHandler.dump(new PrintWriterPrinter(pw), " ");
9339 }
9340 }
9341
9342 void dumpServices(PrintWriter pw) {
9343 synchronized (this) {
9344 if (checkCallingPermission(android.Manifest.permission.DUMP)
9345 != PackageManager.PERMISSION_GRANTED) {
9346 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9347 + Binder.getCallingPid()
9348 + ", uid=" + Binder.getCallingUid()
9349 + " without permission "
9350 + android.Manifest.permission.DUMP);
9351 return;
9352 }
9353 pw.println("Services in Current Activity Manager State:");
9354
9355 boolean needSep = false;
9356
9357 if (mServices.size() > 0) {
9358 pw.println(" Active services:");
9359 Iterator<ServiceRecord> it = mServices.values().iterator();
9360 while (it.hasNext()) {
9361 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009362 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009363 r.dump(pw, " ");
9364 }
9365 needSep = true;
9366 }
9367
9368 if (mPendingServices.size() > 0) {
9369 if (needSep) pw.println(" ");
9370 pw.println(" Pending services:");
9371 for (int i=0; i<mPendingServices.size(); i++) {
9372 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009373 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009374 r.dump(pw, " ");
9375 }
9376 needSep = true;
9377 }
9378
9379 if (mRestartingServices.size() > 0) {
9380 if (needSep) pw.println(" ");
9381 pw.println(" Restarting services:");
9382 for (int i=0; i<mRestartingServices.size(); i++) {
9383 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009384 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009385 r.dump(pw, " ");
9386 }
9387 needSep = true;
9388 }
9389
9390 if (mStoppingServices.size() > 0) {
9391 if (needSep) pw.println(" ");
9392 pw.println(" Stopping services:");
9393 for (int i=0; i<mStoppingServices.size(); i++) {
9394 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009395 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009396 r.dump(pw, " ");
9397 }
9398 needSep = true;
9399 }
9400
9401 if (mServiceConnections.size() > 0) {
9402 if (needSep) pw.println(" ");
9403 pw.println(" Connection bindings to services:");
9404 Iterator<ConnectionRecord> it
9405 = mServiceConnections.values().iterator();
9406 while (it.hasNext()) {
9407 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009408 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009409 r.dump(pw, " ");
9410 }
9411 }
9412 }
9413 }
9414
9415 void dumpProviders(PrintWriter pw) {
9416 synchronized (this) {
9417 if (checkCallingPermission(android.Manifest.permission.DUMP)
9418 != PackageManager.PERMISSION_GRANTED) {
9419 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9420 + Binder.getCallingPid()
9421 + ", uid=" + Binder.getCallingUid()
9422 + " without permission "
9423 + android.Manifest.permission.DUMP);
9424 return;
9425 }
9426
9427 pw.println("Content Providers in Current Activity Manager State:");
9428
9429 boolean needSep = false;
9430
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009431 if (mProvidersByClass.size() > 0) {
9432 if (needSep) pw.println(" ");
9433 pw.println(" Published content providers (by class):");
9434 Iterator it = mProvidersByClass.entrySet().iterator();
9435 while (it.hasNext()) {
9436 Map.Entry e = (Map.Entry)it.next();
9437 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009438 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009439 r.dump(pw, " ");
9440 }
9441 needSep = true;
9442 }
9443
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009444 if (mProvidersByName.size() > 0) {
9445 pw.println(" ");
9446 pw.println(" Authority to provider mappings:");
9447 Iterator it = mProvidersByName.entrySet().iterator();
9448 while (it.hasNext()) {
9449 Map.Entry e = (Map.Entry)it.next();
9450 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9451 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9452 pw.println(r);
9453 }
9454 needSep = true;
9455 }
9456
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009457 if (mLaunchingProviders.size() > 0) {
9458 if (needSep) pw.println(" ");
9459 pw.println(" Launching content providers:");
9460 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009461 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9462 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009463 }
9464 needSep = true;
9465 }
9466
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009467 if (mGrantedUriPermissions.size() > 0) {
9468 pw.println();
9469 pw.println("Granted Uri Permissions:");
9470 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9471 int uid = mGrantedUriPermissions.keyAt(i);
9472 HashMap<Uri, UriPermission> perms
9473 = mGrantedUriPermissions.valueAt(i);
9474 pw.print(" * UID "); pw.print(uid);
9475 pw.println(" holds:");
9476 for (UriPermission perm : perms.values()) {
9477 pw.print(" "); pw.println(perm);
9478 perm.dump(pw, " ");
9479 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009480 }
9481 }
9482 }
9483 }
9484
9485 void dumpSenders(PrintWriter pw) {
9486 synchronized (this) {
9487 if (checkCallingPermission(android.Manifest.permission.DUMP)
9488 != PackageManager.PERMISSION_GRANTED) {
9489 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9490 + Binder.getCallingPid()
9491 + ", uid=" + Binder.getCallingUid()
9492 + " without permission "
9493 + android.Manifest.permission.DUMP);
9494 return;
9495 }
9496
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009497 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009498
9499 if (this.mIntentSenderRecords.size() > 0) {
9500 Iterator<WeakReference<PendingIntentRecord>> it
9501 = mIntentSenderRecords.values().iterator();
9502 while (it.hasNext()) {
9503 WeakReference<PendingIntentRecord> ref = it.next();
9504 PendingIntentRecord rec = ref != null ? ref.get(): null;
9505 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009506 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009507 rec.dump(pw, " ");
9508 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009509 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009510 }
9511 }
9512 }
9513 }
9514 }
9515
9516 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009517 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009518 TaskRecord lastTask = null;
9519 for (int i=list.size()-1; i>=0; i--) {
9520 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009521 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009522 if (lastTask != r.task) {
9523 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009524 pw.print(prefix);
9525 pw.print(full ? "* " : " ");
9526 pw.println(lastTask);
9527 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009528 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009529 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009530 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009531 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9532 pw.print(" #"); pw.print(i); pw.print(": ");
9533 pw.println(r);
9534 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009535 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009536 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009537 }
9538 }
9539
9540 private static final int dumpProcessList(PrintWriter pw, List list,
9541 String prefix, String normalLabel, String persistentLabel,
9542 boolean inclOomAdj) {
9543 int numPers = 0;
9544 for (int i=list.size()-1; i>=0; i--) {
9545 ProcessRecord r = (ProcessRecord)list.get(i);
9546 if (false) {
9547 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9548 + " #" + i + ":");
9549 r.dump(pw, prefix + " ");
9550 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009551 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009552 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009553 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9554 if (r.adjSource != null || r.adjTarget != null) {
9555 pw.println(prefix + " " + r.adjTarget
9556 + " used by " + r.adjSource);
9557 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009558 } else {
9559 pw.println(String.format("%s%s #%2d: %s",
9560 prefix, (r.persistent ? persistentLabel : normalLabel),
9561 i, r.toString()));
9562 }
9563 if (r.persistent) {
9564 numPers++;
9565 }
9566 }
9567 return numPers;
9568 }
9569
9570 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9571 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009572 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009573 long uptime = SystemClock.uptimeMillis();
9574 long realtime = SystemClock.elapsedRealtime();
9575
9576 if (isCheckinRequest) {
9577 // short checkin version
9578 pw.println(uptime + "," + realtime);
9579 pw.flush();
9580 } else {
9581 pw.println("Applications Memory Usage (kB):");
9582 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9583 }
9584 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9585 ProcessRecord r = (ProcessRecord)list.get(i);
9586 if (r.thread != null) {
9587 if (!isCheckinRequest) {
9588 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9589 pw.flush();
9590 }
9591 try {
9592 r.thread.asBinder().dump(fd, args);
9593 } catch (RemoteException e) {
9594 if (!isCheckinRequest) {
9595 pw.println("Got RemoteException!");
9596 pw.flush();
9597 }
9598 }
9599 }
9600 }
9601 }
9602
9603 /**
9604 * Searches array of arguments for the specified string
9605 * @param args array of argument strings
9606 * @param value value to search for
9607 * @return true if the value is contained in the array
9608 */
9609 private static boolean scanArgs(String[] args, String value) {
9610 if (args != null) {
9611 for (String arg : args) {
9612 if (value.equals(arg)) {
9613 return true;
9614 }
9615 }
9616 }
9617 return false;
9618 }
9619
Dianne Hackborn75b03852009-06-12 15:43:26 -07009620 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009621 int count = mHistory.size();
9622
9623 // convert the token to an entry in the history.
9624 HistoryRecord r = null;
9625 int index = -1;
9626 for (int i=count-1; i>=0; i--) {
9627 Object o = mHistory.get(i);
9628 if (o == token) {
9629 r = (HistoryRecord)o;
9630 index = i;
9631 break;
9632 }
9633 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009634
9635 return index;
9636 }
9637
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009638 private final void killServicesLocked(ProcessRecord app,
9639 boolean allowRestart) {
9640 // Report disconnected services.
9641 if (false) {
9642 // XXX we are letting the client link to the service for
9643 // death notifications.
9644 if (app.services.size() > 0) {
9645 Iterator it = app.services.iterator();
9646 while (it.hasNext()) {
9647 ServiceRecord r = (ServiceRecord)it.next();
9648 if (r.connections.size() > 0) {
9649 Iterator<ConnectionRecord> jt
9650 = r.connections.values().iterator();
9651 while (jt.hasNext()) {
9652 ConnectionRecord c = jt.next();
9653 if (c.binding.client != app) {
9654 try {
9655 //c.conn.connected(r.className, null);
9656 } catch (Exception e) {
9657 // todo: this should be asynchronous!
9658 Log.w(TAG, "Exception thrown disconnected servce "
9659 + r.shortName
9660 + " from app " + app.processName, e);
9661 }
9662 }
9663 }
9664 }
9665 }
9666 }
9667 }
9668
9669 // Clean up any connections this application has to other services.
9670 if (app.connections.size() > 0) {
9671 Iterator<ConnectionRecord> it = app.connections.iterator();
9672 while (it.hasNext()) {
9673 ConnectionRecord r = it.next();
9674 removeConnectionLocked(r, app, null);
9675 }
9676 }
9677 app.connections.clear();
9678
9679 if (app.services.size() != 0) {
9680 // Any services running in the application need to be placed
9681 // back in the pending list.
9682 Iterator it = app.services.iterator();
9683 while (it.hasNext()) {
9684 ServiceRecord sr = (ServiceRecord)it.next();
9685 synchronized (sr.stats.getBatteryStats()) {
9686 sr.stats.stopLaunchedLocked();
9687 }
9688 sr.app = null;
9689 sr.executeNesting = 0;
9690 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009691
9692 boolean hasClients = sr.bindings.size() > 0;
9693 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009694 Iterator<IntentBindRecord> bindings
9695 = sr.bindings.values().iterator();
9696 while (bindings.hasNext()) {
9697 IntentBindRecord b = bindings.next();
9698 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9699 + ": shouldUnbind=" + b.hasBound);
9700 b.binder = null;
9701 b.requested = b.received = b.hasBound = false;
9702 }
9703 }
9704
9705 if (sr.crashCount >= 2) {
9706 Log.w(TAG, "Service crashed " + sr.crashCount
9707 + " times, stopping: " + sr);
9708 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9709 sr.crashCount, sr.shortName, app.pid);
9710 bringDownServiceLocked(sr, true);
9711 } else if (!allowRestart) {
9712 bringDownServiceLocked(sr, true);
9713 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009714 boolean canceled = scheduleServiceRestartLocked(sr, true);
9715
9716 // Should the service remain running? Note that in the
9717 // extreme case of so many attempts to deliver a command
9718 // that it failed, that we also will stop it here.
9719 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9720 if (sr.pendingStarts.size() == 0) {
9721 sr.startRequested = false;
9722 if (!hasClients) {
9723 // Whoops, no reason to restart!
9724 bringDownServiceLocked(sr, true);
9725 }
9726 }
9727 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009728 }
9729 }
9730
9731 if (!allowRestart) {
9732 app.services.clear();
9733 }
9734 }
9735
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009736 // Make sure we have no more records on the stopping list.
9737 int i = mStoppingServices.size();
9738 while (i > 0) {
9739 i--;
9740 ServiceRecord sr = mStoppingServices.get(i);
9741 if (sr.app == app) {
9742 mStoppingServices.remove(i);
9743 }
9744 }
9745
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009746 app.executingServices.clear();
9747 }
9748
9749 private final void removeDyingProviderLocked(ProcessRecord proc,
9750 ContentProviderRecord cpr) {
9751 synchronized (cpr) {
9752 cpr.launchingApp = null;
9753 cpr.notifyAll();
9754 }
9755
9756 mProvidersByClass.remove(cpr.info.name);
9757 String names[] = cpr.info.authority.split(";");
9758 for (int j = 0; j < names.length; j++) {
9759 mProvidersByName.remove(names[j]);
9760 }
9761
9762 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9763 while (cit.hasNext()) {
9764 ProcessRecord capp = cit.next();
9765 if (!capp.persistent && capp.thread != null
9766 && capp.pid != 0
9767 && capp.pid != MY_PID) {
9768 Log.i(TAG, "Killing app " + capp.processName
9769 + " (pid " + capp.pid
9770 + ") because provider " + cpr.info.name
9771 + " is in dying process " + proc.processName);
9772 Process.killProcess(capp.pid);
9773 }
9774 }
9775
9776 mLaunchingProviders.remove(cpr);
9777 }
9778
9779 /**
9780 * Main code for cleaning up a process when it has gone away. This is
9781 * called both as a result of the process dying, or directly when stopping
9782 * a process when running in single process mode.
9783 */
9784 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9785 boolean restarting, int index) {
9786 if (index >= 0) {
9787 mLRUProcesses.remove(index);
9788 }
9789
9790 // Dismiss any open dialogs.
9791 if (app.crashDialog != null) {
9792 app.crashDialog.dismiss();
9793 app.crashDialog = null;
9794 }
9795 if (app.anrDialog != null) {
9796 app.anrDialog.dismiss();
9797 app.anrDialog = null;
9798 }
9799 if (app.waitDialog != null) {
9800 app.waitDialog.dismiss();
9801 app.waitDialog = null;
9802 }
9803
9804 app.crashing = false;
9805 app.notResponding = false;
9806
9807 app.resetPackageList();
9808 app.thread = null;
9809 app.forcingToForeground = null;
9810 app.foregroundServices = false;
9811
9812 killServicesLocked(app, true);
9813
9814 boolean restart = false;
9815
9816 int NL = mLaunchingProviders.size();
9817
9818 // Remove published content providers.
9819 if (!app.pubProviders.isEmpty()) {
9820 Iterator it = app.pubProviders.values().iterator();
9821 while (it.hasNext()) {
9822 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9823 cpr.provider = null;
9824 cpr.app = null;
9825
9826 // See if someone is waiting for this provider... in which
9827 // case we don't remove it, but just let it restart.
9828 int i = 0;
9829 if (!app.bad) {
9830 for (; i<NL; i++) {
9831 if (mLaunchingProviders.get(i) == cpr) {
9832 restart = true;
9833 break;
9834 }
9835 }
9836 } else {
9837 i = NL;
9838 }
9839
9840 if (i >= NL) {
9841 removeDyingProviderLocked(app, cpr);
9842 NL = mLaunchingProviders.size();
9843 }
9844 }
9845 app.pubProviders.clear();
9846 }
9847
9848 // Look through the content providers we are waiting to have launched,
9849 // and if any run in this process then either schedule a restart of
9850 // the process or kill the client waiting for it if this process has
9851 // gone bad.
9852 for (int i=0; i<NL; i++) {
9853 ContentProviderRecord cpr = (ContentProviderRecord)
9854 mLaunchingProviders.get(i);
9855 if (cpr.launchingApp == app) {
9856 if (!app.bad) {
9857 restart = true;
9858 } else {
9859 removeDyingProviderLocked(app, cpr);
9860 NL = mLaunchingProviders.size();
9861 }
9862 }
9863 }
9864
9865 // Unregister from connected content providers.
9866 if (!app.conProviders.isEmpty()) {
9867 Iterator it = app.conProviders.iterator();
9868 while (it.hasNext()) {
9869 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9870 cpr.clients.remove(app);
9871 }
9872 app.conProviders.clear();
9873 }
9874
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009875 // At this point there may be remaining entries in mLaunchingProviders
9876 // where we were the only one waiting, so they are no longer of use.
9877 // Look for these and clean up if found.
9878 // XXX Commented out for now. Trying to figure out a way to reproduce
9879 // the actual situation to identify what is actually going on.
9880 if (false) {
9881 for (int i=0; i<NL; i++) {
9882 ContentProviderRecord cpr = (ContentProviderRecord)
9883 mLaunchingProviders.get(i);
9884 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9885 synchronized (cpr) {
9886 cpr.launchingApp = null;
9887 cpr.notifyAll();
9888 }
9889 }
9890 }
9891 }
9892
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009893 skipCurrentReceiverLocked(app);
9894
9895 // Unregister any receivers.
9896 if (app.receivers.size() > 0) {
9897 Iterator<ReceiverList> it = app.receivers.iterator();
9898 while (it.hasNext()) {
9899 removeReceiverLocked(it.next());
9900 }
9901 app.receivers.clear();
9902 }
9903
Christopher Tate181fafa2009-05-14 11:12:14 -07009904 // If the app is undergoing backup, tell the backup manager about it
9905 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9906 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9907 try {
9908 IBackupManager bm = IBackupManager.Stub.asInterface(
9909 ServiceManager.getService(Context.BACKUP_SERVICE));
9910 bm.agentDisconnected(app.info.packageName);
9911 } catch (RemoteException e) {
9912 // can't happen; backup manager is local
9913 }
9914 }
9915
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009916 // If the caller is restarting this app, then leave it in its
9917 // current lists and let the caller take care of it.
9918 if (restarting) {
9919 return;
9920 }
9921
9922 if (!app.persistent) {
9923 if (DEBUG_PROCESSES) Log.v(TAG,
9924 "Removing non-persistent process during cleanup: " + app);
9925 mProcessNames.remove(app.processName, app.info.uid);
9926 } else if (!app.removed) {
9927 // This app is persistent, so we need to keep its record around.
9928 // If it is not already on the pending app list, add it there
9929 // and start a new process for it.
9930 app.thread = null;
9931 app.forcingToForeground = null;
9932 app.foregroundServices = false;
9933 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9934 mPersistentStartingProcesses.add(app);
9935 restart = true;
9936 }
9937 }
9938 mProcessesOnHold.remove(app);
9939
The Android Open Source Project4df24232009-03-05 14:34:35 -08009940 if (app == mHomeProcess) {
9941 mHomeProcess = null;
9942 }
9943
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009944 if (restart) {
9945 // We have components that still need to be running in the
9946 // process, so re-launch it.
9947 mProcessNames.put(app.processName, app.info.uid, app);
9948 startProcessLocked(app, "restart", app.processName);
9949 } else if (app.pid > 0 && app.pid != MY_PID) {
9950 // Goodbye!
9951 synchronized (mPidsSelfLocked) {
9952 mPidsSelfLocked.remove(app.pid);
9953 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9954 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009955 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009956 }
9957 }
9958
9959 // =========================================================
9960 // SERVICES
9961 // =========================================================
9962
9963 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9964 ActivityManager.RunningServiceInfo info =
9965 new ActivityManager.RunningServiceInfo();
9966 info.service = r.name;
9967 if (r.app != null) {
9968 info.pid = r.app.pid;
9969 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -07009970 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009971 info.process = r.processName;
9972 info.foreground = r.isForeground;
9973 info.activeSince = r.createTime;
9974 info.started = r.startRequested;
9975 info.clientCount = r.connections.size();
9976 info.crashCount = r.crashCount;
9977 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07009978 if (r.isForeground) {
9979 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
9980 }
9981 if (r.startRequested) {
9982 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
9983 }
9984 if (r.app != null && r.app.pid == Process.myPid()) {
9985 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
9986 }
9987 if (r.app != null && r.app.persistent) {
9988 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
9989 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009990 for (ConnectionRecord conn : r.connections.values()) {
9991 if (conn.clientLabel != 0) {
9992 info.clientPackage = conn.binding.client.info.packageName;
9993 info.clientLabel = conn.clientLabel;
9994 break;
9995 }
9996 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009997 return info;
9998 }
9999
10000 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10001 int flags) {
10002 synchronized (this) {
10003 ArrayList<ActivityManager.RunningServiceInfo> res
10004 = new ArrayList<ActivityManager.RunningServiceInfo>();
10005
10006 if (mServices.size() > 0) {
10007 Iterator<ServiceRecord> it = mServices.values().iterator();
10008 while (it.hasNext() && res.size() < maxNum) {
10009 res.add(makeRunningServiceInfoLocked(it.next()));
10010 }
10011 }
10012
10013 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10014 ServiceRecord r = mRestartingServices.get(i);
10015 ActivityManager.RunningServiceInfo info =
10016 makeRunningServiceInfoLocked(r);
10017 info.restarting = r.nextRestartTime;
10018 res.add(info);
10019 }
10020
10021 return res;
10022 }
10023 }
10024
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010025 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10026 synchronized (this) {
10027 ServiceRecord r = mServices.get(name);
10028 if (r != null) {
10029 for (ConnectionRecord conn : r.connections.values()) {
10030 if (conn.clientIntent != null) {
10031 return conn.clientIntent;
10032 }
10033 }
10034 }
10035 }
10036 return null;
10037 }
10038
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010039 private final ServiceRecord findServiceLocked(ComponentName name,
10040 IBinder token) {
10041 ServiceRecord r = mServices.get(name);
10042 return r == token ? r : null;
10043 }
10044
10045 private final class ServiceLookupResult {
10046 final ServiceRecord record;
10047 final String permission;
10048
10049 ServiceLookupResult(ServiceRecord _record, String _permission) {
10050 record = _record;
10051 permission = _permission;
10052 }
10053 };
10054
10055 private ServiceLookupResult findServiceLocked(Intent service,
10056 String resolvedType) {
10057 ServiceRecord r = null;
10058 if (service.getComponent() != null) {
10059 r = mServices.get(service.getComponent());
10060 }
10061 if (r == null) {
10062 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10063 r = mServicesByIntent.get(filter);
10064 }
10065
10066 if (r == null) {
10067 try {
10068 ResolveInfo rInfo =
10069 ActivityThread.getPackageManager().resolveService(
10070 service, resolvedType, 0);
10071 ServiceInfo sInfo =
10072 rInfo != null ? rInfo.serviceInfo : null;
10073 if (sInfo == null) {
10074 return null;
10075 }
10076
10077 ComponentName name = new ComponentName(
10078 sInfo.applicationInfo.packageName, sInfo.name);
10079 r = mServices.get(name);
10080 } catch (RemoteException ex) {
10081 // pm is in same process, this will never happen.
10082 }
10083 }
10084 if (r != null) {
10085 int callingPid = Binder.getCallingPid();
10086 int callingUid = Binder.getCallingUid();
10087 if (checkComponentPermission(r.permission,
10088 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10089 != PackageManager.PERMISSION_GRANTED) {
10090 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10091 + " from pid=" + callingPid
10092 + ", uid=" + callingUid
10093 + " requires " + r.permission);
10094 return new ServiceLookupResult(null, r.permission);
10095 }
10096 return new ServiceLookupResult(r, null);
10097 }
10098 return null;
10099 }
10100
10101 private class ServiceRestarter implements Runnable {
10102 private ServiceRecord mService;
10103
10104 void setService(ServiceRecord service) {
10105 mService = service;
10106 }
10107
10108 public void run() {
10109 synchronized(ActivityManagerService.this) {
10110 performServiceRestartLocked(mService);
10111 }
10112 }
10113 }
10114
10115 private ServiceLookupResult retrieveServiceLocked(Intent service,
10116 String resolvedType, int callingPid, int callingUid) {
10117 ServiceRecord r = null;
10118 if (service.getComponent() != null) {
10119 r = mServices.get(service.getComponent());
10120 }
10121 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10122 r = mServicesByIntent.get(filter);
10123 if (r == null) {
10124 try {
10125 ResolveInfo rInfo =
10126 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010127 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010128 ServiceInfo sInfo =
10129 rInfo != null ? rInfo.serviceInfo : null;
10130 if (sInfo == null) {
10131 Log.w(TAG, "Unable to start service " + service +
10132 ": not found");
10133 return null;
10134 }
10135
10136 ComponentName name = new ComponentName(
10137 sInfo.applicationInfo.packageName, sInfo.name);
10138 r = mServices.get(name);
10139 if (r == null) {
10140 filter = new Intent.FilterComparison(service.cloneFilter());
10141 ServiceRestarter res = new ServiceRestarter();
10142 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10143 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10144 synchronized (stats) {
10145 ss = stats.getServiceStatsLocked(
10146 sInfo.applicationInfo.uid, sInfo.packageName,
10147 sInfo.name);
10148 }
10149 r = new ServiceRecord(ss, name, filter, sInfo, res);
10150 res.setService(r);
10151 mServices.put(name, r);
10152 mServicesByIntent.put(filter, r);
10153
10154 // Make sure this component isn't in the pending list.
10155 int N = mPendingServices.size();
10156 for (int i=0; i<N; i++) {
10157 ServiceRecord pr = mPendingServices.get(i);
10158 if (pr.name.equals(name)) {
10159 mPendingServices.remove(i);
10160 i--;
10161 N--;
10162 }
10163 }
10164 }
10165 } catch (RemoteException ex) {
10166 // pm is in same process, this will never happen.
10167 }
10168 }
10169 if (r != null) {
10170 if (checkComponentPermission(r.permission,
10171 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10172 != PackageManager.PERMISSION_GRANTED) {
10173 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10174 + " from pid=" + Binder.getCallingPid()
10175 + ", uid=" + Binder.getCallingUid()
10176 + " requires " + r.permission);
10177 return new ServiceLookupResult(null, r.permission);
10178 }
10179 return new ServiceLookupResult(r, null);
10180 }
10181 return null;
10182 }
10183
10184 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10185 long now = SystemClock.uptimeMillis();
10186 if (r.executeNesting == 0 && r.app != null) {
10187 if (r.app.executingServices.size() == 0) {
10188 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10189 msg.obj = r.app;
10190 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10191 }
10192 r.app.executingServices.add(r);
10193 }
10194 r.executeNesting++;
10195 r.executingStart = now;
10196 }
10197
10198 private final void sendServiceArgsLocked(ServiceRecord r,
10199 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010200 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010201 if (N == 0) {
10202 return;
10203 }
10204
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010205 int i = 0;
10206 while (i < N) {
10207 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010208 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010209 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010210 + r.name + " " + r.intent + " args=" + si.intent);
10211 if (si.intent == null && N > 0) {
10212 // If somehow we got a dummy start at the front, then
10213 // just drop it here.
10214 i++;
10215 continue;
10216 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010217 bumpServiceExecutingLocked(r);
10218 if (!oomAdjusted) {
10219 oomAdjusted = true;
10220 updateOomAdjLocked(r.app);
10221 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010222 int flags = 0;
10223 if (si.deliveryCount > 0) {
10224 flags |= Service.START_FLAG_RETRY;
10225 }
10226 if (si.doneExecutingCount > 0) {
10227 flags |= Service.START_FLAG_REDELIVERY;
10228 }
10229 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10230 si.deliveredTime = SystemClock.uptimeMillis();
10231 r.deliveredStarts.add(si);
10232 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010233 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010234 } catch (RemoteException e) {
10235 // Remote process gone... we'll let the normal cleanup take
10236 // care of this.
10237 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010238 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010239 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010240 break;
10241 }
10242 }
10243 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010244 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010245 } else {
10246 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010247 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010248 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010249 }
10250 }
10251 }
10252
10253 private final boolean requestServiceBindingLocked(ServiceRecord r,
10254 IntentBindRecord i, boolean rebind) {
10255 if (r.app == null || r.app.thread == null) {
10256 // If service is not currently running, can't yet bind.
10257 return false;
10258 }
10259 if ((!i.requested || rebind) && i.apps.size() > 0) {
10260 try {
10261 bumpServiceExecutingLocked(r);
10262 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10263 + ": shouldUnbind=" + i.hasBound);
10264 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10265 if (!rebind) {
10266 i.requested = true;
10267 }
10268 i.hasBound = true;
10269 i.doRebind = false;
10270 } catch (RemoteException e) {
10271 return false;
10272 }
10273 }
10274 return true;
10275 }
10276
10277 private final void requestServiceBindingsLocked(ServiceRecord r) {
10278 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10279 while (bindings.hasNext()) {
10280 IntentBindRecord i = bindings.next();
10281 if (!requestServiceBindingLocked(r, i, false)) {
10282 break;
10283 }
10284 }
10285 }
10286
10287 private final void realStartServiceLocked(ServiceRecord r,
10288 ProcessRecord app) throws RemoteException {
10289 if (app.thread == null) {
10290 throw new RemoteException();
10291 }
10292
10293 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010294 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010295
10296 app.services.add(r);
10297 bumpServiceExecutingLocked(r);
10298 updateLRUListLocked(app, true);
10299
10300 boolean created = false;
10301 try {
10302 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10303 + r.name + " " + r.intent);
10304 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
10305 System.identityHashCode(r), r.shortName,
10306 r.intent.getIntent().toString(), r.app.pid);
10307 synchronized (r.stats.getBatteryStats()) {
10308 r.stats.startLaunchedLocked();
10309 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010310 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010311 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010312 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010313 created = true;
10314 } finally {
10315 if (!created) {
10316 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010317 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010318 }
10319 }
10320
10321 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010322
10323 // If the service is in the started state, and there are no
10324 // pending arguments, then fake up one so its onStartCommand() will
10325 // be called.
10326 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10327 r.lastStartId++;
10328 if (r.lastStartId < 1) {
10329 r.lastStartId = 1;
10330 }
10331 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10332 }
10333
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010334 sendServiceArgsLocked(r, true);
10335 }
10336
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010337 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10338 boolean allowCancel) {
10339 boolean canceled = false;
10340
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010341 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010342 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010343 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010344
10345 // Any delivered but not yet finished starts should be put back
10346 // on the pending list.
10347 final int N = r.deliveredStarts.size();
10348 if (N > 0) {
10349 for (int i=N-1; i>=0; i--) {
10350 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10351 if (si.intent == null) {
10352 // We'll generate this again if needed.
10353 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10354 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10355 r.pendingStarts.add(0, si);
10356 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10357 dur *= 2;
10358 if (minDuration < dur) minDuration = dur;
10359 if (resetTime < dur) resetTime = dur;
10360 } else {
10361 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10362 + r.name);
10363 canceled = true;
10364 }
10365 }
10366 r.deliveredStarts.clear();
10367 }
10368
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010369 r.totalRestartCount++;
10370 if (r.restartDelay == 0) {
10371 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010372 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010373 } else {
10374 // If it has been a "reasonably long time" since the service
10375 // was started, then reset our restart duration back to
10376 // the beginning, so we don't infinitely increase the duration
10377 // on a service that just occasionally gets killed (which is
10378 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010379 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010380 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010381 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010382 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010383 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010384 if (r.restartDelay < minDuration) {
10385 r.restartDelay = minDuration;
10386 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010387 }
10388 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010389
10390 r.nextRestartTime = now + r.restartDelay;
10391
10392 // Make sure that we don't end up restarting a bunch of services
10393 // all at the same time.
10394 boolean repeat;
10395 do {
10396 repeat = false;
10397 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10398 ServiceRecord r2 = mRestartingServices.get(i);
10399 if (r2 != r && r.nextRestartTime
10400 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10401 && r.nextRestartTime
10402 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10403 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10404 r.restartDelay = r.nextRestartTime - now;
10405 repeat = true;
10406 break;
10407 }
10408 }
10409 } while (repeat);
10410
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010411 if (!mRestartingServices.contains(r)) {
10412 mRestartingServices.add(r);
10413 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010414
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010415 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010416
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010417 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010418 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010419 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10420 Log.w(TAG, "Scheduling restart of crashed service "
10421 + r.shortName + " in " + r.restartDelay + "ms");
10422 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10423 r.shortName, r.restartDelay);
10424
10425 Message msg = Message.obtain();
10426 msg.what = SERVICE_ERROR_MSG;
10427 msg.obj = r;
10428 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010429
10430 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010431 }
10432
10433 final void performServiceRestartLocked(ServiceRecord r) {
10434 if (!mRestartingServices.contains(r)) {
10435 return;
10436 }
10437 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10438 }
10439
10440 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10441 if (r.restartDelay == 0) {
10442 return false;
10443 }
10444 r.resetRestartCounter();
10445 mRestartingServices.remove(r);
10446 mHandler.removeCallbacks(r.restarter);
10447 return true;
10448 }
10449
10450 private final boolean bringUpServiceLocked(ServiceRecord r,
10451 int intentFlags, boolean whileRestarting) {
10452 //Log.i(TAG, "Bring up service:");
10453 //r.dump(" ");
10454
10455 if (r.app != null) {
10456 sendServiceArgsLocked(r, false);
10457 return true;
10458 }
10459
10460 if (!whileRestarting && r.restartDelay > 0) {
10461 // If waiting for a restart, then do nothing.
10462 return true;
10463 }
10464
10465 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10466 + " " + r.intent);
10467
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010468 // We are now bringing the service up, so no longer in the
10469 // restarting state.
10470 mRestartingServices.remove(r);
10471
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010472 final String appName = r.processName;
10473 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10474 if (app != null && app.thread != null) {
10475 try {
10476 realStartServiceLocked(r, app);
10477 return true;
10478 } catch (RemoteException e) {
10479 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10480 }
10481
10482 // If a dead object exception was thrown -- fall through to
10483 // restart the application.
10484 }
10485
10486 if (!mPendingServices.contains(r)) {
10487 // Not running -- get it started, and enqueue this service record
10488 // to be executed when the app comes up.
10489 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070010490 "service", r.name, false) == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010491 Log.w(TAG, "Unable to launch app "
10492 + r.appInfo.packageName + "/"
10493 + r.appInfo.uid + " for service "
10494 + r.intent.getIntent() + ": process is bad");
10495 bringDownServiceLocked(r, true);
10496 return false;
10497 }
10498 mPendingServices.add(r);
10499 }
10500 return true;
10501 }
10502
10503 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10504 //Log.i(TAG, "Bring down service:");
10505 //r.dump(" ");
10506
10507 // Does it still need to run?
10508 if (!force && r.startRequested) {
10509 return;
10510 }
10511 if (r.connections.size() > 0) {
10512 if (!force) {
10513 // XXX should probably keep a count of the number of auto-create
10514 // connections directly in the service.
10515 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10516 while (it.hasNext()) {
10517 ConnectionRecord cr = it.next();
10518 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10519 return;
10520 }
10521 }
10522 }
10523
10524 // Report to all of the connections that the service is no longer
10525 // available.
10526 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10527 while (it.hasNext()) {
10528 ConnectionRecord c = it.next();
10529 try {
10530 // todo: shouldn't be a synchronous call!
10531 c.conn.connected(r.name, null);
10532 } catch (Exception e) {
10533 Log.w(TAG, "Failure disconnecting service " + r.name +
10534 " to connection " + c.conn.asBinder() +
10535 " (in " + c.binding.client.processName + ")", e);
10536 }
10537 }
10538 }
10539
10540 // Tell the service that it has been unbound.
10541 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10542 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10543 while (it.hasNext()) {
10544 IntentBindRecord ibr = it.next();
10545 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10546 + ": hasBound=" + ibr.hasBound);
10547 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10548 try {
10549 bumpServiceExecutingLocked(r);
10550 updateOomAdjLocked(r.app);
10551 ibr.hasBound = false;
10552 r.app.thread.scheduleUnbindService(r,
10553 ibr.intent.getIntent());
10554 } catch (Exception e) {
10555 Log.w(TAG, "Exception when unbinding service "
10556 + r.shortName, e);
10557 serviceDoneExecutingLocked(r, true);
10558 }
10559 }
10560 }
10561 }
10562
10563 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10564 + " " + r.intent);
10565 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10566 System.identityHashCode(r), r.shortName,
10567 (r.app != null) ? r.app.pid : -1);
10568
10569 mServices.remove(r.name);
10570 mServicesByIntent.remove(r.intent);
10571 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10572 r.totalRestartCount = 0;
10573 unscheduleServiceRestartLocked(r);
10574
10575 // Also make sure it is not on the pending list.
10576 int N = mPendingServices.size();
10577 for (int i=0; i<N; i++) {
10578 if (mPendingServices.get(i) == r) {
10579 mPendingServices.remove(i);
10580 if (DEBUG_SERVICE) Log.v(
10581 TAG, "Removed pending service: " + r.shortName);
10582 i--;
10583 N--;
10584 }
10585 }
10586
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010587 r.cancelNotification();
10588 r.isForeground = false;
10589 r.foregroundId = 0;
10590 r.foregroundNoti = null;
10591
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010592 // Clear start entries.
10593 r.deliveredStarts.clear();
10594 r.pendingStarts.clear();
10595
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010596 if (r.app != null) {
10597 synchronized (r.stats.getBatteryStats()) {
10598 r.stats.stopLaunchedLocked();
10599 }
10600 r.app.services.remove(r);
10601 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010602 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010603 if (DEBUG_SERVICE) Log.v(TAG,
10604 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010605 bumpServiceExecutingLocked(r);
10606 mStoppingServices.add(r);
10607 updateOomAdjLocked(r.app);
10608 r.app.thread.scheduleStopService(r);
10609 } catch (Exception e) {
10610 Log.w(TAG, "Exception when stopping service "
10611 + r.shortName, e);
10612 serviceDoneExecutingLocked(r, true);
10613 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010614 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010615 } else {
10616 if (DEBUG_SERVICE) Log.v(
10617 TAG, "Removed service that has no process: " + r.shortName);
10618 }
10619 } else {
10620 if (DEBUG_SERVICE) Log.v(
10621 TAG, "Removed service that is not running: " + r.shortName);
10622 }
10623 }
10624
10625 ComponentName startServiceLocked(IApplicationThread caller,
10626 Intent service, String resolvedType,
10627 int callingPid, int callingUid) {
10628 synchronized(this) {
10629 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10630 + " type=" + resolvedType + " args=" + service.getExtras());
10631
10632 if (caller != null) {
10633 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10634 if (callerApp == null) {
10635 throw new SecurityException(
10636 "Unable to find app for caller " + caller
10637 + " (pid=" + Binder.getCallingPid()
10638 + ") when starting service " + service);
10639 }
10640 }
10641
10642 ServiceLookupResult res =
10643 retrieveServiceLocked(service, resolvedType,
10644 callingPid, callingUid);
10645 if (res == null) {
10646 return null;
10647 }
10648 if (res.record == null) {
10649 return new ComponentName("!", res.permission != null
10650 ? res.permission : "private to package");
10651 }
10652 ServiceRecord r = res.record;
10653 if (unscheduleServiceRestartLocked(r)) {
10654 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10655 + r.shortName);
10656 }
10657 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010658 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010659 r.lastStartId++;
10660 if (r.lastStartId < 1) {
10661 r.lastStartId = 1;
10662 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010663 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010664 r.lastActivity = SystemClock.uptimeMillis();
10665 synchronized (r.stats.getBatteryStats()) {
10666 r.stats.startRunningLocked();
10667 }
10668 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10669 return new ComponentName("!", "Service process is bad");
10670 }
10671 return r.name;
10672 }
10673 }
10674
10675 public ComponentName startService(IApplicationThread caller, Intent service,
10676 String resolvedType) {
10677 // Refuse possible leaked file descriptors
10678 if (service != null && service.hasFileDescriptors() == true) {
10679 throw new IllegalArgumentException("File descriptors passed in Intent");
10680 }
10681
10682 synchronized(this) {
10683 final int callingPid = Binder.getCallingPid();
10684 final int callingUid = Binder.getCallingUid();
10685 final long origId = Binder.clearCallingIdentity();
10686 ComponentName res = startServiceLocked(caller, service,
10687 resolvedType, callingPid, callingUid);
10688 Binder.restoreCallingIdentity(origId);
10689 return res;
10690 }
10691 }
10692
10693 ComponentName startServiceInPackage(int uid,
10694 Intent service, String resolvedType) {
10695 synchronized(this) {
10696 final long origId = Binder.clearCallingIdentity();
10697 ComponentName res = startServiceLocked(null, service,
10698 resolvedType, -1, uid);
10699 Binder.restoreCallingIdentity(origId);
10700 return res;
10701 }
10702 }
10703
10704 public int stopService(IApplicationThread caller, Intent service,
10705 String resolvedType) {
10706 // Refuse possible leaked file descriptors
10707 if (service != null && service.hasFileDescriptors() == true) {
10708 throw new IllegalArgumentException("File descriptors passed in Intent");
10709 }
10710
10711 synchronized(this) {
10712 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10713 + " type=" + resolvedType);
10714
10715 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10716 if (caller != null && callerApp == null) {
10717 throw new SecurityException(
10718 "Unable to find app for caller " + caller
10719 + " (pid=" + Binder.getCallingPid()
10720 + ") when stopping service " + service);
10721 }
10722
10723 // If this service is active, make sure it is stopped.
10724 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10725 if (r != null) {
10726 if (r.record != null) {
10727 synchronized (r.record.stats.getBatteryStats()) {
10728 r.record.stats.stopRunningLocked();
10729 }
10730 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010731 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010732 final long origId = Binder.clearCallingIdentity();
10733 bringDownServiceLocked(r.record, false);
10734 Binder.restoreCallingIdentity(origId);
10735 return 1;
10736 }
10737 return -1;
10738 }
10739 }
10740
10741 return 0;
10742 }
10743
10744 public IBinder peekService(Intent service, String resolvedType) {
10745 // Refuse possible leaked file descriptors
10746 if (service != null && service.hasFileDescriptors() == true) {
10747 throw new IllegalArgumentException("File descriptors passed in Intent");
10748 }
10749
10750 IBinder ret = null;
10751
10752 synchronized(this) {
10753 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10754
10755 if (r != null) {
10756 // r.record is null if findServiceLocked() failed the caller permission check
10757 if (r.record == null) {
10758 throw new SecurityException(
10759 "Permission Denial: Accessing service " + r.record.name
10760 + " from pid=" + Binder.getCallingPid()
10761 + ", uid=" + Binder.getCallingUid()
10762 + " requires " + r.permission);
10763 }
10764 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10765 if (ib != null) {
10766 ret = ib.binder;
10767 }
10768 }
10769 }
10770
10771 return ret;
10772 }
10773
10774 public boolean stopServiceToken(ComponentName className, IBinder token,
10775 int startId) {
10776 synchronized(this) {
10777 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10778 + " " + token + " startId=" + startId);
10779 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010780 if (r != null) {
10781 if (startId >= 0) {
10782 // Asked to only stop if done with all work. Note that
10783 // to avoid leaks, we will take this as dropping all
10784 // start items up to and including this one.
10785 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10786 if (si != null) {
10787 while (r.deliveredStarts.size() > 0) {
10788 if (r.deliveredStarts.remove(0) == si) {
10789 break;
10790 }
10791 }
10792 }
10793
10794 if (r.lastStartId != startId) {
10795 return false;
10796 }
10797
10798 if (r.deliveredStarts.size() > 0) {
10799 Log.w(TAG, "stopServiceToken startId " + startId
10800 + " is last, but have " + r.deliveredStarts.size()
10801 + " remaining args");
10802 }
10803 }
10804
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010805 synchronized (r.stats.getBatteryStats()) {
10806 r.stats.stopRunningLocked();
10807 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010808 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010809 }
10810 final long origId = Binder.clearCallingIdentity();
10811 bringDownServiceLocked(r, false);
10812 Binder.restoreCallingIdentity(origId);
10813 return true;
10814 }
10815 }
10816 return false;
10817 }
10818
10819 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010820 int id, Notification notification, boolean removeNotification) {
10821 final long origId = Binder.clearCallingIdentity();
10822 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010823 synchronized(this) {
10824 ServiceRecord r = findServiceLocked(className, token);
10825 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010826 if (id != 0) {
10827 if (notification == null) {
10828 throw new IllegalArgumentException("null notification");
10829 }
10830 if (r.foregroundId != id) {
10831 r.cancelNotification();
10832 r.foregroundId = id;
10833 }
10834 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10835 r.foregroundNoti = notification;
10836 r.isForeground = true;
10837 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010838 if (r.app != null) {
10839 updateServiceForegroundLocked(r.app, true);
10840 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010841 } else {
10842 if (r.isForeground) {
10843 r.isForeground = false;
10844 if (r.app != null) {
10845 updateServiceForegroundLocked(r.app, true);
10846 }
10847 }
10848 if (removeNotification) {
10849 r.cancelNotification();
10850 r.foregroundId = 0;
10851 r.foregroundNoti = null;
10852 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010853 }
10854 }
10855 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010856 } finally {
10857 Binder.restoreCallingIdentity(origId);
10858 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010859 }
10860
10861 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10862 boolean anyForeground = false;
10863 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10864 if (sr.isForeground) {
10865 anyForeground = true;
10866 break;
10867 }
10868 }
10869 if (anyForeground != proc.foregroundServices) {
10870 proc.foregroundServices = anyForeground;
10871 if (oomAdj) {
10872 updateOomAdjLocked();
10873 }
10874 }
10875 }
10876
10877 public int bindService(IApplicationThread caller, IBinder token,
10878 Intent service, String resolvedType,
10879 IServiceConnection connection, int flags) {
10880 // Refuse possible leaked file descriptors
10881 if (service != null && service.hasFileDescriptors() == true) {
10882 throw new IllegalArgumentException("File descriptors passed in Intent");
10883 }
10884
10885 synchronized(this) {
10886 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10887 + " type=" + resolvedType + " conn=" + connection.asBinder()
10888 + " flags=0x" + Integer.toHexString(flags));
10889 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10890 if (callerApp == null) {
10891 throw new SecurityException(
10892 "Unable to find app for caller " + caller
10893 + " (pid=" + Binder.getCallingPid()
10894 + ") when binding service " + service);
10895 }
10896
10897 HistoryRecord activity = null;
10898 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010899 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010900 if (aindex < 0) {
10901 Log.w(TAG, "Binding with unknown activity: " + token);
10902 return 0;
10903 }
10904 activity = (HistoryRecord)mHistory.get(aindex);
10905 }
10906
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010907 int clientLabel = 0;
10908 PendingIntent clientIntent = null;
10909
10910 if (callerApp.info.uid == Process.SYSTEM_UID) {
10911 // Hacky kind of thing -- allow system stuff to tell us
10912 // what they are, so we can report this elsewhere for
10913 // others to know why certain services are running.
10914 try {
10915 clientIntent = (PendingIntent)service.getParcelableExtra(
10916 Intent.EXTRA_CLIENT_INTENT);
10917 } catch (RuntimeException e) {
10918 }
10919 if (clientIntent != null) {
10920 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
10921 if (clientLabel != 0) {
10922 // There are no useful extras in the intent, trash them.
10923 // System code calling with this stuff just needs to know
10924 // this will happen.
10925 service = service.cloneFilter();
10926 }
10927 }
10928 }
10929
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010930 ServiceLookupResult res =
10931 retrieveServiceLocked(service, resolvedType,
10932 Binder.getCallingPid(), Binder.getCallingUid());
10933 if (res == null) {
10934 return 0;
10935 }
10936 if (res.record == null) {
10937 return -1;
10938 }
10939 ServiceRecord s = res.record;
10940
10941 final long origId = Binder.clearCallingIdentity();
10942
10943 if (unscheduleServiceRestartLocked(s)) {
10944 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10945 + s.shortName);
10946 }
10947
10948 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10949 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010950 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010951
10952 IBinder binder = connection.asBinder();
10953 s.connections.put(binder, c);
10954 b.connections.add(c);
10955 if (activity != null) {
10956 if (activity.connections == null) {
10957 activity.connections = new HashSet<ConnectionRecord>();
10958 }
10959 activity.connections.add(c);
10960 }
10961 b.client.connections.add(c);
10962 mServiceConnections.put(binder, c);
10963
10964 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10965 s.lastActivity = SystemClock.uptimeMillis();
10966 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10967 return 0;
10968 }
10969 }
10970
10971 if (s.app != null) {
10972 // This could have made the service more important.
10973 updateOomAdjLocked(s.app);
10974 }
10975
10976 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10977 + ": received=" + b.intent.received
10978 + " apps=" + b.intent.apps.size()
10979 + " doRebind=" + b.intent.doRebind);
10980
10981 if (s.app != null && b.intent.received) {
10982 // Service is already running, so we can immediately
10983 // publish the connection.
10984 try {
10985 c.conn.connected(s.name, b.intent.binder);
10986 } catch (Exception e) {
10987 Log.w(TAG, "Failure sending service " + s.shortName
10988 + " to connection " + c.conn.asBinder()
10989 + " (in " + c.binding.client.processName + ")", e);
10990 }
10991
10992 // If this is the first app connected back to this binding,
10993 // and the service had previously asked to be told when
10994 // rebound, then do so.
10995 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10996 requestServiceBindingLocked(s, b.intent, true);
10997 }
10998 } else if (!b.intent.requested) {
10999 requestServiceBindingLocked(s, b.intent, false);
11000 }
11001
11002 Binder.restoreCallingIdentity(origId);
11003 }
11004
11005 return 1;
11006 }
11007
11008 private void removeConnectionLocked(
11009 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11010 IBinder binder = c.conn.asBinder();
11011 AppBindRecord b = c.binding;
11012 ServiceRecord s = b.service;
11013 s.connections.remove(binder);
11014 b.connections.remove(c);
11015 if (c.activity != null && c.activity != skipAct) {
11016 if (c.activity.connections != null) {
11017 c.activity.connections.remove(c);
11018 }
11019 }
11020 if (b.client != skipApp) {
11021 b.client.connections.remove(c);
11022 }
11023 mServiceConnections.remove(binder);
11024
11025 if (b.connections.size() == 0) {
11026 b.intent.apps.remove(b.client);
11027 }
11028
11029 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11030 + ": shouldUnbind=" + b.intent.hasBound);
11031 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11032 && b.intent.hasBound) {
11033 try {
11034 bumpServiceExecutingLocked(s);
11035 updateOomAdjLocked(s.app);
11036 b.intent.hasBound = false;
11037 // Assume the client doesn't want to know about a rebind;
11038 // we will deal with that later if it asks for one.
11039 b.intent.doRebind = false;
11040 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11041 } catch (Exception e) {
11042 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11043 serviceDoneExecutingLocked(s, true);
11044 }
11045 }
11046
11047 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11048 bringDownServiceLocked(s, false);
11049 }
11050 }
11051
11052 public boolean unbindService(IServiceConnection connection) {
11053 synchronized (this) {
11054 IBinder binder = connection.asBinder();
11055 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11056 ConnectionRecord r = mServiceConnections.get(binder);
11057 if (r == null) {
11058 Log.w(TAG, "Unbind failed: could not find connection for "
11059 + connection.asBinder());
11060 return false;
11061 }
11062
11063 final long origId = Binder.clearCallingIdentity();
11064
11065 removeConnectionLocked(r, null, null);
11066
11067 if (r.binding.service.app != null) {
11068 // This could have made the service less important.
11069 updateOomAdjLocked(r.binding.service.app);
11070 }
11071
11072 Binder.restoreCallingIdentity(origId);
11073 }
11074
11075 return true;
11076 }
11077
11078 public void publishService(IBinder token, Intent intent, IBinder service) {
11079 // Refuse possible leaked file descriptors
11080 if (intent != null && intent.hasFileDescriptors() == true) {
11081 throw new IllegalArgumentException("File descriptors passed in Intent");
11082 }
11083
11084 synchronized(this) {
11085 if (!(token instanceof ServiceRecord)) {
11086 throw new IllegalArgumentException("Invalid service token");
11087 }
11088 ServiceRecord r = (ServiceRecord)token;
11089
11090 final long origId = Binder.clearCallingIdentity();
11091
11092 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11093 + " " + intent + ": " + service);
11094 if (r != null) {
11095 Intent.FilterComparison filter
11096 = new Intent.FilterComparison(intent);
11097 IntentBindRecord b = r.bindings.get(filter);
11098 if (b != null && !b.received) {
11099 b.binder = service;
11100 b.requested = true;
11101 b.received = true;
11102 if (r.connections.size() > 0) {
11103 Iterator<ConnectionRecord> it
11104 = r.connections.values().iterator();
11105 while (it.hasNext()) {
11106 ConnectionRecord c = it.next();
11107 if (!filter.equals(c.binding.intent.intent)) {
11108 if (DEBUG_SERVICE) Log.v(
11109 TAG, "Not publishing to: " + c);
11110 if (DEBUG_SERVICE) Log.v(
11111 TAG, "Bound intent: " + c.binding.intent.intent);
11112 if (DEBUG_SERVICE) Log.v(
11113 TAG, "Published intent: " + intent);
11114 continue;
11115 }
11116 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11117 try {
11118 c.conn.connected(r.name, service);
11119 } catch (Exception e) {
11120 Log.w(TAG, "Failure sending service " + r.name +
11121 " to connection " + c.conn.asBinder() +
11122 " (in " + c.binding.client.processName + ")", e);
11123 }
11124 }
11125 }
11126 }
11127
11128 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11129
11130 Binder.restoreCallingIdentity(origId);
11131 }
11132 }
11133 }
11134
11135 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11136 // Refuse possible leaked file descriptors
11137 if (intent != null && intent.hasFileDescriptors() == true) {
11138 throw new IllegalArgumentException("File descriptors passed in Intent");
11139 }
11140
11141 synchronized(this) {
11142 if (!(token instanceof ServiceRecord)) {
11143 throw new IllegalArgumentException("Invalid service token");
11144 }
11145 ServiceRecord r = (ServiceRecord)token;
11146
11147 final long origId = Binder.clearCallingIdentity();
11148
11149 if (r != null) {
11150 Intent.FilterComparison filter
11151 = new Intent.FilterComparison(intent);
11152 IntentBindRecord b = r.bindings.get(filter);
11153 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11154 + " at " + b + ": apps="
11155 + (b != null ? b.apps.size() : 0));
11156 if (b != null) {
11157 if (b.apps.size() > 0) {
11158 // Applications have already bound since the last
11159 // unbind, so just rebind right here.
11160 requestServiceBindingLocked(r, b, true);
11161 } else {
11162 // Note to tell the service the next time there is
11163 // a new client.
11164 b.doRebind = true;
11165 }
11166 }
11167
11168 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11169
11170 Binder.restoreCallingIdentity(origId);
11171 }
11172 }
11173 }
11174
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011175 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011176 synchronized(this) {
11177 if (!(token instanceof ServiceRecord)) {
11178 throw new IllegalArgumentException("Invalid service token");
11179 }
11180 ServiceRecord r = (ServiceRecord)token;
11181 boolean inStopping = mStoppingServices.contains(token);
11182 if (r != null) {
11183 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11184 + ": nesting=" + r.executeNesting
11185 + ", inStopping=" + inStopping);
11186 if (r != token) {
11187 Log.w(TAG, "Done executing service " + r.name
11188 + " with incorrect token: given " + token
11189 + ", expected " + r);
11190 return;
11191 }
11192
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011193 if (type == 1) {
11194 // This is a call from a service start... take care of
11195 // book-keeping.
11196 r.callStart = true;
11197 switch (res) {
11198 case Service.START_STICKY_COMPATIBILITY:
11199 case Service.START_STICKY: {
11200 // We are done with the associated start arguments.
11201 r.findDeliveredStart(startId, true);
11202 // Don't stop if killed.
11203 r.stopIfKilled = false;
11204 break;
11205 }
11206 case Service.START_NOT_STICKY: {
11207 // We are done with the associated start arguments.
11208 r.findDeliveredStart(startId, true);
11209 if (r.lastStartId == startId) {
11210 // There is no more work, and this service
11211 // doesn't want to hang around if killed.
11212 r.stopIfKilled = true;
11213 }
11214 break;
11215 }
11216 case Service.START_REDELIVER_INTENT: {
11217 // We'll keep this item until they explicitly
11218 // call stop for it, but keep track of the fact
11219 // that it was delivered.
11220 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11221 if (si != null) {
11222 si.deliveryCount = 0;
11223 si.doneExecutingCount++;
11224 // Don't stop if killed.
11225 r.stopIfKilled = true;
11226 }
11227 break;
11228 }
11229 default:
11230 throw new IllegalArgumentException(
11231 "Unknown service start result: " + res);
11232 }
11233 if (res == Service.START_STICKY_COMPATIBILITY) {
11234 r.callStart = false;
11235 }
11236 }
11237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011238 final long origId = Binder.clearCallingIdentity();
11239 serviceDoneExecutingLocked(r, inStopping);
11240 Binder.restoreCallingIdentity(origId);
11241 } else {
11242 Log.w(TAG, "Done executing unknown service " + r.name
11243 + " with token " + token);
11244 }
11245 }
11246 }
11247
11248 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11249 r.executeNesting--;
11250 if (r.executeNesting <= 0 && r.app != null) {
11251 r.app.executingServices.remove(r);
11252 if (r.app.executingServices.size() == 0) {
11253 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11254 }
11255 if (inStopping) {
11256 mStoppingServices.remove(r);
11257 }
11258 updateOomAdjLocked(r.app);
11259 }
11260 }
11261
11262 void serviceTimeout(ProcessRecord proc) {
11263 synchronized(this) {
11264 if (proc.executingServices.size() == 0 || proc.thread == null) {
11265 return;
11266 }
11267 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11268 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11269 ServiceRecord timeout = null;
11270 long nextTime = 0;
11271 while (it.hasNext()) {
11272 ServiceRecord sr = it.next();
11273 if (sr.executingStart < maxTime) {
11274 timeout = sr;
11275 break;
11276 }
11277 if (sr.executingStart > nextTime) {
11278 nextTime = sr.executingStart;
11279 }
11280 }
11281 if (timeout != null && mLRUProcesses.contains(proc)) {
11282 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011283 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011284 + timeout.name);
11285 } else {
11286 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11287 msg.obj = proc;
11288 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11289 }
11290 }
11291 }
11292
11293 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011294 // BACKUP AND RESTORE
11295 // =========================================================
11296
11297 // Cause the target app to be launched if necessary and its backup agent
11298 // instantiated. The backup agent will invoke backupAgentCreated() on the
11299 // activity manager to announce its creation.
11300 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11301 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11302 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11303
11304 synchronized(this) {
11305 // !!! TODO: currently no check here that we're already bound
11306 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11307 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11308 synchronized (stats) {
11309 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11310 }
11311
11312 BackupRecord r = new BackupRecord(ss, app, backupMode);
11313 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11314 // startProcessLocked() returns existing proc's record if it's already running
11315 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011316 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011317 if (proc == null) {
11318 Log.e(TAG, "Unable to start backup agent process " + r);
11319 return false;
11320 }
11321
11322 r.app = proc;
11323 mBackupTarget = r;
11324 mBackupAppName = app.packageName;
11325
Christopher Tate6fa95972009-06-05 18:43:55 -070011326 // Try not to kill the process during backup
11327 updateOomAdjLocked(proc);
11328
Christopher Tate181fafa2009-05-14 11:12:14 -070011329 // If the process is already attached, schedule the creation of the backup agent now.
11330 // If it is not yet live, this will be done when it attaches to the framework.
11331 if (proc.thread != null) {
11332 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11333 try {
11334 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11335 } catch (RemoteException e) {
11336 // !!! TODO: notify the backup manager that we crashed, or rely on
11337 // death notices, or...?
11338 }
11339 } else {
11340 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11341 }
11342 // Invariants: at this point, the target app process exists and the application
11343 // is either already running or in the process of coming up. mBackupTarget and
11344 // mBackupAppName describe the app, so that when it binds back to the AM we
11345 // know that it's scheduled for a backup-agent operation.
11346 }
11347
11348 return true;
11349 }
11350
11351 // A backup agent has just come up
11352 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11353 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11354 + " = " + agent);
11355
11356 synchronized(this) {
11357 if (!agentPackageName.equals(mBackupAppName)) {
11358 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11359 return;
11360 }
11361
Christopher Tate043dadc2009-06-02 16:11:00 -070011362 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011363 try {
11364 IBackupManager bm = IBackupManager.Stub.asInterface(
11365 ServiceManager.getService(Context.BACKUP_SERVICE));
11366 bm.agentConnected(agentPackageName, agent);
11367 } catch (RemoteException e) {
11368 // can't happen; the backup manager service is local
11369 } catch (Exception e) {
11370 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11371 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011372 } finally {
11373 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011374 }
11375 }
11376 }
11377
11378 // done with this agent
11379 public void unbindBackupAgent(ApplicationInfo appInfo) {
11380 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011381 if (appInfo == null) {
11382 Log.w(TAG, "unbind backup agent for null app");
11383 return;
11384 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011385
11386 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011387 if (mBackupAppName == null) {
11388 Log.w(TAG, "Unbinding backup agent with no active backup");
11389 return;
11390 }
11391
Christopher Tate181fafa2009-05-14 11:12:14 -070011392 if (!mBackupAppName.equals(appInfo.packageName)) {
11393 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11394 return;
11395 }
11396
Christopher Tate6fa95972009-06-05 18:43:55 -070011397 ProcessRecord proc = mBackupTarget.app;
11398 mBackupTarget = null;
11399 mBackupAppName = null;
11400
11401 // Not backing this app up any more; reset its OOM adjustment
11402 updateOomAdjLocked(proc);
11403
Christopher Tatec7b31e32009-06-10 15:49:30 -070011404 // If the app crashed during backup, 'thread' will be null here
11405 if (proc.thread != null) {
11406 try {
11407 proc.thread.scheduleDestroyBackupAgent(appInfo);
11408 } catch (Exception e) {
11409 Log.e(TAG, "Exception when unbinding backup agent:");
11410 e.printStackTrace();
11411 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011412 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011413 }
11414 }
11415 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011416 // BROADCASTS
11417 // =========================================================
11418
11419 private final List getStickies(String action, IntentFilter filter,
11420 List cur) {
11421 final ContentResolver resolver = mContext.getContentResolver();
11422 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11423 if (list == null) {
11424 return cur;
11425 }
11426 int N = list.size();
11427 for (int i=0; i<N; i++) {
11428 Intent intent = list.get(i);
11429 if (filter.match(resolver, intent, true, TAG) >= 0) {
11430 if (cur == null) {
11431 cur = new ArrayList<Intent>();
11432 }
11433 cur.add(intent);
11434 }
11435 }
11436 return cur;
11437 }
11438
11439 private final void scheduleBroadcastsLocked() {
11440 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11441 + mBroadcastsScheduled);
11442
11443 if (mBroadcastsScheduled) {
11444 return;
11445 }
11446 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11447 mBroadcastsScheduled = true;
11448 }
11449
11450 public Intent registerReceiver(IApplicationThread caller,
11451 IIntentReceiver receiver, IntentFilter filter, String permission) {
11452 synchronized(this) {
11453 ProcessRecord callerApp = null;
11454 if (caller != null) {
11455 callerApp = getRecordForAppLocked(caller);
11456 if (callerApp == null) {
11457 throw new SecurityException(
11458 "Unable to find app for caller " + caller
11459 + " (pid=" + Binder.getCallingPid()
11460 + ") when registering receiver " + receiver);
11461 }
11462 }
11463
11464 List allSticky = null;
11465
11466 // Look for any matching sticky broadcasts...
11467 Iterator actions = filter.actionsIterator();
11468 if (actions != null) {
11469 while (actions.hasNext()) {
11470 String action = (String)actions.next();
11471 allSticky = getStickies(action, filter, allSticky);
11472 }
11473 } else {
11474 allSticky = getStickies(null, filter, allSticky);
11475 }
11476
11477 // The first sticky in the list is returned directly back to
11478 // the client.
11479 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11480
11481 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11482 + ": " + sticky);
11483
11484 if (receiver == null) {
11485 return sticky;
11486 }
11487
11488 ReceiverList rl
11489 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11490 if (rl == null) {
11491 rl = new ReceiverList(this, callerApp,
11492 Binder.getCallingPid(),
11493 Binder.getCallingUid(), receiver);
11494 if (rl.app != null) {
11495 rl.app.receivers.add(rl);
11496 } else {
11497 try {
11498 receiver.asBinder().linkToDeath(rl, 0);
11499 } catch (RemoteException e) {
11500 return sticky;
11501 }
11502 rl.linkedToDeath = true;
11503 }
11504 mRegisteredReceivers.put(receiver.asBinder(), rl);
11505 }
11506 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11507 rl.add(bf);
11508 if (!bf.debugCheck()) {
11509 Log.w(TAG, "==> For Dynamic broadast");
11510 }
11511 mReceiverResolver.addFilter(bf);
11512
11513 // Enqueue broadcasts for all existing stickies that match
11514 // this filter.
11515 if (allSticky != null) {
11516 ArrayList receivers = new ArrayList();
11517 receivers.add(bf);
11518
11519 int N = allSticky.size();
11520 for (int i=0; i<N; i++) {
11521 Intent intent = (Intent)allSticky.get(i);
11522 BroadcastRecord r = new BroadcastRecord(intent, null,
11523 null, -1, -1, null, receivers, null, 0, null, null,
11524 false);
11525 if (mParallelBroadcasts.size() == 0) {
11526 scheduleBroadcastsLocked();
11527 }
11528 mParallelBroadcasts.add(r);
11529 }
11530 }
11531
11532 return sticky;
11533 }
11534 }
11535
11536 public void unregisterReceiver(IIntentReceiver receiver) {
11537 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11538
11539 boolean doNext = false;
11540
11541 synchronized(this) {
11542 ReceiverList rl
11543 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11544 if (rl != null) {
11545 if (rl.curBroadcast != null) {
11546 BroadcastRecord r = rl.curBroadcast;
11547 doNext = finishReceiverLocked(
11548 receiver.asBinder(), r.resultCode, r.resultData,
11549 r.resultExtras, r.resultAbort, true);
11550 }
11551
11552 if (rl.app != null) {
11553 rl.app.receivers.remove(rl);
11554 }
11555 removeReceiverLocked(rl);
11556 if (rl.linkedToDeath) {
11557 rl.linkedToDeath = false;
11558 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11559 }
11560 }
11561 }
11562
11563 if (!doNext) {
11564 return;
11565 }
11566
11567 final long origId = Binder.clearCallingIdentity();
11568 processNextBroadcast(false);
11569 trimApplications();
11570 Binder.restoreCallingIdentity(origId);
11571 }
11572
11573 void removeReceiverLocked(ReceiverList rl) {
11574 mRegisteredReceivers.remove(rl.receiver.asBinder());
11575 int N = rl.size();
11576 for (int i=0; i<N; i++) {
11577 mReceiverResolver.removeFilter(rl.get(i));
11578 }
11579 }
11580
11581 private final int broadcastIntentLocked(ProcessRecord callerApp,
11582 String callerPackage, Intent intent, String resolvedType,
11583 IIntentReceiver resultTo, int resultCode, String resultData,
11584 Bundle map, String requiredPermission,
11585 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11586 intent = new Intent(intent);
11587
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011588 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011589 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11590 + " ordered=" + ordered);
11591 if ((resultTo != null) && !ordered) {
11592 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11593 }
11594
11595 // Handle special intents: if this broadcast is from the package
11596 // manager about a package being removed, we need to remove all of
11597 // its activities from the history stack.
11598 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11599 intent.getAction());
11600 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11601 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11602 || uidRemoved) {
11603 if (checkComponentPermission(
11604 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11605 callingPid, callingUid, -1)
11606 == PackageManager.PERMISSION_GRANTED) {
11607 if (uidRemoved) {
11608 final Bundle intentExtras = intent.getExtras();
11609 final int uid = intentExtras != null
11610 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11611 if (uid >= 0) {
11612 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11613 synchronized (bs) {
11614 bs.removeUidStatsLocked(uid);
11615 }
11616 }
11617 } else {
11618 Uri data = intent.getData();
11619 String ssp;
11620 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11621 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11622 uninstallPackageLocked(ssp,
11623 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011624 AttributeCache ac = AttributeCache.instance();
11625 if (ac != null) {
11626 ac.removePackage(ssp);
11627 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011628 }
11629 }
11630 }
11631 } else {
11632 String msg = "Permission Denial: " + intent.getAction()
11633 + " broadcast from " + callerPackage + " (pid=" + callingPid
11634 + ", uid=" + callingUid + ")"
11635 + " requires "
11636 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11637 Log.w(TAG, msg);
11638 throw new SecurityException(msg);
11639 }
11640 }
11641
11642 /*
11643 * If this is the time zone changed action, queue up a message that will reset the timezone
11644 * of all currently running processes. This message will get queued up before the broadcast
11645 * happens.
11646 */
11647 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11648 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11649 }
11650
Dianne Hackborn854060af2009-07-09 18:14:31 -070011651 /*
11652 * Prevent non-system code (defined here to be non-persistent
11653 * processes) from sending protected broadcasts.
11654 */
11655 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11656 || callingUid == Process.SHELL_UID || callingUid == 0) {
11657 // Always okay.
11658 } else if (callerApp == null || !callerApp.persistent) {
11659 try {
11660 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11661 intent.getAction())) {
11662 String msg = "Permission Denial: not allowed to send broadcast "
11663 + intent.getAction() + " from pid="
11664 + callingPid + ", uid=" + callingUid;
11665 Log.w(TAG, msg);
11666 throw new SecurityException(msg);
11667 }
11668 } catch (RemoteException e) {
11669 Log.w(TAG, "Remote exception", e);
11670 return BROADCAST_SUCCESS;
11671 }
11672 }
11673
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011674 // Add to the sticky list if requested.
11675 if (sticky) {
11676 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11677 callingPid, callingUid)
11678 != PackageManager.PERMISSION_GRANTED) {
11679 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11680 + callingPid + ", uid=" + callingUid
11681 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11682 Log.w(TAG, msg);
11683 throw new SecurityException(msg);
11684 }
11685 if (requiredPermission != null) {
11686 Log.w(TAG, "Can't broadcast sticky intent " + intent
11687 + " and enforce permission " + requiredPermission);
11688 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11689 }
11690 if (intent.getComponent() != null) {
11691 throw new SecurityException(
11692 "Sticky broadcasts can't target a specific component");
11693 }
11694 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11695 if (list == null) {
11696 list = new ArrayList<Intent>();
11697 mStickyBroadcasts.put(intent.getAction(), list);
11698 }
11699 int N = list.size();
11700 int i;
11701 for (i=0; i<N; i++) {
11702 if (intent.filterEquals(list.get(i))) {
11703 // This sticky already exists, replace it.
11704 list.set(i, new Intent(intent));
11705 break;
11706 }
11707 }
11708 if (i >= N) {
11709 list.add(new Intent(intent));
11710 }
11711 }
11712
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011713 // Figure out who all will receive this broadcast.
11714 List receivers = null;
11715 List<BroadcastFilter> registeredReceivers = null;
11716 try {
11717 if (intent.getComponent() != null) {
11718 // Broadcast is going to one specific receiver class...
11719 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011720 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011721 if (ai != null) {
11722 receivers = new ArrayList();
11723 ResolveInfo ri = new ResolveInfo();
11724 ri.activityInfo = ai;
11725 receivers.add(ri);
11726 }
11727 } else {
11728 // Need to resolve the intent to interested receivers...
11729 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11730 == 0) {
11731 receivers =
11732 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011733 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011734 }
Mihai Preda074edef2009-05-18 17:13:31 +020011735 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011736 }
11737 } catch (RemoteException ex) {
11738 // pm is in same process, this will never happen.
11739 }
11740
11741 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11742 if (!ordered && NR > 0) {
11743 // If we are not serializing this broadcast, then send the
11744 // registered receivers separately so they don't wait for the
11745 // components to be launched.
11746 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11747 callerPackage, callingPid, callingUid, requiredPermission,
11748 registeredReceivers, resultTo, resultCode, resultData, map,
11749 ordered);
11750 if (DEBUG_BROADCAST) Log.v(
11751 TAG, "Enqueueing parallel broadcast " + r
11752 + ": prev had " + mParallelBroadcasts.size());
11753 mParallelBroadcasts.add(r);
11754 scheduleBroadcastsLocked();
11755 registeredReceivers = null;
11756 NR = 0;
11757 }
11758
11759 // Merge into one list.
11760 int ir = 0;
11761 if (receivers != null) {
11762 // A special case for PACKAGE_ADDED: do not allow the package
11763 // being added to see this broadcast. This prevents them from
11764 // using this as a back door to get run as soon as they are
11765 // installed. Maybe in the future we want to have a special install
11766 // broadcast or such for apps, but we'd like to deliberately make
11767 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011768 boolean skip = false;
11769 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011770 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011771 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11772 skip = true;
11773 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11774 skip = true;
11775 }
11776 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011777 ? intent.getData().getSchemeSpecificPart()
11778 : null;
11779 if (skipPackage != null && receivers != null) {
11780 int NT = receivers.size();
11781 for (int it=0; it<NT; it++) {
11782 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11783 if (curt.activityInfo.packageName.equals(skipPackage)) {
11784 receivers.remove(it);
11785 it--;
11786 NT--;
11787 }
11788 }
11789 }
11790
11791 int NT = receivers != null ? receivers.size() : 0;
11792 int it = 0;
11793 ResolveInfo curt = null;
11794 BroadcastFilter curr = null;
11795 while (it < NT && ir < NR) {
11796 if (curt == null) {
11797 curt = (ResolveInfo)receivers.get(it);
11798 }
11799 if (curr == null) {
11800 curr = registeredReceivers.get(ir);
11801 }
11802 if (curr.getPriority() >= curt.priority) {
11803 // Insert this broadcast record into the final list.
11804 receivers.add(it, curr);
11805 ir++;
11806 curr = null;
11807 it++;
11808 NT++;
11809 } else {
11810 // Skip to the next ResolveInfo in the final list.
11811 it++;
11812 curt = null;
11813 }
11814 }
11815 }
11816 while (ir < NR) {
11817 if (receivers == null) {
11818 receivers = new ArrayList();
11819 }
11820 receivers.add(registeredReceivers.get(ir));
11821 ir++;
11822 }
11823
11824 if ((receivers != null && receivers.size() > 0)
11825 || resultTo != null) {
11826 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11827 callerPackage, callingPid, callingUid, requiredPermission,
11828 receivers, resultTo, resultCode, resultData, map, ordered);
11829 if (DEBUG_BROADCAST) Log.v(
11830 TAG, "Enqueueing ordered broadcast " + r
11831 + ": prev had " + mOrderedBroadcasts.size());
11832 if (DEBUG_BROADCAST) {
11833 int seq = r.intent.getIntExtra("seq", -1);
11834 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11835 }
11836 mOrderedBroadcasts.add(r);
11837 scheduleBroadcastsLocked();
11838 }
11839
11840 return BROADCAST_SUCCESS;
11841 }
11842
11843 public final int broadcastIntent(IApplicationThread caller,
11844 Intent intent, String resolvedType, IIntentReceiver resultTo,
11845 int resultCode, String resultData, Bundle map,
11846 String requiredPermission, boolean serialized, boolean sticky) {
11847 // Refuse possible leaked file descriptors
11848 if (intent != null && intent.hasFileDescriptors() == true) {
11849 throw new IllegalArgumentException("File descriptors passed in Intent");
11850 }
11851
11852 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011853 int flags = intent.getFlags();
11854
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011855 if (!mSystemReady) {
11856 // if the caller really truly claims to know what they're doing, go
11857 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011858 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11859 intent = new Intent(intent);
11860 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11861 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11862 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11863 + " before boot completion");
11864 throw new IllegalStateException("Cannot broadcast before boot completed");
11865 }
11866 }
11867
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011868 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
11869 throw new IllegalArgumentException(
11870 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
11871 }
11872
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011873 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11874 final int callingPid = Binder.getCallingPid();
11875 final int callingUid = Binder.getCallingUid();
11876 final long origId = Binder.clearCallingIdentity();
11877 int res = broadcastIntentLocked(callerApp,
11878 callerApp != null ? callerApp.info.packageName : null,
11879 intent, resolvedType, resultTo,
11880 resultCode, resultData, map, requiredPermission, serialized,
11881 sticky, callingPid, callingUid);
11882 Binder.restoreCallingIdentity(origId);
11883 return res;
11884 }
11885 }
11886
11887 int broadcastIntentInPackage(String packageName, int uid,
11888 Intent intent, String resolvedType, IIntentReceiver resultTo,
11889 int resultCode, String resultData, Bundle map,
11890 String requiredPermission, boolean serialized, boolean sticky) {
11891 synchronized(this) {
11892 final long origId = Binder.clearCallingIdentity();
11893 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11894 resultTo, resultCode, resultData, map, requiredPermission,
11895 serialized, sticky, -1, uid);
11896 Binder.restoreCallingIdentity(origId);
11897 return res;
11898 }
11899 }
11900
11901 public final void unbroadcastIntent(IApplicationThread caller,
11902 Intent intent) {
11903 // Refuse possible leaked file descriptors
11904 if (intent != null && intent.hasFileDescriptors() == true) {
11905 throw new IllegalArgumentException("File descriptors passed in Intent");
11906 }
11907
11908 synchronized(this) {
11909 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11910 != PackageManager.PERMISSION_GRANTED) {
11911 String msg = "Permission Denial: unbroadcastIntent() from pid="
11912 + Binder.getCallingPid()
11913 + ", uid=" + Binder.getCallingUid()
11914 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11915 Log.w(TAG, msg);
11916 throw new SecurityException(msg);
11917 }
11918 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11919 if (list != null) {
11920 int N = list.size();
11921 int i;
11922 for (i=0; i<N; i++) {
11923 if (intent.filterEquals(list.get(i))) {
11924 list.remove(i);
11925 break;
11926 }
11927 }
11928 }
11929 }
11930 }
11931
11932 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11933 String resultData, Bundle resultExtras, boolean resultAbort,
11934 boolean explicit) {
11935 if (mOrderedBroadcasts.size() == 0) {
11936 if (explicit) {
11937 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11938 }
11939 return false;
11940 }
11941 BroadcastRecord r = mOrderedBroadcasts.get(0);
11942 if (r.receiver == null) {
11943 if (explicit) {
11944 Log.w(TAG, "finishReceiver called but none active");
11945 }
11946 return false;
11947 }
11948 if (r.receiver != receiver) {
11949 Log.w(TAG, "finishReceiver called but active receiver is different");
11950 return false;
11951 }
11952 int state = r.state;
11953 r.state = r.IDLE;
11954 if (state == r.IDLE) {
11955 if (explicit) {
11956 Log.w(TAG, "finishReceiver called but state is IDLE");
11957 }
11958 }
11959 r.receiver = null;
11960 r.intent.setComponent(null);
11961 if (r.curApp != null) {
11962 r.curApp.curReceiver = null;
11963 }
11964 if (r.curFilter != null) {
11965 r.curFilter.receiverList.curBroadcast = null;
11966 }
11967 r.curFilter = null;
11968 r.curApp = null;
11969 r.curComponent = null;
11970 r.curReceiver = null;
11971 mPendingBroadcast = null;
11972
11973 r.resultCode = resultCode;
11974 r.resultData = resultData;
11975 r.resultExtras = resultExtras;
11976 r.resultAbort = resultAbort;
11977
11978 // We will process the next receiver right now if this is finishing
11979 // an app receiver (which is always asynchronous) or after we have
11980 // come back from calling a receiver.
11981 return state == BroadcastRecord.APP_RECEIVE
11982 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11983 }
11984
11985 public void finishReceiver(IBinder who, int resultCode, String resultData,
11986 Bundle resultExtras, boolean resultAbort) {
11987 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11988
11989 // Refuse possible leaked file descriptors
11990 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11991 throw new IllegalArgumentException("File descriptors passed in Bundle");
11992 }
11993
11994 boolean doNext;
11995
11996 final long origId = Binder.clearCallingIdentity();
11997
11998 synchronized(this) {
11999 doNext = finishReceiverLocked(
12000 who, resultCode, resultData, resultExtras, resultAbort, true);
12001 }
12002
12003 if (doNext) {
12004 processNextBroadcast(false);
12005 }
12006 trimApplications();
12007
12008 Binder.restoreCallingIdentity(origId);
12009 }
12010
12011 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12012 if (r.nextReceiver > 0) {
12013 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12014 if (curReceiver instanceof BroadcastFilter) {
12015 BroadcastFilter bf = (BroadcastFilter) curReceiver;
12016 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
12017 System.identityHashCode(r),
12018 r.intent.getAction(),
12019 r.nextReceiver - 1,
12020 System.identityHashCode(bf));
12021 } else {
12022 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12023 System.identityHashCode(r),
12024 r.intent.getAction(),
12025 r.nextReceiver - 1,
12026 ((ResolveInfo)curReceiver).toString());
12027 }
12028 } else {
12029 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12030 + r);
12031 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12032 System.identityHashCode(r),
12033 r.intent.getAction(),
12034 r.nextReceiver,
12035 "NONE");
12036 }
12037 }
12038
12039 private final void broadcastTimeout() {
12040 synchronized (this) {
12041 if (mOrderedBroadcasts.size() == 0) {
12042 return;
12043 }
12044 long now = SystemClock.uptimeMillis();
12045 BroadcastRecord r = mOrderedBroadcasts.get(0);
12046 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
12047 if (DEBUG_BROADCAST) Log.v(TAG,
12048 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
12049 + (r.startTime + BROADCAST_TIMEOUT));
12050 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12051 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12052 return;
12053 }
12054
12055 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
12056 r.startTime = now;
12057 r.anrCount++;
12058
12059 // Current receiver has passed its expiration date.
12060 if (r.nextReceiver <= 0) {
12061 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12062 return;
12063 }
12064
12065 ProcessRecord app = null;
12066
12067 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12068 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12069 logBroadcastReceiverDiscard(r);
12070 if (curReceiver instanceof BroadcastFilter) {
12071 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12072 if (bf.receiverList.pid != 0
12073 && bf.receiverList.pid != MY_PID) {
12074 synchronized (this.mPidsSelfLocked) {
12075 app = this.mPidsSelfLocked.get(
12076 bf.receiverList.pid);
12077 }
12078 }
12079 } else {
12080 app = r.curApp;
12081 }
12082
12083 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070012084 appNotRespondingLocked(app, null, null,
12085 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012086 }
12087
12088 if (mPendingBroadcast == r) {
12089 mPendingBroadcast = null;
12090 }
12091
12092 // Move on to the next receiver.
12093 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12094 r.resultExtras, r.resultAbort, true);
12095 scheduleBroadcastsLocked();
12096 }
12097 }
12098
12099 private final void processCurBroadcastLocked(BroadcastRecord r,
12100 ProcessRecord app) throws RemoteException {
12101 if (app.thread == null) {
12102 throw new RemoteException();
12103 }
12104 r.receiver = app.thread.asBinder();
12105 r.curApp = app;
12106 app.curReceiver = r;
12107 updateLRUListLocked(app, true);
12108
12109 // Tell the application to launch this receiver.
12110 r.intent.setComponent(r.curComponent);
12111
12112 boolean started = false;
12113 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012114 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012115 "Delivering to component " + r.curComponent
12116 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012117 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012118 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12119 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12120 started = true;
12121 } finally {
12122 if (!started) {
12123 r.receiver = null;
12124 r.curApp = null;
12125 app.curReceiver = null;
12126 }
12127 }
12128
12129 }
12130
12131 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
12132 Intent intent, int resultCode, String data,
12133 Bundle extras, boolean ordered) throws RemoteException {
12134 if (app != null && app.thread != null) {
12135 // If we have an app thread, do the call through that so it is
12136 // correctly ordered with other one-way calls.
12137 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
12138 data, extras, ordered);
12139 } else {
12140 receiver.performReceive(intent, resultCode, data, extras, ordered);
12141 }
12142 }
12143
12144 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12145 BroadcastFilter filter, boolean ordered) {
12146 boolean skip = false;
12147 if (filter.requiredPermission != null) {
12148 int perm = checkComponentPermission(filter.requiredPermission,
12149 r.callingPid, r.callingUid, -1);
12150 if (perm != PackageManager.PERMISSION_GRANTED) {
12151 Log.w(TAG, "Permission Denial: broadcasting "
12152 + r.intent.toString()
12153 + " from " + r.callerPackage + " (pid="
12154 + r.callingPid + ", uid=" + r.callingUid + ")"
12155 + " requires " + filter.requiredPermission
12156 + " due to registered receiver " + filter);
12157 skip = true;
12158 }
12159 }
12160 if (r.requiredPermission != null) {
12161 int perm = checkComponentPermission(r.requiredPermission,
12162 filter.receiverList.pid, filter.receiverList.uid, -1);
12163 if (perm != PackageManager.PERMISSION_GRANTED) {
12164 Log.w(TAG, "Permission Denial: receiving "
12165 + r.intent.toString()
12166 + " to " + filter.receiverList.app
12167 + " (pid=" + filter.receiverList.pid
12168 + ", uid=" + filter.receiverList.uid + ")"
12169 + " requires " + r.requiredPermission
12170 + " due to sender " + r.callerPackage
12171 + " (uid " + r.callingUid + ")");
12172 skip = true;
12173 }
12174 }
12175
12176 if (!skip) {
12177 // If this is not being sent as an ordered broadcast, then we
12178 // don't want to touch the fields that keep track of the current
12179 // state of ordered broadcasts.
12180 if (ordered) {
12181 r.receiver = filter.receiverList.receiver.asBinder();
12182 r.curFilter = filter;
12183 filter.receiverList.curBroadcast = r;
12184 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012185 if (filter.receiverList.app != null) {
12186 // Bump hosting application to no longer be in background
12187 // scheduling class. Note that we can't do that if there
12188 // isn't an app... but we can only be in that case for
12189 // things that directly call the IActivityManager API, which
12190 // are already core system stuff so don't matter for this.
12191 r.curApp = filter.receiverList.app;
12192 filter.receiverList.app.curReceiver = r;
12193 updateOomAdjLocked();
12194 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012195 }
12196 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012197 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012198 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012199 Log.i(TAG, "Delivering to " + filter.receiverList.app
12200 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012201 }
12202 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12203 new Intent(r.intent), r.resultCode,
12204 r.resultData, r.resultExtras, r.ordered);
12205 if (ordered) {
12206 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12207 }
12208 } catch (RemoteException e) {
12209 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12210 if (ordered) {
12211 r.receiver = null;
12212 r.curFilter = null;
12213 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012214 if (filter.receiverList.app != null) {
12215 filter.receiverList.app.curReceiver = null;
12216 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012217 }
12218 }
12219 }
12220 }
12221
12222 private final void processNextBroadcast(boolean fromMsg) {
12223 synchronized(this) {
12224 BroadcastRecord r;
12225
12226 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12227 + mParallelBroadcasts.size() + " broadcasts, "
12228 + mOrderedBroadcasts.size() + " serialized broadcasts");
12229
12230 updateCpuStats();
12231
12232 if (fromMsg) {
12233 mBroadcastsScheduled = false;
12234 }
12235
12236 // First, deliver any non-serialized broadcasts right away.
12237 while (mParallelBroadcasts.size() > 0) {
12238 r = mParallelBroadcasts.remove(0);
12239 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012240 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12241 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012242 for (int i=0; i<N; i++) {
12243 Object target = r.receivers.get(i);
12244 if (DEBUG_BROADCAST) Log.v(TAG,
12245 "Delivering non-serialized to registered "
12246 + target + ": " + r);
12247 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12248 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012249 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12250 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012251 }
12252
12253 // Now take care of the next serialized one...
12254
12255 // If we are waiting for a process to come up to handle the next
12256 // broadcast, then do nothing at this point. Just in case, we
12257 // check that the process we're waiting for still exists.
12258 if (mPendingBroadcast != null) {
12259 Log.i(TAG, "processNextBroadcast: waiting for "
12260 + mPendingBroadcast.curApp);
12261
12262 boolean isDead;
12263 synchronized (mPidsSelfLocked) {
12264 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12265 }
12266 if (!isDead) {
12267 // It's still alive, so keep waiting
12268 return;
12269 } else {
12270 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12271 + " died before responding to broadcast");
12272 mPendingBroadcast = null;
12273 }
12274 }
12275
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012276 boolean looped = false;
12277
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012278 do {
12279 if (mOrderedBroadcasts.size() == 0) {
12280 // No more broadcasts pending, so all done!
12281 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012282 if (looped) {
12283 // If we had finished the last ordered broadcast, then
12284 // make sure all processes have correct oom and sched
12285 // adjustments.
12286 updateOomAdjLocked();
12287 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012288 return;
12289 }
12290 r = mOrderedBroadcasts.get(0);
12291 boolean forceReceive = false;
12292
12293 // Ensure that even if something goes awry with the timeout
12294 // detection, we catch "hung" broadcasts here, discard them,
12295 // and continue to make progress.
12296 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12297 long now = SystemClock.uptimeMillis();
12298 if (r.dispatchTime > 0) {
12299 if ((numReceivers > 0) &&
12300 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12301 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12302 + " now=" + now
12303 + " dispatchTime=" + r.dispatchTime
12304 + " startTime=" + r.startTime
12305 + " intent=" + r.intent
12306 + " numReceivers=" + numReceivers
12307 + " nextReceiver=" + r.nextReceiver
12308 + " state=" + r.state);
12309 broadcastTimeout(); // forcibly finish this broadcast
12310 forceReceive = true;
12311 r.state = BroadcastRecord.IDLE;
12312 }
12313 }
12314
12315 if (r.state != BroadcastRecord.IDLE) {
12316 if (DEBUG_BROADCAST) Log.d(TAG,
12317 "processNextBroadcast() called when not idle (state="
12318 + r.state + ")");
12319 return;
12320 }
12321
12322 if (r.receivers == null || r.nextReceiver >= numReceivers
12323 || r.resultAbort || forceReceive) {
12324 // No more receivers for this broadcast! Send the final
12325 // result if requested...
12326 if (r.resultTo != null) {
12327 try {
12328 if (DEBUG_BROADCAST) {
12329 int seq = r.intent.getIntExtra("seq", -1);
12330 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12331 + " seq=" + seq + " app=" + r.callerApp);
12332 }
12333 performReceive(r.callerApp, r.resultTo,
12334 new Intent(r.intent), r.resultCode,
12335 r.resultData, r.resultExtras, false);
12336 } catch (RemoteException e) {
12337 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12338 }
12339 }
12340
12341 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12342 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12343
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012344 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12345 + r);
12346
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012347 // ... and on to the next...
12348 mOrderedBroadcasts.remove(0);
12349 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012350 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012351 continue;
12352 }
12353 } while (r == null);
12354
12355 // Get the next receiver...
12356 int recIdx = r.nextReceiver++;
12357
12358 // Keep track of when this receiver started, and make sure there
12359 // is a timeout message pending to kill it if need be.
12360 r.startTime = SystemClock.uptimeMillis();
12361 if (recIdx == 0) {
12362 r.dispatchTime = r.startTime;
12363
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012364 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12365 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012366 if (DEBUG_BROADCAST) Log.v(TAG,
12367 "Submitting BROADCAST_TIMEOUT_MSG for "
12368 + (r.startTime + BROADCAST_TIMEOUT));
12369 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12370 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12371 }
12372
12373 Object nextReceiver = r.receivers.get(recIdx);
12374 if (nextReceiver instanceof BroadcastFilter) {
12375 // Simple case: this is a registered receiver who gets
12376 // a direct call.
12377 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12378 if (DEBUG_BROADCAST) Log.v(TAG,
12379 "Delivering serialized to registered "
12380 + filter + ": " + r);
12381 deliverToRegisteredReceiver(r, filter, r.ordered);
12382 if (r.receiver == null || !r.ordered) {
12383 // The receiver has already finished, so schedule to
12384 // process the next one.
12385 r.state = BroadcastRecord.IDLE;
12386 scheduleBroadcastsLocked();
12387 }
12388 return;
12389 }
12390
12391 // Hard case: need to instantiate the receiver, possibly
12392 // starting its application process to host it.
12393
12394 ResolveInfo info =
12395 (ResolveInfo)nextReceiver;
12396
12397 boolean skip = false;
12398 int perm = checkComponentPermission(info.activityInfo.permission,
12399 r.callingPid, r.callingUid,
12400 info.activityInfo.exported
12401 ? -1 : info.activityInfo.applicationInfo.uid);
12402 if (perm != PackageManager.PERMISSION_GRANTED) {
12403 Log.w(TAG, "Permission Denial: broadcasting "
12404 + r.intent.toString()
12405 + " from " + r.callerPackage + " (pid=" + r.callingPid
12406 + ", uid=" + r.callingUid + ")"
12407 + " requires " + info.activityInfo.permission
12408 + " due to receiver " + info.activityInfo.packageName
12409 + "/" + info.activityInfo.name);
12410 skip = true;
12411 }
12412 if (r.callingUid != Process.SYSTEM_UID &&
12413 r.requiredPermission != null) {
12414 try {
12415 perm = ActivityThread.getPackageManager().
12416 checkPermission(r.requiredPermission,
12417 info.activityInfo.applicationInfo.packageName);
12418 } catch (RemoteException e) {
12419 perm = PackageManager.PERMISSION_DENIED;
12420 }
12421 if (perm != PackageManager.PERMISSION_GRANTED) {
12422 Log.w(TAG, "Permission Denial: receiving "
12423 + r.intent + " to "
12424 + info.activityInfo.applicationInfo.packageName
12425 + " requires " + r.requiredPermission
12426 + " due to sender " + r.callerPackage
12427 + " (uid " + r.callingUid + ")");
12428 skip = true;
12429 }
12430 }
12431 if (r.curApp != null && r.curApp.crashing) {
12432 // If the target process is crashing, just skip it.
12433 skip = true;
12434 }
12435
12436 if (skip) {
12437 r.receiver = null;
12438 r.curFilter = null;
12439 r.state = BroadcastRecord.IDLE;
12440 scheduleBroadcastsLocked();
12441 return;
12442 }
12443
12444 r.state = BroadcastRecord.APP_RECEIVE;
12445 String targetProcess = info.activityInfo.processName;
12446 r.curComponent = new ComponentName(
12447 info.activityInfo.applicationInfo.packageName,
12448 info.activityInfo.name);
12449 r.curReceiver = info.activityInfo;
12450
12451 // Is this receiver's application already running?
12452 ProcessRecord app = getProcessRecordLocked(targetProcess,
12453 info.activityInfo.applicationInfo.uid);
12454 if (app != null && app.thread != null) {
12455 try {
12456 processCurBroadcastLocked(r, app);
12457 return;
12458 } catch (RemoteException e) {
12459 Log.w(TAG, "Exception when sending broadcast to "
12460 + r.curComponent, e);
12461 }
12462
12463 // If a dead object exception was thrown -- fall through to
12464 // restart the application.
12465 }
12466
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012467 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012468 if ((r.curApp=startProcessLocked(targetProcess,
12469 info.activityInfo.applicationInfo, true,
12470 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012471 "broadcast", r.curComponent,
12472 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12473 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012474 // Ah, this recipient is unavailable. Finish it if necessary,
12475 // and mark the broadcast record as ready for the next.
12476 Log.w(TAG, "Unable to launch app "
12477 + info.activityInfo.applicationInfo.packageName + "/"
12478 + info.activityInfo.applicationInfo.uid + " for broadcast "
12479 + r.intent + ": process is bad");
12480 logBroadcastReceiverDiscard(r);
12481 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12482 r.resultExtras, r.resultAbort, true);
12483 scheduleBroadcastsLocked();
12484 r.state = BroadcastRecord.IDLE;
12485 return;
12486 }
12487
12488 mPendingBroadcast = r;
12489 }
12490 }
12491
12492 // =========================================================
12493 // INSTRUMENTATION
12494 // =========================================================
12495
12496 public boolean startInstrumentation(ComponentName className,
12497 String profileFile, int flags, Bundle arguments,
12498 IInstrumentationWatcher watcher) {
12499 // Refuse possible leaked file descriptors
12500 if (arguments != null && arguments.hasFileDescriptors()) {
12501 throw new IllegalArgumentException("File descriptors passed in Bundle");
12502 }
12503
12504 synchronized(this) {
12505 InstrumentationInfo ii = null;
12506 ApplicationInfo ai = null;
12507 try {
12508 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012509 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012510 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012511 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012512 } catch (PackageManager.NameNotFoundException e) {
12513 }
12514 if (ii == null) {
12515 reportStartInstrumentationFailure(watcher, className,
12516 "Unable to find instrumentation info for: " + className);
12517 return false;
12518 }
12519 if (ai == null) {
12520 reportStartInstrumentationFailure(watcher, className,
12521 "Unable to find instrumentation target package: " + ii.targetPackage);
12522 return false;
12523 }
12524
12525 int match = mContext.getPackageManager().checkSignatures(
12526 ii.targetPackage, ii.packageName);
12527 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12528 String msg = "Permission Denial: starting instrumentation "
12529 + className + " from pid="
12530 + Binder.getCallingPid()
12531 + ", uid=" + Binder.getCallingPid()
12532 + " not allowed because package " + ii.packageName
12533 + " does not have a signature matching the target "
12534 + ii.targetPackage;
12535 reportStartInstrumentationFailure(watcher, className, msg);
12536 throw new SecurityException(msg);
12537 }
12538
12539 final long origId = Binder.clearCallingIdentity();
12540 uninstallPackageLocked(ii.targetPackage, -1, true);
12541 ProcessRecord app = addAppLocked(ai);
12542 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012543 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012544 app.instrumentationProfileFile = profileFile;
12545 app.instrumentationArguments = arguments;
12546 app.instrumentationWatcher = watcher;
12547 app.instrumentationResultClass = className;
12548 Binder.restoreCallingIdentity(origId);
12549 }
12550
12551 return true;
12552 }
12553
12554 /**
12555 * Report errors that occur while attempting to start Instrumentation. Always writes the
12556 * error to the logs, but if somebody is watching, send the report there too. This enables
12557 * the "am" command to report errors with more information.
12558 *
12559 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12560 * @param cn The component name of the instrumentation.
12561 * @param report The error report.
12562 */
12563 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12564 ComponentName cn, String report) {
12565 Log.w(TAG, report);
12566 try {
12567 if (watcher != null) {
12568 Bundle results = new Bundle();
12569 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12570 results.putString("Error", report);
12571 watcher.instrumentationStatus(cn, -1, results);
12572 }
12573 } catch (RemoteException e) {
12574 Log.w(TAG, e);
12575 }
12576 }
12577
12578 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12579 if (app.instrumentationWatcher != null) {
12580 try {
12581 // NOTE: IInstrumentationWatcher *must* be oneway here
12582 app.instrumentationWatcher.instrumentationFinished(
12583 app.instrumentationClass,
12584 resultCode,
12585 results);
12586 } catch (RemoteException e) {
12587 }
12588 }
12589 app.instrumentationWatcher = null;
12590 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012591 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012592 app.instrumentationProfileFile = null;
12593 app.instrumentationArguments = null;
12594
12595 uninstallPackageLocked(app.processName, -1, false);
12596 }
12597
12598 public void finishInstrumentation(IApplicationThread target,
12599 int resultCode, Bundle results) {
12600 // Refuse possible leaked file descriptors
12601 if (results != null && results.hasFileDescriptors()) {
12602 throw new IllegalArgumentException("File descriptors passed in Intent");
12603 }
12604
12605 synchronized(this) {
12606 ProcessRecord app = getRecordForAppLocked(target);
12607 if (app == null) {
12608 Log.w(TAG, "finishInstrumentation: no app for " + target);
12609 return;
12610 }
12611 final long origId = Binder.clearCallingIdentity();
12612 finishInstrumentationLocked(app, resultCode, results);
12613 Binder.restoreCallingIdentity(origId);
12614 }
12615 }
12616
12617 // =========================================================
12618 // CONFIGURATION
12619 // =========================================================
12620
12621 public ConfigurationInfo getDeviceConfigurationInfo() {
12622 ConfigurationInfo config = new ConfigurationInfo();
12623 synchronized (this) {
12624 config.reqTouchScreen = mConfiguration.touchscreen;
12625 config.reqKeyboardType = mConfiguration.keyboard;
12626 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012627 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12628 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012629 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12630 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012631 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12632 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012633 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12634 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012635 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012636 }
12637 return config;
12638 }
12639
12640 public Configuration getConfiguration() {
12641 Configuration ci;
12642 synchronized(this) {
12643 ci = new Configuration(mConfiguration);
12644 }
12645 return ci;
12646 }
12647
12648 public void updateConfiguration(Configuration values) {
12649 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12650 "updateConfiguration()");
12651
12652 synchronized(this) {
12653 if (values == null && mWindowManager != null) {
12654 // sentinel: fetch the current configuration from the window manager
12655 values = mWindowManager.computeNewConfiguration();
12656 }
12657
12658 final long origId = Binder.clearCallingIdentity();
12659 updateConfigurationLocked(values, null);
12660 Binder.restoreCallingIdentity(origId);
12661 }
12662 }
12663
12664 /**
12665 * Do either or both things: (1) change the current configuration, and (2)
12666 * make sure the given activity is running with the (now) current
12667 * configuration. Returns true if the activity has been left running, or
12668 * false if <var>starting</var> is being destroyed to match the new
12669 * configuration.
12670 */
12671 public boolean updateConfigurationLocked(Configuration values,
12672 HistoryRecord starting) {
12673 int changes = 0;
12674
12675 boolean kept = true;
12676
12677 if (values != null) {
12678 Configuration newConfig = new Configuration(mConfiguration);
12679 changes = newConfig.updateFrom(values);
12680 if (changes != 0) {
12681 if (DEBUG_SWITCH) {
12682 Log.i(TAG, "Updating configuration to: " + values);
12683 }
12684
12685 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12686
12687 if (values.locale != null) {
12688 saveLocaleLocked(values.locale,
12689 !values.locale.equals(mConfiguration.locale),
12690 values.userSetLocale);
12691 }
12692
12693 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012694 Log.i(TAG, "Config changed: " + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012695
12696 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12697 msg.obj = new Configuration(mConfiguration);
12698 mHandler.sendMessage(msg);
12699
12700 final int N = mLRUProcesses.size();
12701 for (int i=0; i<N; i++) {
12702 ProcessRecord app = mLRUProcesses.get(i);
12703 try {
12704 if (app.thread != null) {
12705 app.thread.scheduleConfigurationChanged(mConfiguration);
12706 }
12707 } catch (Exception e) {
12708 }
12709 }
12710 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12711 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12712 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012713
12714 AttributeCache ac = AttributeCache.instance();
12715 if (ac != null) {
12716 ac.updateConfiguration(mConfiguration);
12717 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012718 }
12719 }
12720
12721 if (changes != 0 && starting == null) {
12722 // If the configuration changed, and the caller is not already
12723 // in the process of starting an activity, then find the top
12724 // activity to check if its configuration needs to change.
12725 starting = topRunningActivityLocked(null);
12726 }
12727
12728 if (starting != null) {
12729 kept = ensureActivityConfigurationLocked(starting, changes);
12730 if (kept) {
12731 // If this didn't result in the starting activity being
12732 // destroyed, then we need to make sure at this point that all
12733 // other activities are made visible.
12734 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12735 + ", ensuring others are correct.");
12736 ensureActivitiesVisibleLocked(starting, changes);
12737 }
12738 }
12739
12740 return kept;
12741 }
12742
12743 private final boolean relaunchActivityLocked(HistoryRecord r,
12744 int changes, boolean andResume) {
12745 List<ResultInfo> results = null;
12746 List<Intent> newIntents = null;
12747 if (andResume) {
12748 results = r.results;
12749 newIntents = r.newIntents;
12750 }
12751 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12752 + " with results=" + results + " newIntents=" + newIntents
12753 + " andResume=" + andResume);
12754 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12755 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12756 r.task.taskId, r.shortComponentName);
12757
12758 r.startFreezingScreenLocked(r.app, 0);
12759
12760 try {
12761 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12762 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12763 changes, !andResume);
12764 // Note: don't need to call pauseIfSleepingLocked() here, because
12765 // the caller will only pass in 'andResume' if this activity is
12766 // currently resumed, which implies we aren't sleeping.
12767 } catch (RemoteException e) {
12768 return false;
12769 }
12770
12771 if (andResume) {
12772 r.results = null;
12773 r.newIntents = null;
12774 }
12775
12776 return true;
12777 }
12778
12779 /**
12780 * Make sure the given activity matches the current configuration. Returns
12781 * false if the activity had to be destroyed. Returns true if the
12782 * configuration is the same, or the activity will remain running as-is
12783 * for whatever reason. Ensures the HistoryRecord is updated with the
12784 * correct configuration and all other bookkeeping is handled.
12785 */
12786 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12787 int globalChanges) {
12788 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12789
12790 // Short circuit: if the two configurations are the exact same
12791 // object (the common case), then there is nothing to do.
12792 Configuration newConfig = mConfiguration;
12793 if (r.configuration == newConfig) {
12794 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12795 return true;
12796 }
12797
12798 // We don't worry about activities that are finishing.
12799 if (r.finishing) {
12800 if (DEBUG_SWITCH) Log.i(TAG,
12801 "Configuration doesn't matter in finishing " + r);
12802 r.stopFreezingScreenLocked(false);
12803 return true;
12804 }
12805
12806 // Okay we now are going to make this activity have the new config.
12807 // But then we need to figure out how it needs to deal with that.
12808 Configuration oldConfig = r.configuration;
12809 r.configuration = newConfig;
12810
12811 // If the activity isn't currently running, just leave the new
12812 // configuration and it will pick that up next time it starts.
12813 if (r.app == null || r.app.thread == null) {
12814 if (DEBUG_SWITCH) Log.i(TAG,
12815 "Configuration doesn't matter not running " + r);
12816 r.stopFreezingScreenLocked(false);
12817 return true;
12818 }
12819
12820 // If the activity isn't persistent, there is a chance we will
12821 // need to restart it.
12822 if (!r.persistent) {
12823
12824 // Figure out what has changed between the two configurations.
12825 int changes = oldConfig.diff(newConfig);
12826 if (DEBUG_SWITCH) {
12827 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12828 + Integer.toHexString(changes) + ", handles=0x"
12829 + Integer.toHexString(r.info.configChanges));
12830 }
12831 if ((changes&(~r.info.configChanges)) != 0) {
12832 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12833 r.configChangeFlags |= changes;
12834 r.startFreezingScreenLocked(r.app, globalChanges);
12835 if (r.app == null || r.app.thread == null) {
12836 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12837 destroyActivityLocked(r, true);
12838 } else if (r.state == ActivityState.PAUSING) {
12839 // A little annoying: we are waiting for this activity to
12840 // finish pausing. Let's not do anything now, but just
12841 // flag that it needs to be restarted when done pausing.
12842 r.configDestroy = true;
12843 return true;
12844 } else if (r.state == ActivityState.RESUMED) {
12845 // Try to optimize this case: the configuration is changing
12846 // and we need to restart the top, resumed activity.
12847 // Instead of doing the normal handshaking, just say
12848 // "restart!".
12849 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12850 relaunchActivityLocked(r, r.configChangeFlags, true);
12851 r.configChangeFlags = 0;
12852 } else {
12853 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12854 relaunchActivityLocked(r, r.configChangeFlags, false);
12855 r.configChangeFlags = 0;
12856 }
12857
12858 // All done... tell the caller we weren't able to keep this
12859 // activity around.
12860 return false;
12861 }
12862 }
12863
12864 // Default case: the activity can handle this new configuration, so
12865 // hand it over. Note that we don't need to give it the new
12866 // configuration, since we always send configuration changes to all
12867 // process when they happen so it can just use whatever configuration
12868 // it last got.
12869 if (r.app != null && r.app.thread != null) {
12870 try {
12871 r.app.thread.scheduleActivityConfigurationChanged(r);
12872 } catch (RemoteException e) {
12873 // If process died, whatever.
12874 }
12875 }
12876 r.stopFreezingScreenLocked(false);
12877
12878 return true;
12879 }
12880
12881 /**
12882 * Save the locale. You must be inside a synchronized (this) block.
12883 */
12884 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12885 if(isDiff) {
12886 SystemProperties.set("user.language", l.getLanguage());
12887 SystemProperties.set("user.region", l.getCountry());
12888 }
12889
12890 if(isPersist) {
12891 SystemProperties.set("persist.sys.language", l.getLanguage());
12892 SystemProperties.set("persist.sys.country", l.getCountry());
12893 SystemProperties.set("persist.sys.localevar", l.getVariant());
12894 }
12895 }
12896
12897 // =========================================================
12898 // LIFETIME MANAGEMENT
12899 // =========================================================
12900
12901 private final int computeOomAdjLocked(
12902 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12903 if (mAdjSeq == app.adjSeq) {
12904 // This adjustment has already been computed.
12905 return app.curAdj;
12906 }
12907
12908 if (app.thread == null) {
12909 app.adjSeq = mAdjSeq;
12910 return (app.curAdj=EMPTY_APP_ADJ);
12911 }
12912
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012913 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
12914 // The max adjustment doesn't allow this app to be anything
12915 // below foreground, so it is not worth doing work for it.
12916 app.adjType = "fixed";
12917 app.adjSeq = mAdjSeq;
12918 app.curRawAdj = app.maxAdj;
12919 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
12920 return (app.curAdj=app.maxAdj);
12921 }
12922
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070012923 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012924 app.adjSource = null;
12925 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012926
The Android Open Source Project4df24232009-03-05 14:34:35 -080012927 // Determine the importance of the process, starting with most
12928 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012929 int adj;
12930 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012931 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012932 // The last app on the list is the foreground app.
12933 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012934 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012935 } else if (app.instrumentationClass != null) {
12936 // Don't want to kill running instrumentation.
12937 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012938 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012939 } else if (app.persistentActivities > 0) {
12940 // Special persistent activities... shouldn't be used these days.
12941 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012942 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012943 } else if (app.curReceiver != null ||
12944 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12945 // An app that is currently receiving a broadcast also
12946 // counts as being in the foreground.
12947 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012948 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012949 } else if (app.executingServices.size() > 0) {
12950 // An app that is currently executing a service callback also
12951 // counts as being in the foreground.
12952 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012953 app.adjType = "exec-service";
12954 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012955 // The user is aware of this app, so make it visible.
12956 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012957 app.adjType = "foreground-service";
12958 } else if (app.forcingToForeground != null) {
12959 // The user is aware of this app, so make it visible.
12960 adj = VISIBLE_APP_ADJ;
12961 app.adjType = "force-foreground";
12962 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012963 } else if (app == mHomeProcess) {
12964 // This process is hosting what we currently consider to be the
12965 // home app, so we don't want to let it go into the background.
12966 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012967 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012968 } else if ((N=app.activities.size()) != 0) {
12969 // This app is in the background with paused activities.
12970 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012971 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012972 for (int j=0; j<N; j++) {
12973 if (((HistoryRecord)app.activities.get(j)).visible) {
12974 // This app has a visible activity!
12975 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012976 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012977 break;
12978 }
12979 }
12980 } else {
12981 // A very not-needed process.
12982 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012983 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012984 }
12985
The Android Open Source Project4df24232009-03-05 14:34:35 -080012986 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012987 // there are applications dependent on our services or providers, but
12988 // this gives us a baseline and makes sure we don't get into an
12989 // infinite recursion.
12990 app.adjSeq = mAdjSeq;
12991 app.curRawAdj = adj;
12992 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12993
Christopher Tate6fa95972009-06-05 18:43:55 -070012994 if (mBackupTarget != null && app == mBackupTarget.app) {
12995 // If possible we want to avoid killing apps while they're being backed up
12996 if (adj > BACKUP_APP_ADJ) {
12997 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12998 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012999 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070013000 }
13001 }
13002
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013003 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013004 final long now = SystemClock.uptimeMillis();
13005 // This process is more important if the top activity is
13006 // bound to the service.
13007 Iterator jt = app.services.iterator();
13008 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13009 ServiceRecord s = (ServiceRecord)jt.next();
13010 if (s.startRequested) {
13011 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13012 // This service has seen some activity within
13013 // recent memory, so we will keep its process ahead
13014 // of the background processes.
13015 if (adj > SECONDARY_SERVER_ADJ) {
13016 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013017 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013018 }
13019 }
13020 }
13021 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
13022 Iterator<ConnectionRecord> kt
13023 = s.connections.values().iterator();
13024 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13025 // XXX should compute this based on the max of
13026 // all connected clients.
13027 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013028 if (cr.binding.client == app) {
13029 // Binding to ourself is not interesting.
13030 continue;
13031 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013032 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13033 ProcessRecord client = cr.binding.client;
13034 int myHiddenAdj = hiddenAdj;
13035 if (myHiddenAdj > client.hiddenAdj) {
13036 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13037 myHiddenAdj = client.hiddenAdj;
13038 } else {
13039 myHiddenAdj = VISIBLE_APP_ADJ;
13040 }
13041 }
13042 int clientAdj = computeOomAdjLocked(
13043 client, myHiddenAdj, TOP_APP);
13044 if (adj > clientAdj) {
13045 adj = clientAdj > VISIBLE_APP_ADJ
13046 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013047 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013048 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13049 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013050 app.adjSource = cr.binding.client;
13051 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013052 }
13053 }
13054 HistoryRecord a = cr.activity;
13055 //if (a != null) {
13056 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13057 //}
13058 if (a != null && adj > FOREGROUND_APP_ADJ &&
13059 (a.state == ActivityState.RESUMED
13060 || a.state == ActivityState.PAUSING)) {
13061 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013062 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013063 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13064 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013065 app.adjSource = a;
13066 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013067 }
13068 }
13069 }
13070 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013071
13072 // Finally, f this process has active services running in it, we
13073 // would like to avoid killing it unless it would prevent the current
13074 // application from running. By default we put the process in
13075 // with the rest of the background processes; as we scan through
13076 // its services we may bump it up from there.
13077 if (adj > hiddenAdj) {
13078 adj = hiddenAdj;
13079 app.adjType = "bg-services";
13080 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013081 }
13082
13083 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013084 Iterator jt = app.pubProviders.values().iterator();
13085 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13086 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13087 if (cpr.clients.size() != 0) {
13088 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13089 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13090 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013091 if (client == app) {
13092 // Being our own client is not interesting.
13093 continue;
13094 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013095 int myHiddenAdj = hiddenAdj;
13096 if (myHiddenAdj > client.hiddenAdj) {
13097 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13098 myHiddenAdj = client.hiddenAdj;
13099 } else {
13100 myHiddenAdj = FOREGROUND_APP_ADJ;
13101 }
13102 }
13103 int clientAdj = computeOomAdjLocked(
13104 client, myHiddenAdj, TOP_APP);
13105 if (adj > clientAdj) {
13106 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013107 ? clientAdj : FOREGROUND_APP_ADJ;
13108 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013109 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13110 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013111 app.adjSource = client;
13112 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013113 }
13114 }
13115 }
13116 // If the provider has external (non-framework) process
13117 // dependencies, ensure that its adjustment is at least
13118 // FOREGROUND_APP_ADJ.
13119 if (cpr.externals != 0) {
13120 if (adj > FOREGROUND_APP_ADJ) {
13121 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013122 app.adjType = "provider";
13123 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013124 }
13125 }
13126 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013127
13128 // Finally, if this process has published any content providers,
13129 // then its adjustment makes it at least as important as any of the
13130 // processes using those providers, and no less important than
13131 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
13132 if (adj > CONTENT_PROVIDER_ADJ) {
13133 adj = CONTENT_PROVIDER_ADJ;
13134 app.adjType = "pub-providers";
13135 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013136 }
13137
13138 app.curRawAdj = adj;
13139
13140 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13141 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13142 if (adj > app.maxAdj) {
13143 adj = app.maxAdj;
13144 }
13145
13146 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013147 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013148 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
13149 : Process.THREAD_GROUP_DEFAULT;
13150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013151 return adj;
13152 }
13153
13154 /**
13155 * Ask a given process to GC right now.
13156 */
13157 final void performAppGcLocked(ProcessRecord app) {
13158 try {
13159 app.lastRequestedGc = SystemClock.uptimeMillis();
13160 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013161 if (app.reportLowMemory) {
13162 app.reportLowMemory = false;
13163 app.thread.scheduleLowMemory();
13164 } else {
13165 app.thread.processInBackground();
13166 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013167 }
13168 } catch (Exception e) {
13169 // whatever.
13170 }
13171 }
13172
13173 /**
13174 * Returns true if things are idle enough to perform GCs.
13175 */
13176 private final boolean canGcNow() {
13177 return mParallelBroadcasts.size() == 0
13178 && mOrderedBroadcasts.size() == 0
13179 && (mSleeping || (mResumedActivity != null &&
13180 mResumedActivity.idle));
13181 }
13182
13183 /**
13184 * Perform GCs on all processes that are waiting for it, but only
13185 * if things are idle.
13186 */
13187 final void performAppGcsLocked() {
13188 final int N = mProcessesToGc.size();
13189 if (N <= 0) {
13190 return;
13191 }
13192 if (canGcNow()) {
13193 while (mProcessesToGc.size() > 0) {
13194 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013195 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13196 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13197 <= SystemClock.uptimeMillis()) {
13198 // To avoid spamming the system, we will GC processes one
13199 // at a time, waiting a few seconds between each.
13200 performAppGcLocked(proc);
13201 scheduleAppGcsLocked();
13202 return;
13203 } else {
13204 // It hasn't been long enough since we last GCed this
13205 // process... put it in the list to wait for its time.
13206 addProcessToGcListLocked(proc);
13207 break;
13208 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013209 }
13210 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013211
13212 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013213 }
13214 }
13215
13216 /**
13217 * If all looks good, perform GCs on all processes waiting for them.
13218 */
13219 final void performAppGcsIfAppropriateLocked() {
13220 if (canGcNow()) {
13221 performAppGcsLocked();
13222 return;
13223 }
13224 // Still not idle, wait some more.
13225 scheduleAppGcsLocked();
13226 }
13227
13228 /**
13229 * Schedule the execution of all pending app GCs.
13230 */
13231 final void scheduleAppGcsLocked() {
13232 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013233
13234 if (mProcessesToGc.size() > 0) {
13235 // Schedule a GC for the time to the next process.
13236 ProcessRecord proc = mProcessesToGc.get(0);
13237 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13238
13239 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13240 long now = SystemClock.uptimeMillis();
13241 if (when < (now+GC_TIMEOUT)) {
13242 when = now + GC_TIMEOUT;
13243 }
13244 mHandler.sendMessageAtTime(msg, when);
13245 }
13246 }
13247
13248 /**
13249 * Add a process to the array of processes waiting to be GCed. Keeps the
13250 * list in sorted order by the last GC time. The process can't already be
13251 * on the list.
13252 */
13253 final void addProcessToGcListLocked(ProcessRecord proc) {
13254 boolean added = false;
13255 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13256 if (mProcessesToGc.get(i).lastRequestedGc <
13257 proc.lastRequestedGc) {
13258 added = true;
13259 mProcessesToGc.add(i+1, proc);
13260 break;
13261 }
13262 }
13263 if (!added) {
13264 mProcessesToGc.add(0, proc);
13265 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013266 }
13267
13268 /**
13269 * Set up to ask a process to GC itself. This will either do it
13270 * immediately, or put it on the list of processes to gc the next
13271 * time things are idle.
13272 */
13273 final void scheduleAppGcLocked(ProcessRecord app) {
13274 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013275 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013276 return;
13277 }
13278 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013279 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013280 scheduleAppGcsLocked();
13281 }
13282 }
13283
13284 private final boolean updateOomAdjLocked(
13285 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13286 app.hiddenAdj = hiddenAdj;
13287
13288 if (app.thread == null) {
13289 return true;
13290 }
13291
13292 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
13293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013294 if (app.pid != 0 && app.pid != MY_PID) {
13295 if (app.curRawAdj != app.setRawAdj) {
13296 if (app.curRawAdj > FOREGROUND_APP_ADJ
13297 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13298 // If this app is transitioning from foreground to
13299 // non-foreground, have it do a gc.
13300 scheduleAppGcLocked(app);
13301 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13302 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13303 // Likewise do a gc when an app is moving in to the
13304 // background (such as a service stopping).
13305 scheduleAppGcLocked(app);
13306 }
13307 app.setRawAdj = app.curRawAdj;
13308 }
13309 if (adj != app.setAdj) {
13310 if (Process.setOomAdj(app.pid, adj)) {
13311 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13312 TAG, "Set app " + app.processName +
13313 " oom adj to " + adj);
13314 app.setAdj = adj;
13315 } else {
13316 return false;
13317 }
13318 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013319 if (app.setSchedGroup != app.curSchedGroup) {
13320 app.setSchedGroup = app.curSchedGroup;
13321 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13322 "Setting process group of " + app.processName
13323 + " to " + app.curSchedGroup);
13324 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013325 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013326 try {
13327 Process.setProcessGroup(app.pid, app.curSchedGroup);
13328 } catch (Exception e) {
13329 Log.w(TAG, "Failed setting process group of " + app.pid
13330 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013331 e.printStackTrace();
13332 } finally {
13333 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013334 }
13335 }
13336 if (false) {
13337 if (app.thread != null) {
13338 try {
13339 app.thread.setSchedulingGroup(app.curSchedGroup);
13340 } catch (RemoteException e) {
13341 }
13342 }
13343 }
13344 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013345 }
13346
13347 return true;
13348 }
13349
13350 private final HistoryRecord resumedAppLocked() {
13351 HistoryRecord resumedActivity = mResumedActivity;
13352 if (resumedActivity == null || resumedActivity.app == null) {
13353 resumedActivity = mPausingActivity;
13354 if (resumedActivity == null || resumedActivity.app == null) {
13355 resumedActivity = topRunningActivityLocked(null);
13356 }
13357 }
13358 return resumedActivity;
13359 }
13360
13361 private final boolean updateOomAdjLocked(ProcessRecord app) {
13362 final HistoryRecord TOP_ACT = resumedAppLocked();
13363 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13364 int curAdj = app.curAdj;
13365 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13366 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13367
13368 mAdjSeq++;
13369
13370 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13371 if (res) {
13372 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13373 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13374 if (nowHidden != wasHidden) {
13375 // Changed to/from hidden state, so apps after it in the LRU
13376 // list may also be changed.
13377 updateOomAdjLocked();
13378 }
13379 }
13380 return res;
13381 }
13382
13383 private final boolean updateOomAdjLocked() {
13384 boolean didOomAdj = true;
13385 final HistoryRecord TOP_ACT = resumedAppLocked();
13386 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13387
13388 if (false) {
13389 RuntimeException e = new RuntimeException();
13390 e.fillInStackTrace();
13391 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13392 }
13393
13394 mAdjSeq++;
13395
13396 // First try updating the OOM adjustment for each of the
13397 // application processes based on their current state.
13398 int i = mLRUProcesses.size();
13399 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13400 while (i > 0) {
13401 i--;
13402 ProcessRecord app = mLRUProcesses.get(i);
13403 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13404 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13405 && app.curAdj == curHiddenAdj) {
13406 curHiddenAdj++;
13407 }
13408 } else {
13409 didOomAdj = false;
13410 }
13411 }
13412
13413 // todo: for now pretend like OOM ADJ didn't work, because things
13414 // aren't behaving as expected on Linux -- it's not killing processes.
13415 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13416 }
13417
13418 private final void trimApplications() {
13419 synchronized (this) {
13420 int i;
13421
13422 // First remove any unused application processes whose package
13423 // has been removed.
13424 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13425 final ProcessRecord app = mRemovedProcesses.get(i);
13426 if (app.activities.size() == 0
13427 && app.curReceiver == null && app.services.size() == 0) {
13428 Log.i(
13429 TAG, "Exiting empty application process "
13430 + app.processName + " ("
13431 + (app.thread != null ? app.thread.asBinder() : null)
13432 + ")\n");
13433 if (app.pid > 0 && app.pid != MY_PID) {
13434 Process.killProcess(app.pid);
13435 } else {
13436 try {
13437 app.thread.scheduleExit();
13438 } catch (Exception e) {
13439 // Ignore exceptions.
13440 }
13441 }
13442 cleanUpApplicationRecordLocked(app, false, -1);
13443 mRemovedProcesses.remove(i);
13444
13445 if (app.persistent) {
13446 if (app.persistent) {
13447 addAppLocked(app.info);
13448 }
13449 }
13450 }
13451 }
13452
13453 // Now try updating the OOM adjustment for each of the
13454 // application processes based on their current state.
13455 // If the setOomAdj() API is not supported, then go with our
13456 // back-up plan...
13457 if (!updateOomAdjLocked()) {
13458
13459 // Count how many processes are running services.
13460 int numServiceProcs = 0;
13461 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13462 final ProcessRecord app = mLRUProcesses.get(i);
13463
13464 if (app.persistent || app.services.size() != 0
13465 || app.curReceiver != null
13466 || app.persistentActivities > 0) {
13467 // Don't count processes holding services against our
13468 // maximum process count.
13469 if (localLOGV) Log.v(
13470 TAG, "Not trimming app " + app + " with services: "
13471 + app.services);
13472 numServiceProcs++;
13473 }
13474 }
13475
13476 int curMaxProcs = mProcessLimit;
13477 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13478 if (mAlwaysFinishActivities) {
13479 curMaxProcs = 1;
13480 }
13481 curMaxProcs += numServiceProcs;
13482
13483 // Quit as many processes as we can to get down to the desired
13484 // process count. First remove any processes that no longer
13485 // have activites running in them.
13486 for ( i=0;
13487 i<mLRUProcesses.size()
13488 && mLRUProcesses.size() > curMaxProcs;
13489 i++) {
13490 final ProcessRecord app = mLRUProcesses.get(i);
13491 // Quit an application only if it is not currently
13492 // running any activities.
13493 if (!app.persistent && app.activities.size() == 0
13494 && app.curReceiver == null && app.services.size() == 0) {
13495 Log.i(
13496 TAG, "Exiting empty application process "
13497 + app.processName + " ("
13498 + (app.thread != null ? app.thread.asBinder() : null)
13499 + ")\n");
13500 if (app.pid > 0 && app.pid != MY_PID) {
13501 Process.killProcess(app.pid);
13502 } else {
13503 try {
13504 app.thread.scheduleExit();
13505 } catch (Exception e) {
13506 // Ignore exceptions.
13507 }
13508 }
13509 // todo: For now we assume the application is not buggy
13510 // or evil, and will quit as a result of our request.
13511 // Eventually we need to drive this off of the death
13512 // notification, and kill the process if it takes too long.
13513 cleanUpApplicationRecordLocked(app, false, i);
13514 i--;
13515 }
13516 }
13517
13518 // If we still have too many processes, now from the least
13519 // recently used process we start finishing activities.
13520 if (Config.LOGV) Log.v(
13521 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13522 " of " + curMaxProcs + " processes");
13523 for ( i=0;
13524 i<mLRUProcesses.size()
13525 && mLRUProcesses.size() > curMaxProcs;
13526 i++) {
13527 final ProcessRecord app = mLRUProcesses.get(i);
13528 // Quit the application only if we have a state saved for
13529 // all of its activities.
13530 boolean canQuit = !app.persistent && app.curReceiver == null
13531 && app.services.size() == 0
13532 && app.persistentActivities == 0;
13533 int NUMA = app.activities.size();
13534 int j;
13535 if (Config.LOGV) Log.v(
13536 TAG, "Looking to quit " + app.processName);
13537 for (j=0; j<NUMA && canQuit; j++) {
13538 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13539 if (Config.LOGV) Log.v(
13540 TAG, " " + r.intent.getComponent().flattenToShortString()
13541 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13542 canQuit = (r.haveState || !r.stateNotNeeded)
13543 && !r.visible && r.stopped;
13544 }
13545 if (canQuit) {
13546 // Finish all of the activities, and then the app itself.
13547 for (j=0; j<NUMA; j++) {
13548 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13549 if (!r.finishing) {
13550 destroyActivityLocked(r, false);
13551 }
13552 r.resultTo = null;
13553 }
13554 Log.i(TAG, "Exiting application process "
13555 + app.processName + " ("
13556 + (app.thread != null ? app.thread.asBinder() : null)
13557 + ")\n");
13558 if (app.pid > 0 && app.pid != MY_PID) {
13559 Process.killProcess(app.pid);
13560 } else {
13561 try {
13562 app.thread.scheduleExit();
13563 } catch (Exception e) {
13564 // Ignore exceptions.
13565 }
13566 }
13567 // todo: For now we assume the application is not buggy
13568 // or evil, and will quit as a result of our request.
13569 // Eventually we need to drive this off of the death
13570 // notification, and kill the process if it takes too long.
13571 cleanUpApplicationRecordLocked(app, false, i);
13572 i--;
13573 //dump();
13574 }
13575 }
13576
13577 }
13578
13579 int curMaxActivities = MAX_ACTIVITIES;
13580 if (mAlwaysFinishActivities) {
13581 curMaxActivities = 1;
13582 }
13583
13584 // Finally, if there are too many activities now running, try to
13585 // finish as many as we can to get back down to the limit.
13586 for ( i=0;
13587 i<mLRUActivities.size()
13588 && mLRUActivities.size() > curMaxActivities;
13589 i++) {
13590 final HistoryRecord r
13591 = (HistoryRecord)mLRUActivities.get(i);
13592
13593 // We can finish this one if we have its icicle saved and
13594 // it is not persistent.
13595 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13596 && r.stopped && !r.persistent && !r.finishing) {
13597 final int origSize = mLRUActivities.size();
13598 destroyActivityLocked(r, true);
13599
13600 // This will remove it from the LRU list, so keep
13601 // our index at the same value. Note that this check to
13602 // see if the size changes is just paranoia -- if
13603 // something unexpected happens, we don't want to end up
13604 // in an infinite loop.
13605 if (origSize > mLRUActivities.size()) {
13606 i--;
13607 }
13608 }
13609 }
13610 }
13611 }
13612
13613 /** This method sends the specified signal to each of the persistent apps */
13614 public void signalPersistentProcesses(int sig) throws RemoteException {
13615 if (sig != Process.SIGNAL_USR1) {
13616 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13617 }
13618
13619 synchronized (this) {
13620 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13621 != PackageManager.PERMISSION_GRANTED) {
13622 throw new SecurityException("Requires permission "
13623 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13624 }
13625
13626 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13627 ProcessRecord r = mLRUProcesses.get(i);
13628 if (r.thread != null && r.persistent) {
13629 Process.sendSignal(r.pid, sig);
13630 }
13631 }
13632 }
13633 }
13634
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013635 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013636 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013637
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013638 try {
13639 synchronized (this) {
13640 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13641 // its own permission.
13642 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13643 != PackageManager.PERMISSION_GRANTED) {
13644 throw new SecurityException("Requires permission "
13645 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013646 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013647
13648 if (start && fd == null) {
13649 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013650 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013651
13652 ProcessRecord proc = null;
13653 try {
13654 int pid = Integer.parseInt(process);
13655 synchronized (mPidsSelfLocked) {
13656 proc = mPidsSelfLocked.get(pid);
13657 }
13658 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013659 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013660
13661 if (proc == null) {
13662 HashMap<String, SparseArray<ProcessRecord>> all
13663 = mProcessNames.getMap();
13664 SparseArray<ProcessRecord> procs = all.get(process);
13665 if (procs != null && procs.size() > 0) {
13666 proc = procs.valueAt(0);
13667 }
13668 }
13669
13670 if (proc == null || proc.thread == null) {
13671 throw new IllegalArgumentException("Unknown process: " + process);
13672 }
13673
13674 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13675 if (isSecure) {
13676 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13677 throw new SecurityException("Process not debuggable: " + proc);
13678 }
13679 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013680
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013681 proc.thread.profilerControl(start, path, fd);
13682 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013683 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013684 }
13685 } catch (RemoteException e) {
13686 throw new IllegalStateException("Process disappeared");
13687 } finally {
13688 if (fd != null) {
13689 try {
13690 fd.close();
13691 } catch (IOException e) {
13692 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013693 }
13694 }
13695 }
13696
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013697 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13698 public void monitor() {
13699 synchronized (this) { }
13700 }
13701}