blob: e953b81b93adb57f6069d762cc43451a4691cb9b [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
19import com.android.internal.os.BatteryStatsImpl;
Dianne Hackbornde7faf62009-06-30 13:27:30 -070020import com.android.server.AttributeCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import com.android.server.IntentResolver;
22import com.android.server.ProcessMap;
23import com.android.server.ProcessStats;
24import com.android.server.SystemServer;
25import com.android.server.Watchdog;
26import com.android.server.WindowManagerService;
27
28import android.app.Activity;
29import android.app.ActivityManager;
30import android.app.ActivityManagerNative;
31import android.app.ActivityThread;
32import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020033import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.app.Dialog;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070035import android.app.IActivityController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.app.IActivityWatcher;
37import android.app.IApplicationThread;
38import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.app.IServiceConnection;
40import android.app.IThumbnailReceiver;
41import android.app.Instrumentation;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070042import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.app.PendingIntent;
44import android.app.ResultInfo;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070045import android.app.Service;
Christopher Tate181fafa2009-05-14 11:12:14 -070046import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020047import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.ComponentName;
49import android.content.ContentResolver;
50import android.content.Context;
51import android.content.Intent;
52import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070053import android.content.IIntentReceiver;
54import android.content.IIntentSender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -070055import android.content.IntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.content.pm.ActivityInfo;
57import android.content.pm.ApplicationInfo;
58import android.content.pm.ConfigurationInfo;
59import android.content.pm.IPackageDataObserver;
60import android.content.pm.IPackageManager;
61import android.content.pm.InstrumentationInfo;
62import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070063import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import android.content.pm.ProviderInfo;
65import android.content.pm.ResolveInfo;
66import android.content.pm.ServiceInfo;
67import android.content.res.Configuration;
68import android.graphics.Bitmap;
69import android.net.Uri;
70import android.os.Binder;
71import android.os.Bundle;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070072import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.os.Environment;
74import android.os.FileUtils;
75import android.os.Handler;
76import android.os.IBinder;
77import android.os.IPermissionController;
78import android.os.Looper;
79import android.os.Message;
80import android.os.Parcel;
81import android.os.ParcelFileDescriptor;
82import android.os.PowerManager;
83import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070084import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.os.RemoteException;
86import android.os.ServiceManager;
87import android.os.SystemClock;
88import android.os.SystemProperties;
89import android.provider.Checkin;
90import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020091import android.server.data.CrashData;
92import android.server.data.StackTraceElementData;
93import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094import android.text.TextUtils;
95import android.util.Config;
96import android.util.EventLog;
97import android.util.Log;
98import android.util.PrintWriterPrinter;
99import android.util.SparseArray;
100import android.view.Gravity;
101import android.view.LayoutInflater;
102import android.view.View;
103import android.view.WindowManager;
104import android.view.WindowManagerPolicy;
105
106import dalvik.system.Zygote;
107
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200108import java.io.ByteArrayInputStream;
109import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110import java.io.File;
111import java.io.FileDescriptor;
112import java.io.FileInputStream;
113import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200114import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115import java.io.PrintWriter;
116import java.lang.IllegalStateException;
117import java.lang.ref.WeakReference;
118import java.util.ArrayList;
119import java.util.HashMap;
120import java.util.HashSet;
121import java.util.Iterator;
122import java.util.List;
123import java.util.Locale;
124import java.util.Map;
125
126public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
127 static final String TAG = "ActivityManager";
128 static final boolean DEBUG = false;
129 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
130 static final boolean DEBUG_SWITCH = localLOGV || false;
131 static final boolean DEBUG_TASKS = localLOGV || false;
132 static final boolean DEBUG_PAUSE = localLOGV || false;
133 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
134 static final boolean DEBUG_TRANSITION = localLOGV || false;
135 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700136 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 static final boolean DEBUG_SERVICE = localLOGV || false;
138 static final boolean DEBUG_VISBILITY = localLOGV || false;
139 static final boolean DEBUG_PROCESSES = localLOGV || false;
Dianne Hackborna1e989b2009-09-01 19:54:29 -0700140 static final boolean DEBUG_PROVIDER = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700142 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700143 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 static final boolean VALIDATE_TOKENS = false;
145 static final boolean SHOW_ACTIVITY_START_TIME = true;
146
147 // Control over CPU and battery monitoring.
148 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
149 static final boolean MONITOR_CPU_USAGE = true;
150 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
151 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
152 static final boolean MONITOR_THREAD_CPU_USAGE = false;
153
154 // Event log tags
155 static final int LOG_CONFIGURATION_CHANGED = 2719;
156 static final int LOG_CPU = 2721;
157 static final int LOG_AM_FINISH_ACTIVITY = 30001;
158 static final int LOG_TASK_TO_FRONT = 30002;
159 static final int LOG_AM_NEW_INTENT = 30003;
160 static final int LOG_AM_CREATE_TASK = 30004;
161 static final int LOG_AM_CREATE_ACTIVITY = 30005;
162 static final int LOG_AM_RESTART_ACTIVITY = 30006;
163 static final int LOG_AM_RESUME_ACTIVITY = 30007;
164 static final int LOG_ANR = 30008;
165 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
166 static final int LOG_AM_PROCESS_BOUND = 30010;
167 static final int LOG_AM_PROCESS_DIED = 30011;
168 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
169 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
170 static final int LOG_AM_PROCESS_START = 30014;
171 static final int LOG_AM_PROCESS_BAD = 30015;
172 static final int LOG_AM_PROCESS_GOOD = 30016;
173 static final int LOG_AM_LOW_MEMORY = 30017;
174 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
175 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
176 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
177 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
178 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
179 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
180 static final int LOG_AM_CREATE_SERVICE = 30030;
181 static final int LOG_AM_DESTROY_SERVICE = 30031;
182 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
183 static final int LOG_AM_DROP_PROCESS = 30033;
184 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
185 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
186 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
187
188 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
189 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
190
Dianne Hackborn1655be42009-05-08 14:29:01 -0700191 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700192 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700193
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 private static final String SYSTEM_SECURE = "ro.secure";
195
196 // This is the maximum number of application processes we would like
197 // to have running. Due to the asynchronous nature of things, we can
198 // temporarily go beyond this limit.
199 static final int MAX_PROCESSES = 2;
200
201 // Set to false to leave processes running indefinitely, relying on
202 // the kernel killing them as resources are required.
203 static final boolean ENFORCE_PROCESS_LIMIT = false;
204
205 // This is the maximum number of activities that we would like to have
206 // running at a given time.
207 static final int MAX_ACTIVITIES = 20;
208
209 // Maximum number of recent tasks that we can remember.
210 static final int MAX_RECENT_TASKS = 20;
211
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700212 // Amount of time after a call to stopAppSwitches() during which we will
213 // prevent further untrusted switches from happening.
214 static final long APP_SWITCH_DELAY_TIME = 5*1000;
215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 // How long until we reset a task when the user returns to it. Currently
217 // 30 minutes.
218 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
219
220 // Set to true to disable the icon that is shown while a new activity
221 // is being started.
222 static final boolean SHOW_APP_STARTING_ICON = true;
223
224 // How long we wait until giving up on the last activity to pause. This
225 // is short because it directly impacts the responsiveness of starting the
226 // next activity.
227 static final int PAUSE_TIMEOUT = 500;
228
229 /**
230 * How long we can hold the launch wake lock before giving up.
231 */
232 static final int LAUNCH_TIMEOUT = 10*1000;
233
234 // How long we wait for a launched process to attach to the activity manager
235 // before we decide it's never going to come up for real.
236 static final int PROC_START_TIMEOUT = 10*1000;
237
238 // How long we wait until giving up on the last activity telling us it
239 // is idle.
240 static final int IDLE_TIMEOUT = 10*1000;
241
242 // How long to wait after going idle before forcing apps to GC.
243 static final int GC_TIMEOUT = 5*1000;
244
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700245 // The minimum amount of time between successive GC requests for a process.
246 static final int GC_MIN_INTERVAL = 60*1000;
247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 // How long we wait until giving up on an activity telling us it has
249 // finished destroying itself.
250 static final int DESTROY_TIMEOUT = 10*1000;
251
252 // How long we allow a receiver to run before giving up on it.
253 static final int BROADCAST_TIMEOUT = 10*1000;
254
255 // How long we wait for a service to finish executing.
256 static final int SERVICE_TIMEOUT = 20*1000;
257
258 // How long a service needs to be running until restarting its process
259 // is no longer considered to be a relaunch of the service.
260 static final int SERVICE_RESTART_DURATION = 5*1000;
261
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700262 // How long a service needs to be running until it will start back at
263 // SERVICE_RESTART_DURATION after being killed.
264 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
265
266 // Multiplying factor to increase restart duration time by, for each time
267 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
268 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
269
270 // The minimum amount of time between restarting services that we allow.
271 // That is, when multiple services are restarting, we won't allow each
272 // to restart less than this amount of time from the last one.
273 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
274
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 // Maximum amount of time for there to be no activity on a service before
276 // we consider it non-essential and allow its process to go on the
277 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700278 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279
280 // How long we wait until we timeout on key dispatching.
281 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
282
283 // The minimum time we allow between crashes, for us to consider this
284 // application to be bad and stop and its services and reject broadcasts.
285 static final int MIN_CRASH_INTERVAL = 60*1000;
286
287 // How long we wait until we timeout on key dispatching during instrumentation.
288 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
289
290 // OOM adjustments for processes in various states:
291
292 // This is a process without anything currently running in it. Definitely
293 // the first to go! Value set in system/rootdir/init.rc on startup.
294 // This value is initalized in the constructor, careful when refering to
295 // this static variable externally.
296 static int EMPTY_APP_ADJ;
297
298 // This is a process with a content provider that does not have any clients
299 // attached to it. If it did have any clients, its adjustment would be the
300 // one for the highest-priority of those processes.
301 static int CONTENT_PROVIDER_ADJ;
302
303 // This is a process only hosting activities that are not visible,
304 // so it can be killed without any disruption. Value set in
305 // system/rootdir/init.rc on startup.
306 final int HIDDEN_APP_MAX_ADJ;
307 static int HIDDEN_APP_MIN_ADJ;
308
The Android Open Source Project4df24232009-03-05 14:34:35 -0800309 // This is a process holding the home application -- we want to try
310 // avoiding killing it, even if it would normally be in the background,
311 // because the user interacts with it so much.
312 final int HOME_APP_ADJ;
313
Christopher Tate6fa95972009-06-05 18:43:55 -0700314 // This is a process currently hosting a backup operation. Killing it
315 // is not entirely fatal but is generally a bad idea.
316 final int BACKUP_APP_ADJ;
317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 // This is a process holding a secondary server -- killing it will not
319 // have much of an impact as far as the user is concerned. Value set in
320 // system/rootdir/init.rc on startup.
321 final int SECONDARY_SERVER_ADJ;
322
323 // This is a process only hosting activities that are visible to the
324 // user, so we'd prefer they don't disappear. Value set in
325 // system/rootdir/init.rc on startup.
326 final int VISIBLE_APP_ADJ;
327
328 // This is the process running the current foreground app. We'd really
329 // rather not kill it! Value set in system/rootdir/init.rc on startup.
330 final int FOREGROUND_APP_ADJ;
331
332 // This is a process running a core server, such as telephony. Definitely
333 // don't want to kill it, but doing so is not completely fatal.
334 static final int CORE_SERVER_ADJ = -12;
335
336 // The system process runs at the default adjustment.
337 static final int SYSTEM_ADJ = -16;
338
339 // Memory pages are 4K.
340 static final int PAGE_SIZE = 4*1024;
341
Jacek Surazski82a73df2009-06-17 14:33:18 +0200342 // System property defining error report receiver for system apps
343 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
344
345 // System property defining default error report receiver
346 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 // Corresponding memory levels for above adjustments.
349 final int EMPTY_APP_MEM;
350 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800351 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700352 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 final int SECONDARY_SERVER_MEM;
354 final int VISIBLE_APP_MEM;
355 final int FOREGROUND_APP_MEM;
356
357 final int MY_PID;
358
359 static final String[] EMPTY_STRING_ARRAY = new String[0];
360
361 enum ActivityState {
362 INITIALIZING,
363 RESUMED,
364 PAUSING,
365 PAUSED,
366 STOPPING,
367 STOPPED,
368 FINISHING,
369 DESTROYING,
370 DESTROYED
371 }
372
373 /**
374 * The back history of all previous (and possibly still
375 * running) activities. It contains HistoryRecord objects.
376 */
377 final ArrayList mHistory = new ArrayList();
378
379 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700380 * Description of a request to start a new activity, which has been held
381 * due to app switches being disabled.
382 */
383 class PendingActivityLaunch {
384 HistoryRecord r;
385 HistoryRecord sourceRecord;
386 Uri[] grantedUriPermissions;
387 int grantedMode;
388 boolean onlyIfNeeded;
389 }
390
391 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
392 = new ArrayList<PendingActivityLaunch>();
393
394 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 * List of all active broadcasts that are to be executed immediately
396 * (without waiting for another broadcast to finish). Currently this only
397 * contains broadcasts to registered receivers, to avoid spinning up
398 * a bunch of processes to execute IntentReceiver components.
399 */
400 final ArrayList<BroadcastRecord> mParallelBroadcasts
401 = new ArrayList<BroadcastRecord>();
402
403 /**
404 * List of all active broadcasts that are to be executed one at a time.
405 * The object at the top of the list is the currently activity broadcasts;
406 * those after it are waiting for the top to finish..
407 */
408 final ArrayList<BroadcastRecord> mOrderedBroadcasts
409 = new ArrayList<BroadcastRecord>();
410
411 /**
412 * Set when we current have a BROADCAST_INTENT_MSG in flight.
413 */
414 boolean mBroadcastsScheduled = false;
415
416 /**
417 * Set to indicate whether to issue an onUserLeaving callback when a
418 * newly launched activity is being brought in front of us.
419 */
420 boolean mUserLeaving = false;
421
422 /**
423 * When we are in the process of pausing an activity, before starting the
424 * next one, this variable holds the activity that is currently being paused.
425 */
426 HistoryRecord mPausingActivity = null;
427
428 /**
429 * Current activity that is resumed, or null if there is none.
430 */
431 HistoryRecord mResumedActivity = null;
432
433 /**
434 * Activity we have told the window manager to have key focus.
435 */
436 HistoryRecord mFocusedActivity = null;
437
438 /**
439 * This is the last activity that we put into the paused state. This is
440 * used to determine if we need to do an activity transition while sleeping,
441 * when we normally hold the top activity paused.
442 */
443 HistoryRecord mLastPausedActivity = null;
444
445 /**
446 * List of activities that are waiting for a new activity
447 * to become visible before completing whatever operation they are
448 * supposed to do.
449 */
450 final ArrayList mWaitingVisibleActivities = new ArrayList();
451
452 /**
453 * List of activities that are ready to be stopped, but waiting
454 * for the next activity to settle down before doing so. It contains
455 * HistoryRecord objects.
456 */
457 final ArrayList<HistoryRecord> mStoppingActivities
458 = new ArrayList<HistoryRecord>();
459
460 /**
Dianne Hackbornbfe319e2009-09-21 00:34:05 -0700461 * Animations that for the current transition have requested not to
462 * be considered for the transition animation.
463 */
464 final ArrayList<HistoryRecord> mNoAnimActivities
465 = new ArrayList<HistoryRecord>();
466
467 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 * List of intents that were used to start the most recent tasks.
469 */
470 final ArrayList<TaskRecord> mRecentTasks
471 = new ArrayList<TaskRecord>();
472
473 /**
474 * List of activities that are ready to be finished, but waiting
475 * for the previous activity to settle down before doing so. It contains
476 * HistoryRecord objects.
477 */
478 final ArrayList mFinishingActivities = new ArrayList();
479
480 /**
481 * All of the applications we currently have running organized by name.
482 * The keys are strings of the application package name (as
483 * returned by the package manager), and the keys are ApplicationRecord
484 * objects.
485 */
486 final ProcessMap<ProcessRecord> mProcessNames
487 = new ProcessMap<ProcessRecord>();
488
489 /**
490 * The last time that various processes have crashed.
491 */
492 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
493
494 /**
495 * Set of applications that we consider to be bad, and will reject
496 * incoming broadcasts from (which the user has no control over).
497 * Processes are added to this set when they have crashed twice within
498 * a minimum amount of time; they are removed from it when they are
499 * later restarted (hopefully due to some user action). The value is the
500 * time it was added to the list.
501 */
502 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
503
504 /**
505 * All of the processes we currently have running organized by pid.
506 * The keys are the pid running the application.
507 *
508 * <p>NOTE: This object is protected by its own lock, NOT the global
509 * activity manager lock!
510 */
511 final SparseArray<ProcessRecord> mPidsSelfLocked
512 = new SparseArray<ProcessRecord>();
513
514 /**
515 * All of the processes that have been forced to be foreground. The key
516 * is the pid of the caller who requested it (we hold a death
517 * link on it).
518 */
519 abstract class ForegroundToken implements IBinder.DeathRecipient {
520 int pid;
521 IBinder token;
522 }
523 final SparseArray<ForegroundToken> mForegroundProcesses
524 = new SparseArray<ForegroundToken>();
525
526 /**
527 * List of records for processes that someone had tried to start before the
528 * system was ready. We don't start them at that point, but ensure they
529 * are started by the time booting is complete.
530 */
531 final ArrayList<ProcessRecord> mProcessesOnHold
532 = new ArrayList<ProcessRecord>();
533
534 /**
535 * List of records for processes that we have started and are waiting
536 * for them to call back. This is really only needed when running in
537 * single processes mode, in which case we do not have a unique pid for
538 * each process.
539 */
540 final ArrayList<ProcessRecord> mStartingProcesses
541 = new ArrayList<ProcessRecord>();
542
543 /**
544 * List of persistent applications that are in the process
545 * of being started.
546 */
547 final ArrayList<ProcessRecord> mPersistentStartingProcesses
548 = new ArrayList<ProcessRecord>();
549
550 /**
551 * Processes that are being forcibly torn down.
552 */
553 final ArrayList<ProcessRecord> mRemovedProcesses
554 = new ArrayList<ProcessRecord>();
555
556 /**
557 * List of running applications, sorted by recent usage.
558 * The first entry in the list is the least recently used.
559 * It contains ApplicationRecord objects. This list does NOT include
560 * any persistent application records (since we never want to exit them).
561 */
562 final ArrayList<ProcessRecord> mLRUProcesses
563 = new ArrayList<ProcessRecord>();
564
565 /**
566 * List of processes that should gc as soon as things are idle.
567 */
568 final ArrayList<ProcessRecord> mProcessesToGc
569 = new ArrayList<ProcessRecord>();
570
571 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800572 * This is the process holding what we currently consider to be
573 * the "home" activity.
574 */
575 private ProcessRecord mHomeProcess;
576
577 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 * List of running activities, sorted by recent usage.
579 * The first entry in the list is the least recently used.
580 * It contains HistoryRecord objects.
581 */
582 private final ArrayList mLRUActivities = new ArrayList();
583
584 /**
585 * Set of PendingResultRecord objects that are currently active.
586 */
587 final HashSet mPendingResultRecords = new HashSet();
588
589 /**
590 * Set of IntentSenderRecord objects that are currently active.
591 */
592 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
593 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
594
595 /**
596 * Intent broadcast that we have tried to start, but are
597 * waiting for its application's process to be created. We only
598 * need one (instead of a list) because we always process broadcasts
599 * one at a time, so no others can be started while waiting for this
600 * one.
601 */
602 BroadcastRecord mPendingBroadcast = null;
603
604 /**
605 * Keeps track of all IIntentReceivers that have been registered for
606 * broadcasts. Hash keys are the receiver IBinder, hash value is
607 * a ReceiverList.
608 */
609 final HashMap mRegisteredReceivers = new HashMap();
610
611 /**
612 * Resolver for broadcast intents to registered receivers.
613 * Holds BroadcastFilter (subclass of IntentFilter).
614 */
615 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
616 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
617 @Override
618 protected boolean allowFilterResult(
619 BroadcastFilter filter, List<BroadcastFilter> dest) {
620 IBinder target = filter.receiverList.receiver.asBinder();
621 for (int i=dest.size()-1; i>=0; i--) {
622 if (dest.get(i).receiverList.receiver.asBinder() == target) {
623 return false;
624 }
625 }
626 return true;
627 }
628 };
629
630 /**
631 * State of all active sticky broadcasts. Keys are the action of the
632 * sticky Intent, values are an ArrayList of all broadcasted intents with
633 * that action (which should usually be one).
634 */
635 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
636 new HashMap<String, ArrayList<Intent>>();
637
638 /**
639 * All currently running services.
640 */
641 final HashMap<ComponentName, ServiceRecord> mServices =
642 new HashMap<ComponentName, ServiceRecord>();
643
644 /**
645 * All currently running services indexed by the Intent used to start them.
646 */
647 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
648 new HashMap<Intent.FilterComparison, ServiceRecord>();
649
650 /**
651 * All currently bound service connections. Keys are the IBinder of
652 * the client's IServiceConnection.
653 */
654 final HashMap<IBinder, ConnectionRecord> mServiceConnections
655 = new HashMap<IBinder, ConnectionRecord>();
656
657 /**
658 * List of services that we have been asked to start,
659 * but haven't yet been able to. It is used to hold start requests
660 * while waiting for their corresponding application thread to get
661 * going.
662 */
663 final ArrayList<ServiceRecord> mPendingServices
664 = new ArrayList<ServiceRecord>();
665
666 /**
667 * List of services that are scheduled to restart following a crash.
668 */
669 final ArrayList<ServiceRecord> mRestartingServices
670 = new ArrayList<ServiceRecord>();
671
672 /**
673 * List of services that are in the process of being stopped.
674 */
675 final ArrayList<ServiceRecord> mStoppingServices
676 = new ArrayList<ServiceRecord>();
677
678 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700679 * Backup/restore process management
680 */
681 String mBackupAppName = null;
682 BackupRecord mBackupTarget = null;
683
684 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 * List of PendingThumbnailsRecord objects of clients who are still
686 * waiting to receive all of the thumbnails for a task.
687 */
688 final ArrayList mPendingThumbnails = new ArrayList();
689
690 /**
691 * List of HistoryRecord objects that have been finished and must
692 * still report back to a pending thumbnail receiver.
693 */
694 final ArrayList mCancelledThumbnails = new ArrayList();
695
696 /**
697 * All of the currently running global content providers. Keys are a
698 * string containing the provider name and values are a
699 * ContentProviderRecord object containing the data about it. Note
700 * that a single provider may be published under multiple names, so
701 * there may be multiple entries here for a single one in mProvidersByClass.
702 */
703 final HashMap mProvidersByName = new HashMap();
704
705 /**
706 * All of the currently running global content providers. Keys are a
707 * string containing the provider's implementation class and values are a
708 * ContentProviderRecord object containing the data about it.
709 */
710 final HashMap mProvidersByClass = new HashMap();
711
712 /**
713 * List of content providers who have clients waiting for them. The
714 * application is currently being launched and the provider will be
715 * removed from this list once it is published.
716 */
717 final ArrayList mLaunchingProviders = new ArrayList();
718
719 /**
720 * Global set of specific Uri permissions that have been granted.
721 */
722 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
723 = new SparseArray<HashMap<Uri, UriPermission>>();
724
725 /**
726 * Thread-local storage used to carry caller permissions over through
727 * indirect content-provider access.
728 * @see #ActivityManagerService.openContentUri()
729 */
730 private class Identity {
731 public int pid;
732 public int uid;
733
734 Identity(int _pid, int _uid) {
735 pid = _pid;
736 uid = _uid;
737 }
738 }
739 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
740
741 /**
742 * All information we have collected about the runtime performance of
743 * any user id that can impact battery performance.
744 */
745 final BatteryStatsService mBatteryStatsService;
746
747 /**
748 * information about component usage
749 */
750 final UsageStatsService mUsageStatsService;
751
752 /**
753 * Current configuration information. HistoryRecord objects are given
754 * a reference to this object to indicate which configuration they are
755 * currently running in, so this object must be kept immutable.
756 */
757 Configuration mConfiguration = new Configuration();
758
759 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700760 * Hardware-reported OpenGLES version.
761 */
762 final int GL_ES_VERSION;
763
764 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 * List of initialization arguments to pass to all processes when binding applications to them.
766 * For example, references to the commonly used services.
767 */
768 HashMap<String, IBinder> mAppBindArgs;
769
770 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700771 * Temporary to avoid allocations. Protected by main lock.
772 */
773 final StringBuilder mStringBuilder = new StringBuilder(256);
774
775 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 * Used to control how we initialize the service.
777 */
778 boolean mStartRunning = false;
779 ComponentName mTopComponent;
780 String mTopAction;
781 String mTopData;
782 boolean mSystemReady = false;
783 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700784 boolean mWaitingUpdate = false;
785 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786
787 Context mContext;
788
789 int mFactoryTest;
790
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700791 boolean mCheckedForSetup;
792
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700794 * The time at which we will allow normal application switches again,
795 * after a call to {@link #stopAppSwitches()}.
796 */
797 long mAppSwitchesAllowedTime;
798
799 /**
800 * This is set to true after the first switch after mAppSwitchesAllowedTime
801 * is set; any switches after that will clear the time.
802 */
803 boolean mDidAppSwitch;
804
805 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806 * Set while we are wanting to sleep, to prevent any
807 * activities from being started/resumed.
808 */
809 boolean mSleeping = false;
810
811 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700812 * Set if we are shutting down the system, similar to sleeping.
813 */
814 boolean mShuttingDown = false;
815
816 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 * Set when the system is going to sleep, until we have
818 * successfully paused the current activity and released our wake lock.
819 * At that point the system is allowed to actually sleep.
820 */
821 PowerManager.WakeLock mGoingToSleep;
822
823 /**
824 * We don't want to allow the device to go to sleep while in the process
825 * of launching an activity. This is primarily to allow alarm intent
826 * receivers to launch an activity and get that to run before the device
827 * goes back to sleep.
828 */
829 PowerManager.WakeLock mLaunchingActivity;
830
831 /**
832 * Task identifier that activities are currently being started
833 * in. Incremented each time a new task is created.
834 * todo: Replace this with a TokenSpace class that generates non-repeating
835 * integers that won't wrap.
836 */
837 int mCurTask = 1;
838
839 /**
840 * Current sequence id for oom_adj computation traversal.
841 */
842 int mAdjSeq = 0;
843
844 /**
845 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
846 * is set, indicating the user wants processes started in such a way
847 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
848 * running in each process (thus no pre-initialized process, etc).
849 */
850 boolean mSimpleProcessManagement = false;
851
852 /**
853 * System monitoring: number of processes that died since the last
854 * N procs were started.
855 */
856 int[] mProcDeaths = new int[20];
857
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700858 /**
859 * This is set if we had to do a delayed dexopt of an app before launching
860 * it, to increasing the ANR timeouts in that case.
861 */
862 boolean mDidDexOpt;
863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 String mDebugApp = null;
865 boolean mWaitForDebugger = false;
866 boolean mDebugTransient = false;
867 String mOrigDebugApp = null;
868 boolean mOrigWaitForDebugger = false;
869 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700870 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700872 final RemoteCallbackList<IActivityWatcher> mWatchers
873 = new RemoteCallbackList<IActivityWatcher>();
874
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 /**
876 * Callback of last caller to {@link #requestPss}.
877 */
878 Runnable mRequestPssCallback;
879
880 /**
881 * Remaining processes for which we are waiting results from the last
882 * call to {@link #requestPss}.
883 */
884 final ArrayList<ProcessRecord> mRequestPssList
885 = new ArrayList<ProcessRecord>();
886
887 /**
888 * Runtime statistics collection thread. This object's lock is used to
889 * protect all related state.
890 */
891 final Thread mProcessStatsThread;
892
893 /**
894 * Used to collect process stats when showing not responding dialog.
895 * Protected by mProcessStatsThread.
896 */
897 final ProcessStats mProcessStats = new ProcessStats(
898 MONITOR_THREAD_CPU_USAGE);
899 long mLastCpuTime = 0;
900 long mLastWriteTime = 0;
901
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700902 long mInitialStartTime = 0;
903
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 /**
905 * Set to true after the system has finished booting.
906 */
907 boolean mBooted = false;
908
909 int mProcessLimit = 0;
910
911 WindowManagerService mWindowManager;
912
913 static ActivityManagerService mSelf;
914 static ActivityThread mSystemThread;
915
916 private final class AppDeathRecipient implements IBinder.DeathRecipient {
917 final ProcessRecord mApp;
918 final int mPid;
919 final IApplicationThread mAppThread;
920
921 AppDeathRecipient(ProcessRecord app, int pid,
922 IApplicationThread thread) {
923 if (localLOGV) Log.v(
924 TAG, "New death recipient " + this
925 + " for thread " + thread.asBinder());
926 mApp = app;
927 mPid = pid;
928 mAppThread = thread;
929 }
930
931 public void binderDied() {
932 if (localLOGV) Log.v(
933 TAG, "Death received in " + this
934 + " for thread " + mAppThread.asBinder());
935 removeRequestedPss(mApp);
936 synchronized(ActivityManagerService.this) {
937 appDiedLocked(mApp, mPid, mAppThread);
938 }
939 }
940 }
941
942 static final int SHOW_ERROR_MSG = 1;
943 static final int SHOW_NOT_RESPONDING_MSG = 2;
944 static final int SHOW_FACTORY_ERROR_MSG = 3;
945 static final int UPDATE_CONFIGURATION_MSG = 4;
946 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
947 static final int WAIT_FOR_DEBUGGER_MSG = 6;
948 static final int BROADCAST_INTENT_MSG = 7;
949 static final int BROADCAST_TIMEOUT_MSG = 8;
950 static final int PAUSE_TIMEOUT_MSG = 9;
951 static final int IDLE_TIMEOUT_MSG = 10;
952 static final int IDLE_NOW_MSG = 11;
953 static final int SERVICE_TIMEOUT_MSG = 12;
954 static final int UPDATE_TIME_ZONE = 13;
955 static final int SHOW_UID_ERROR_MSG = 14;
956 static final int IM_FEELING_LUCKY_MSG = 15;
957 static final int LAUNCH_TIMEOUT_MSG = 16;
958 static final int DESTROY_TIMEOUT_MSG = 17;
959 static final int SERVICE_ERROR_MSG = 18;
960 static final int RESUME_TOP_ACTIVITY_MSG = 19;
961 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700962 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700963 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964
965 AlertDialog mUidAlert;
966
967 final Handler mHandler = new Handler() {
968 //public Handler() {
969 // if (localLOGV) Log.v(TAG, "Handler started!");
970 //}
971
972 public void handleMessage(Message msg) {
973 switch (msg.what) {
974 case SHOW_ERROR_MSG: {
975 HashMap data = (HashMap) msg.obj;
976 byte[] crashData = (byte[])data.get("crashData");
977 if (crashData != null) {
978 // This needs to be *un*synchronized to avoid deadlock.
979 ContentResolver resolver = mContext.getContentResolver();
980 Checkin.reportCrash(resolver, crashData);
981 }
982 synchronized (ActivityManagerService.this) {
983 ProcessRecord proc = (ProcessRecord)data.get("app");
984 if (proc != null && proc.crashDialog != null) {
985 Log.e(TAG, "App already has crash dialog: " + proc);
986 return;
987 }
988 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700989 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800990 Dialog d = new AppErrorDialog(
991 mContext, res, proc,
992 (Integer)data.get("flags"),
993 (String)data.get("shortMsg"),
994 (String)data.get("longMsg"));
995 d.show();
996 proc.crashDialog = d;
997 } else {
998 // The device is asleep, so just pretend that the user
999 // saw a crash dialog and hit "force quit".
1000 res.set(0);
1001 }
1002 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001003
1004 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005 } break;
1006 case SHOW_NOT_RESPONDING_MSG: {
1007 synchronized (ActivityManagerService.this) {
1008 HashMap data = (HashMap) msg.obj;
1009 ProcessRecord proc = (ProcessRecord)data.get("app");
1010 if (proc != null && proc.anrDialog != null) {
1011 Log.e(TAG, "App already has anr dialog: " + proc);
1012 return;
1013 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001014
1015 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1016 null, null, 0, null, null, null,
1017 false, false, MY_PID, Process.SYSTEM_UID);
1018
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1020 mContext, proc, (HistoryRecord)data.get("activity"));
1021 d.show();
1022 proc.anrDialog = d;
1023 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001024
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001025 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 } break;
1027 case SHOW_FACTORY_ERROR_MSG: {
1028 Dialog d = new FactoryErrorDialog(
1029 mContext, msg.getData().getCharSequence("msg"));
1030 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001031 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001032 } break;
1033 case UPDATE_CONFIGURATION_MSG: {
1034 final ContentResolver resolver = mContext.getContentResolver();
1035 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1036 } break;
1037 case GC_BACKGROUND_PROCESSES_MSG: {
1038 synchronized (ActivityManagerService.this) {
1039 performAppGcsIfAppropriateLocked();
1040 }
1041 } break;
1042 case WAIT_FOR_DEBUGGER_MSG: {
1043 synchronized (ActivityManagerService.this) {
1044 ProcessRecord app = (ProcessRecord)msg.obj;
1045 if (msg.arg1 != 0) {
1046 if (!app.waitedForDebugger) {
1047 Dialog d = new AppWaitingForDebuggerDialog(
1048 ActivityManagerService.this,
1049 mContext, app);
1050 app.waitDialog = d;
1051 app.waitedForDebugger = true;
1052 d.show();
1053 }
1054 } else {
1055 if (app.waitDialog != null) {
1056 app.waitDialog.dismiss();
1057 app.waitDialog = null;
1058 }
1059 }
1060 }
1061 } break;
1062 case BROADCAST_INTENT_MSG: {
1063 if (DEBUG_BROADCAST) Log.v(
1064 TAG, "Received BROADCAST_INTENT_MSG");
1065 processNextBroadcast(true);
1066 } break;
1067 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001068 if (mDidDexOpt) {
1069 mDidDexOpt = false;
1070 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1071 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1072 return;
1073 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 broadcastTimeout();
1075 } break;
1076 case PAUSE_TIMEOUT_MSG: {
1077 IBinder token = (IBinder)msg.obj;
1078 // We don't at this point know if the activity is fullscreen,
1079 // so we need to be conservative and assume it isn't.
1080 Log.w(TAG, "Activity pause timeout for " + token);
1081 activityPaused(token, null, true);
1082 } break;
1083 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001084 if (mDidDexOpt) {
1085 mDidDexOpt = false;
1086 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1087 nmsg.obj = msg.obj;
1088 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1089 return;
1090 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091 // We don't at this point know if the activity is fullscreen,
1092 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001093 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 Log.w(TAG, "Activity idle timeout for " + token);
1095 activityIdleInternal(token, true);
1096 } break;
1097 case DESTROY_TIMEOUT_MSG: {
1098 IBinder token = (IBinder)msg.obj;
1099 // We don't at this point know if the activity is fullscreen,
1100 // so we need to be conservative and assume it isn't.
1101 Log.w(TAG, "Activity destroy timeout for " + token);
1102 activityDestroyed(token);
1103 } break;
1104 case IDLE_NOW_MSG: {
1105 IBinder token = (IBinder)msg.obj;
1106 activityIdle(token);
1107 } break;
1108 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001109 if (mDidDexOpt) {
1110 mDidDexOpt = false;
1111 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1112 nmsg.obj = msg.obj;
1113 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1114 return;
1115 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116 serviceTimeout((ProcessRecord)msg.obj);
1117 } break;
1118 case UPDATE_TIME_ZONE: {
1119 synchronized (ActivityManagerService.this) {
1120 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1121 ProcessRecord r = mLRUProcesses.get(i);
1122 if (r.thread != null) {
1123 try {
1124 r.thread.updateTimeZone();
1125 } catch (RemoteException ex) {
1126 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1127 }
1128 }
1129 }
1130 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001131 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132 case SHOW_UID_ERROR_MSG: {
1133 // XXX This is a temporary dialog, no need to localize.
1134 AlertDialog d = new BaseErrorDialog(mContext);
1135 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1136 d.setCancelable(false);
1137 d.setTitle("System UIDs Inconsistent");
1138 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1139 d.setButton("I'm Feeling Lucky",
1140 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1141 mUidAlert = d;
1142 d.show();
1143 } break;
1144 case IM_FEELING_LUCKY_MSG: {
1145 if (mUidAlert != null) {
1146 mUidAlert.dismiss();
1147 mUidAlert = null;
1148 }
1149 } break;
1150 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001151 if (mDidDexOpt) {
1152 mDidDexOpt = false;
1153 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1154 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1155 return;
1156 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 synchronized (ActivityManagerService.this) {
1158 if (mLaunchingActivity.isHeld()) {
1159 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1160 mLaunchingActivity.release();
1161 }
1162 }
1163 } break;
1164 case SERVICE_ERROR_MSG: {
1165 ServiceRecord srv = (ServiceRecord)msg.obj;
1166 // This needs to be *un*synchronized to avoid deadlock.
1167 Checkin.logEvent(mContext.getContentResolver(),
1168 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1169 srv.name.toShortString());
1170 } break;
1171 case RESUME_TOP_ACTIVITY_MSG: {
1172 synchronized (ActivityManagerService.this) {
1173 resumeTopActivityLocked(null);
1174 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001175 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001177 if (mDidDexOpt) {
1178 mDidDexOpt = false;
1179 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1180 nmsg.obj = msg.obj;
1181 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1182 return;
1183 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 ProcessRecord app = (ProcessRecord)msg.obj;
1185 synchronized (ActivityManagerService.this) {
1186 processStartTimedOutLocked(app);
1187 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001188 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001189 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1190 synchronized (ActivityManagerService.this) {
1191 doPendingActivityLaunchesLocked(true);
1192 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001193 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001194 case KILL_APPLICATION_MSG: {
1195 synchronized (ActivityManagerService.this) {
1196 int uid = msg.arg1;
1197 boolean restart = (msg.arg2 == 1);
1198 String pkg = (String) msg.obj;
1199 uninstallPackageLocked(pkg, uid, restart);
1200 }
1201 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 }
1203 }
1204 };
1205
1206 public static void setSystemProcess() {
1207 try {
1208 ActivityManagerService m = mSelf;
1209
1210 ServiceManager.addService("activity", m);
1211 ServiceManager.addService("meminfo", new MemBinder(m));
1212 if (MONITOR_CPU_USAGE) {
1213 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1214 }
1215 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1216 ServiceManager.addService("activity.services", new ServicesBinder(m));
1217 ServiceManager.addService("activity.senders", new SendersBinder(m));
1218 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1219 ServiceManager.addService("permission", new PermissionController(m));
1220
1221 ApplicationInfo info =
1222 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001223 "android", STOCK_PM_FLAGS);
Mike Cleron432b7132009-09-24 15:28:29 -07001224 mSystemThread.installSystemApplicationInfo(info);
1225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 synchronized (mSelf) {
1227 ProcessRecord app = mSelf.newProcessRecordLocked(
1228 mSystemThread.getApplicationThread(), info,
1229 info.processName);
1230 app.persistent = true;
1231 app.pid = Process.myPid();
1232 app.maxAdj = SYSTEM_ADJ;
1233 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1234 synchronized (mSelf.mPidsSelfLocked) {
1235 mSelf.mPidsSelfLocked.put(app.pid, app);
1236 }
1237 mSelf.updateLRUListLocked(app, true);
1238 }
1239 } catch (PackageManager.NameNotFoundException e) {
1240 throw new RuntimeException(
1241 "Unable to find android system package", e);
1242 }
1243 }
1244
1245 public void setWindowManager(WindowManagerService wm) {
1246 mWindowManager = wm;
1247 }
1248
1249 public static final Context main(int factoryTest) {
1250 AThread thr = new AThread();
1251 thr.start();
1252
1253 synchronized (thr) {
1254 while (thr.mService == null) {
1255 try {
1256 thr.wait();
1257 } catch (InterruptedException e) {
1258 }
1259 }
1260 }
1261
1262 ActivityManagerService m = thr.mService;
1263 mSelf = m;
1264 ActivityThread at = ActivityThread.systemMain();
1265 mSystemThread = at;
1266 Context context = at.getSystemContext();
1267 m.mContext = context;
1268 m.mFactoryTest = factoryTest;
1269 PowerManager pm =
1270 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1271 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1272 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1273 m.mLaunchingActivity.setReferenceCounted(false);
1274
1275 m.mBatteryStatsService.publish(context);
1276 m.mUsageStatsService.publish(context);
1277
1278 synchronized (thr) {
1279 thr.mReady = true;
1280 thr.notifyAll();
1281 }
1282
1283 m.startRunning(null, null, null, null);
1284
1285 return context;
1286 }
1287
1288 public static ActivityManagerService self() {
1289 return mSelf;
1290 }
1291
1292 static class AThread extends Thread {
1293 ActivityManagerService mService;
1294 boolean mReady = false;
1295
1296 public AThread() {
1297 super("ActivityManager");
1298 }
1299
1300 public void run() {
1301 Looper.prepare();
1302
1303 android.os.Process.setThreadPriority(
1304 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1305
1306 ActivityManagerService m = new ActivityManagerService();
1307
1308 synchronized (this) {
1309 mService = m;
1310 notifyAll();
1311 }
1312
1313 synchronized (this) {
1314 while (!mReady) {
1315 try {
1316 wait();
1317 } catch (InterruptedException e) {
1318 }
1319 }
1320 }
1321
1322 Looper.loop();
1323 }
1324 }
1325
1326 static class BroadcastsBinder extends Binder {
1327 ActivityManagerService mActivityManagerService;
1328 BroadcastsBinder(ActivityManagerService activityManagerService) {
1329 mActivityManagerService = activityManagerService;
1330 }
1331
1332 @Override
1333 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1334 mActivityManagerService.dumpBroadcasts(pw);
1335 }
1336 }
1337
1338 static class ServicesBinder extends Binder {
1339 ActivityManagerService mActivityManagerService;
1340 ServicesBinder(ActivityManagerService activityManagerService) {
1341 mActivityManagerService = activityManagerService;
1342 }
1343
1344 @Override
1345 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1346 mActivityManagerService.dumpServices(pw);
1347 }
1348 }
1349
1350 static class SendersBinder extends Binder {
1351 ActivityManagerService mActivityManagerService;
1352 SendersBinder(ActivityManagerService activityManagerService) {
1353 mActivityManagerService = activityManagerService;
1354 }
1355
1356 @Override
1357 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1358 mActivityManagerService.dumpSenders(pw);
1359 }
1360 }
1361
1362 static class ProvidersBinder extends Binder {
1363 ActivityManagerService mActivityManagerService;
1364 ProvidersBinder(ActivityManagerService activityManagerService) {
1365 mActivityManagerService = activityManagerService;
1366 }
1367
1368 @Override
1369 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1370 mActivityManagerService.dumpProviders(pw);
1371 }
1372 }
1373
1374 static class MemBinder extends Binder {
1375 ActivityManagerService mActivityManagerService;
1376 MemBinder(ActivityManagerService activityManagerService) {
1377 mActivityManagerService = activityManagerService;
1378 }
1379
1380 @Override
1381 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1382 ActivityManagerService service = mActivityManagerService;
1383 ArrayList<ProcessRecord> procs;
1384 synchronized (mActivityManagerService) {
1385 if (args != null && args.length > 0
1386 && args[0].charAt(0) != '-') {
1387 procs = new ArrayList<ProcessRecord>();
1388 int pid = -1;
1389 try {
1390 pid = Integer.parseInt(args[0]);
1391 } catch (NumberFormatException e) {
1392
1393 }
1394 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1395 ProcessRecord proc = service.mLRUProcesses.get(i);
1396 if (proc.pid == pid) {
1397 procs.add(proc);
1398 } else if (proc.processName.equals(args[0])) {
1399 procs.add(proc);
1400 }
1401 }
1402 if (procs.size() <= 0) {
1403 pw.println("No process found for: " + args[0]);
1404 return;
1405 }
1406 } else {
1407 procs = service.mLRUProcesses;
1408 }
1409 }
1410 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1411 }
1412 }
1413
1414 static class CpuBinder extends Binder {
1415 ActivityManagerService mActivityManagerService;
1416 CpuBinder(ActivityManagerService activityManagerService) {
1417 mActivityManagerService = activityManagerService;
1418 }
1419
1420 @Override
1421 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1422 synchronized (mActivityManagerService.mProcessStatsThread) {
1423 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1424 }
1425 }
1426 }
1427
1428 private ActivityManagerService() {
1429 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1430 if (v != null && Integer.getInteger(v) != 0) {
1431 mSimpleProcessManagement = true;
1432 }
1433 v = System.getenv("ANDROID_DEBUG_APP");
1434 if (v != null) {
1435 mSimpleProcessManagement = true;
1436 }
1437
1438 MY_PID = Process.myPid();
1439
1440 File dataDir = Environment.getDataDirectory();
1441 File systemDir = new File(dataDir, "system");
1442 systemDir.mkdirs();
1443 mBatteryStatsService = new BatteryStatsService(new File(
1444 systemDir, "batterystats.bin").toString());
1445 mBatteryStatsService.getActiveStatistics().readLocked();
1446 mBatteryStatsService.getActiveStatistics().writeLocked();
1447
1448 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001449 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001450
Jack Palevichb90d28c2009-07-22 15:35:24 -07001451 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1452 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1453
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001454 mConfiguration.makeDefault();
1455 mProcessStats.init();
1456
1457 // Add ourself to the Watchdog monitors.
1458 Watchdog.getInstance().addMonitor(this);
1459
1460 // These values are set in system/rootdir/init.rc on startup.
1461 FOREGROUND_APP_ADJ =
1462 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1463 VISIBLE_APP_ADJ =
1464 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1465 SECONDARY_SERVER_ADJ =
1466 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001467 BACKUP_APP_ADJ =
1468 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001469 HOME_APP_ADJ =
1470 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001471 HIDDEN_APP_MIN_ADJ =
1472 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1473 CONTENT_PROVIDER_ADJ =
1474 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1475 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1476 EMPTY_APP_ADJ =
1477 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1478 FOREGROUND_APP_MEM =
1479 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1480 VISIBLE_APP_MEM =
1481 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1482 SECONDARY_SERVER_MEM =
1483 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001484 BACKUP_APP_MEM =
1485 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001486 HOME_APP_MEM =
1487 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001488 HIDDEN_APP_MEM =
1489 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1490 EMPTY_APP_MEM =
1491 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1492
1493 mProcessStatsThread = new Thread("ProcessStats") {
1494 public void run() {
1495 while (true) {
1496 try {
1497 try {
1498 synchronized(this) {
1499 final long now = SystemClock.uptimeMillis();
1500 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1501 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1502 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1503 // + ", write delay=" + nextWriteDelay);
1504 if (nextWriteDelay < nextCpuDelay) {
1505 nextCpuDelay = nextWriteDelay;
1506 }
1507 if (nextCpuDelay > 0) {
1508 this.wait(nextCpuDelay);
1509 }
1510 }
1511 } catch (InterruptedException e) {
1512 }
1513
1514 updateCpuStatsNow();
1515 } catch (Exception e) {
1516 Log.e(TAG, "Unexpected exception collecting process stats", e);
1517 }
1518 }
1519 }
1520 };
1521 mProcessStatsThread.start();
1522 }
1523
1524 @Override
1525 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1526 throws RemoteException {
1527 try {
1528 return super.onTransact(code, data, reply, flags);
1529 } catch (RuntimeException e) {
1530 // The activity manager only throws security exceptions, so let's
1531 // log all others.
1532 if (!(e instanceof SecurityException)) {
1533 Log.e(TAG, "Activity Manager Crash", e);
1534 }
1535 throw e;
1536 }
1537 }
1538
1539 void updateCpuStats() {
1540 synchronized (mProcessStatsThread) {
1541 final long now = SystemClock.uptimeMillis();
1542 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1543 mProcessStatsThread.notify();
1544 }
1545 }
1546 }
1547
1548 void updateCpuStatsNow() {
1549 synchronized (mProcessStatsThread) {
1550 final long now = SystemClock.uptimeMillis();
1551 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001552
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 if (MONITOR_CPU_USAGE &&
1554 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1555 mLastCpuTime = now;
1556 haveNewCpuStats = true;
1557 mProcessStats.update();
1558 //Log.i(TAG, mProcessStats.printCurrentState());
1559 //Log.i(TAG, "Total CPU usage: "
1560 // + mProcessStats.getTotalCpuPercent() + "%");
1561
1562 // Log the cpu usage if the property is set.
1563 if ("true".equals(SystemProperties.get("events.cpu"))) {
1564 int user = mProcessStats.getLastUserTime();
1565 int system = mProcessStats.getLastSystemTime();
1566 int iowait = mProcessStats.getLastIoWaitTime();
1567 int irq = mProcessStats.getLastIrqTime();
1568 int softIrq = mProcessStats.getLastSoftIrqTime();
1569 int idle = mProcessStats.getLastIdleTime();
1570
1571 int total = user + system + iowait + irq + softIrq + idle;
1572 if (total == 0) total = 1;
1573
1574 EventLog.writeEvent(LOG_CPU,
1575 ((user+system+iowait+irq+softIrq) * 100) / total,
1576 (user * 100) / total,
1577 (system * 100) / total,
1578 (iowait * 100) / total,
1579 (irq * 100) / total,
1580 (softIrq * 100) / total);
1581 }
1582 }
1583
Amith Yamasanie43530a2009-08-21 13:11:37 -07001584 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001585 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001586 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001587 synchronized(mPidsSelfLocked) {
1588 if (haveNewCpuStats) {
1589 if (mBatteryStatsService.isOnBattery()) {
1590 final int N = mProcessStats.countWorkingStats();
1591 for (int i=0; i<N; i++) {
1592 ProcessStats.Stats st
1593 = mProcessStats.getWorkingStats(i);
1594 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1595 if (pr != null) {
1596 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1597 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001598 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001599 } else {
1600 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001601 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001602 if (ps != null) {
1603 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001604 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001605 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001606 }
1607 }
1608 }
1609 }
1610 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001612 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1613 mLastWriteTime = now;
1614 mBatteryStatsService.getActiveStatistics().writeLocked();
1615 }
1616 }
1617 }
1618 }
1619
1620 /**
1621 * Initialize the application bind args. These are passed to each
1622 * process when the bindApplication() IPC is sent to the process. They're
1623 * lazily setup to make sure the services are running when they're asked for.
1624 */
1625 private HashMap<String, IBinder> getCommonServicesLocked() {
1626 if (mAppBindArgs == null) {
1627 mAppBindArgs = new HashMap<String, IBinder>();
1628
1629 // Setup the application init args
1630 mAppBindArgs.put("package", ServiceManager.getService("package"));
1631 mAppBindArgs.put("window", ServiceManager.getService("window"));
1632 mAppBindArgs.put(Context.ALARM_SERVICE,
1633 ServiceManager.getService(Context.ALARM_SERVICE));
1634 }
1635 return mAppBindArgs;
1636 }
1637
1638 private final void setFocusedActivityLocked(HistoryRecord r) {
1639 if (mFocusedActivity != r) {
1640 mFocusedActivity = r;
1641 mWindowManager.setFocusedApp(r, true);
1642 }
1643 }
1644
1645 private final void updateLRUListLocked(ProcessRecord app,
1646 boolean oomAdj) {
1647 // put it on the LRU to keep track of when it should be exited.
1648 int lrui = mLRUProcesses.indexOf(app);
1649 if (lrui >= 0) mLRUProcesses.remove(lrui);
1650 mLRUProcesses.add(app);
1651 //Log.i(TAG, "Putting proc to front: " + app.processName);
1652 if (oomAdj) {
1653 updateOomAdjLocked();
1654 }
1655 }
1656
1657 private final boolean updateLRUListLocked(HistoryRecord r) {
1658 final boolean hadit = mLRUActivities.remove(r);
1659 mLRUActivities.add(r);
1660 return hadit;
1661 }
1662
1663 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1664 int i = mHistory.size()-1;
1665 while (i >= 0) {
1666 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1667 if (!r.finishing && r != notTop) {
1668 return r;
1669 }
1670 i--;
1671 }
1672 return null;
1673 }
1674
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001675 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1676 int i = mHistory.size()-1;
1677 while (i >= 0) {
1678 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1679 if (!r.finishing && !r.delayedResume && r != notTop) {
1680 return r;
1681 }
1682 i--;
1683 }
1684 return null;
1685 }
1686
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001687 /**
1688 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001689 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 *
1691 * @param token If non-null, any history records matching this token will be skipped.
1692 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1693 *
1694 * @return Returns the HistoryRecord of the next activity on the stack.
1695 */
1696 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1697 int i = mHistory.size()-1;
1698 while (i >= 0) {
1699 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1700 // Note: the taskId check depends on real taskId fields being non-zero
1701 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1702 return r;
1703 }
1704 i--;
1705 }
1706 return null;
1707 }
1708
1709 private final ProcessRecord getProcessRecordLocked(
1710 String processName, int uid) {
1711 if (uid == Process.SYSTEM_UID) {
1712 // The system gets to run in any process. If there are multiple
1713 // processes with the same uid, just pick the first (this
1714 // should never happen).
1715 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1716 processName);
1717 return procs != null ? procs.valueAt(0) : null;
1718 }
1719 ProcessRecord proc = mProcessNames.get(processName, uid);
1720 return proc;
1721 }
1722
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001723 private void ensurePackageDexOpt(String packageName) {
1724 IPackageManager pm = ActivityThread.getPackageManager();
1725 try {
1726 if (pm.performDexOpt(packageName)) {
1727 mDidDexOpt = true;
1728 }
1729 } catch (RemoteException e) {
1730 }
1731 }
1732
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001733 private boolean isNextTransitionForward() {
1734 int transit = mWindowManager.getPendingAppTransition();
1735 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1736 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1737 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1738 }
1739
1740 private final boolean realStartActivityLocked(HistoryRecord r,
1741 ProcessRecord app, boolean andResume, boolean checkConfig)
1742 throws RemoteException {
1743
1744 r.startFreezingScreenLocked(app, 0);
1745 mWindowManager.setAppVisibility(r, true);
1746
1747 // Have the window manager re-evaluate the orientation of
1748 // the screen based on the new activity order. Note that
1749 // as a result of this, it can call back into the activity
1750 // manager with a new orientation. We don't care about that,
1751 // because the activity is not currently running so we are
1752 // just restarting it anyway.
1753 if (checkConfig) {
1754 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001755 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001756 r.mayFreezeScreenLocked(app) ? r : null);
1757 updateConfigurationLocked(config, r);
1758 }
1759
1760 r.app = app;
1761
1762 if (localLOGV) Log.v(TAG, "Launching: " + r);
1763
1764 int idx = app.activities.indexOf(r);
1765 if (idx < 0) {
1766 app.activities.add(r);
1767 }
1768 updateLRUListLocked(app, true);
1769
1770 try {
1771 if (app.thread == null) {
1772 throw new RemoteException();
1773 }
1774 List<ResultInfo> results = null;
1775 List<Intent> newIntents = null;
1776 if (andResume) {
1777 results = r.results;
1778 newIntents = r.newIntents;
1779 }
1780 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1781 + " icicle=" + r.icicle
1782 + " with results=" + results + " newIntents=" + newIntents
1783 + " andResume=" + andResume);
1784 if (andResume) {
1785 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1786 System.identityHashCode(r),
1787 r.task.taskId, r.shortComponentName);
1788 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001789 if (r.isHomeActivity) {
1790 mHomeProcess = app;
1791 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001792 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001793 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001794 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001795 r.info, r.icicle, results, newIntents, !andResume,
1796 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001797 } catch (RemoteException e) {
1798 if (r.launchFailed) {
1799 // This is the second time we failed -- finish activity
1800 // and give up.
1801 Log.e(TAG, "Second failure launching "
1802 + r.intent.getComponent().flattenToShortString()
1803 + ", giving up", e);
1804 appDiedLocked(app, app.pid, app.thread);
1805 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1806 "2nd-crash");
1807 return false;
1808 }
1809
1810 // This is the first time we failed -- restart process and
1811 // retry.
1812 app.activities.remove(r);
1813 throw e;
1814 }
1815
1816 r.launchFailed = false;
1817 if (updateLRUListLocked(r)) {
1818 Log.w(TAG, "Activity " + r
1819 + " being launched, but already in LRU list");
1820 }
1821
1822 if (andResume) {
1823 // As part of the process of launching, ActivityThread also performs
1824 // a resume.
1825 r.state = ActivityState.RESUMED;
1826 r.icicle = null;
1827 r.haveState = false;
1828 r.stopped = false;
1829 mResumedActivity = r;
1830 r.task.touchActiveTime();
1831 completeResumeLocked(r);
1832 pauseIfSleepingLocked();
1833 } else {
1834 // This activity is not starting in the resumed state... which
1835 // should look like we asked it to pause+stop (but remain visible),
1836 // and it has done so and reported back the current icicle and
1837 // other state.
1838 r.state = ActivityState.STOPPED;
1839 r.stopped = true;
1840 }
1841
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001842 // Launch the new version setup screen if needed. We do this -after-
1843 // launching the initial activity (that is, home), so that it can have
1844 // a chance to initialize itself while in the background, making the
1845 // switch back to it faster and look better.
1846 startSetupActivityLocked();
1847
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001848 return true;
1849 }
1850
1851 private final void startSpecificActivityLocked(HistoryRecord r,
1852 boolean andResume, boolean checkConfig) {
1853 // Is this activity's application already running?
1854 ProcessRecord app = getProcessRecordLocked(r.processName,
1855 r.info.applicationInfo.uid);
1856
1857 if (r.startTime == 0) {
1858 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001859 if (mInitialStartTime == 0) {
1860 mInitialStartTime = r.startTime;
1861 }
1862 } else if (mInitialStartTime == 0) {
1863 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001864 }
1865
1866 if (app != null && app.thread != null) {
1867 try {
1868 realStartActivityLocked(r, app, andResume, checkConfig);
1869 return;
1870 } catch (RemoteException e) {
1871 Log.w(TAG, "Exception when starting activity "
1872 + r.intent.getComponent().flattenToShortString(), e);
1873 }
1874
1875 // If a dead object exception was thrown -- fall through to
1876 // restart the application.
1877 }
1878
1879 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001880 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001881 }
1882
1883 private final ProcessRecord startProcessLocked(String processName,
1884 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001885 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001886 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1887 // We don't have to do anything more if:
1888 // (1) There is an existing application record; and
1889 // (2) The caller doesn't think it is dead, OR there is no thread
1890 // object attached to it so we know it couldn't have crashed; and
1891 // (3) There is a pid assigned to it, so it is either starting or
1892 // already running.
1893 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1894 + " app=" + app + " knownToBeDead=" + knownToBeDead
1895 + " thread=" + (app != null ? app.thread : null)
1896 + " pid=" + (app != null ? app.pid : -1));
1897 if (app != null &&
1898 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1899 return app;
1900 }
1901
1902 String hostingNameStr = hostingName != null
1903 ? hostingName.flattenToShortString() : null;
1904
1905 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1906 // If we are in the background, then check to see if this process
1907 // is bad. If so, we will just silently fail.
1908 if (mBadProcesses.get(info.processName, info.uid) != null) {
1909 return null;
1910 }
1911 } else {
1912 // When the user is explicitly starting a process, then clear its
1913 // crash count so that we won't make it bad until they see at
1914 // least one crash dialog again, and make the process good again
1915 // if it had been bad.
1916 mProcessCrashTimes.remove(info.processName, info.uid);
1917 if (mBadProcesses.get(info.processName, info.uid) != null) {
1918 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1919 info.processName);
1920 mBadProcesses.remove(info.processName, info.uid);
1921 if (app != null) {
1922 app.bad = false;
1923 }
1924 }
1925 }
1926
1927 if (app == null) {
1928 app = newProcessRecordLocked(null, info, processName);
1929 mProcessNames.put(processName, info.uid, app);
1930 } else {
1931 // If this is a new package in the process, add the package to the list
1932 app.addPackage(info.packageName);
1933 }
1934
1935 // If the system is not ready yet, then hold off on starting this
1936 // process until it is.
1937 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001938 && !isAllowedWhileBooting(info)
1939 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001940 if (!mProcessesOnHold.contains(app)) {
1941 mProcessesOnHold.add(app);
1942 }
1943 return app;
1944 }
1945
1946 startProcessLocked(app, hostingType, hostingNameStr);
1947 return (app.pid != 0) ? app : null;
1948 }
1949
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001950 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1951 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1952 }
1953
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001954 private final void startProcessLocked(ProcessRecord app,
1955 String hostingType, String hostingNameStr) {
1956 if (app.pid > 0 && app.pid != MY_PID) {
1957 synchronized (mPidsSelfLocked) {
1958 mPidsSelfLocked.remove(app.pid);
1959 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1960 }
1961 app.pid = 0;
1962 }
1963
1964 mProcessesOnHold.remove(app);
1965
1966 updateCpuStats();
1967
1968 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1969 mProcDeaths[0] = 0;
1970
1971 try {
1972 int uid = app.info.uid;
1973 int[] gids = null;
1974 try {
1975 gids = mContext.getPackageManager().getPackageGids(
1976 app.info.packageName);
1977 } catch (PackageManager.NameNotFoundException e) {
1978 Log.w(TAG, "Unable to retrieve gids", e);
1979 }
1980 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1981 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1982 && mTopComponent != null
1983 && app.processName.equals(mTopComponent.getPackageName())) {
1984 uid = 0;
1985 }
1986 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1987 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1988 uid = 0;
1989 }
1990 }
1991 int debugFlags = 0;
1992 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1993 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1994 }
1995 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1996 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1997 }
1998 if ("1".equals(SystemProperties.get("debug.assert"))) {
1999 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
2000 }
2001 int pid = Process.start("android.app.ActivityThread",
2002 mSimpleProcessManagement ? app.processName : null, uid, uid,
2003 gids, debugFlags, null);
2004 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
2005 synchronized (bs) {
2006 if (bs.isOnBattery()) {
2007 app.batteryStats.incStartsLocked();
2008 }
2009 }
2010
2011 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
2012 app.processName, hostingType,
2013 hostingNameStr != null ? hostingNameStr : "");
2014
2015 if (app.persistent) {
2016 Watchdog.getInstance().processStarted(app, app.processName, pid);
2017 }
2018
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07002019 StringBuilder buf = mStringBuilder;
2020 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002021 buf.append("Start proc ");
2022 buf.append(app.processName);
2023 buf.append(" for ");
2024 buf.append(hostingType);
2025 if (hostingNameStr != null) {
2026 buf.append(" ");
2027 buf.append(hostingNameStr);
2028 }
2029 buf.append(": pid=");
2030 buf.append(pid);
2031 buf.append(" uid=");
2032 buf.append(uid);
2033 buf.append(" gids={");
2034 if (gids != null) {
2035 for (int gi=0; gi<gids.length; gi++) {
2036 if (gi != 0) buf.append(", ");
2037 buf.append(gids[gi]);
2038
2039 }
2040 }
2041 buf.append("}");
2042 Log.i(TAG, buf.toString());
2043 if (pid == 0 || pid == MY_PID) {
2044 // Processes are being emulated with threads.
2045 app.pid = MY_PID;
2046 app.removed = false;
2047 mStartingProcesses.add(app);
2048 } else if (pid > 0) {
2049 app.pid = pid;
2050 app.removed = false;
2051 synchronized (mPidsSelfLocked) {
2052 this.mPidsSelfLocked.put(pid, app);
2053 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2054 msg.obj = app;
2055 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2056 }
2057 } else {
2058 app.pid = 0;
2059 RuntimeException e = new RuntimeException(
2060 "Failure starting process " + app.processName
2061 + ": returned pid=" + pid);
2062 Log.e(TAG, e.getMessage(), e);
2063 }
2064 } catch (RuntimeException e) {
2065 // XXX do better error recovery.
2066 app.pid = 0;
2067 Log.e(TAG, "Failure starting process " + app.processName, e);
2068 }
2069 }
2070
2071 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2072 if (mPausingActivity != null) {
2073 RuntimeException e = new RuntimeException();
2074 Log.e(TAG, "Trying to pause when pause is already pending for "
2075 + mPausingActivity, e);
2076 }
2077 HistoryRecord prev = mResumedActivity;
2078 if (prev == null) {
2079 RuntimeException e = new RuntimeException();
2080 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2081 resumeTopActivityLocked(null);
2082 return;
2083 }
2084 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2085 mResumedActivity = null;
2086 mPausingActivity = prev;
2087 mLastPausedActivity = prev;
2088 prev.state = ActivityState.PAUSING;
2089 prev.task.touchActiveTime();
2090
2091 updateCpuStats();
2092
2093 if (prev.app != null && prev.app.thread != null) {
2094 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2095 try {
2096 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2097 System.identityHashCode(prev),
2098 prev.shortComponentName);
2099 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2100 prev.configChangeFlags);
2101 updateUsageStats(prev, false);
2102 } catch (Exception e) {
2103 // Ignore exception, if process died other code will cleanup.
2104 Log.w(TAG, "Exception thrown during pause", e);
2105 mPausingActivity = null;
2106 mLastPausedActivity = null;
2107 }
2108 } else {
2109 mPausingActivity = null;
2110 mLastPausedActivity = null;
2111 }
2112
2113 // If we are not going to sleep, we want to ensure the device is
2114 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002115 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002116 mLaunchingActivity.acquire();
2117 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2118 // To be safe, don't allow the wake lock to be held for too long.
2119 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2120 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2121 }
2122 }
2123
2124
2125 if (mPausingActivity != null) {
2126 // Have the window manager pause its key dispatching until the new
2127 // activity has started. If we're pausing the activity just because
2128 // the screen is being turned off and the UI is sleeping, don't interrupt
2129 // key dispatch; the same activity will pick it up again on wakeup.
2130 if (!uiSleeping) {
2131 prev.pauseKeyDispatchingLocked();
2132 } else {
2133 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2134 }
2135
2136 // Schedule a pause timeout in case the app doesn't respond.
2137 // We don't give it much time because this directly impacts the
2138 // responsiveness seen by the user.
2139 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2140 msg.obj = prev;
2141 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2142 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2143 } else {
2144 // This activity failed to schedule the
2145 // pause, so just treat it as being paused now.
2146 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2147 resumeTopActivityLocked(null);
2148 }
2149 }
2150
2151 private final void completePauseLocked() {
2152 HistoryRecord prev = mPausingActivity;
2153 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2154
2155 if (prev != null) {
2156 if (prev.finishing) {
2157 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2158 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2159 } else if (prev.app != null) {
2160 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2161 if (prev.waitingVisible) {
2162 prev.waitingVisible = false;
2163 mWaitingVisibleActivities.remove(prev);
2164 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2165 TAG, "Complete pause, no longer waiting: " + prev);
2166 }
2167 if (prev.configDestroy) {
2168 // The previous is being paused because the configuration
2169 // is changing, which means it is actually stopping...
2170 // To juggle the fact that we are also starting a new
2171 // instance right now, we need to first completely stop
2172 // the current instance before starting the new one.
2173 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2174 destroyActivityLocked(prev, true);
2175 } else {
2176 mStoppingActivities.add(prev);
2177 if (mStoppingActivities.size() > 3) {
2178 // If we already have a few activities waiting to stop,
2179 // then give up on things going idle and start clearing
2180 // them out.
2181 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2182 Message msg = Message.obtain();
2183 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2184 mHandler.sendMessage(msg);
2185 }
2186 }
2187 } else {
2188 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2189 prev = null;
2190 }
2191 mPausingActivity = null;
2192 }
2193
Dianne Hackborn55280a92009-05-07 15:53:46 -07002194 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002195 resumeTopActivityLocked(prev);
2196 } else {
2197 if (mGoingToSleep.isHeld()) {
2198 mGoingToSleep.release();
2199 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002200 if (mShuttingDown) {
2201 notifyAll();
2202 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002203 }
2204
2205 if (prev != null) {
2206 prev.resumeKeyDispatchingLocked();
2207 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002208
2209 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2210 long diff = 0;
2211 synchronized (mProcessStatsThread) {
2212 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2213 }
2214 if (diff > 0) {
2215 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2216 synchronized (bsi) {
2217 BatteryStatsImpl.Uid.Proc ps =
2218 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2219 prev.info.packageName);
2220 if (ps != null) {
2221 ps.addForegroundTimeLocked(diff);
2222 }
2223 }
2224 }
2225 }
2226 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002227 }
2228
2229 /**
2230 * Once we know that we have asked an application to put an activity in
2231 * the resumed state (either by launching it or explicitly telling it),
2232 * this function updates the rest of our state to match that fact.
2233 */
2234 private final void completeResumeLocked(HistoryRecord next) {
2235 next.idle = false;
2236 next.results = null;
2237 next.newIntents = null;
2238
2239 // schedule an idle timeout in case the app doesn't do it for us.
2240 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2241 msg.obj = next;
2242 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2243
2244 if (false) {
2245 // The activity was never told to pause, so just keep
2246 // things going as-is. To maintain our own state,
2247 // we need to emulate it coming back and saying it is
2248 // idle.
2249 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2250 msg.obj = next;
2251 mHandler.sendMessage(msg);
2252 }
2253
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002254 reportResumedActivity(next);
2255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002256 next.thumbnail = null;
2257 setFocusedActivityLocked(next);
2258 next.resumeKeyDispatchingLocked();
2259 ensureActivitiesVisibleLocked(null, 0);
2260 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002261 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002262
2263 // Mark the point when the activity is resuming
2264 // TODO: To be more accurate, the mark should be before the onCreate,
2265 // not after the onResume. But for subsequent starts, onResume is fine.
2266 if (next.app != null) {
2267 synchronized (mProcessStatsThread) {
2268 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2269 }
2270 } else {
2271 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2272 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002273 }
2274
2275 /**
2276 * Make sure that all activities that need to be visible (that is, they
2277 * currently can be seen by the user) actually are.
2278 */
2279 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2280 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2281 if (DEBUG_VISBILITY) Log.v(
2282 TAG, "ensureActivitiesVisible behind " + top
2283 + " configChanges=0x" + Integer.toHexString(configChanges));
2284
2285 // If the top activity is not fullscreen, then we need to
2286 // make sure any activities under it are now visible.
2287 final int count = mHistory.size();
2288 int i = count-1;
2289 while (mHistory.get(i) != top) {
2290 i--;
2291 }
2292 HistoryRecord r;
2293 boolean behindFullscreen = false;
2294 for (; i>=0; i--) {
2295 r = (HistoryRecord)mHistory.get(i);
2296 if (DEBUG_VISBILITY) Log.v(
2297 TAG, "Make visible? " + r + " finishing=" + r.finishing
2298 + " state=" + r.state);
2299 if (r.finishing) {
2300 continue;
2301 }
2302
2303 final boolean doThisProcess = onlyThisProcess == null
2304 || onlyThisProcess.equals(r.processName);
2305
2306 // First: if this is not the current activity being started, make
2307 // sure it matches the current configuration.
2308 if (r != starting && doThisProcess) {
2309 ensureActivityConfigurationLocked(r, 0);
2310 }
2311
2312 if (r.app == null || r.app.thread == null) {
2313 if (onlyThisProcess == null
2314 || onlyThisProcess.equals(r.processName)) {
2315 // This activity needs to be visible, but isn't even
2316 // running... get it started, but don't resume it
2317 // at this point.
2318 if (DEBUG_VISBILITY) Log.v(
2319 TAG, "Start and freeze screen for " + r);
2320 if (r != starting) {
2321 r.startFreezingScreenLocked(r.app, configChanges);
2322 }
2323 if (!r.visible) {
2324 if (DEBUG_VISBILITY) Log.v(
2325 TAG, "Starting and making visible: " + r);
2326 mWindowManager.setAppVisibility(r, true);
2327 }
2328 if (r != starting) {
2329 startSpecificActivityLocked(r, false, false);
2330 }
2331 }
2332
2333 } else if (r.visible) {
2334 // If this activity is already visible, then there is nothing
2335 // else to do here.
2336 if (DEBUG_VISBILITY) Log.v(
2337 TAG, "Skipping: already visible at " + r);
2338 r.stopFreezingScreenLocked(false);
2339
2340 } else if (onlyThisProcess == null) {
2341 // This activity is not currently visible, but is running.
2342 // Tell it to become visible.
2343 r.visible = true;
2344 if (r.state != ActivityState.RESUMED && r != starting) {
2345 // If this activity is paused, tell it
2346 // to now show its window.
2347 if (DEBUG_VISBILITY) Log.v(
2348 TAG, "Making visible and scheduling visibility: " + r);
2349 try {
2350 mWindowManager.setAppVisibility(r, true);
2351 r.app.thread.scheduleWindowVisibility(r, true);
2352 r.stopFreezingScreenLocked(false);
2353 } catch (Exception e) {
2354 // Just skip on any failure; we'll make it
2355 // visible when it next restarts.
2356 Log.w(TAG, "Exception thrown making visibile: "
2357 + r.intent.getComponent(), e);
2358 }
2359 }
2360 }
2361
2362 // Aggregate current change flags.
2363 configChanges |= r.configChangeFlags;
2364
2365 if (r.fullscreen) {
2366 // At this point, nothing else needs to be shown
2367 if (DEBUG_VISBILITY) Log.v(
2368 TAG, "Stopping: fullscreen at " + r);
2369 behindFullscreen = true;
2370 i--;
2371 break;
2372 }
2373 }
2374
2375 // Now for any activities that aren't visible to the user, make
2376 // sure they no longer are keeping the screen frozen.
2377 while (i >= 0) {
2378 r = (HistoryRecord)mHistory.get(i);
2379 if (DEBUG_VISBILITY) Log.v(
2380 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2381 + " state=" + r.state
2382 + " behindFullscreen=" + behindFullscreen);
2383 if (!r.finishing) {
2384 if (behindFullscreen) {
2385 if (r.visible) {
2386 if (DEBUG_VISBILITY) Log.v(
2387 TAG, "Making invisible: " + r);
2388 r.visible = false;
2389 try {
2390 mWindowManager.setAppVisibility(r, false);
2391 if ((r.state == ActivityState.STOPPING
2392 || r.state == ActivityState.STOPPED)
2393 && r.app != null && r.app.thread != null) {
2394 if (DEBUG_VISBILITY) Log.v(
2395 TAG, "Scheduling invisibility: " + r);
2396 r.app.thread.scheduleWindowVisibility(r, false);
2397 }
2398 } catch (Exception e) {
2399 // Just skip on any failure; we'll make it
2400 // visible when it next restarts.
2401 Log.w(TAG, "Exception thrown making hidden: "
2402 + r.intent.getComponent(), e);
2403 }
2404 } else {
2405 if (DEBUG_VISBILITY) Log.v(
2406 TAG, "Already invisible: " + r);
2407 }
2408 } else if (r.fullscreen) {
2409 if (DEBUG_VISBILITY) Log.v(
2410 TAG, "Now behindFullscreen: " + r);
2411 behindFullscreen = true;
2412 }
2413 }
2414 i--;
2415 }
2416 }
2417
2418 /**
2419 * Version of ensureActivitiesVisible that can easily be called anywhere.
2420 */
2421 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2422 int configChanges) {
2423 HistoryRecord r = topRunningActivityLocked(null);
2424 if (r != null) {
2425 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2426 }
2427 }
2428
2429 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2430 if (resumed) {
2431 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2432 } else {
2433 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2434 }
2435 }
2436
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002437 private boolean startHomeActivityLocked() {
2438 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2439 && mTopAction == null) {
2440 // We are running in factory test mode, but unable to find
2441 // the factory test app, so just sit around displaying the
2442 // error message and don't try to start anything.
2443 return false;
2444 }
2445 Intent intent = new Intent(
2446 mTopAction,
2447 mTopData != null ? Uri.parse(mTopData) : null);
2448 intent.setComponent(mTopComponent);
2449 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2450 intent.addCategory(Intent.CATEGORY_HOME);
2451 }
2452 ActivityInfo aInfo =
2453 intent.resolveActivityInfo(mContext.getPackageManager(),
2454 STOCK_PM_FLAGS);
2455 if (aInfo != null) {
2456 intent.setComponent(new ComponentName(
2457 aInfo.applicationInfo.packageName, aInfo.name));
2458 // Don't do this if the home app is currently being
2459 // instrumented.
2460 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2461 aInfo.applicationInfo.uid);
2462 if (app == null || app.instrumentationClass == null) {
2463 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2464 startActivityLocked(null, intent, null, null, 0, aInfo,
2465 null, null, 0, 0, 0, false, false);
2466 }
2467 }
2468
2469
2470 return true;
2471 }
2472
2473 /**
2474 * Starts the "new version setup screen" if appropriate.
2475 */
2476 private void startSetupActivityLocked() {
2477 // Only do this once per boot.
2478 if (mCheckedForSetup) {
2479 return;
2480 }
2481
2482 // We will show this screen if the current one is a different
2483 // version than the last one shown, and we are not running in
2484 // low-level factory test mode.
2485 final ContentResolver resolver = mContext.getContentResolver();
2486 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2487 Settings.Secure.getInt(resolver,
2488 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2489 mCheckedForSetup = true;
2490
2491 // See if we should be showing the platform update setup UI.
2492 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2493 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2494 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2495
2496 // We don't allow third party apps to replace this.
2497 ResolveInfo ri = null;
2498 for (int i=0; ris != null && i<ris.size(); i++) {
2499 if ((ris.get(i).activityInfo.applicationInfo.flags
2500 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2501 ri = ris.get(i);
2502 break;
2503 }
2504 }
2505
2506 if (ri != null) {
2507 String vers = ri.activityInfo.metaData != null
2508 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2509 : null;
2510 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2511 vers = ri.activityInfo.applicationInfo.metaData.getString(
2512 Intent.METADATA_SETUP_VERSION);
2513 }
2514 String lastVers = Settings.Secure.getString(
2515 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2516 if (vers != null && !vers.equals(lastVers)) {
2517 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2518 intent.setComponent(new ComponentName(
2519 ri.activityInfo.packageName, ri.activityInfo.name));
2520 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2521 null, null, 0, 0, 0, false, false);
2522 }
2523 }
2524 }
2525 }
2526
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002527 private void reportResumedActivity(HistoryRecord r) {
2528 //Log.i(TAG, "**** REPORT RESUME: " + r);
2529
2530 final int identHash = System.identityHashCode(r);
2531 updateUsageStats(r, true);
2532
2533 int i = mWatchers.beginBroadcast();
2534 while (i > 0) {
2535 i--;
2536 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2537 if (w != null) {
2538 try {
2539 w.activityResuming(identHash);
2540 } catch (RemoteException e) {
2541 }
2542 }
2543 }
2544 mWatchers.finishBroadcast();
2545 }
2546
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002547 /**
2548 * Ensure that the top activity in the stack is resumed.
2549 *
2550 * @param prev The previously resumed activity, for when in the process
2551 * of pausing; can be null to call from elsewhere.
2552 *
2553 * @return Returns true if something is being resumed, or false if
2554 * nothing happened.
2555 */
2556 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2557 // Find the first activity that is not finishing.
2558 HistoryRecord next = topRunningActivityLocked(null);
2559
2560 // Remember how we'll process this pause/resume situation, and ensure
2561 // that the state is reset however we wind up proceeding.
2562 final boolean userLeaving = mUserLeaving;
2563 mUserLeaving = false;
2564
2565 if (next == null) {
2566 // There are no more activities! Let's just start up the
2567 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002568 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002569 }
2570
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002571 next.delayedResume = false;
2572
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002573 // If the top activity is the resumed one, nothing to do.
2574 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2575 // Make sure we have executed any pending transitions, since there
2576 // should be nothing left to do at this point.
2577 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002578 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002579 return false;
2580 }
2581
2582 // If we are sleeping, and there is no resumed activity, and the top
2583 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002584 if ((mSleeping || mShuttingDown)
2585 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002586 // Make sure we have executed any pending transitions, since there
2587 // should be nothing left to do at this point.
2588 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002589 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002590 return false;
2591 }
2592
2593 // The activity may be waiting for stop, but that is no longer
2594 // appropriate for it.
2595 mStoppingActivities.remove(next);
2596 mWaitingVisibleActivities.remove(next);
2597
2598 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2599
2600 // If we are currently pausing an activity, then don't do anything
2601 // until that is done.
2602 if (mPausingActivity != null) {
2603 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2604 return false;
2605 }
2606
2607 // We need to start pausing the current activity so the top one
2608 // can be resumed...
2609 if (mResumedActivity != null) {
2610 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2611 startPausingLocked(userLeaving, false);
2612 return true;
2613 }
2614
2615 if (prev != null && prev != next) {
2616 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2617 prev.waitingVisible = true;
2618 mWaitingVisibleActivities.add(prev);
2619 if (DEBUG_SWITCH) Log.v(
2620 TAG, "Resuming top, waiting visible to hide: " + prev);
2621 } else {
2622 // The next activity is already visible, so hide the previous
2623 // activity's windows right now so we can show the new one ASAP.
2624 // We only do this if the previous is finishing, which should mean
2625 // it is on top of the one being resumed so hiding it quickly
2626 // is good. Otherwise, we want to do the normal route of allowing
2627 // the resumed activity to be shown so we can decide if the
2628 // previous should actually be hidden depending on whether the
2629 // new one is found to be full-screen or not.
2630 if (prev.finishing) {
2631 mWindowManager.setAppVisibility(prev, false);
2632 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2633 + prev + ", waitingVisible="
2634 + (prev != null ? prev.waitingVisible : null)
2635 + ", nowVisible=" + next.nowVisible);
2636 } else {
2637 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2638 + prev + ", waitingVisible="
2639 + (prev != null ? prev.waitingVisible : null)
2640 + ", nowVisible=" + next.nowVisible);
2641 }
2642 }
2643 }
2644
2645 // We are starting up the next activity, so tell the window manager
2646 // that the previous one will be hidden soon. This way it can know
2647 // to ignore it when computing the desired screen orientation.
2648 if (prev != null) {
2649 if (prev.finishing) {
2650 if (DEBUG_TRANSITION) Log.v(TAG,
2651 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002652 if (mNoAnimActivities.contains(prev)) {
2653 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2654 } else {
2655 mWindowManager.prepareAppTransition(prev.task == next.task
2656 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2657 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2658 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002659 mWindowManager.setAppWillBeHidden(prev);
2660 mWindowManager.setAppVisibility(prev, false);
2661 } else {
2662 if (DEBUG_TRANSITION) Log.v(TAG,
2663 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002664 if (mNoAnimActivities.contains(next)) {
2665 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2666 } else {
2667 mWindowManager.prepareAppTransition(prev.task == next.task
2668 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2669 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2670 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002671 }
2672 if (false) {
2673 mWindowManager.setAppWillBeHidden(prev);
2674 mWindowManager.setAppVisibility(prev, false);
2675 }
2676 } else if (mHistory.size() > 1) {
2677 if (DEBUG_TRANSITION) Log.v(TAG,
2678 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002679 if (mNoAnimActivities.contains(next)) {
2680 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2681 } else {
2682 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2683 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002684 }
2685
2686 if (next.app != null && next.app.thread != null) {
2687 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2688
2689 // This activity is now becoming visible.
2690 mWindowManager.setAppVisibility(next, true);
2691
2692 HistoryRecord lastResumedActivity = mResumedActivity;
2693 ActivityState lastState = next.state;
2694
2695 updateCpuStats();
2696
2697 next.state = ActivityState.RESUMED;
2698 mResumedActivity = next;
2699 next.task.touchActiveTime();
2700 updateLRUListLocked(next.app, true);
2701 updateLRUListLocked(next);
2702
2703 // Have the window manager re-evaluate the orientation of
2704 // the screen based on the new activity order.
2705 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002706 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002707 next.mayFreezeScreenLocked(next.app) ? next : null);
2708 if (config != null) {
2709 next.frozenBeforeDestroy = true;
2710 }
2711 if (!updateConfigurationLocked(config, next)) {
2712 // The configuration update wasn't able to keep the existing
2713 // instance of the activity, and instead started a new one.
2714 // We should be all done, but let's just make sure our activity
2715 // is still at the top and schedule another run if something
2716 // weird happened.
2717 HistoryRecord nextNext = topRunningActivityLocked(null);
2718 if (DEBUG_SWITCH) Log.i(TAG,
2719 "Activity config changed during resume: " + next
2720 + ", new next: " + nextNext);
2721 if (nextNext != next) {
2722 // Do over!
2723 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2724 }
2725 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002726 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002727 return true;
2728 }
2729
2730 try {
2731 // Deliver all pending results.
2732 ArrayList a = next.results;
2733 if (a != null) {
2734 final int N = a.size();
2735 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002736 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002737 TAG, "Delivering results to " + next
2738 + ": " + a);
2739 next.app.thread.scheduleSendResult(next, a);
2740 }
2741 }
2742
2743 if (next.newIntents != null) {
2744 next.app.thread.scheduleNewIntent(next.newIntents, next);
2745 }
2746
2747 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2748 System.identityHashCode(next),
2749 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002750
2751 next.app.thread.scheduleResumeActivity(next,
2752 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002753
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002754 pauseIfSleepingLocked();
2755
2756 } catch (Exception e) {
2757 // Whoops, need to restart this activity!
2758 next.state = lastState;
2759 mResumedActivity = lastResumedActivity;
2760 if (Config.LOGD) Log.d(TAG,
2761 "Restarting because process died: " + next);
2762 if (!next.hasBeenLaunched) {
2763 next.hasBeenLaunched = true;
2764 } else {
2765 if (SHOW_APP_STARTING_ICON) {
2766 mWindowManager.setAppStartingWindow(
2767 next, next.packageName, next.theme,
2768 next.nonLocalizedLabel,
2769 next.labelRes, next.icon, null, true);
2770 }
2771 }
2772 startSpecificActivityLocked(next, true, false);
2773 return true;
2774 }
2775
2776 // From this point on, if something goes wrong there is no way
2777 // to recover the activity.
2778 try {
2779 next.visible = true;
2780 completeResumeLocked(next);
2781 } catch (Exception e) {
2782 // If any exception gets thrown, toss away this
2783 // activity and try the next one.
2784 Log.w(TAG, "Exception thrown during resume of " + next, e);
2785 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2786 "resume-exception");
2787 return true;
2788 }
2789
2790 // Didn't need to use the icicle, and it is now out of date.
2791 next.icicle = null;
2792 next.haveState = false;
2793 next.stopped = false;
2794
2795 } else {
2796 // Whoops, need to restart this activity!
2797 if (!next.hasBeenLaunched) {
2798 next.hasBeenLaunched = true;
2799 } else {
2800 if (SHOW_APP_STARTING_ICON) {
2801 mWindowManager.setAppStartingWindow(
2802 next, next.packageName, next.theme,
2803 next.nonLocalizedLabel,
2804 next.labelRes, next.icon, null, true);
2805 }
2806 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2807 }
2808 startSpecificActivityLocked(next, true, true);
2809 }
2810
2811 return true;
2812 }
2813
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002814 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2815 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002816 final int NH = mHistory.size();
2817
2818 int addPos = -1;
2819
2820 if (!newTask) {
2821 // If starting in an existing task, find where that is...
2822 HistoryRecord next = null;
2823 boolean startIt = true;
2824 for (int i = NH-1; i >= 0; i--) {
2825 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2826 if (p.finishing) {
2827 continue;
2828 }
2829 if (p.task == r.task) {
2830 // Here it is! Now, if this is not yet visible to the
2831 // user, then just add it without starting; it will
2832 // get started when the user navigates back to it.
2833 addPos = i+1;
2834 if (!startIt) {
2835 mHistory.add(addPos, r);
2836 r.inHistory = true;
2837 r.task.numActivities++;
2838 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2839 r.info.screenOrientation, r.fullscreen);
2840 if (VALIDATE_TOKENS) {
2841 mWindowManager.validateAppTokens(mHistory);
2842 }
2843 return;
2844 }
2845 break;
2846 }
2847 if (p.fullscreen) {
2848 startIt = false;
2849 }
2850 next = p;
2851 }
2852 }
2853
2854 // Place a new activity at top of stack, so it is next to interact
2855 // with the user.
2856 if (addPos < 0) {
2857 addPos = mHistory.size();
2858 }
2859
2860 // If we are not placing the new activity frontmost, we do not want
2861 // to deliver the onUserLeaving callback to the actual frontmost
2862 // activity
2863 if (addPos < NH) {
2864 mUserLeaving = false;
2865 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2866 }
2867
2868 // Slot the activity into the history stack and proceed
2869 mHistory.add(addPos, r);
2870 r.inHistory = true;
2871 r.frontOfTask = newTask;
2872 r.task.numActivities++;
2873 if (NH > 0) {
2874 // We want to show the starting preview window if we are
2875 // switching to a new task, or the next activity's process is
2876 // not currently running.
2877 boolean showStartingIcon = newTask;
2878 ProcessRecord proc = r.app;
2879 if (proc == null) {
2880 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2881 }
2882 if (proc == null || proc.thread == null) {
2883 showStartingIcon = true;
2884 }
2885 if (DEBUG_TRANSITION) Log.v(TAG,
2886 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002887 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2888 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2889 mNoAnimActivities.add(r);
2890 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2891 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2892 mNoAnimActivities.remove(r);
2893 } else {
2894 mWindowManager.prepareAppTransition(newTask
2895 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2896 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2897 mNoAnimActivities.remove(r);
2898 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002899 mWindowManager.addAppToken(
2900 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2901 boolean doShow = true;
2902 if (newTask) {
2903 // Even though this activity is starting fresh, we still need
2904 // to reset it to make sure we apply affinities to move any
2905 // existing activities from other tasks in to it.
2906 // If the caller has requested that the target task be
2907 // reset, then do so.
2908 if ((r.intent.getFlags()
2909 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2910 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002911 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002912 }
2913 }
2914 if (SHOW_APP_STARTING_ICON && doShow) {
2915 // Figure out if we are transitioning from another activity that is
2916 // "has the same starting icon" as the next one. This allows the
2917 // window manager to keep the previous window it had previously
2918 // created, if it still had one.
2919 HistoryRecord prev = mResumedActivity;
2920 if (prev != null) {
2921 // We don't want to reuse the previous starting preview if:
2922 // (1) The current activity is in a different task.
2923 if (prev.task != r.task) prev = null;
2924 // (2) The current activity is already displayed.
2925 else if (prev.nowVisible) prev = null;
2926 }
2927 mWindowManager.setAppStartingWindow(
2928 r, r.packageName, r.theme, r.nonLocalizedLabel,
2929 r.labelRes, r.icon, prev, showStartingIcon);
2930 }
2931 } else {
2932 // If this is the first activity, don't do any fancy animations,
2933 // because there is nothing for it to animate on top of.
2934 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2935 r.info.screenOrientation, r.fullscreen);
2936 }
2937 if (VALIDATE_TOKENS) {
2938 mWindowManager.validateAppTokens(mHistory);
2939 }
2940
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002941 if (doResume) {
2942 resumeTopActivityLocked(null);
2943 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002944 }
2945
2946 /**
2947 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002948 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2949 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002950 * an instance of that activity in the stack and, if found, finish all
2951 * activities on top of it and return the instance.
2952 *
2953 * @param newR Description of the new activity being started.
2954 * @return Returns the old activity that should be continue to be used,
2955 * or null if none was found.
2956 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002957 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002958 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002959 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002960
2961 // First find the requested task.
2962 while (i > 0) {
2963 i--;
2964 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2965 if (r.task.taskId == taskId) {
2966 i++;
2967 break;
2968 }
2969 }
2970
2971 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002972 while (i > 0) {
2973 i--;
2974 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2975 if (r.finishing) {
2976 continue;
2977 }
2978 if (r.task.taskId != taskId) {
2979 return null;
2980 }
2981 if (r.realActivity.equals(newR.realActivity)) {
2982 // Here it is! Now finish everything in front...
2983 HistoryRecord ret = r;
2984 if (doClear) {
2985 while (i < (mHistory.size()-1)) {
2986 i++;
2987 r = (HistoryRecord)mHistory.get(i);
2988 if (r.finishing) {
2989 continue;
2990 }
2991 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2992 null, "clear")) {
2993 i--;
2994 }
2995 }
2996 }
2997
2998 // Finally, if this is a normal launch mode (that is, not
2999 // expecting onNewIntent()), then we will finish the current
3000 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003001 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
3002 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003003 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003004 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003005 if (index >= 0) {
3006 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
3007 null, "clear");
3008 }
3009 return null;
3010 }
3011 }
3012
3013 return ret;
3014 }
3015 }
3016
3017 return null;
3018 }
3019
3020 /**
3021 * Find the activity in the history stack within the given task. Returns
3022 * the index within the history at which it's found, or < 0 if not found.
3023 */
3024 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3025 int i = mHistory.size();
3026 while (i > 0) {
3027 i--;
3028 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3029 if (candidate.task.taskId != task) {
3030 break;
3031 }
3032 if (candidate.realActivity.equals(r.realActivity)) {
3033 return i;
3034 }
3035 }
3036
3037 return -1;
3038 }
3039
3040 /**
3041 * Reorder the history stack so that the activity at the given index is
3042 * brought to the front.
3043 */
3044 private final HistoryRecord moveActivityToFrontLocked(int where) {
3045 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3046 int top = mHistory.size();
3047 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3048 mHistory.add(top, newTop);
3049 oldTop.frontOfTask = false;
3050 newTop.frontOfTask = true;
3051 return newTop;
3052 }
3053
3054 /**
3055 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3056 * method will be called at the proper time.
3057 */
3058 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3059 boolean sent = false;
3060 if (r.state == ActivityState.RESUMED
3061 && r.app != null && r.app.thread != null) {
3062 try {
3063 ArrayList<Intent> ar = new ArrayList<Intent>();
3064 ar.add(new Intent(intent));
3065 r.app.thread.scheduleNewIntent(ar, r);
3066 sent = true;
3067 } catch (Exception e) {
3068 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3069 }
3070 }
3071 if (!sent) {
3072 r.addNewIntentLocked(new Intent(intent));
3073 }
3074 }
3075
3076 private final void logStartActivity(int tag, HistoryRecord r,
3077 TaskRecord task) {
3078 EventLog.writeEvent(tag,
3079 System.identityHashCode(r), task.taskId,
3080 r.shortComponentName, r.intent.getAction(),
3081 r.intent.getType(), r.intent.getDataString(),
3082 r.intent.getFlags());
3083 }
3084
3085 private final int startActivityLocked(IApplicationThread caller,
3086 Intent intent, String resolvedType,
3087 Uri[] grantedUriPermissions,
3088 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3089 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003090 int callingPid, int callingUid, boolean onlyIfNeeded,
3091 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003092 Log.i(TAG, "Starting activity: " + intent);
3093
3094 HistoryRecord sourceRecord = null;
3095 HistoryRecord resultRecord = null;
3096 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003097 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003098 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003099 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3100 if (index >= 0) {
3101 sourceRecord = (HistoryRecord)mHistory.get(index);
3102 if (requestCode >= 0 && !sourceRecord.finishing) {
3103 resultRecord = sourceRecord;
3104 }
3105 }
3106 }
3107
3108 int launchFlags = intent.getFlags();
3109
3110 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3111 && sourceRecord != null) {
3112 // Transfer the result target from the source activity to the new
3113 // one being started, including any failures.
3114 if (requestCode >= 0) {
3115 return START_FORWARD_AND_REQUEST_CONFLICT;
3116 }
3117 resultRecord = sourceRecord.resultTo;
3118 resultWho = sourceRecord.resultWho;
3119 requestCode = sourceRecord.requestCode;
3120 sourceRecord.resultTo = null;
3121 if (resultRecord != null) {
3122 resultRecord.removeResultsLocked(
3123 sourceRecord, resultWho, requestCode);
3124 }
3125 }
3126
3127 int err = START_SUCCESS;
3128
3129 if (intent.getComponent() == null) {
3130 // We couldn't find a class that can handle the given Intent.
3131 // That's the end of that!
3132 err = START_INTENT_NOT_RESOLVED;
3133 }
3134
3135 if (err == START_SUCCESS && aInfo == null) {
3136 // We couldn't find the specific class specified in the Intent.
3137 // Also the end of the line.
3138 err = START_CLASS_NOT_FOUND;
3139 }
3140
3141 ProcessRecord callerApp = null;
3142 if (err == START_SUCCESS && caller != null) {
3143 callerApp = getRecordForAppLocked(caller);
3144 if (callerApp != null) {
3145 callingPid = callerApp.pid;
3146 callingUid = callerApp.info.uid;
3147 } else {
3148 Log.w(TAG, "Unable to find app for caller " + caller
3149 + " (pid=" + callingPid + ") when starting: "
3150 + intent.toString());
3151 err = START_PERMISSION_DENIED;
3152 }
3153 }
3154
3155 if (err != START_SUCCESS) {
3156 if (resultRecord != null) {
3157 sendActivityResultLocked(-1,
3158 resultRecord, resultWho, requestCode,
3159 Activity.RESULT_CANCELED, null);
3160 }
3161 return err;
3162 }
3163
3164 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3165 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3166 if (perm != PackageManager.PERMISSION_GRANTED) {
3167 if (resultRecord != null) {
3168 sendActivityResultLocked(-1,
3169 resultRecord, resultWho, requestCode,
3170 Activity.RESULT_CANCELED, null);
3171 }
3172 String msg = "Permission Denial: starting " + intent.toString()
3173 + " from " + callerApp + " (pid=" + callingPid
3174 + ", uid=" + callingUid + ")"
3175 + " requires " + aInfo.permission;
3176 Log.w(TAG, msg);
3177 throw new SecurityException(msg);
3178 }
3179
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003180 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003181 boolean abort = false;
3182 try {
3183 // The Intent we give to the watcher has the extra data
3184 // stripped off, since it can contain private information.
3185 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003186 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003187 aInfo.applicationInfo.packageName);
3188 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003189 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003190 }
3191
3192 if (abort) {
3193 if (resultRecord != null) {
3194 sendActivityResultLocked(-1,
3195 resultRecord, resultWho, requestCode,
3196 Activity.RESULT_CANCELED, null);
3197 }
3198 // We pretend to the caller that it was really started, but
3199 // they will just get a cancel result.
3200 return START_SUCCESS;
3201 }
3202 }
3203
3204 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3205 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003206 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003207
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003208 if (mResumedActivity == null
3209 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3210 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3211 PendingActivityLaunch pal = new PendingActivityLaunch();
3212 pal.r = r;
3213 pal.sourceRecord = sourceRecord;
3214 pal.grantedUriPermissions = grantedUriPermissions;
3215 pal.grantedMode = grantedMode;
3216 pal.onlyIfNeeded = onlyIfNeeded;
3217 mPendingActivityLaunches.add(pal);
3218 return START_SWITCHES_CANCELED;
3219 }
3220 }
3221
3222 if (mDidAppSwitch) {
3223 // This is the second allowed switch since we stopped switches,
3224 // so now just generally allow switches. Use case: user presses
3225 // home (switches disabled, switch to home, mDidAppSwitch now true);
3226 // user taps a home icon (coming from home so allowed, we hit here
3227 // and now allow anyone to switch again).
3228 mAppSwitchesAllowedTime = 0;
3229 } else {
3230 mDidAppSwitch = true;
3231 }
3232
3233 doPendingActivityLaunchesLocked(false);
3234
3235 return startActivityUncheckedLocked(r, sourceRecord,
3236 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3237 }
3238
3239 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3240 final int N = mPendingActivityLaunches.size();
3241 if (N <= 0) {
3242 return;
3243 }
3244 for (int i=0; i<N; i++) {
3245 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3246 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3247 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3248 doResume && i == (N-1));
3249 }
3250 mPendingActivityLaunches.clear();
3251 }
3252
3253 private final int startActivityUncheckedLocked(HistoryRecord r,
3254 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3255 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3256 final Intent intent = r.intent;
3257 final int callingUid = r.launchedFromUid;
3258
3259 int launchFlags = intent.getFlags();
3260
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003261 // We'll invoke onUserLeaving before onPause only if the launching
3262 // activity did not explicitly state that this is an automated launch.
3263 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3264 if (DEBUG_USER_LEAVING) Log.v(TAG,
3265 "startActivity() => mUserLeaving=" + mUserLeaving);
3266
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003267 // If the caller has asked not to resume at this point, we make note
3268 // of this in the record so that we can skip it when trying to find
3269 // the top running activity.
3270 if (!doResume) {
3271 r.delayedResume = true;
3272 }
3273
3274 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3275 != 0 ? r : null;
3276
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003277 // If the onlyIfNeeded flag is set, then we can do this if the activity
3278 // being launched is the same as the one making the call... or, as
3279 // a special case, if we do not know the caller then we count the
3280 // current top activity as the caller.
3281 if (onlyIfNeeded) {
3282 HistoryRecord checkedCaller = sourceRecord;
3283 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003284 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003285 }
3286 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3287 // Caller is not the same as launcher, so always needed.
3288 onlyIfNeeded = false;
3289 }
3290 }
3291
3292 if (grantedUriPermissions != null && callingUid > 0) {
3293 for (int i=0; i<grantedUriPermissions.length; i++) {
3294 grantUriPermissionLocked(callingUid, r.packageName,
3295 grantedUriPermissions[i], grantedMode, r);
3296 }
3297 }
3298
3299 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3300 intent, r);
3301
3302 if (sourceRecord == null) {
3303 // This activity is not being started from another... in this
3304 // case we -always- start a new task.
3305 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3306 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3307 + intent);
3308 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3309 }
3310 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3311 // The original activity who is starting us is running as a single
3312 // instance... this new activity it is starting must go on its
3313 // own task.
3314 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3315 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3316 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3317 // The activity being started is a single instance... it always
3318 // gets launched into its own task.
3319 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3320 }
3321
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003322 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003323 // For whatever reason this activity is being launched into a new
3324 // task... yet the caller has requested a result back. Well, that
3325 // is pretty messed up, so instead immediately send back a cancel
3326 // and let the new task continue launched as normal without a
3327 // dependency on its originator.
3328 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3329 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003330 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003331 Activity.RESULT_CANCELED, null);
3332 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003333 }
3334
3335 boolean addingToTask = false;
3336 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3337 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3338 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3339 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3340 // If bring to front is requested, and no result is requested, and
3341 // we can find a task that was started with this same
3342 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003343 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003344 // See if there is a task to bring to the front. If this is
3345 // a SINGLE_INSTANCE activity, there can be one and only one
3346 // instance of it in the history, and it is always in its own
3347 // unique task, so we do a special search.
3348 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3349 ? findTaskLocked(intent, r.info)
3350 : findActivityLocked(intent, r.info);
3351 if (taskTop != null) {
3352 if (taskTop.task.intent == null) {
3353 // This task was started because of movement of
3354 // the activity based on affinity... now that we
3355 // are actually launching it, we can assign the
3356 // base intent.
3357 taskTop.task.setIntent(intent, r.info);
3358 }
3359 // If the target task is not in the front, then we need
3360 // to bring it to the front... except... well, with
3361 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3362 // to have the same behavior as if a new instance was
3363 // being started, which means not bringing it to the front
3364 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003365 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003366 if (curTop.task != taskTop.task) {
3367 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3368 boolean callerAtFront = sourceRecord == null
3369 || curTop.task == sourceRecord.task;
3370 if (callerAtFront) {
3371 // We really do want to push this one into the
3372 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003373 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003374 }
3375 }
3376 // If the caller has requested that the target task be
3377 // reset, then do so.
3378 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3379 taskTop = resetTaskIfNeededLocked(taskTop, r);
3380 }
3381 if (onlyIfNeeded) {
3382 // We don't need to start a new activity, and
3383 // the client said not to do anything if that
3384 // is the case, so this is it! And for paranoia, make
3385 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003386 if (doResume) {
3387 resumeTopActivityLocked(null);
3388 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003389 return START_RETURN_INTENT_TO_CALLER;
3390 }
3391 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3392 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3393 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3394 // In this situation we want to remove all activities
3395 // from the task up to the one being started. In most
3396 // cases this means we are resetting the task to its
3397 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003398 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003399 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003400 if (top != null) {
3401 if (top.frontOfTask) {
3402 // Activity aliases may mean we use different
3403 // intents for the top activity, so make sure
3404 // the task now has the identity of the new
3405 // intent.
3406 top.task.setIntent(r.intent, r.info);
3407 }
3408 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3409 deliverNewIntentLocked(top, r.intent);
3410 } else {
3411 // A special case: we need to
3412 // start the activity because it is not currently
3413 // running, and the caller has asked to clear the
3414 // current task to have this activity at the top.
3415 addingToTask = true;
3416 // Now pretend like this activity is being started
3417 // by the top of its task, so it is put in the
3418 // right place.
3419 sourceRecord = taskTop;
3420 }
3421 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3422 // In this case the top activity on the task is the
3423 // same as the one being launched, so we take that
3424 // as a request to bring the task to the foreground.
3425 // If the top activity in the task is the root
3426 // activity, deliver this new intent to it if it
3427 // desires.
3428 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3429 && taskTop.realActivity.equals(r.realActivity)) {
3430 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3431 if (taskTop.frontOfTask) {
3432 taskTop.task.setIntent(r.intent, r.info);
3433 }
3434 deliverNewIntentLocked(taskTop, r.intent);
3435 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3436 // In this case we are launching the root activity
3437 // of the task, but with a different intent. We
3438 // should start a new instance on top.
3439 addingToTask = true;
3440 sourceRecord = taskTop;
3441 }
3442 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3443 // In this case an activity is being launched in to an
3444 // existing task, without resetting that task. This
3445 // is typically the situation of launching an activity
3446 // from a notification or shortcut. We want to place
3447 // the new activity on top of the current task.
3448 addingToTask = true;
3449 sourceRecord = taskTop;
3450 } else if (!taskTop.task.rootWasReset) {
3451 // In this case we are launching in to an existing task
3452 // that has not yet been started from its front door.
3453 // The current task has been brought to the front.
3454 // Ideally, we'd probably like to place this new task
3455 // at the bottom of its stack, but that's a little hard
3456 // to do with the current organization of the code so
3457 // for now we'll just drop it.
3458 taskTop.task.setIntent(r.intent, r.info);
3459 }
3460 if (!addingToTask) {
3461 // We didn't do anything... but it was needed (a.k.a., client
3462 // don't use that intent!) And for paranoia, make
3463 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003464 if (doResume) {
3465 resumeTopActivityLocked(null);
3466 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003467 return START_TASK_TO_FRONT;
3468 }
3469 }
3470 }
3471 }
3472
3473 //String uri = r.intent.toURI();
3474 //Intent intent2 = new Intent(uri);
3475 //Log.i(TAG, "Given intent: " + r.intent);
3476 //Log.i(TAG, "URI is: " + uri);
3477 //Log.i(TAG, "To intent: " + intent2);
3478
3479 if (r.packageName != null) {
3480 // If the activity being launched is the same as the one currently
3481 // at the top, then we need to check if it should only be launched
3482 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003483 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3484 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003485 if (top.realActivity.equals(r.realActivity)) {
3486 if (top.app != null && top.app.thread != null) {
3487 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3488 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3489 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3490 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3491 // For paranoia, make sure we have correctly
3492 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003493 if (doResume) {
3494 resumeTopActivityLocked(null);
3495 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003496 if (onlyIfNeeded) {
3497 // We don't need to start a new activity, and
3498 // the client said not to do anything if that
3499 // is the case, so this is it!
3500 return START_RETURN_INTENT_TO_CALLER;
3501 }
3502 deliverNewIntentLocked(top, r.intent);
3503 return START_DELIVERED_TO_TOP;
3504 }
3505 }
3506 }
3507 }
3508
3509 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003510 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003511 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003512 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003513 Activity.RESULT_CANCELED, null);
3514 }
3515 return START_CLASS_NOT_FOUND;
3516 }
3517
3518 boolean newTask = false;
3519
3520 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003521 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003522 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3523 // todo: should do better management of integers.
3524 mCurTask++;
3525 if (mCurTask <= 0) {
3526 mCurTask = 1;
3527 }
3528 r.task = new TaskRecord(mCurTask, r.info, intent,
3529 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3530 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3531 + " in new task " + r.task);
3532 newTask = true;
3533 addRecentTask(r.task);
3534
3535 } else if (sourceRecord != null) {
3536 if (!addingToTask &&
3537 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3538 // In this case, we are adding the activity to an existing
3539 // task, but the caller has asked to clear that task if the
3540 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003541 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003542 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003543 if (top != null) {
3544 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3545 deliverNewIntentLocked(top, r.intent);
3546 // For paranoia, make sure we have correctly
3547 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003548 if (doResume) {
3549 resumeTopActivityLocked(null);
3550 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003551 return START_DELIVERED_TO_TOP;
3552 }
3553 } else if (!addingToTask &&
3554 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3555 // In this case, we are launching an activity in our own task
3556 // that may already be running somewhere in the history, and
3557 // we want to shuffle it to the front of the stack if so.
3558 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3559 if (where >= 0) {
3560 HistoryRecord top = moveActivityToFrontLocked(where);
3561 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3562 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003563 if (doResume) {
3564 resumeTopActivityLocked(null);
3565 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003566 return START_DELIVERED_TO_TOP;
3567 }
3568 }
3569 // An existing activity is starting this new activity, so we want
3570 // to keep the new one in the same task as the one that is starting
3571 // it.
3572 r.task = sourceRecord.task;
3573 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3574 + " in existing task " + r.task);
3575
3576 } else {
3577 // This not being started from an existing activity, and not part
3578 // of a new task... just put it in the top task, though these days
3579 // this case should never happen.
3580 final int N = mHistory.size();
3581 HistoryRecord prev =
3582 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3583 r.task = prev != null
3584 ? prev.task
3585 : new TaskRecord(mCurTask, r.info, intent,
3586 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3587 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3588 + " in new guessed " + r.task);
3589 }
3590 if (newTask) {
3591 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3592 }
3593 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003594 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003595 return START_SUCCESS;
3596 }
3597
3598 public final int startActivity(IApplicationThread caller,
3599 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3600 int grantedMode, IBinder resultTo,
3601 String resultWho, int requestCode, boolean onlyIfNeeded,
3602 boolean debug) {
3603 // Refuse possible leaked file descriptors
3604 if (intent != null && intent.hasFileDescriptors()) {
3605 throw new IllegalArgumentException("File descriptors passed in Intent");
3606 }
3607
The Android Open Source Project4df24232009-03-05 14:34:35 -08003608 final boolean componentSpecified = intent.getComponent() != null;
3609
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003610 // Don't modify the client's object!
3611 intent = new Intent(intent);
3612
3613 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003614 ActivityInfo aInfo;
3615 try {
3616 ResolveInfo rInfo =
3617 ActivityThread.getPackageManager().resolveIntent(
3618 intent, resolvedType,
3619 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003620 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003621 aInfo = rInfo != null ? rInfo.activityInfo : null;
3622 } catch (RemoteException e) {
3623 aInfo = null;
3624 }
3625
3626 if (aInfo != null) {
3627 // Store the found target back into the intent, because now that
3628 // we have it we never want to do this again. For example, if the
3629 // user navigates back to this point in the history, we should
3630 // always restart the exact same activity.
3631 intent.setComponent(new ComponentName(
3632 aInfo.applicationInfo.packageName, aInfo.name));
3633
3634 // Don't debug things in the system process
3635 if (debug) {
3636 if (!aInfo.processName.equals("system")) {
3637 setDebugApp(aInfo.processName, true, false);
3638 }
3639 }
3640 }
3641
3642 synchronized(this) {
3643 final long origId = Binder.clearCallingIdentity();
3644 int res = startActivityLocked(caller, intent, resolvedType,
3645 grantedUriPermissions, grantedMode, aInfo,
3646 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003647 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003648 Binder.restoreCallingIdentity(origId);
3649 return res;
3650 }
3651 }
3652
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003653 public int startActivityIntentSender(IApplicationThread caller,
3654 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003655 IBinder resultTo, String resultWho, int requestCode,
3656 int flagsMask, int flagsValues) {
3657 // Refuse possible leaked file descriptors
3658 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3659 throw new IllegalArgumentException("File descriptors passed in Intent");
3660 }
3661
3662 IIntentSender sender = intent.getTarget();
3663 if (!(sender instanceof PendingIntentRecord)) {
3664 throw new IllegalArgumentException("Bad PendingIntent object");
3665 }
3666
3667 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003668
3669 synchronized (this) {
3670 // If this is coming from the currently resumed activity, it is
3671 // effectively saying that app switches are allowed at this point.
3672 if (mResumedActivity != null
3673 && mResumedActivity.info.applicationInfo.uid ==
3674 Binder.getCallingUid()) {
3675 mAppSwitchesAllowedTime = 0;
3676 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003677 }
3678
3679 return pir.sendInner(0, fillInIntent, resolvedType,
3680 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3681 }
3682
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003683 public boolean startNextMatchingActivity(IBinder callingActivity,
3684 Intent intent) {
3685 // Refuse possible leaked file descriptors
3686 if (intent != null && intent.hasFileDescriptors() == true) {
3687 throw new IllegalArgumentException("File descriptors passed in Intent");
3688 }
3689
3690 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003691 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003692 if (index < 0) {
3693 return false;
3694 }
3695 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3696 if (r.app == null || r.app.thread == null) {
3697 // The caller is not running... d'oh!
3698 return false;
3699 }
3700 intent = new Intent(intent);
3701 // The caller is not allowed to change the data.
3702 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3703 // And we are resetting to find the next component...
3704 intent.setComponent(null);
3705
3706 ActivityInfo aInfo = null;
3707 try {
3708 List<ResolveInfo> resolves =
3709 ActivityThread.getPackageManager().queryIntentActivities(
3710 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003711 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003712
3713 // Look for the original activity in the list...
3714 final int N = resolves != null ? resolves.size() : 0;
3715 for (int i=0; i<N; i++) {
3716 ResolveInfo rInfo = resolves.get(i);
3717 if (rInfo.activityInfo.packageName.equals(r.packageName)
3718 && rInfo.activityInfo.name.equals(r.info.name)) {
3719 // We found the current one... the next matching is
3720 // after it.
3721 i++;
3722 if (i<N) {
3723 aInfo = resolves.get(i).activityInfo;
3724 }
3725 break;
3726 }
3727 }
3728 } catch (RemoteException e) {
3729 }
3730
3731 if (aInfo == null) {
3732 // Nobody who is next!
3733 return false;
3734 }
3735
3736 intent.setComponent(new ComponentName(
3737 aInfo.applicationInfo.packageName, aInfo.name));
3738 intent.setFlags(intent.getFlags()&~(
3739 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3740 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3741 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3742 Intent.FLAG_ACTIVITY_NEW_TASK));
3743
3744 // Okay now we need to start the new activity, replacing the
3745 // currently running activity. This is a little tricky because
3746 // we want to start the new one as if the current one is finished,
3747 // but not finish the current one first so that there is no flicker.
3748 // And thus...
3749 final boolean wasFinishing = r.finishing;
3750 r.finishing = true;
3751
3752 // Propagate reply information over to the new activity.
3753 final HistoryRecord resultTo = r.resultTo;
3754 final String resultWho = r.resultWho;
3755 final int requestCode = r.requestCode;
3756 r.resultTo = null;
3757 if (resultTo != null) {
3758 resultTo.removeResultsLocked(r, resultWho, requestCode);
3759 }
3760
3761 final long origId = Binder.clearCallingIdentity();
3762 // XXX we are not dealing with propagating grantedUriPermissions...
3763 // those are not yet exposed to user code, so there is no need.
3764 int res = startActivityLocked(r.app.thread, intent,
3765 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003766 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003767 Binder.restoreCallingIdentity(origId);
3768
3769 r.finishing = wasFinishing;
3770 if (res != START_SUCCESS) {
3771 return false;
3772 }
3773 return true;
3774 }
3775 }
3776
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003777 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003778 Intent intent, String resolvedType, IBinder resultTo,
3779 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003780
3781 // This is so super not safe, that only the system (or okay root)
3782 // can do it.
3783 final int callingUid = Binder.getCallingUid();
3784 if (callingUid != 0 && callingUid != Process.myUid()) {
3785 throw new SecurityException(
3786 "startActivityInPackage only available to the system");
3787 }
3788
The Android Open Source Project4df24232009-03-05 14:34:35 -08003789 final boolean componentSpecified = intent.getComponent() != null;
3790
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003791 // Don't modify the client's object!
3792 intent = new Intent(intent);
3793
3794 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003795 ActivityInfo aInfo;
3796 try {
3797 ResolveInfo rInfo =
3798 ActivityThread.getPackageManager().resolveIntent(
3799 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003800 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003801 aInfo = rInfo != null ? rInfo.activityInfo : null;
3802 } catch (RemoteException e) {
3803 aInfo = null;
3804 }
3805
3806 if (aInfo != null) {
3807 // Store the found target back into the intent, because now that
3808 // we have it we never want to do this again. For example, if the
3809 // user navigates back to this point in the history, we should
3810 // always restart the exact same activity.
3811 intent.setComponent(new ComponentName(
3812 aInfo.applicationInfo.packageName, aInfo.name));
3813 }
3814
3815 synchronized(this) {
3816 return startActivityLocked(null, intent, resolvedType,
3817 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003818 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003819 }
3820 }
3821
3822 private final void addRecentTask(TaskRecord task) {
3823 // Remove any existing entries that are the same kind of task.
3824 int N = mRecentTasks.size();
3825 for (int i=0; i<N; i++) {
3826 TaskRecord tr = mRecentTasks.get(i);
3827 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3828 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3829 mRecentTasks.remove(i);
3830 i--;
3831 N--;
3832 if (task.intent == null) {
3833 // If the new recent task we are adding is not fully
3834 // specified, then replace it with the existing recent task.
3835 task = tr;
3836 }
3837 }
3838 }
3839 if (N >= MAX_RECENT_TASKS) {
3840 mRecentTasks.remove(N-1);
3841 }
3842 mRecentTasks.add(0, task);
3843 }
3844
3845 public void setRequestedOrientation(IBinder token,
3846 int requestedOrientation) {
3847 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003848 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003849 if (index < 0) {
3850 return;
3851 }
3852 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3853 final long origId = Binder.clearCallingIdentity();
3854 mWindowManager.setAppOrientation(r, requestedOrientation);
3855 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003856 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003857 r.mayFreezeScreenLocked(r.app) ? r : null);
3858 if (config != null) {
3859 r.frozenBeforeDestroy = true;
3860 if (!updateConfigurationLocked(config, r)) {
3861 resumeTopActivityLocked(null);
3862 }
3863 }
3864 Binder.restoreCallingIdentity(origId);
3865 }
3866 }
3867
3868 public int getRequestedOrientation(IBinder token) {
3869 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003870 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003871 if (index < 0) {
3872 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3873 }
3874 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3875 return mWindowManager.getAppOrientation(r);
3876 }
3877 }
3878
3879 private final void stopActivityLocked(HistoryRecord r) {
3880 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3881 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3882 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3883 if (!r.finishing) {
3884 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3885 "no-history");
3886 }
3887 } else if (r.app != null && r.app.thread != null) {
3888 if (mFocusedActivity == r) {
3889 setFocusedActivityLocked(topRunningActivityLocked(null));
3890 }
3891 r.resumeKeyDispatchingLocked();
3892 try {
3893 r.stopped = false;
3894 r.state = ActivityState.STOPPING;
3895 if (DEBUG_VISBILITY) Log.v(
3896 TAG, "Stopping visible=" + r.visible + " for " + r);
3897 if (!r.visible) {
3898 mWindowManager.setAppVisibility(r, false);
3899 }
3900 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3901 } catch (Exception e) {
3902 // Maybe just ignore exceptions here... if the process
3903 // has crashed, our death notification will clean things
3904 // up.
3905 Log.w(TAG, "Exception thrown during pause", e);
3906 // Just in case, assume it to be stopped.
3907 r.stopped = true;
3908 r.state = ActivityState.STOPPED;
3909 if (r.configDestroy) {
3910 destroyActivityLocked(r, true);
3911 }
3912 }
3913 }
3914 }
3915
3916 /**
3917 * @return Returns true if the activity is being finished, false if for
3918 * some reason it is being left as-is.
3919 */
3920 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3921 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003922 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003923 TAG, "Finishing activity: token=" + token
3924 + ", result=" + resultCode + ", data=" + resultData);
3925
Dianne Hackborn75b03852009-06-12 15:43:26 -07003926 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003927 if (index < 0) {
3928 return false;
3929 }
3930 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3931
3932 // Is this the last activity left?
3933 boolean lastActivity = true;
3934 for (int i=mHistory.size()-1; i>=0; i--) {
3935 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3936 if (!p.finishing && p != r) {
3937 lastActivity = false;
3938 break;
3939 }
3940 }
3941
3942 // If this is the last activity, but it is the home activity, then
3943 // just don't finish it.
3944 if (lastActivity) {
3945 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3946 return false;
3947 }
3948 }
3949
3950 finishActivityLocked(r, index, resultCode, resultData, reason);
3951 return true;
3952 }
3953
3954 /**
3955 * @return Returns true if this activity has been removed from the history
3956 * list, or false if it is still in the list and will be removed later.
3957 */
3958 private final boolean finishActivityLocked(HistoryRecord r, int index,
3959 int resultCode, Intent resultData, String reason) {
3960 if (r.finishing) {
3961 Log.w(TAG, "Duplicate finish request for " + r);
3962 return false;
3963 }
3964
3965 r.finishing = true;
3966 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3967 System.identityHashCode(r),
3968 r.task.taskId, r.shortComponentName, reason);
3969 r.task.numActivities--;
3970 if (r.frontOfTask && index < (mHistory.size()-1)) {
3971 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3972 if (next.task == r.task) {
3973 next.frontOfTask = true;
3974 }
3975 }
3976
3977 r.pauseKeyDispatchingLocked();
3978 if (mFocusedActivity == r) {
3979 setFocusedActivityLocked(topRunningActivityLocked(null));
3980 }
3981
3982 // send the result
3983 HistoryRecord resultTo = r.resultTo;
3984 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003985 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3986 + " who=" + r.resultWho + " req=" + r.requestCode
3987 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003988 if (r.info.applicationInfo.uid > 0) {
3989 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3990 r.packageName, resultData, r);
3991 }
3992 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3993 resultData);
3994 r.resultTo = null;
3995 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003996 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003997
3998 // Make sure this HistoryRecord is not holding on to other resources,
3999 // because clients have remote IPC references to this object so we
4000 // can't assume that will go away and want to avoid circular IPC refs.
4001 r.results = null;
4002 r.pendingResults = null;
4003 r.newIntents = null;
4004 r.icicle = null;
4005
4006 if (mPendingThumbnails.size() > 0) {
4007 // There are clients waiting to receive thumbnails so, in case
4008 // this is an activity that someone is waiting for, add it
4009 // to the pending list so we can correctly update the clients.
4010 mCancelledThumbnails.add(r);
4011 }
4012
4013 if (mResumedActivity == r) {
4014 boolean endTask = index <= 0
4015 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
4016 if (DEBUG_TRANSITION) Log.v(TAG,
4017 "Prepare close transition: finishing " + r);
4018 mWindowManager.prepareAppTransition(endTask
4019 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
4020 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
4021
4022 // Tell window manager to prepare for this one to be removed.
4023 mWindowManager.setAppVisibility(r, false);
4024
4025 if (mPausingActivity == null) {
4026 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4027 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4028 startPausingLocked(false, false);
4029 }
4030
4031 } else if (r.state != ActivityState.PAUSING) {
4032 // If the activity is PAUSING, we will complete the finish once
4033 // it is done pausing; else we can just directly finish it here.
4034 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4035 return finishCurrentActivityLocked(r, index,
4036 FINISH_AFTER_PAUSE) == null;
4037 } else {
4038 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4039 }
4040
4041 return false;
4042 }
4043
4044 private static final int FINISH_IMMEDIATELY = 0;
4045 private static final int FINISH_AFTER_PAUSE = 1;
4046 private static final int FINISH_AFTER_VISIBLE = 2;
4047
4048 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4049 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004050 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004051 if (index < 0) {
4052 return null;
4053 }
4054
4055 return finishCurrentActivityLocked(r, index, mode);
4056 }
4057
4058 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4059 int index, int mode) {
4060 // First things first: if this activity is currently visible,
4061 // and the resumed activity is not yet visible, then hold off on
4062 // finishing until the resumed one becomes visible.
4063 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4064 if (!mStoppingActivities.contains(r)) {
4065 mStoppingActivities.add(r);
4066 if (mStoppingActivities.size() > 3) {
4067 // If we already have a few activities waiting to stop,
4068 // then give up on things going idle and start clearing
4069 // them out.
4070 Message msg = Message.obtain();
4071 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4072 mHandler.sendMessage(msg);
4073 }
4074 }
4075 r.state = ActivityState.STOPPING;
4076 updateOomAdjLocked();
4077 return r;
4078 }
4079
4080 // make sure the record is cleaned out of other places.
4081 mStoppingActivities.remove(r);
4082 mWaitingVisibleActivities.remove(r);
4083 if (mResumedActivity == r) {
4084 mResumedActivity = null;
4085 }
4086 final ActivityState prevState = r.state;
4087 r.state = ActivityState.FINISHING;
4088
4089 if (mode == FINISH_IMMEDIATELY
4090 || prevState == ActivityState.STOPPED
4091 || prevState == ActivityState.INITIALIZING) {
4092 // If this activity is already stopped, we can just finish
4093 // it right now.
4094 return destroyActivityLocked(r, true) ? null : r;
4095 } else {
4096 // Need to go through the full pause cycle to get this
4097 // activity into the stopped state and then finish it.
4098 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4099 mFinishingActivities.add(r);
4100 resumeTopActivityLocked(null);
4101 }
4102 return r;
4103 }
4104
4105 /**
4106 * This is the internal entry point for handling Activity.finish().
4107 *
4108 * @param token The Binder token referencing the Activity we want to finish.
4109 * @param resultCode Result code, if any, from this Activity.
4110 * @param resultData Result data (Intent), if any, from this Activity.
4111 *
4112 * @result Returns true if the activity successfully finished, or false if it is still running.
4113 */
4114 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4115 // Refuse possible leaked file descriptors
4116 if (resultData != null && resultData.hasFileDescriptors() == true) {
4117 throw new IllegalArgumentException("File descriptors passed in Intent");
4118 }
4119
4120 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004121 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004122 // Find the first activity that is not finishing.
4123 HistoryRecord next = topRunningActivityLocked(token, 0);
4124 if (next != null) {
4125 // ask watcher if this is allowed
4126 boolean resumeOK = true;
4127 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004128 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004129 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004130 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004131 }
4132
4133 if (!resumeOK) {
4134 return false;
4135 }
4136 }
4137 }
4138 final long origId = Binder.clearCallingIdentity();
4139 boolean res = requestFinishActivityLocked(token, resultCode,
4140 resultData, "app-request");
4141 Binder.restoreCallingIdentity(origId);
4142 return res;
4143 }
4144 }
4145
4146 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4147 String resultWho, int requestCode, int resultCode, Intent data) {
4148
4149 if (callingUid > 0) {
4150 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4151 data, r);
4152 }
4153
The Android Open Source Project10592532009-03-18 17:39:46 -07004154 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4155 + " : who=" + resultWho + " req=" + requestCode
4156 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004157 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4158 try {
4159 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4160 list.add(new ResultInfo(resultWho, requestCode,
4161 resultCode, data));
4162 r.app.thread.scheduleSendResult(r, list);
4163 return;
4164 } catch (Exception e) {
4165 Log.w(TAG, "Exception thrown sending result to " + r, e);
4166 }
4167 }
4168
4169 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4170 }
4171
4172 public final void finishSubActivity(IBinder token, String resultWho,
4173 int requestCode) {
4174 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004175 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004176 if (index < 0) {
4177 return;
4178 }
4179 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4180
4181 final long origId = Binder.clearCallingIdentity();
4182
4183 int i;
4184 for (i=mHistory.size()-1; i>=0; i--) {
4185 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4186 if (r.resultTo == self && r.requestCode == requestCode) {
4187 if ((r.resultWho == null && resultWho == null) ||
4188 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4189 finishActivityLocked(r, i,
4190 Activity.RESULT_CANCELED, null, "request-sub");
4191 }
4192 }
4193 }
4194
4195 Binder.restoreCallingIdentity(origId);
4196 }
4197 }
4198
4199 /**
4200 * Perform clean-up of service connections in an activity record.
4201 */
4202 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4203 // Throw away any services that have been bound by this activity.
4204 if (r.connections != null) {
4205 Iterator<ConnectionRecord> it = r.connections.iterator();
4206 while (it.hasNext()) {
4207 ConnectionRecord c = it.next();
4208 removeConnectionLocked(c, null, r);
4209 }
4210 r.connections = null;
4211 }
4212 }
4213
4214 /**
4215 * Perform the common clean-up of an activity record. This is called both
4216 * as part of destroyActivityLocked() (when destroying the client-side
4217 * representation) and cleaning things up as a result of its hosting
4218 * processing going away, in which case there is no remaining client-side
4219 * state to destroy so only the cleanup here is needed.
4220 */
4221 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4222 if (mResumedActivity == r) {
4223 mResumedActivity = null;
4224 }
4225 if (mFocusedActivity == r) {
4226 mFocusedActivity = null;
4227 }
4228
4229 r.configDestroy = false;
4230 r.frozenBeforeDestroy = false;
4231
4232 // Make sure this record is no longer in the pending finishes list.
4233 // This could happen, for example, if we are trimming activities
4234 // down to the max limit while they are still waiting to finish.
4235 mFinishingActivities.remove(r);
4236 mWaitingVisibleActivities.remove(r);
4237
4238 // Remove any pending results.
4239 if (r.finishing && r.pendingResults != null) {
4240 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4241 PendingIntentRecord rec = apr.get();
4242 if (rec != null) {
4243 cancelIntentSenderLocked(rec, false);
4244 }
4245 }
4246 r.pendingResults = null;
4247 }
4248
4249 if (cleanServices) {
4250 cleanUpActivityServicesLocked(r);
4251 }
4252
4253 if (mPendingThumbnails.size() > 0) {
4254 // There are clients waiting to receive thumbnails so, in case
4255 // this is an activity that someone is waiting for, add it
4256 // to the pending list so we can correctly update the clients.
4257 mCancelledThumbnails.add(r);
4258 }
4259
4260 // Get rid of any pending idle timeouts.
4261 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4262 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4263 }
4264
4265 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4266 if (r.state != ActivityState.DESTROYED) {
4267 mHistory.remove(r);
4268 r.inHistory = false;
4269 r.state = ActivityState.DESTROYED;
4270 mWindowManager.removeAppToken(r);
4271 if (VALIDATE_TOKENS) {
4272 mWindowManager.validateAppTokens(mHistory);
4273 }
4274 cleanUpActivityServicesLocked(r);
4275 removeActivityUriPermissionsLocked(r);
4276 }
4277 }
4278
4279 /**
4280 * Destroy the current CLIENT SIDE instance of an activity. This may be
4281 * called both when actually finishing an activity, or when performing
4282 * a configuration switch where we destroy the current client-side object
4283 * but then create a new client-side object for this same HistoryRecord.
4284 */
4285 private final boolean destroyActivityLocked(HistoryRecord r,
4286 boolean removeFromApp) {
4287 if (DEBUG_SWITCH) Log.v(
4288 TAG, "Removing activity: token=" + r
4289 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4290 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4291 System.identityHashCode(r),
4292 r.task.taskId, r.shortComponentName);
4293
4294 boolean removedFromHistory = false;
4295
4296 cleanUpActivityLocked(r, false);
4297
4298 if (r.app != null) {
4299 if (removeFromApp) {
4300 int idx = r.app.activities.indexOf(r);
4301 if (idx >= 0) {
4302 r.app.activities.remove(idx);
4303 }
4304 if (r.persistent) {
4305 decPersistentCountLocked(r.app);
4306 }
4307 }
4308
4309 boolean skipDestroy = false;
4310
4311 try {
4312 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4313 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4314 r.configChangeFlags);
4315 } catch (Exception e) {
4316 // We can just ignore exceptions here... if the process
4317 // has crashed, our death notification will clean things
4318 // up.
4319 //Log.w(TAG, "Exception thrown during finish", e);
4320 if (r.finishing) {
4321 removeActivityFromHistoryLocked(r);
4322 removedFromHistory = true;
4323 skipDestroy = true;
4324 }
4325 }
4326
4327 r.app = null;
4328 r.nowVisible = false;
4329
4330 if (r.finishing && !skipDestroy) {
4331 r.state = ActivityState.DESTROYING;
4332 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4333 msg.obj = r;
4334 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4335 } else {
4336 r.state = ActivityState.DESTROYED;
4337 }
4338 } else {
4339 // remove this record from the history.
4340 if (r.finishing) {
4341 removeActivityFromHistoryLocked(r);
4342 removedFromHistory = true;
4343 } else {
4344 r.state = ActivityState.DESTROYED;
4345 }
4346 }
4347
4348 r.configChangeFlags = 0;
4349
4350 if (!mLRUActivities.remove(r)) {
4351 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4352 }
4353
4354 return removedFromHistory;
4355 }
4356
4357 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4358 ProcessRecord app)
4359 {
4360 int i = list.size();
4361 if (localLOGV) Log.v(
4362 TAG, "Removing app " + app + " from list " + list
4363 + " with " + i + " entries");
4364 while (i > 0) {
4365 i--;
4366 HistoryRecord r = (HistoryRecord)list.get(i);
4367 if (localLOGV) Log.v(
4368 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4369 if (r.app == app) {
4370 if (localLOGV) Log.v(TAG, "Removing this entry!");
4371 list.remove(i);
4372 }
4373 }
4374 }
4375
4376 /**
4377 * Main function for removing an existing process from the activity manager
4378 * as a result of that process going away. Clears out all connections
4379 * to the process.
4380 */
4381 private final void handleAppDiedLocked(ProcessRecord app,
4382 boolean restarting) {
4383 cleanUpApplicationRecordLocked(app, restarting, -1);
4384 if (!restarting) {
4385 mLRUProcesses.remove(app);
4386 }
4387
4388 // Just in case...
4389 if (mPausingActivity != null && mPausingActivity.app == app) {
4390 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4391 mPausingActivity = null;
4392 }
4393 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4394 mLastPausedActivity = null;
4395 }
4396
4397 // Remove this application's activities from active lists.
4398 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4399 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4400 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4401 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4402
4403 boolean atTop = true;
4404 boolean hasVisibleActivities = false;
4405
4406 // Clean out the history list.
4407 int i = mHistory.size();
4408 if (localLOGV) Log.v(
4409 TAG, "Removing app " + app + " from history with " + i + " entries");
4410 while (i > 0) {
4411 i--;
4412 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4413 if (localLOGV) Log.v(
4414 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4415 if (r.app == app) {
4416 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4417 if (localLOGV) Log.v(
4418 TAG, "Removing this entry! frozen=" + r.haveState
4419 + " finishing=" + r.finishing);
4420 mHistory.remove(i);
4421
4422 r.inHistory = false;
4423 mWindowManager.removeAppToken(r);
4424 if (VALIDATE_TOKENS) {
4425 mWindowManager.validateAppTokens(mHistory);
4426 }
4427 removeActivityUriPermissionsLocked(r);
4428
4429 } else {
4430 // We have the current state for this activity, so
4431 // it can be restarted later when needed.
4432 if (localLOGV) Log.v(
4433 TAG, "Keeping entry, setting app to null");
4434 if (r.visible) {
4435 hasVisibleActivities = true;
4436 }
4437 r.app = null;
4438 r.nowVisible = false;
4439 if (!r.haveState) {
4440 r.icicle = null;
4441 }
4442 }
4443
4444 cleanUpActivityLocked(r, true);
4445 r.state = ActivityState.STOPPED;
4446 }
4447 atTop = false;
4448 }
4449
4450 app.activities.clear();
4451
4452 if (app.instrumentationClass != null) {
4453 Log.w(TAG, "Crash of app " + app.processName
4454 + " running instrumentation " + app.instrumentationClass);
4455 Bundle info = new Bundle();
4456 info.putString("shortMsg", "Process crashed.");
4457 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4458 }
4459
4460 if (!restarting) {
4461 if (!resumeTopActivityLocked(null)) {
4462 // If there was nothing to resume, and we are not already
4463 // restarting this process, but there is a visible activity that
4464 // is hosted by the process... then make sure all visible
4465 // activities are running, taking care of restarting this
4466 // process.
4467 if (hasVisibleActivities) {
4468 ensureActivitiesVisibleLocked(null, 0);
4469 }
4470 }
4471 }
4472 }
4473
4474 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4475 IBinder threadBinder = thread.asBinder();
4476
4477 // Find the application record.
4478 int count = mLRUProcesses.size();
4479 int i;
4480 for (i=0; i<count; i++) {
4481 ProcessRecord rec = mLRUProcesses.get(i);
4482 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4483 return i;
4484 }
4485 }
4486 return -1;
4487 }
4488
4489 private final ProcessRecord getRecordForAppLocked(
4490 IApplicationThread thread) {
4491 if (thread == null) {
4492 return null;
4493 }
4494
4495 int appIndex = getLRURecordIndexForAppLocked(thread);
4496 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4497 }
4498
4499 private final void appDiedLocked(ProcessRecord app, int pid,
4500 IApplicationThread thread) {
4501
4502 mProcDeaths[0]++;
4503
4504 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4505 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4506 + ") has died.");
4507 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4508 if (localLOGV) Log.v(
4509 TAG, "Dying app: " + app + ", pid: " + pid
4510 + ", thread: " + thread.asBinder());
4511 boolean doLowMem = app.instrumentationClass == null;
4512 handleAppDiedLocked(app, false);
4513
4514 if (doLowMem) {
4515 // If there are no longer any background processes running,
4516 // and the app that died was not running instrumentation,
4517 // then tell everyone we are now low on memory.
4518 boolean haveBg = false;
4519 int count = mLRUProcesses.size();
4520 int i;
4521 for (i=0; i<count; i++) {
4522 ProcessRecord rec = mLRUProcesses.get(i);
4523 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4524 haveBg = true;
4525 break;
4526 }
4527 }
4528
4529 if (!haveBg) {
4530 Log.i(TAG, "Low Memory: No more background processes.");
4531 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004532 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004533 for (i=0; i<count; i++) {
4534 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004535 if (rec.thread != null &&
4536 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4537 // The low memory report is overriding any current
4538 // state for a GC request. Make sure to do
4539 // visible/foreground processes first.
4540 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4541 rec.lastRequestedGc = 0;
4542 } else {
4543 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004544 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004545 rec.reportLowMemory = true;
4546 rec.lastLowMemory = now;
4547 mProcessesToGc.remove(rec);
4548 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004549 }
4550 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004551 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004552 }
4553 }
4554 } else if (Config.LOGD) {
4555 Log.d(TAG, "Received spurious death notification for thread "
4556 + thread.asBinder());
4557 }
4558 }
4559
4560 final String readFile(String filename) {
4561 try {
4562 FileInputStream fs = new FileInputStream(filename);
4563 byte[] inp = new byte[8192];
4564 int size = fs.read(inp);
4565 fs.close();
4566 return new String(inp, 0, 0, size);
4567 } catch (java.io.IOException e) {
4568 }
4569 return "";
4570 }
4571
4572 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004573 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004574 if (app.notResponding || app.crashing) {
4575 return;
4576 }
4577
4578 // Log the ANR to the event log.
4579 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4580
4581 // If we are on a secure build and the application is not interesting to the user (it is
4582 // not visible or in the background), just kill it instead of displaying a dialog.
4583 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4584 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4585 Process.killProcess(app.pid);
4586 return;
4587 }
4588
4589 // DeviceMonitor.start();
4590
4591 String processInfo = null;
4592 if (MONITOR_CPU_USAGE) {
4593 updateCpuStatsNow();
4594 synchronized (mProcessStatsThread) {
4595 processInfo = mProcessStats.printCurrentState();
4596 }
4597 }
4598
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004599 StringBuilder info = mStringBuilder;
4600 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004601 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004602 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004603 if (reportedActivity != null && reportedActivity.app != null) {
4604 info.append(" (last in ");
4605 info.append(reportedActivity.app.processName);
4606 info.append(")");
4607 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004608 if (annotation != null) {
4609 info.append("\nAnnotation: ");
4610 info.append(annotation);
4611 }
4612 if (MONITOR_CPU_USAGE) {
4613 info.append("\nCPU usage:\n");
4614 info.append(processInfo);
4615 }
4616 Log.i(TAG, info.toString());
4617
4618 // The application is not responding. Dump as many thread traces as we can.
4619 boolean fileDump = prepareTraceFile(true);
4620 if (!fileDump) {
4621 // Dumping traces to the log, just dump the process that isn't responding so
4622 // we don't overflow the log
4623 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4624 } else {
4625 // Dumping traces to a file so dump all active processes we know about
4626 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004627 // First, these are the most important processes.
4628 final int[] imppids = new int[3];
4629 int i=0;
4630 imppids[0] = app.pid;
4631 i++;
4632 if (reportedActivity != null && reportedActivity.app != null
4633 && reportedActivity.app.thread != null
4634 && reportedActivity.app.pid != app.pid) {
4635 imppids[i] = reportedActivity.app.pid;
4636 i++;
4637 }
4638 imppids[i] = Process.myPid();
4639 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4640 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4641 synchronized (this) {
4642 try {
4643 wait(200);
4644 } catch (InterruptedException e) {
4645 }
4646 }
4647 }
4648 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004649 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004650 boolean done = false;
4651 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4652 if (imppids[j] == r.pid) {
4653 done = true;
4654 break;
4655 }
4656 }
4657 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004658 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004659 synchronized (this) {
4660 try {
4661 wait(200);
4662 } catch (InterruptedException e) {
4663 }
4664 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004665 }
4666 }
4667 }
4668 }
4669
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004670 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004671 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004672 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004673 app.pid, info.toString());
4674 if (res != 0) {
4675 if (res < 0) {
4676 // wait until the SIGQUIT has had a chance to process before killing the
4677 // process.
4678 try {
4679 wait(2000);
4680 } catch (InterruptedException e) {
4681 }
4682
4683 Process.killProcess(app.pid);
4684 return;
4685 }
4686 }
4687 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004688 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004689 }
4690 }
4691
4692 makeAppNotRespondingLocked(app,
4693 activity != null ? activity.shortComponentName : null,
4694 annotation != null ? "ANR " + annotation : "ANR",
4695 info.toString(), null);
4696 Message msg = Message.obtain();
4697 HashMap map = new HashMap();
4698 msg.what = SHOW_NOT_RESPONDING_MSG;
4699 msg.obj = map;
4700 map.put("app", app);
4701 if (activity != null) {
4702 map.put("activity", activity);
4703 }
4704
4705 mHandler.sendMessage(msg);
4706 return;
4707 }
4708
4709 /**
4710 * If a stack trace file has been configured, prepare the filesystem
4711 * by creating the directory if it doesn't exist and optionally
4712 * removing the old trace file.
4713 *
4714 * @param removeExisting If set, the existing trace file will be removed.
4715 * @return Returns true if the trace file preparations succeeded
4716 */
4717 public static boolean prepareTraceFile(boolean removeExisting) {
4718 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4719 boolean fileReady = false;
4720 if (!TextUtils.isEmpty(tracesPath)) {
4721 File f = new File(tracesPath);
4722 if (!f.exists()) {
4723 // Ensure the enclosing directory exists
4724 File dir = f.getParentFile();
4725 if (!dir.exists()) {
4726 fileReady = dir.mkdirs();
4727 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004728 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004729 } else if (dir.isDirectory()) {
4730 fileReady = true;
4731 }
4732 } else if (removeExisting) {
4733 // Remove the previous traces file, so we don't fill the disk.
4734 // The VM will recreate it
4735 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4736 fileReady = f.delete();
4737 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004738
4739 if (removeExisting) {
4740 try {
4741 f.createNewFile();
4742 FileUtils.setPermissions(f.getAbsolutePath(),
4743 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4744 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4745 fileReady = true;
4746 } catch (IOException e) {
4747 Log.w(TAG, "Unable to make ANR traces file", e);
4748 }
4749 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004750 }
4751
4752 return fileReady;
4753 }
4754
4755
4756 private final void decPersistentCountLocked(ProcessRecord app)
4757 {
4758 app.persistentActivities--;
4759 if (app.persistentActivities > 0) {
4760 // Still more of 'em...
4761 return;
4762 }
4763 if (app.persistent) {
4764 // Ah, but the application itself is persistent. Whatever!
4765 return;
4766 }
4767
4768 // App is no longer persistent... make sure it and the ones
4769 // following it in the LRU list have the correc oom_adj.
4770 updateOomAdjLocked();
4771 }
4772
4773 public void setPersistent(IBinder token, boolean isPersistent) {
4774 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4775 != PackageManager.PERMISSION_GRANTED) {
4776 String msg = "Permission Denial: setPersistent() from pid="
4777 + Binder.getCallingPid()
4778 + ", uid=" + Binder.getCallingUid()
4779 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4780 Log.w(TAG, msg);
4781 throw new SecurityException(msg);
4782 }
4783
4784 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004785 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004786 if (index < 0) {
4787 return;
4788 }
4789 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4790 ProcessRecord app = r.app;
4791
4792 if (localLOGV) Log.v(
4793 TAG, "Setting persistence " + isPersistent + ": " + r);
4794
4795 if (isPersistent) {
4796 if (r.persistent) {
4797 // Okay okay, I heard you already!
4798 if (localLOGV) Log.v(TAG, "Already persistent!");
4799 return;
4800 }
4801 r.persistent = true;
4802 app.persistentActivities++;
4803 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4804 if (app.persistentActivities > 1) {
4805 // We aren't the first...
4806 if (localLOGV) Log.v(TAG, "Not the first!");
4807 return;
4808 }
4809 if (app.persistent) {
4810 // This would be redundant.
4811 if (localLOGV) Log.v(TAG, "App is persistent!");
4812 return;
4813 }
4814
4815 // App is now persistent... make sure it and the ones
4816 // following it now have the correct oom_adj.
4817 final long origId = Binder.clearCallingIdentity();
4818 updateOomAdjLocked();
4819 Binder.restoreCallingIdentity(origId);
4820
4821 } else {
4822 if (!r.persistent) {
4823 // Okay okay, I heard you already!
4824 return;
4825 }
4826 r.persistent = false;
4827 final long origId = Binder.clearCallingIdentity();
4828 decPersistentCountLocked(app);
4829 Binder.restoreCallingIdentity(origId);
4830
4831 }
4832 }
4833 }
4834
4835 public boolean clearApplicationUserData(final String packageName,
4836 final IPackageDataObserver observer) {
4837 int uid = Binder.getCallingUid();
4838 int pid = Binder.getCallingPid();
4839 long callingId = Binder.clearCallingIdentity();
4840 try {
4841 IPackageManager pm = ActivityThread.getPackageManager();
4842 int pkgUid = -1;
4843 synchronized(this) {
4844 try {
4845 pkgUid = pm.getPackageUid(packageName);
4846 } catch (RemoteException e) {
4847 }
4848 if (pkgUid == -1) {
4849 Log.w(TAG, "Invalid packageName:" + packageName);
4850 return false;
4851 }
4852 if (uid == pkgUid || checkComponentPermission(
4853 android.Manifest.permission.CLEAR_APP_USER_DATA,
4854 pid, uid, -1)
4855 == PackageManager.PERMISSION_GRANTED) {
4856 restartPackageLocked(packageName, pkgUid);
4857 } else {
4858 throw new SecurityException(pid+" does not have permission:"+
4859 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4860 "for process:"+packageName);
4861 }
4862 }
4863
4864 try {
4865 //clear application user data
4866 pm.clearApplicationUserData(packageName, observer);
4867 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4868 Uri.fromParts("package", packageName, null));
4869 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4870 broadcastIntentLocked(null, null, intent,
4871 null, null, 0, null, null, null,
4872 false, false, MY_PID, Process.SYSTEM_UID);
4873 } catch (RemoteException e) {
4874 }
4875 } finally {
4876 Binder.restoreCallingIdentity(callingId);
4877 }
4878 return true;
4879 }
4880
4881 public void restartPackage(final String packageName) {
4882 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4883 != PackageManager.PERMISSION_GRANTED) {
4884 String msg = "Permission Denial: restartPackage() from pid="
4885 + Binder.getCallingPid()
4886 + ", uid=" + Binder.getCallingUid()
4887 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4888 Log.w(TAG, msg);
4889 throw new SecurityException(msg);
4890 }
4891
4892 long callingId = Binder.clearCallingIdentity();
4893 try {
4894 IPackageManager pm = ActivityThread.getPackageManager();
4895 int pkgUid = -1;
4896 synchronized(this) {
4897 try {
4898 pkgUid = pm.getPackageUid(packageName);
4899 } catch (RemoteException e) {
4900 }
4901 if (pkgUid == -1) {
4902 Log.w(TAG, "Invalid packageName: " + packageName);
4903 return;
4904 }
4905 restartPackageLocked(packageName, pkgUid);
4906 }
4907 } finally {
4908 Binder.restoreCallingIdentity(callingId);
4909 }
4910 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004911
4912 /*
4913 * The pkg name and uid have to be specified.
4914 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4915 */
4916 public void killApplicationWithUid(String pkg, int uid) {
4917 if (pkg == null) {
4918 return;
4919 }
4920 // Make sure the uid is valid.
4921 if (uid < 0) {
4922 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4923 return;
4924 }
4925 int callerUid = Binder.getCallingUid();
4926 // Only the system server can kill an application
4927 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004928 // Post an aysnc message to kill the application
4929 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4930 msg.arg1 = uid;
4931 msg.arg2 = 0;
4932 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004933 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004934 } else {
4935 throw new SecurityException(callerUid + " cannot kill pkg: " +
4936 pkg);
4937 }
4938 }
4939
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004940 public void closeSystemDialogs(String reason) {
4941 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4942 if (reason != null) {
4943 intent.putExtra("reason", reason);
4944 }
4945
4946 final int uid = Binder.getCallingUid();
4947 final long origId = Binder.clearCallingIdentity();
4948 synchronized (this) {
4949 int i = mWatchers.beginBroadcast();
4950 while (i > 0) {
4951 i--;
4952 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4953 if (w != null) {
4954 try {
4955 w.closingSystemDialogs(reason);
4956 } catch (RemoteException e) {
4957 }
4958 }
4959 }
4960 mWatchers.finishBroadcast();
4961
Dianne Hackbornffa42482009-09-23 22:20:11 -07004962 mWindowManager.closeSystemDialogs(reason);
4963
4964 for (i=mHistory.size()-1; i>=0; i--) {
4965 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4966 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
4967 finishActivityLocked(r, i,
4968 Activity.RESULT_CANCELED, null, "close-sys");
4969 }
4970 }
4971
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004972 broadcastIntentLocked(null, null, intent, null,
4973 null, 0, null, null, null, false, false, -1, uid);
4974 }
4975 Binder.restoreCallingIdentity(origId);
4976 }
4977
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004978 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004979 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004980 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
4981 for (int i=pids.length-1; i>=0; i--) {
4982 infos[i] = new Debug.MemoryInfo();
4983 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004984 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004985 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004986 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07004987
4988 public void killApplicationProcess(String processName, int uid) {
4989 if (processName == null) {
4990 return;
4991 }
4992
4993 int callerUid = Binder.getCallingUid();
4994 // Only the system server can kill an application
4995 if (callerUid == Process.SYSTEM_UID) {
4996 synchronized (this) {
4997 ProcessRecord app = getProcessRecordLocked(processName, uid);
4998 if (app != null) {
4999 try {
5000 app.thread.scheduleSuicide();
5001 } catch (RemoteException e) {
5002 // If the other end already died, then our work here is done.
5003 }
5004 } else {
5005 Log.w(TAG, "Process/uid not found attempting kill of "
5006 + processName + " / " + uid);
5007 }
5008 }
5009 } else {
5010 throw new SecurityException(callerUid + " cannot kill app process: " +
5011 processName);
5012 }
5013 }
5014
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005015 private void restartPackageLocked(final String packageName, int uid) {
5016 uninstallPackageLocked(packageName, uid, false);
5017 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5018 Uri.fromParts("package", packageName, null));
5019 intent.putExtra(Intent.EXTRA_UID, uid);
5020 broadcastIntentLocked(null, null, intent,
5021 null, null, 0, null, null, null,
5022 false, false, MY_PID, Process.SYSTEM_UID);
5023 }
5024
5025 private final void uninstallPackageLocked(String name, int uid,
5026 boolean callerWillRestart) {
5027 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
5028
5029 int i, N;
5030
5031 final String procNamePrefix = name + ":";
5032 if (uid < 0) {
5033 try {
5034 uid = ActivityThread.getPackageManager().getPackageUid(name);
5035 } catch (RemoteException e) {
5036 }
5037 }
5038
5039 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5040 while (badApps.hasNext()) {
5041 SparseArray<Long> ba = badApps.next();
5042 if (ba.get(uid) != null) {
5043 badApps.remove();
5044 }
5045 }
5046
5047 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
5048
5049 // Remove all processes this package may have touched: all with the
5050 // same UID (except for the system or root user), and all whose name
5051 // matches the package name.
5052 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5053 final int NA = apps.size();
5054 for (int ia=0; ia<NA; ia++) {
5055 ProcessRecord app = apps.valueAt(ia);
5056 if (app.removed) {
5057 procs.add(app);
5058 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5059 || app.processName.equals(name)
5060 || app.processName.startsWith(procNamePrefix)) {
5061 app.removed = true;
5062 procs.add(app);
5063 }
5064 }
5065 }
5066
5067 N = procs.size();
5068 for (i=0; i<N; i++) {
5069 removeProcessLocked(procs.get(i), callerWillRestart);
5070 }
5071
5072 for (i=mHistory.size()-1; i>=0; i--) {
5073 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5074 if (r.packageName.equals(name)) {
5075 if (Config.LOGD) Log.d(
5076 TAG, " Force finishing activity "
5077 + r.intent.getComponent().flattenToShortString());
5078 if (r.app != null) {
5079 r.app.removed = true;
5080 }
5081 r.app = null;
5082 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5083 }
5084 }
5085
5086 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5087 for (ServiceRecord service : mServices.values()) {
5088 if (service.packageName.equals(name)) {
5089 if (service.app != null) {
5090 service.app.removed = true;
5091 }
5092 service.app = null;
5093 services.add(service);
5094 }
5095 }
5096
5097 N = services.size();
5098 for (i=0; i<N; i++) {
5099 bringDownServiceLocked(services.get(i), true);
5100 }
5101
5102 resumeTopActivityLocked(null);
5103 }
5104
5105 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5106 final String name = app.processName;
5107 final int uid = app.info.uid;
5108 if (Config.LOGD) Log.d(
5109 TAG, "Force removing process " + app + " (" + name
5110 + "/" + uid + ")");
5111
5112 mProcessNames.remove(name, uid);
5113 boolean needRestart = false;
5114 if (app.pid > 0 && app.pid != MY_PID) {
5115 int pid = app.pid;
5116 synchronized (mPidsSelfLocked) {
5117 mPidsSelfLocked.remove(pid);
5118 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5119 }
5120 handleAppDiedLocked(app, true);
5121 mLRUProcesses.remove(app);
5122 Process.killProcess(pid);
5123
5124 if (app.persistent) {
5125 if (!callerWillRestart) {
5126 addAppLocked(app.info);
5127 } else {
5128 needRestart = true;
5129 }
5130 }
5131 } else {
5132 mRemovedProcesses.add(app);
5133 }
5134
5135 return needRestart;
5136 }
5137
5138 private final void processStartTimedOutLocked(ProcessRecord app) {
5139 final int pid = app.pid;
5140 boolean gone = false;
5141 synchronized (mPidsSelfLocked) {
5142 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5143 if (knownApp != null && knownApp.thread == null) {
5144 mPidsSelfLocked.remove(pid);
5145 gone = true;
5146 }
5147 }
5148
5149 if (gone) {
5150 Log.w(TAG, "Process " + app + " failed to attach");
5151 mProcessNames.remove(app.processName, app.info.uid);
5152 Process.killProcess(pid);
5153 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5154 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5155 mPendingBroadcast = null;
5156 scheduleBroadcastsLocked();
5157 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005158 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5159 Log.w(TAG, "Unattached app died before backup, skipping");
5160 try {
5161 IBackupManager bm = IBackupManager.Stub.asInterface(
5162 ServiceManager.getService(Context.BACKUP_SERVICE));
5163 bm.agentDisconnected(app.info.packageName);
5164 } catch (RemoteException e) {
5165 // Can't happen; the backup manager is local
5166 }
5167 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005168 } else {
5169 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5170 }
5171 }
5172
5173 private final boolean attachApplicationLocked(IApplicationThread thread,
5174 int pid) {
5175
5176 // Find the application record that is being attached... either via
5177 // the pid if we are running in multiple processes, or just pull the
5178 // next app record if we are emulating process with anonymous threads.
5179 ProcessRecord app;
5180 if (pid != MY_PID && pid >= 0) {
5181 synchronized (mPidsSelfLocked) {
5182 app = mPidsSelfLocked.get(pid);
5183 }
5184 } else if (mStartingProcesses.size() > 0) {
5185 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005186 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005187 } else {
5188 app = null;
5189 }
5190
5191 if (app == null) {
5192 Log.w(TAG, "No pending application record for pid " + pid
5193 + " (IApplicationThread " + thread + "); dropping process");
5194 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5195 if (pid > 0 && pid != MY_PID) {
5196 Process.killProcess(pid);
5197 } else {
5198 try {
5199 thread.scheduleExit();
5200 } catch (Exception e) {
5201 // Ignore exceptions.
5202 }
5203 }
5204 return false;
5205 }
5206
5207 // If this application record is still attached to a previous
5208 // process, clean it up now.
5209 if (app.thread != null) {
5210 handleAppDiedLocked(app, true);
5211 }
5212
5213 // Tell the process all about itself.
5214
5215 if (localLOGV) Log.v(
5216 TAG, "Binding process pid " + pid + " to record " + app);
5217
5218 String processName = app.processName;
5219 try {
5220 thread.asBinder().linkToDeath(new AppDeathRecipient(
5221 app, pid, thread), 0);
5222 } catch (RemoteException e) {
5223 app.resetPackageList();
5224 startProcessLocked(app, "link fail", processName);
5225 return false;
5226 }
5227
5228 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5229
5230 app.thread = thread;
5231 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005232 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005233 app.forcingToForeground = null;
5234 app.foregroundServices = false;
5235 app.debugging = false;
5236
5237 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5238
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005239 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5240 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005241
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005242 if (!normalMode) {
5243 Log.i(TAG, "Launching preboot mode app: " + app);
5244 }
5245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005246 if (localLOGV) Log.v(
5247 TAG, "New app record " + app
5248 + " thread=" + thread.asBinder() + " pid=" + pid);
5249 try {
5250 int testMode = IApplicationThread.DEBUG_OFF;
5251 if (mDebugApp != null && mDebugApp.equals(processName)) {
5252 testMode = mWaitForDebugger
5253 ? IApplicationThread.DEBUG_WAIT
5254 : IApplicationThread.DEBUG_ON;
5255 app.debugging = true;
5256 if (mDebugTransient) {
5257 mDebugApp = mOrigDebugApp;
5258 mWaitForDebugger = mOrigWaitForDebugger;
5259 }
5260 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005261
Christopher Tate181fafa2009-05-14 11:12:14 -07005262 // If the app is being launched for restore or full backup, set it up specially
5263 boolean isRestrictedBackupMode = false;
5264 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5265 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5266 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5267 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005268
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005269 ensurePackageDexOpt(app.instrumentationInfo != null
5270 ? app.instrumentationInfo.packageName
5271 : app.info.packageName);
5272 if (app.instrumentationClass != null) {
5273 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005274 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07005275 thread.bindApplication(processName, app.instrumentationInfo != null
5276 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005277 app.instrumentationClass, app.instrumentationProfileFile,
5278 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005279 isRestrictedBackupMode || !normalMode,
5280 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005281 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005282 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005283 } catch (Exception e) {
5284 // todo: Yikes! What should we do? For now we will try to
5285 // start another process, but that could easily get us in
5286 // an infinite loop of restarting processes...
5287 Log.w(TAG, "Exception thrown during bind!", e);
5288
5289 app.resetPackageList();
5290 startProcessLocked(app, "bind fail", processName);
5291 return false;
5292 }
5293
5294 // Remove this record from the list of starting applications.
5295 mPersistentStartingProcesses.remove(app);
5296 mProcessesOnHold.remove(app);
5297
5298 boolean badApp = false;
5299 boolean didSomething = false;
5300
5301 // See if the top visible activity is waiting to run in this process...
5302 HistoryRecord hr = topRunningActivityLocked(null);
5303 if (hr != null) {
5304 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5305 && processName.equals(hr.processName)) {
5306 try {
5307 if (realStartActivityLocked(hr, app, true, true)) {
5308 didSomething = true;
5309 }
5310 } catch (Exception e) {
5311 Log.w(TAG, "Exception in new application when starting activity "
5312 + hr.intent.getComponent().flattenToShortString(), e);
5313 badApp = true;
5314 }
5315 } else {
5316 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5317 }
5318 }
5319
5320 // Find any services that should be running in this process...
5321 if (!badApp && mPendingServices.size() > 0) {
5322 ServiceRecord sr = null;
5323 try {
5324 for (int i=0; i<mPendingServices.size(); i++) {
5325 sr = mPendingServices.get(i);
5326 if (app.info.uid != sr.appInfo.uid
5327 || !processName.equals(sr.processName)) {
5328 continue;
5329 }
5330
5331 mPendingServices.remove(i);
5332 i--;
5333 realStartServiceLocked(sr, app);
5334 didSomething = true;
5335 }
5336 } catch (Exception e) {
5337 Log.w(TAG, "Exception in new application when starting service "
5338 + sr.shortName, e);
5339 badApp = true;
5340 }
5341 }
5342
5343 // Check if the next broadcast receiver is in this process...
5344 BroadcastRecord br = mPendingBroadcast;
5345 if (!badApp && br != null && br.curApp == app) {
5346 try {
5347 mPendingBroadcast = null;
5348 processCurBroadcastLocked(br, app);
5349 didSomething = true;
5350 } catch (Exception e) {
5351 Log.w(TAG, "Exception in new application when starting receiver "
5352 + br.curComponent.flattenToShortString(), e);
5353 badApp = true;
5354 logBroadcastReceiverDiscard(br);
5355 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5356 br.resultExtras, br.resultAbort, true);
5357 scheduleBroadcastsLocked();
5358 }
5359 }
5360
Christopher Tate181fafa2009-05-14 11:12:14 -07005361 // Check whether the next backup agent is in this process...
5362 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5363 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005364 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005365 try {
5366 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5367 } catch (Exception e) {
5368 Log.w(TAG, "Exception scheduling backup agent creation: ");
5369 e.printStackTrace();
5370 }
5371 }
5372
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005373 if (badApp) {
5374 // todo: Also need to kill application to deal with all
5375 // kinds of exceptions.
5376 handleAppDiedLocked(app, false);
5377 return false;
5378 }
5379
5380 if (!didSomething) {
5381 updateOomAdjLocked();
5382 }
5383
5384 return true;
5385 }
5386
5387 public final void attachApplication(IApplicationThread thread) {
5388 synchronized (this) {
5389 int callingPid = Binder.getCallingPid();
5390 final long origId = Binder.clearCallingIdentity();
5391 attachApplicationLocked(thread, callingPid);
5392 Binder.restoreCallingIdentity(origId);
5393 }
5394 }
5395
5396 public final void activityIdle(IBinder token) {
5397 final long origId = Binder.clearCallingIdentity();
5398 activityIdleInternal(token, false);
5399 Binder.restoreCallingIdentity(origId);
5400 }
5401
5402 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5403 boolean remove) {
5404 int N = mStoppingActivities.size();
5405 if (N <= 0) return null;
5406
5407 ArrayList<HistoryRecord> stops = null;
5408
5409 final boolean nowVisible = mResumedActivity != null
5410 && mResumedActivity.nowVisible
5411 && !mResumedActivity.waitingVisible;
5412 for (int i=0; i<N; i++) {
5413 HistoryRecord s = mStoppingActivities.get(i);
5414 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5415 + nowVisible + " waitingVisible=" + s.waitingVisible
5416 + " finishing=" + s.finishing);
5417 if (s.waitingVisible && nowVisible) {
5418 mWaitingVisibleActivities.remove(s);
5419 s.waitingVisible = false;
5420 if (s.finishing) {
5421 // If this activity is finishing, it is sitting on top of
5422 // everyone else but we now know it is no longer needed...
5423 // so get rid of it. Otherwise, we need to go through the
5424 // normal flow and hide it once we determine that it is
5425 // hidden by the activities in front of it.
5426 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5427 mWindowManager.setAppVisibility(s, false);
5428 }
5429 }
5430 if (!s.waitingVisible && remove) {
5431 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5432 if (stops == null) {
5433 stops = new ArrayList<HistoryRecord>();
5434 }
5435 stops.add(s);
5436 mStoppingActivities.remove(i);
5437 N--;
5438 i--;
5439 }
5440 }
5441
5442 return stops;
5443 }
5444
5445 void enableScreenAfterBoot() {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005446 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5447 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005448 mWindowManager.enableScreenAfterBoot();
5449 }
5450
5451 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5452 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5453
5454 ArrayList<HistoryRecord> stops = null;
5455 ArrayList<HistoryRecord> finishes = null;
5456 ArrayList<HistoryRecord> thumbnails = null;
5457 int NS = 0;
5458 int NF = 0;
5459 int NT = 0;
5460 IApplicationThread sendThumbnail = null;
5461 boolean booting = false;
5462 boolean enableScreen = false;
5463
5464 synchronized (this) {
5465 if (token != null) {
5466 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5467 }
5468
5469 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005470 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005471 if (index >= 0) {
5472 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5473
5474 // No longer need to keep the device awake.
5475 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5476 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5477 mLaunchingActivity.release();
5478 }
5479
5480 // We are now idle. If someone is waiting for a thumbnail from
5481 // us, we can now deliver.
5482 r.idle = true;
5483 scheduleAppGcsLocked();
5484 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5485 sendThumbnail = r.app.thread;
5486 r.thumbnailNeeded = false;
5487 }
5488
5489 // If this activity is fullscreen, set up to hide those under it.
5490
5491 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5492 ensureActivitiesVisibleLocked(null, 0);
5493
5494 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5495 if (!mBooted && !fromTimeout) {
5496 mBooted = true;
5497 enableScreen = true;
5498 }
5499 }
5500
5501 // Atomically retrieve all of the other things to do.
5502 stops = processStoppingActivitiesLocked(true);
5503 NS = stops != null ? stops.size() : 0;
5504 if ((NF=mFinishingActivities.size()) > 0) {
5505 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5506 mFinishingActivities.clear();
5507 }
5508 if ((NT=mCancelledThumbnails.size()) > 0) {
5509 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5510 mCancelledThumbnails.clear();
5511 }
5512
5513 booting = mBooting;
5514 mBooting = false;
5515 }
5516
5517 int i;
5518
5519 // Send thumbnail if requested.
5520 if (sendThumbnail != null) {
5521 try {
5522 sendThumbnail.requestThumbnail(token);
5523 } catch (Exception e) {
5524 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5525 sendPendingThumbnail(null, token, null, null, true);
5526 }
5527 }
5528
5529 // Stop any activities that are scheduled to do so but have been
5530 // waiting for the next one to start.
5531 for (i=0; i<NS; i++) {
5532 HistoryRecord r = (HistoryRecord)stops.get(i);
5533 synchronized (this) {
5534 if (r.finishing) {
5535 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5536 } else {
5537 stopActivityLocked(r);
5538 }
5539 }
5540 }
5541
5542 // Finish any activities that are scheduled to do so but have been
5543 // waiting for the next one to start.
5544 for (i=0; i<NF; i++) {
5545 HistoryRecord r = (HistoryRecord)finishes.get(i);
5546 synchronized (this) {
5547 destroyActivityLocked(r, true);
5548 }
5549 }
5550
5551 // Report back to any thumbnail receivers.
5552 for (i=0; i<NT; i++) {
5553 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5554 sendPendingThumbnail(r, null, null, null, true);
5555 }
5556
5557 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005558 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005559 }
5560
5561 trimApplications();
5562 //dump();
5563 //mWindowManager.dump();
5564
5565 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005566 enableScreenAfterBoot();
5567 }
5568 }
5569
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005570 final void finishBooting() {
5571 // Ensure that any processes we had put on hold are now started
5572 // up.
5573 final int NP = mProcessesOnHold.size();
5574 if (NP > 0) {
5575 ArrayList<ProcessRecord> procs =
5576 new ArrayList<ProcessRecord>(mProcessesOnHold);
5577 for (int ip=0; ip<NP; ip++) {
5578 this.startProcessLocked(procs.get(ip), "on-hold", null);
5579 }
5580 }
5581 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5582 // Tell anyone interested that we are done booting!
5583 synchronized (this) {
5584 broadcastIntentLocked(null, null,
5585 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5586 null, null, 0, null, null,
5587 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5588 false, false, MY_PID, Process.SYSTEM_UID);
5589 }
5590 }
5591 }
5592
5593 final void ensureBootCompleted() {
5594 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005595 boolean enableScreen;
5596 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005597 booting = mBooting;
5598 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005599 enableScreen = !mBooted;
5600 mBooted = true;
5601 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005602
5603 if (booting) {
5604 finishBooting();
5605 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005606
5607 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005608 enableScreenAfterBoot();
5609 }
5610 }
5611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005612 public final void activityPaused(IBinder token, Bundle icicle) {
5613 // Refuse possible leaked file descriptors
5614 if (icicle != null && icicle.hasFileDescriptors()) {
5615 throw new IllegalArgumentException("File descriptors passed in Bundle");
5616 }
5617
5618 final long origId = Binder.clearCallingIdentity();
5619 activityPaused(token, icicle, false);
5620 Binder.restoreCallingIdentity(origId);
5621 }
5622
5623 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5624 if (DEBUG_PAUSE) Log.v(
5625 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5626 + ", timeout=" + timeout);
5627
5628 HistoryRecord r = null;
5629
5630 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005631 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005632 if (index >= 0) {
5633 r = (HistoryRecord)mHistory.get(index);
5634 if (!timeout) {
5635 r.icicle = icicle;
5636 r.haveState = true;
5637 }
5638 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5639 if (mPausingActivity == r) {
5640 r.state = ActivityState.PAUSED;
5641 completePauseLocked();
5642 } else {
5643 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5644 System.identityHashCode(r), r.shortComponentName,
5645 mPausingActivity != null
5646 ? mPausingActivity.shortComponentName : "(none)");
5647 }
5648 }
5649 }
5650 }
5651
5652 public final void activityStopped(IBinder token, Bitmap thumbnail,
5653 CharSequence description) {
5654 if (localLOGV) Log.v(
5655 TAG, "Activity stopped: token=" + token);
5656
5657 HistoryRecord r = null;
5658
5659 final long origId = Binder.clearCallingIdentity();
5660
5661 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005662 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005663 if (index >= 0) {
5664 r = (HistoryRecord)mHistory.get(index);
5665 r.thumbnail = thumbnail;
5666 r.description = description;
5667 r.stopped = true;
5668 r.state = ActivityState.STOPPED;
5669 if (!r.finishing) {
5670 if (r.configDestroy) {
5671 destroyActivityLocked(r, true);
5672 resumeTopActivityLocked(null);
5673 }
5674 }
5675 }
5676 }
5677
5678 if (r != null) {
5679 sendPendingThumbnail(r, null, null, null, false);
5680 }
5681
5682 trimApplications();
5683
5684 Binder.restoreCallingIdentity(origId);
5685 }
5686
5687 public final void activityDestroyed(IBinder token) {
5688 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5689 synchronized (this) {
5690 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5691
Dianne Hackborn75b03852009-06-12 15:43:26 -07005692 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005693 if (index >= 0) {
5694 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5695 if (r.state == ActivityState.DESTROYING) {
5696 final long origId = Binder.clearCallingIdentity();
5697 removeActivityFromHistoryLocked(r);
5698 Binder.restoreCallingIdentity(origId);
5699 }
5700 }
5701 }
5702 }
5703
5704 public String getCallingPackage(IBinder token) {
5705 synchronized (this) {
5706 HistoryRecord r = getCallingRecordLocked(token);
5707 return r != null && r.app != null ? r.app.processName : null;
5708 }
5709 }
5710
5711 public ComponentName getCallingActivity(IBinder token) {
5712 synchronized (this) {
5713 HistoryRecord r = getCallingRecordLocked(token);
5714 return r != null ? r.intent.getComponent() : null;
5715 }
5716 }
5717
5718 private HistoryRecord getCallingRecordLocked(IBinder token) {
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 if (r != null) {
5723 return r.resultTo;
5724 }
5725 }
5726 return null;
5727 }
5728
5729 public ComponentName getActivityClassForToken(IBinder token) {
5730 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005731 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005732 if (index >= 0) {
5733 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5734 return r.intent.getComponent();
5735 }
5736 return null;
5737 }
5738 }
5739
5740 public String getPackageForToken(IBinder token) {
5741 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005742 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005743 if (index >= 0) {
5744 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5745 return r.packageName;
5746 }
5747 return null;
5748 }
5749 }
5750
5751 public IIntentSender getIntentSender(int type,
5752 String packageName, IBinder token, String resultWho,
5753 int requestCode, Intent intent, String resolvedType, int flags) {
5754 // Refuse possible leaked file descriptors
5755 if (intent != null && intent.hasFileDescriptors() == true) {
5756 throw new IllegalArgumentException("File descriptors passed in Intent");
5757 }
5758
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005759 if (type == INTENT_SENDER_BROADCAST) {
5760 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5761 throw new IllegalArgumentException(
5762 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5763 }
5764 }
5765
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005766 synchronized(this) {
5767 int callingUid = Binder.getCallingUid();
5768 try {
5769 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5770 Process.supportsProcesses()) {
5771 int uid = ActivityThread.getPackageManager()
5772 .getPackageUid(packageName);
5773 if (uid != Binder.getCallingUid()) {
5774 String msg = "Permission Denial: getIntentSender() from pid="
5775 + Binder.getCallingPid()
5776 + ", uid=" + Binder.getCallingUid()
5777 + ", (need uid=" + uid + ")"
5778 + " is not allowed to send as package " + packageName;
5779 Log.w(TAG, msg);
5780 throw new SecurityException(msg);
5781 }
5782 }
5783 } catch (RemoteException e) {
5784 throw new SecurityException(e);
5785 }
5786 HistoryRecord activity = null;
5787 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005788 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005789 if (index < 0) {
5790 return null;
5791 }
5792 activity = (HistoryRecord)mHistory.get(index);
5793 if (activity.finishing) {
5794 return null;
5795 }
5796 }
5797
5798 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5799 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5800 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5801 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5802 |PendingIntent.FLAG_UPDATE_CURRENT);
5803
5804 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5805 type, packageName, activity, resultWho,
5806 requestCode, intent, resolvedType, flags);
5807 WeakReference<PendingIntentRecord> ref;
5808 ref = mIntentSenderRecords.get(key);
5809 PendingIntentRecord rec = ref != null ? ref.get() : null;
5810 if (rec != null) {
5811 if (!cancelCurrent) {
5812 if (updateCurrent) {
5813 rec.key.requestIntent.replaceExtras(intent);
5814 }
5815 return rec;
5816 }
5817 rec.canceled = true;
5818 mIntentSenderRecords.remove(key);
5819 }
5820 if (noCreate) {
5821 return rec;
5822 }
5823 rec = new PendingIntentRecord(this, key, callingUid);
5824 mIntentSenderRecords.put(key, rec.ref);
5825 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5826 if (activity.pendingResults == null) {
5827 activity.pendingResults
5828 = new HashSet<WeakReference<PendingIntentRecord>>();
5829 }
5830 activity.pendingResults.add(rec.ref);
5831 }
5832 return rec;
5833 }
5834 }
5835
5836 public void cancelIntentSender(IIntentSender sender) {
5837 if (!(sender instanceof PendingIntentRecord)) {
5838 return;
5839 }
5840 synchronized(this) {
5841 PendingIntentRecord rec = (PendingIntentRecord)sender;
5842 try {
5843 int uid = ActivityThread.getPackageManager()
5844 .getPackageUid(rec.key.packageName);
5845 if (uid != Binder.getCallingUid()) {
5846 String msg = "Permission Denial: cancelIntentSender() from pid="
5847 + Binder.getCallingPid()
5848 + ", uid=" + Binder.getCallingUid()
5849 + " is not allowed to cancel packges "
5850 + rec.key.packageName;
5851 Log.w(TAG, msg);
5852 throw new SecurityException(msg);
5853 }
5854 } catch (RemoteException e) {
5855 throw new SecurityException(e);
5856 }
5857 cancelIntentSenderLocked(rec, true);
5858 }
5859 }
5860
5861 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5862 rec.canceled = true;
5863 mIntentSenderRecords.remove(rec.key);
5864 if (cleanActivity && rec.key.activity != null) {
5865 rec.key.activity.pendingResults.remove(rec.ref);
5866 }
5867 }
5868
5869 public String getPackageForIntentSender(IIntentSender pendingResult) {
5870 if (!(pendingResult instanceof PendingIntentRecord)) {
5871 return null;
5872 }
5873 synchronized(this) {
5874 try {
5875 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5876 return res.key.packageName;
5877 } catch (ClassCastException e) {
5878 }
5879 }
5880 return null;
5881 }
5882
5883 public void setProcessLimit(int max) {
5884 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5885 "setProcessLimit()");
5886 mProcessLimit = max;
5887 }
5888
5889 public int getProcessLimit() {
5890 return mProcessLimit;
5891 }
5892
5893 void foregroundTokenDied(ForegroundToken token) {
5894 synchronized (ActivityManagerService.this) {
5895 synchronized (mPidsSelfLocked) {
5896 ForegroundToken cur
5897 = mForegroundProcesses.get(token.pid);
5898 if (cur != token) {
5899 return;
5900 }
5901 mForegroundProcesses.remove(token.pid);
5902 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5903 if (pr == null) {
5904 return;
5905 }
5906 pr.forcingToForeground = null;
5907 pr.foregroundServices = false;
5908 }
5909 updateOomAdjLocked();
5910 }
5911 }
5912
5913 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5914 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5915 "setProcessForeground()");
5916 synchronized(this) {
5917 boolean changed = false;
5918
5919 synchronized (mPidsSelfLocked) {
5920 ProcessRecord pr = mPidsSelfLocked.get(pid);
5921 if (pr == null) {
5922 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5923 return;
5924 }
5925 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5926 if (oldToken != null) {
5927 oldToken.token.unlinkToDeath(oldToken, 0);
5928 mForegroundProcesses.remove(pid);
5929 pr.forcingToForeground = null;
5930 changed = true;
5931 }
5932 if (isForeground && token != null) {
5933 ForegroundToken newToken = new ForegroundToken() {
5934 public void binderDied() {
5935 foregroundTokenDied(this);
5936 }
5937 };
5938 newToken.pid = pid;
5939 newToken.token = token;
5940 try {
5941 token.linkToDeath(newToken, 0);
5942 mForegroundProcesses.put(pid, newToken);
5943 pr.forcingToForeground = token;
5944 changed = true;
5945 } catch (RemoteException e) {
5946 // If the process died while doing this, we will later
5947 // do the cleanup with the process death link.
5948 }
5949 }
5950 }
5951
5952 if (changed) {
5953 updateOomAdjLocked();
5954 }
5955 }
5956 }
5957
5958 // =========================================================
5959 // PERMISSIONS
5960 // =========================================================
5961
5962 static class PermissionController extends IPermissionController.Stub {
5963 ActivityManagerService mActivityManagerService;
5964 PermissionController(ActivityManagerService activityManagerService) {
5965 mActivityManagerService = activityManagerService;
5966 }
5967
5968 public boolean checkPermission(String permission, int pid, int uid) {
5969 return mActivityManagerService.checkPermission(permission, pid,
5970 uid) == PackageManager.PERMISSION_GRANTED;
5971 }
5972 }
5973
5974 /**
5975 * This can be called with or without the global lock held.
5976 */
5977 int checkComponentPermission(String permission, int pid, int uid,
5978 int reqUid) {
5979 // We might be performing an operation on behalf of an indirect binder
5980 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5981 // client identity accordingly before proceeding.
5982 Identity tlsIdentity = sCallerIdentity.get();
5983 if (tlsIdentity != null) {
5984 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5985 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5986 uid = tlsIdentity.uid;
5987 pid = tlsIdentity.pid;
5988 }
5989
5990 // Root, system server and our own process get to do everything.
5991 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5992 !Process.supportsProcesses()) {
5993 return PackageManager.PERMISSION_GRANTED;
5994 }
5995 // If the target requires a specific UID, always fail for others.
5996 if (reqUid >= 0 && uid != reqUid) {
5997 return PackageManager.PERMISSION_DENIED;
5998 }
5999 if (permission == null) {
6000 return PackageManager.PERMISSION_GRANTED;
6001 }
6002 try {
6003 return ActivityThread.getPackageManager()
6004 .checkUidPermission(permission, uid);
6005 } catch (RemoteException e) {
6006 // Should never happen, but if it does... deny!
6007 Log.e(TAG, "PackageManager is dead?!?", e);
6008 }
6009 return PackageManager.PERMISSION_DENIED;
6010 }
6011
6012 /**
6013 * As the only public entry point for permissions checking, this method
6014 * can enforce the semantic that requesting a check on a null global
6015 * permission is automatically denied. (Internally a null permission
6016 * string is used when calling {@link #checkComponentPermission} in cases
6017 * when only uid-based security is needed.)
6018 *
6019 * This can be called with or without the global lock held.
6020 */
6021 public int checkPermission(String permission, int pid, int uid) {
6022 if (permission == null) {
6023 return PackageManager.PERMISSION_DENIED;
6024 }
6025 return checkComponentPermission(permission, pid, uid, -1);
6026 }
6027
6028 /**
6029 * Binder IPC calls go through the public entry point.
6030 * This can be called with or without the global lock held.
6031 */
6032 int checkCallingPermission(String permission) {
6033 return checkPermission(permission,
6034 Binder.getCallingPid(),
6035 Binder.getCallingUid());
6036 }
6037
6038 /**
6039 * This can be called with or without the global lock held.
6040 */
6041 void enforceCallingPermission(String permission, String func) {
6042 if (checkCallingPermission(permission)
6043 == PackageManager.PERMISSION_GRANTED) {
6044 return;
6045 }
6046
6047 String msg = "Permission Denial: " + func + " from pid="
6048 + Binder.getCallingPid()
6049 + ", uid=" + Binder.getCallingUid()
6050 + " requires " + permission;
6051 Log.w(TAG, msg);
6052 throw new SecurityException(msg);
6053 }
6054
6055 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6056 ProviderInfo pi, int uid, int modeFlags) {
6057 try {
6058 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6059 if ((pi.readPermission != null) &&
6060 (pm.checkUidPermission(pi.readPermission, uid)
6061 != PackageManager.PERMISSION_GRANTED)) {
6062 return false;
6063 }
6064 }
6065 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6066 if ((pi.writePermission != null) &&
6067 (pm.checkUidPermission(pi.writePermission, uid)
6068 != PackageManager.PERMISSION_GRANTED)) {
6069 return false;
6070 }
6071 }
6072 return true;
6073 } catch (RemoteException e) {
6074 return false;
6075 }
6076 }
6077
6078 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6079 int modeFlags) {
6080 // Root gets to do everything.
6081 if (uid == 0 || !Process.supportsProcesses()) {
6082 return true;
6083 }
6084 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6085 if (perms == null) return false;
6086 UriPermission perm = perms.get(uri);
6087 if (perm == null) return false;
6088 return (modeFlags&perm.modeFlags) == modeFlags;
6089 }
6090
6091 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6092 // Another redirected-binder-call permissions check as in
6093 // {@link checkComponentPermission}.
6094 Identity tlsIdentity = sCallerIdentity.get();
6095 if (tlsIdentity != null) {
6096 uid = tlsIdentity.uid;
6097 pid = tlsIdentity.pid;
6098 }
6099
6100 // Our own process gets to do everything.
6101 if (pid == MY_PID) {
6102 return PackageManager.PERMISSION_GRANTED;
6103 }
6104 synchronized(this) {
6105 return checkUriPermissionLocked(uri, uid, modeFlags)
6106 ? PackageManager.PERMISSION_GRANTED
6107 : PackageManager.PERMISSION_DENIED;
6108 }
6109 }
6110
6111 private void grantUriPermissionLocked(int callingUid,
6112 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6113 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6114 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6115 if (modeFlags == 0) {
6116 return;
6117 }
6118
6119 final IPackageManager pm = ActivityThread.getPackageManager();
6120
6121 // If this is not a content: uri, we can't do anything with it.
6122 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6123 return;
6124 }
6125
6126 String name = uri.getAuthority();
6127 ProviderInfo pi = null;
6128 ContentProviderRecord cpr
6129 = (ContentProviderRecord)mProvidersByName.get(name);
6130 if (cpr != null) {
6131 pi = cpr.info;
6132 } else {
6133 try {
6134 pi = pm.resolveContentProvider(name,
6135 PackageManager.GET_URI_PERMISSION_PATTERNS);
6136 } catch (RemoteException ex) {
6137 }
6138 }
6139 if (pi == null) {
6140 Log.w(TAG, "No content provider found for: " + name);
6141 return;
6142 }
6143
6144 int targetUid;
6145 try {
6146 targetUid = pm.getPackageUid(targetPkg);
6147 if (targetUid < 0) {
6148 return;
6149 }
6150 } catch (RemoteException ex) {
6151 return;
6152 }
6153
6154 // First... does the target actually need this permission?
6155 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6156 // No need to grant the target this permission.
6157 return;
6158 }
6159
6160 // Second... maybe someone else has already granted the
6161 // permission?
6162 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6163 // No need to grant the target this permission.
6164 return;
6165 }
6166
6167 // Third... is the provider allowing granting of URI permissions?
6168 if (!pi.grantUriPermissions) {
6169 throw new SecurityException("Provider " + pi.packageName
6170 + "/" + pi.name
6171 + " does not allow granting of Uri permissions (uri "
6172 + uri + ")");
6173 }
6174 if (pi.uriPermissionPatterns != null) {
6175 final int N = pi.uriPermissionPatterns.length;
6176 boolean allowed = false;
6177 for (int i=0; i<N; i++) {
6178 if (pi.uriPermissionPatterns[i] != null
6179 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6180 allowed = true;
6181 break;
6182 }
6183 }
6184 if (!allowed) {
6185 throw new SecurityException("Provider " + pi.packageName
6186 + "/" + pi.name
6187 + " does not allow granting of permission to path of Uri "
6188 + uri);
6189 }
6190 }
6191
6192 // Fourth... does the caller itself have permission to access
6193 // this uri?
6194 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6195 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6196 throw new SecurityException("Uid " + callingUid
6197 + " does not have permission to uri " + uri);
6198 }
6199 }
6200
6201 // Okay! So here we are: the caller has the assumed permission
6202 // to the uri, and the target doesn't. Let's now give this to
6203 // the target.
6204
6205 HashMap<Uri, UriPermission> targetUris
6206 = mGrantedUriPermissions.get(targetUid);
6207 if (targetUris == null) {
6208 targetUris = new HashMap<Uri, UriPermission>();
6209 mGrantedUriPermissions.put(targetUid, targetUris);
6210 }
6211
6212 UriPermission perm = targetUris.get(uri);
6213 if (perm == null) {
6214 perm = new UriPermission(targetUid, uri);
6215 targetUris.put(uri, perm);
6216
6217 }
6218 perm.modeFlags |= modeFlags;
6219 if (activity == null) {
6220 perm.globalModeFlags |= modeFlags;
6221 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6222 perm.readActivities.add(activity);
6223 if (activity.readUriPermissions == null) {
6224 activity.readUriPermissions = new HashSet<UriPermission>();
6225 }
6226 activity.readUriPermissions.add(perm);
6227 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6228 perm.writeActivities.add(activity);
6229 if (activity.writeUriPermissions == null) {
6230 activity.writeUriPermissions = new HashSet<UriPermission>();
6231 }
6232 activity.writeUriPermissions.add(perm);
6233 }
6234 }
6235
6236 private void grantUriPermissionFromIntentLocked(int callingUid,
6237 String targetPkg, Intent intent, HistoryRecord activity) {
6238 if (intent == null) {
6239 return;
6240 }
6241 Uri data = intent.getData();
6242 if (data == null) {
6243 return;
6244 }
6245 grantUriPermissionLocked(callingUid, targetPkg, data,
6246 intent.getFlags(), activity);
6247 }
6248
6249 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6250 Uri uri, int modeFlags) {
6251 synchronized(this) {
6252 final ProcessRecord r = getRecordForAppLocked(caller);
6253 if (r == null) {
6254 throw new SecurityException("Unable to find app for caller "
6255 + caller
6256 + " when granting permission to uri " + uri);
6257 }
6258 if (targetPkg == null) {
6259 Log.w(TAG, "grantUriPermission: null target");
6260 return;
6261 }
6262 if (uri == null) {
6263 Log.w(TAG, "grantUriPermission: null uri");
6264 return;
6265 }
6266
6267 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6268 null);
6269 }
6270 }
6271
6272 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6273 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6274 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6275 HashMap<Uri, UriPermission> perms
6276 = mGrantedUriPermissions.get(perm.uid);
6277 if (perms != null) {
6278 perms.remove(perm.uri);
6279 if (perms.size() == 0) {
6280 mGrantedUriPermissions.remove(perm.uid);
6281 }
6282 }
6283 }
6284 }
6285
6286 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6287 if (activity.readUriPermissions != null) {
6288 for (UriPermission perm : activity.readUriPermissions) {
6289 perm.readActivities.remove(activity);
6290 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6291 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6292 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6293 removeUriPermissionIfNeededLocked(perm);
6294 }
6295 }
6296 }
6297 if (activity.writeUriPermissions != null) {
6298 for (UriPermission perm : activity.writeUriPermissions) {
6299 perm.writeActivities.remove(activity);
6300 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6301 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6302 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6303 removeUriPermissionIfNeededLocked(perm);
6304 }
6305 }
6306 }
6307 }
6308
6309 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6310 int modeFlags) {
6311 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6312 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6313 if (modeFlags == 0) {
6314 return;
6315 }
6316
6317 final IPackageManager pm = ActivityThread.getPackageManager();
6318
6319 final String authority = uri.getAuthority();
6320 ProviderInfo pi = null;
6321 ContentProviderRecord cpr
6322 = (ContentProviderRecord)mProvidersByName.get(authority);
6323 if (cpr != null) {
6324 pi = cpr.info;
6325 } else {
6326 try {
6327 pi = pm.resolveContentProvider(authority,
6328 PackageManager.GET_URI_PERMISSION_PATTERNS);
6329 } catch (RemoteException ex) {
6330 }
6331 }
6332 if (pi == null) {
6333 Log.w(TAG, "No content provider found for: " + authority);
6334 return;
6335 }
6336
6337 // Does the caller have this permission on the URI?
6338 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6339 // Right now, if you are not the original owner of the permission,
6340 // you are not allowed to revoke it.
6341 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6342 throw new SecurityException("Uid " + callingUid
6343 + " does not have permission to uri " + uri);
6344 //}
6345 }
6346
6347 // Go through all of the permissions and remove any that match.
6348 final List<String> SEGMENTS = uri.getPathSegments();
6349 if (SEGMENTS != null) {
6350 final int NS = SEGMENTS.size();
6351 int N = mGrantedUriPermissions.size();
6352 for (int i=0; i<N; i++) {
6353 HashMap<Uri, UriPermission> perms
6354 = mGrantedUriPermissions.valueAt(i);
6355 Iterator<UriPermission> it = perms.values().iterator();
6356 toploop:
6357 while (it.hasNext()) {
6358 UriPermission perm = it.next();
6359 Uri targetUri = perm.uri;
6360 if (!authority.equals(targetUri.getAuthority())) {
6361 continue;
6362 }
6363 List<String> targetSegments = targetUri.getPathSegments();
6364 if (targetSegments == null) {
6365 continue;
6366 }
6367 if (targetSegments.size() < NS) {
6368 continue;
6369 }
6370 for (int j=0; j<NS; j++) {
6371 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6372 continue toploop;
6373 }
6374 }
6375 perm.clearModes(modeFlags);
6376 if (perm.modeFlags == 0) {
6377 it.remove();
6378 }
6379 }
6380 if (perms.size() == 0) {
6381 mGrantedUriPermissions.remove(
6382 mGrantedUriPermissions.keyAt(i));
6383 N--;
6384 i--;
6385 }
6386 }
6387 }
6388 }
6389
6390 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6391 int modeFlags) {
6392 synchronized(this) {
6393 final ProcessRecord r = getRecordForAppLocked(caller);
6394 if (r == null) {
6395 throw new SecurityException("Unable to find app for caller "
6396 + caller
6397 + " when revoking permission to uri " + uri);
6398 }
6399 if (uri == null) {
6400 Log.w(TAG, "revokeUriPermission: null uri");
6401 return;
6402 }
6403
6404 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6405 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6406 if (modeFlags == 0) {
6407 return;
6408 }
6409
6410 final IPackageManager pm = ActivityThread.getPackageManager();
6411
6412 final String authority = uri.getAuthority();
6413 ProviderInfo pi = null;
6414 ContentProviderRecord cpr
6415 = (ContentProviderRecord)mProvidersByName.get(authority);
6416 if (cpr != null) {
6417 pi = cpr.info;
6418 } else {
6419 try {
6420 pi = pm.resolveContentProvider(authority,
6421 PackageManager.GET_URI_PERMISSION_PATTERNS);
6422 } catch (RemoteException ex) {
6423 }
6424 }
6425 if (pi == null) {
6426 Log.w(TAG, "No content provider found for: " + authority);
6427 return;
6428 }
6429
6430 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6431 }
6432 }
6433
6434 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6435 synchronized (this) {
6436 ProcessRecord app =
6437 who != null ? getRecordForAppLocked(who) : null;
6438 if (app == null) return;
6439
6440 Message msg = Message.obtain();
6441 msg.what = WAIT_FOR_DEBUGGER_MSG;
6442 msg.obj = app;
6443 msg.arg1 = waiting ? 1 : 0;
6444 mHandler.sendMessage(msg);
6445 }
6446 }
6447
6448 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6449 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006450 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006451 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006452 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006453 }
6454
6455 // =========================================================
6456 // TASK MANAGEMENT
6457 // =========================================================
6458
6459 public List getTasks(int maxNum, int flags,
6460 IThumbnailReceiver receiver) {
6461 ArrayList list = new ArrayList();
6462
6463 PendingThumbnailsRecord pending = null;
6464 IApplicationThread topThumbnail = null;
6465 HistoryRecord topRecord = null;
6466
6467 synchronized(this) {
6468 if (localLOGV) Log.v(
6469 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6470 + ", receiver=" + receiver);
6471
6472 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6473 != PackageManager.PERMISSION_GRANTED) {
6474 if (receiver != null) {
6475 // If the caller wants to wait for pending thumbnails,
6476 // it ain't gonna get them.
6477 try {
6478 receiver.finished();
6479 } catch (RemoteException ex) {
6480 }
6481 }
6482 String msg = "Permission Denial: getTasks() from pid="
6483 + Binder.getCallingPid()
6484 + ", uid=" + Binder.getCallingUid()
6485 + " requires " + android.Manifest.permission.GET_TASKS;
6486 Log.w(TAG, msg);
6487 throw new SecurityException(msg);
6488 }
6489
6490 int pos = mHistory.size()-1;
6491 HistoryRecord next =
6492 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6493 HistoryRecord top = null;
6494 CharSequence topDescription = null;
6495 TaskRecord curTask = null;
6496 int numActivities = 0;
6497 int numRunning = 0;
6498 while (pos >= 0 && maxNum > 0) {
6499 final HistoryRecord r = next;
6500 pos--;
6501 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6502
6503 // Initialize state for next task if needed.
6504 if (top == null ||
6505 (top.state == ActivityState.INITIALIZING
6506 && top.task == r.task)) {
6507 top = r;
6508 topDescription = r.description;
6509 curTask = r.task;
6510 numActivities = numRunning = 0;
6511 }
6512
6513 // Add 'r' into the current task.
6514 numActivities++;
6515 if (r.app != null && r.app.thread != null) {
6516 numRunning++;
6517 }
6518 if (topDescription == null) {
6519 topDescription = r.description;
6520 }
6521
6522 if (localLOGV) Log.v(
6523 TAG, r.intent.getComponent().flattenToShortString()
6524 + ": task=" + r.task);
6525
6526 // If the next one is a different task, generate a new
6527 // TaskInfo entry for what we have.
6528 if (next == null || next.task != curTask) {
6529 ActivityManager.RunningTaskInfo ci
6530 = new ActivityManager.RunningTaskInfo();
6531 ci.id = curTask.taskId;
6532 ci.baseActivity = r.intent.getComponent();
6533 ci.topActivity = top.intent.getComponent();
6534 ci.thumbnail = top.thumbnail;
6535 ci.description = topDescription;
6536 ci.numActivities = numActivities;
6537 ci.numRunning = numRunning;
6538 //System.out.println(
6539 // "#" + maxNum + ": " + " descr=" + ci.description);
6540 if (ci.thumbnail == null && receiver != null) {
6541 if (localLOGV) Log.v(
6542 TAG, "State=" + top.state + "Idle=" + top.idle
6543 + " app=" + top.app
6544 + " thr=" + (top.app != null ? top.app.thread : null));
6545 if (top.state == ActivityState.RESUMED
6546 || top.state == ActivityState.PAUSING) {
6547 if (top.idle && top.app != null
6548 && top.app.thread != null) {
6549 topRecord = top;
6550 topThumbnail = top.app.thread;
6551 } else {
6552 top.thumbnailNeeded = true;
6553 }
6554 }
6555 if (pending == null) {
6556 pending = new PendingThumbnailsRecord(receiver);
6557 }
6558 pending.pendingRecords.add(top);
6559 }
6560 list.add(ci);
6561 maxNum--;
6562 top = null;
6563 }
6564 }
6565
6566 if (pending != null) {
6567 mPendingThumbnails.add(pending);
6568 }
6569 }
6570
6571 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6572
6573 if (topThumbnail != null) {
6574 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6575 try {
6576 topThumbnail.requestThumbnail(topRecord);
6577 } catch (Exception e) {
6578 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6579 sendPendingThumbnail(null, topRecord, null, null, true);
6580 }
6581 }
6582
6583 if (pending == null && receiver != null) {
6584 // In this case all thumbnails were available and the client
6585 // is being asked to be told when the remaining ones come in...
6586 // which is unusually, since the top-most currently running
6587 // activity should never have a canned thumbnail! Oh well.
6588 try {
6589 receiver.finished();
6590 } catch (RemoteException ex) {
6591 }
6592 }
6593
6594 return list;
6595 }
6596
6597 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6598 int flags) {
6599 synchronized (this) {
6600 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6601 "getRecentTasks()");
6602
6603 final int N = mRecentTasks.size();
6604 ArrayList<ActivityManager.RecentTaskInfo> res
6605 = new ArrayList<ActivityManager.RecentTaskInfo>(
6606 maxNum < N ? maxNum : N);
6607 for (int i=0; i<N && maxNum > 0; i++) {
6608 TaskRecord tr = mRecentTasks.get(i);
6609 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6610 || (tr.intent == null)
6611 || ((tr.intent.getFlags()
6612 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6613 ActivityManager.RecentTaskInfo rti
6614 = new ActivityManager.RecentTaskInfo();
6615 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6616 rti.baseIntent = new Intent(
6617 tr.intent != null ? tr.intent : tr.affinityIntent);
6618 rti.origActivity = tr.origActivity;
6619 res.add(rti);
6620 maxNum--;
6621 }
6622 }
6623 return res;
6624 }
6625 }
6626
6627 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6628 int j;
6629 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6630 TaskRecord jt = startTask;
6631
6632 // First look backwards
6633 for (j=startIndex-1; j>=0; j--) {
6634 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6635 if (r.task != jt) {
6636 jt = r.task;
6637 if (affinity.equals(jt.affinity)) {
6638 return j;
6639 }
6640 }
6641 }
6642
6643 // Now look forwards
6644 final int N = mHistory.size();
6645 jt = startTask;
6646 for (j=startIndex+1; j<N; j++) {
6647 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6648 if (r.task != jt) {
6649 if (affinity.equals(jt.affinity)) {
6650 return j;
6651 }
6652 jt = r.task;
6653 }
6654 }
6655
6656 // Might it be at the top?
6657 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6658 return N-1;
6659 }
6660
6661 return -1;
6662 }
6663
6664 /**
6665 * Perform a reset of the given task, if needed as part of launching it.
6666 * Returns the new HistoryRecord at the top of the task.
6667 */
6668 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6669 HistoryRecord newActivity) {
6670 boolean forceReset = (newActivity.info.flags
6671 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6672 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6673 if ((newActivity.info.flags
6674 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6675 forceReset = true;
6676 }
6677 }
6678
6679 final TaskRecord task = taskTop.task;
6680
6681 // We are going to move through the history list so that we can look
6682 // at each activity 'target' with 'below' either the interesting
6683 // activity immediately below it in the stack or null.
6684 HistoryRecord target = null;
6685 int targetI = 0;
6686 int taskTopI = -1;
6687 int replyChainEnd = -1;
6688 int lastReparentPos = -1;
6689 for (int i=mHistory.size()-1; i>=-1; i--) {
6690 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6691
6692 if (below != null && below.finishing) {
6693 continue;
6694 }
6695 if (target == null) {
6696 target = below;
6697 targetI = i;
6698 // If we were in the middle of a reply chain before this
6699 // task, it doesn't appear like the root of the chain wants
6700 // anything interesting, so drop it.
6701 replyChainEnd = -1;
6702 continue;
6703 }
6704
6705 final int flags = target.info.flags;
6706
6707 final boolean finishOnTaskLaunch =
6708 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6709 final boolean allowTaskReparenting =
6710 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6711
6712 if (target.task == task) {
6713 // We are inside of the task being reset... we'll either
6714 // finish this activity, push it out for another task,
6715 // or leave it as-is. We only do this
6716 // for activities that are not the root of the task (since
6717 // if we finish the root, we may no longer have the task!).
6718 if (taskTopI < 0) {
6719 taskTopI = targetI;
6720 }
6721 if (below != null && below.task == task) {
6722 final boolean clearWhenTaskReset =
6723 (target.intent.getFlags()
6724 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006725 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006726 // If this activity is sending a reply to a previous
6727 // activity, we can't do anything with it now until
6728 // we reach the start of the reply chain.
6729 // XXX note that we are assuming the result is always
6730 // to the previous activity, which is almost always
6731 // the case but we really shouldn't count on.
6732 if (replyChainEnd < 0) {
6733 replyChainEnd = targetI;
6734 }
Ed Heyl73798232009-03-24 21:32:21 -07006735 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006736 && target.taskAffinity != null
6737 && !target.taskAffinity.equals(task.affinity)) {
6738 // If this activity has an affinity for another
6739 // task, then we need to move it out of here. We will
6740 // move it as far out of the way as possible, to the
6741 // bottom of the activity stack. This also keeps it
6742 // correctly ordered with any activities we previously
6743 // moved.
6744 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6745 if (target.taskAffinity != null
6746 && target.taskAffinity.equals(p.task.affinity)) {
6747 // If the activity currently at the bottom has the
6748 // same task affinity as the one we are moving,
6749 // then merge it into the same task.
6750 target.task = p.task;
6751 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6752 + " out to bottom task " + p.task);
6753 } else {
6754 mCurTask++;
6755 if (mCurTask <= 0) {
6756 mCurTask = 1;
6757 }
6758 target.task = new TaskRecord(mCurTask, target.info, null,
6759 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6760 target.task.affinityIntent = target.intent;
6761 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6762 + " out to new task " + target.task);
6763 }
6764 mWindowManager.setAppGroupId(target, task.taskId);
6765 if (replyChainEnd < 0) {
6766 replyChainEnd = targetI;
6767 }
6768 int dstPos = 0;
6769 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6770 p = (HistoryRecord)mHistory.get(srcPos);
6771 if (p.finishing) {
6772 continue;
6773 }
6774 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6775 + " out to target's task " + target.task);
6776 task.numActivities--;
6777 p.task = target.task;
6778 target.task.numActivities++;
6779 mHistory.remove(srcPos);
6780 mHistory.add(dstPos, p);
6781 mWindowManager.moveAppToken(dstPos, p);
6782 mWindowManager.setAppGroupId(p, p.task.taskId);
6783 dstPos++;
6784 if (VALIDATE_TOKENS) {
6785 mWindowManager.validateAppTokens(mHistory);
6786 }
6787 i++;
6788 }
6789 if (taskTop == p) {
6790 taskTop = below;
6791 }
6792 if (taskTopI == replyChainEnd) {
6793 taskTopI = -1;
6794 }
6795 replyChainEnd = -1;
6796 addRecentTask(target.task);
6797 } else if (forceReset || finishOnTaskLaunch
6798 || clearWhenTaskReset) {
6799 // If the activity should just be removed -- either
6800 // because it asks for it, or the task should be
6801 // cleared -- then finish it and anything that is
6802 // part of its reply chain.
6803 if (clearWhenTaskReset) {
6804 // In this case, we want to finish this activity
6805 // and everything above it, so be sneaky and pretend
6806 // like these are all in the reply chain.
6807 replyChainEnd = targetI+1;
6808 while (replyChainEnd < mHistory.size() &&
6809 ((HistoryRecord)mHistory.get(
6810 replyChainEnd)).task == task) {
6811 replyChainEnd++;
6812 }
6813 replyChainEnd--;
6814 } else if (replyChainEnd < 0) {
6815 replyChainEnd = targetI;
6816 }
6817 HistoryRecord p = null;
6818 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6819 p = (HistoryRecord)mHistory.get(srcPos);
6820 if (p.finishing) {
6821 continue;
6822 }
6823 if (finishActivityLocked(p, srcPos,
6824 Activity.RESULT_CANCELED, null, "reset")) {
6825 replyChainEnd--;
6826 srcPos--;
6827 }
6828 }
6829 if (taskTop == p) {
6830 taskTop = below;
6831 }
6832 if (taskTopI == replyChainEnd) {
6833 taskTopI = -1;
6834 }
6835 replyChainEnd = -1;
6836 } else {
6837 // If we were in the middle of a chain, well the
6838 // activity that started it all doesn't want anything
6839 // special, so leave it all as-is.
6840 replyChainEnd = -1;
6841 }
6842 } else {
6843 // Reached the bottom of the task -- any reply chain
6844 // should be left as-is.
6845 replyChainEnd = -1;
6846 }
6847
6848 } else if (target.resultTo != null) {
6849 // If this activity is sending a reply to a previous
6850 // activity, we can't do anything with it now until
6851 // we reach the start of the reply chain.
6852 // XXX note that we are assuming the result is always
6853 // to the previous activity, which is almost always
6854 // the case but we really shouldn't count on.
6855 if (replyChainEnd < 0) {
6856 replyChainEnd = targetI;
6857 }
6858
6859 } else if (taskTopI >= 0 && allowTaskReparenting
6860 && task.affinity != null
6861 && task.affinity.equals(target.taskAffinity)) {
6862 // We are inside of another task... if this activity has
6863 // an affinity for our task, then either remove it if we are
6864 // clearing or move it over to our task. Note that
6865 // we currently punt on the case where we are resetting a
6866 // task that is not at the top but who has activities above
6867 // with an affinity to it... this is really not a normal
6868 // case, and we will need to later pull that task to the front
6869 // and usually at that point we will do the reset and pick
6870 // up those remaining activities. (This only happens if
6871 // someone starts an activity in a new task from an activity
6872 // in a task that is not currently on top.)
6873 if (forceReset || finishOnTaskLaunch) {
6874 if (replyChainEnd < 0) {
6875 replyChainEnd = targetI;
6876 }
6877 HistoryRecord p = null;
6878 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6879 p = (HistoryRecord)mHistory.get(srcPos);
6880 if (p.finishing) {
6881 continue;
6882 }
6883 if (finishActivityLocked(p, srcPos,
6884 Activity.RESULT_CANCELED, null, "reset")) {
6885 taskTopI--;
6886 lastReparentPos--;
6887 replyChainEnd--;
6888 srcPos--;
6889 }
6890 }
6891 replyChainEnd = -1;
6892 } else {
6893 if (replyChainEnd < 0) {
6894 replyChainEnd = targetI;
6895 }
6896 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6897 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6898 if (p.finishing) {
6899 continue;
6900 }
6901 if (lastReparentPos < 0) {
6902 lastReparentPos = taskTopI;
6903 taskTop = p;
6904 } else {
6905 lastReparentPos--;
6906 }
6907 mHistory.remove(srcPos);
6908 p.task.numActivities--;
6909 p.task = task;
6910 mHistory.add(lastReparentPos, p);
6911 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6912 + " in to resetting task " + task);
6913 task.numActivities++;
6914 mWindowManager.moveAppToken(lastReparentPos, p);
6915 mWindowManager.setAppGroupId(p, p.task.taskId);
6916 if (VALIDATE_TOKENS) {
6917 mWindowManager.validateAppTokens(mHistory);
6918 }
6919 }
6920 replyChainEnd = -1;
6921
6922 // Now we've moved it in to place... but what if this is
6923 // a singleTop activity and we have put it on top of another
6924 // instance of the same activity? Then we drop the instance
6925 // below so it remains singleTop.
6926 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6927 for (int j=lastReparentPos-1; j>=0; j--) {
6928 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6929 if (p.finishing) {
6930 continue;
6931 }
6932 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6933 if (finishActivityLocked(p, j,
6934 Activity.RESULT_CANCELED, null, "replace")) {
6935 taskTopI--;
6936 lastReparentPos--;
6937 }
6938 }
6939 }
6940 }
6941 }
6942 }
6943
6944 target = below;
6945 targetI = i;
6946 }
6947
6948 return taskTop;
6949 }
6950
6951 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006952 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006953 */
6954 public void moveTaskToFront(int task) {
6955 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6956 "moveTaskToFront()");
6957
6958 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006959 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6960 Binder.getCallingUid(), "Task to front")) {
6961 return;
6962 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006963 final long origId = Binder.clearCallingIdentity();
6964 try {
6965 int N = mRecentTasks.size();
6966 for (int i=0; i<N; i++) {
6967 TaskRecord tr = mRecentTasks.get(i);
6968 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07006969 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006970 return;
6971 }
6972 }
6973 for (int i=mHistory.size()-1; i>=0; i--) {
6974 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6975 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07006976 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006977 return;
6978 }
6979 }
6980 } finally {
6981 Binder.restoreCallingIdentity(origId);
6982 }
6983 }
6984 }
6985
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07006986 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006987 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6988
6989 final int task = tr.taskId;
6990 int top = mHistory.size()-1;
6991
6992 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6993 // nothing to do!
6994 return;
6995 }
6996
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006997 ArrayList moved = new ArrayList();
6998
6999 // Applying the affinities may have removed entries from the history,
7000 // so get the size again.
7001 top = mHistory.size()-1;
7002 int pos = top;
7003
7004 // Shift all activities with this task up to the top
7005 // of the stack, keeping them in the same internal order.
7006 while (pos >= 0) {
7007 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7008 if (localLOGV) Log.v(
7009 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7010 boolean first = true;
7011 if (r.task.taskId == task) {
7012 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7013 mHistory.remove(pos);
7014 mHistory.add(top, r);
7015 moved.add(0, r);
7016 top--;
7017 if (first) {
7018 addRecentTask(r.task);
7019 first = false;
7020 }
7021 }
7022 pos--;
7023 }
7024
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007025 if (DEBUG_TRANSITION) Log.v(TAG,
7026 "Prepare to front transition: task=" + tr);
7027 if (reason != null &&
7028 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7029 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7030 HistoryRecord r = topRunningActivityLocked(null);
7031 if (r != null) {
7032 mNoAnimActivities.add(r);
7033 }
7034 } else {
7035 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7036 }
7037
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007038 mWindowManager.moveAppTokensToTop(moved);
7039 if (VALIDATE_TOKENS) {
7040 mWindowManager.validateAppTokens(mHistory);
7041 }
7042
7043 finishTaskMove(task);
7044 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
7045 }
7046
7047 private final void finishTaskMove(int task) {
7048 resumeTopActivityLocked(null);
7049 }
7050
7051 public void moveTaskToBack(int task) {
7052 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7053 "moveTaskToBack()");
7054
7055 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007056 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7057 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7058 Binder.getCallingUid(), "Task to back")) {
7059 return;
7060 }
7061 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007062 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007063 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007064 Binder.restoreCallingIdentity(origId);
7065 }
7066 }
7067
7068 /**
7069 * Moves an activity, and all of the other activities within the same task, to the bottom
7070 * of the history stack. The activity's order within the task is unchanged.
7071 *
7072 * @param token A reference to the activity we wish to move
7073 * @param nonRoot If false then this only works if the activity is the root
7074 * of a task; if true it will work for any activity in a task.
7075 * @return Returns true if the move completed, false if not.
7076 */
7077 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7078 synchronized(this) {
7079 final long origId = Binder.clearCallingIdentity();
7080 int taskId = getTaskForActivityLocked(token, !nonRoot);
7081 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007082 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007083 }
7084 Binder.restoreCallingIdentity(origId);
7085 }
7086 return false;
7087 }
7088
7089 /**
7090 * Worker method for rearranging history stack. Implements the function of moving all
7091 * activities for a specific task (gathering them if disjoint) into a single group at the
7092 * bottom of the stack.
7093 *
7094 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7095 * to premeptively cancel the move.
7096 *
7097 * @param task The taskId to collect and move to the bottom.
7098 * @return Returns true if the move completed, false if not.
7099 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007100 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007101 Log.i(TAG, "moveTaskToBack: " + task);
7102
7103 // If we have a watcher, preflight the move before committing to it. First check
7104 // for *other* available tasks, but if none are available, then try again allowing the
7105 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007106 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007107 HistoryRecord next = topRunningActivityLocked(null, task);
7108 if (next == null) {
7109 next = topRunningActivityLocked(null, 0);
7110 }
7111 if (next != null) {
7112 // ask watcher if this is allowed
7113 boolean moveOK = true;
7114 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007115 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007116 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007117 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007118 }
7119 if (!moveOK) {
7120 return false;
7121 }
7122 }
7123 }
7124
7125 ArrayList moved = new ArrayList();
7126
7127 if (DEBUG_TRANSITION) Log.v(TAG,
7128 "Prepare to back transition: task=" + task);
7129 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
7130
7131 final int N = mHistory.size();
7132 int bottom = 0;
7133 int pos = 0;
7134
7135 // Shift all activities with this task down to the bottom
7136 // of the stack, keeping them in the same internal order.
7137 while (pos < N) {
7138 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7139 if (localLOGV) Log.v(
7140 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7141 if (r.task.taskId == task) {
7142 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7143 mHistory.remove(pos);
7144 mHistory.add(bottom, r);
7145 moved.add(r);
7146 bottom++;
7147 }
7148 pos++;
7149 }
7150
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007151 if (reason != null &&
7152 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7153 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7154 HistoryRecord r = topRunningActivityLocked(null);
7155 if (r != null) {
7156 mNoAnimActivities.add(r);
7157 }
7158 } else {
7159 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7160 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007161 mWindowManager.moveAppTokensToBottom(moved);
7162 if (VALIDATE_TOKENS) {
7163 mWindowManager.validateAppTokens(mHistory);
7164 }
7165
7166 finishTaskMove(task);
7167 return true;
7168 }
7169
7170 public void moveTaskBackwards(int task) {
7171 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7172 "moveTaskBackwards()");
7173
7174 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007175 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7176 Binder.getCallingUid(), "Task backwards")) {
7177 return;
7178 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007179 final long origId = Binder.clearCallingIdentity();
7180 moveTaskBackwardsLocked(task);
7181 Binder.restoreCallingIdentity(origId);
7182 }
7183 }
7184
7185 private final void moveTaskBackwardsLocked(int task) {
7186 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7187 }
7188
7189 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7190 synchronized(this) {
7191 return getTaskForActivityLocked(token, onlyRoot);
7192 }
7193 }
7194
7195 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7196 final int N = mHistory.size();
7197 TaskRecord lastTask = null;
7198 for (int i=0; i<N; i++) {
7199 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7200 if (r == token) {
7201 if (!onlyRoot || lastTask != r.task) {
7202 return r.task.taskId;
7203 }
7204 return -1;
7205 }
7206 lastTask = r.task;
7207 }
7208
7209 return -1;
7210 }
7211
7212 /**
7213 * Returns the top activity in any existing task matching the given
7214 * Intent. Returns null if no such task is found.
7215 */
7216 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7217 ComponentName cls = intent.getComponent();
7218 if (info.targetActivity != null) {
7219 cls = new ComponentName(info.packageName, info.targetActivity);
7220 }
7221
7222 TaskRecord cp = null;
7223
7224 final int N = mHistory.size();
7225 for (int i=(N-1); i>=0; i--) {
7226 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7227 if (!r.finishing && r.task != cp
7228 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7229 cp = r.task;
7230 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7231 // + "/aff=" + r.task.affinity + " to new cls="
7232 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7233 if (r.task.affinity != null) {
7234 if (r.task.affinity.equals(info.taskAffinity)) {
7235 //Log.i(TAG, "Found matching affinity!");
7236 return r;
7237 }
7238 } else if (r.task.intent != null
7239 && r.task.intent.getComponent().equals(cls)) {
7240 //Log.i(TAG, "Found matching class!");
7241 //dump();
7242 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7243 return r;
7244 } else if (r.task.affinityIntent != null
7245 && r.task.affinityIntent.getComponent().equals(cls)) {
7246 //Log.i(TAG, "Found matching class!");
7247 //dump();
7248 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7249 return r;
7250 }
7251 }
7252 }
7253
7254 return null;
7255 }
7256
7257 /**
7258 * Returns the first activity (starting from the top of the stack) that
7259 * is the same as the given activity. Returns null if no such activity
7260 * is found.
7261 */
7262 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7263 ComponentName cls = intent.getComponent();
7264 if (info.targetActivity != null) {
7265 cls = new ComponentName(info.packageName, info.targetActivity);
7266 }
7267
7268 final int N = mHistory.size();
7269 for (int i=(N-1); i>=0; i--) {
7270 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7271 if (!r.finishing) {
7272 if (r.intent.getComponent().equals(cls)) {
7273 //Log.i(TAG, "Found matching class!");
7274 //dump();
7275 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7276 return r;
7277 }
7278 }
7279 }
7280
7281 return null;
7282 }
7283
7284 public void finishOtherInstances(IBinder token, ComponentName className) {
7285 synchronized(this) {
7286 final long origId = Binder.clearCallingIdentity();
7287
7288 int N = mHistory.size();
7289 TaskRecord lastTask = null;
7290 for (int i=0; i<N; i++) {
7291 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7292 if (r.realActivity.equals(className)
7293 && r != token && lastTask != r.task) {
7294 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7295 null, "others")) {
7296 i--;
7297 N--;
7298 }
7299 }
7300 lastTask = r.task;
7301 }
7302
7303 Binder.restoreCallingIdentity(origId);
7304 }
7305 }
7306
7307 // =========================================================
7308 // THUMBNAILS
7309 // =========================================================
7310
7311 public void reportThumbnail(IBinder token,
7312 Bitmap thumbnail, CharSequence description) {
7313 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7314 final long origId = Binder.clearCallingIdentity();
7315 sendPendingThumbnail(null, token, thumbnail, description, true);
7316 Binder.restoreCallingIdentity(origId);
7317 }
7318
7319 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7320 Bitmap thumbnail, CharSequence description, boolean always) {
7321 TaskRecord task = null;
7322 ArrayList receivers = null;
7323
7324 //System.out.println("Send pending thumbnail: " + r);
7325
7326 synchronized(this) {
7327 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007328 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007329 if (index < 0) {
7330 return;
7331 }
7332 r = (HistoryRecord)mHistory.get(index);
7333 }
7334 if (thumbnail == null) {
7335 thumbnail = r.thumbnail;
7336 description = r.description;
7337 }
7338 if (thumbnail == null && !always) {
7339 // If there is no thumbnail, and this entry is not actually
7340 // going away, then abort for now and pick up the next
7341 // thumbnail we get.
7342 return;
7343 }
7344 task = r.task;
7345
7346 int N = mPendingThumbnails.size();
7347 int i=0;
7348 while (i<N) {
7349 PendingThumbnailsRecord pr =
7350 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7351 //System.out.println("Looking in " + pr.pendingRecords);
7352 if (pr.pendingRecords.remove(r)) {
7353 if (receivers == null) {
7354 receivers = new ArrayList();
7355 }
7356 receivers.add(pr);
7357 if (pr.pendingRecords.size() == 0) {
7358 pr.finished = true;
7359 mPendingThumbnails.remove(i);
7360 N--;
7361 continue;
7362 }
7363 }
7364 i++;
7365 }
7366 }
7367
7368 if (receivers != null) {
7369 final int N = receivers.size();
7370 for (int i=0; i<N; i++) {
7371 try {
7372 PendingThumbnailsRecord pr =
7373 (PendingThumbnailsRecord)receivers.get(i);
7374 pr.receiver.newThumbnail(
7375 task != null ? task.taskId : -1, thumbnail, description);
7376 if (pr.finished) {
7377 pr.receiver.finished();
7378 }
7379 } catch (Exception e) {
7380 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7381 }
7382 }
7383 }
7384 }
7385
7386 // =========================================================
7387 // CONTENT PROVIDERS
7388 // =========================================================
7389
7390 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7391 List providers = null;
7392 try {
7393 providers = ActivityThread.getPackageManager().
7394 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007395 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007396 } catch (RemoteException ex) {
7397 }
7398 if (providers != null) {
7399 final int N = providers.size();
7400 for (int i=0; i<N; i++) {
7401 ProviderInfo cpi =
7402 (ProviderInfo)providers.get(i);
7403 ContentProviderRecord cpr =
7404 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7405 if (cpr == null) {
7406 cpr = new ContentProviderRecord(cpi, app.info);
7407 mProvidersByClass.put(cpi.name, cpr);
7408 }
7409 app.pubProviders.put(cpi.name, cpr);
7410 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007411 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007412 }
7413 }
7414 return providers;
7415 }
7416
7417 private final String checkContentProviderPermissionLocked(
7418 ProviderInfo cpi, ProcessRecord r, int mode) {
7419 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7420 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7421 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7422 cpi.exported ? -1 : cpi.applicationInfo.uid)
7423 == PackageManager.PERMISSION_GRANTED
7424 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7425 return null;
7426 }
7427 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7428 cpi.exported ? -1 : cpi.applicationInfo.uid)
7429 == PackageManager.PERMISSION_GRANTED) {
7430 return null;
7431 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007432
7433 PathPermission[] pps = cpi.pathPermissions;
7434 if (pps != null) {
7435 int i = pps.length;
7436 while (i > 0) {
7437 i--;
7438 PathPermission pp = pps[i];
7439 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7440 cpi.exported ? -1 : cpi.applicationInfo.uid)
7441 == PackageManager.PERMISSION_GRANTED
7442 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7443 return null;
7444 }
7445 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7446 cpi.exported ? -1 : cpi.applicationInfo.uid)
7447 == PackageManager.PERMISSION_GRANTED) {
7448 return null;
7449 }
7450 }
7451 }
7452
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007453 String msg = "Permission Denial: opening provider " + cpi.name
7454 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7455 + ", uid=" + callingUid + ") requires "
7456 + cpi.readPermission + " or " + cpi.writePermission;
7457 Log.w(TAG, msg);
7458 return msg;
7459 }
7460
7461 private final ContentProviderHolder getContentProviderImpl(
7462 IApplicationThread caller, String name) {
7463 ContentProviderRecord cpr;
7464 ProviderInfo cpi = null;
7465
7466 synchronized(this) {
7467 ProcessRecord r = null;
7468 if (caller != null) {
7469 r = getRecordForAppLocked(caller);
7470 if (r == null) {
7471 throw new SecurityException(
7472 "Unable to find app for caller " + caller
7473 + " (pid=" + Binder.getCallingPid()
7474 + ") when getting content provider " + name);
7475 }
7476 }
7477
7478 // First check if this content provider has been published...
7479 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7480 if (cpr != null) {
7481 cpi = cpr.info;
7482 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7483 return new ContentProviderHolder(cpi,
7484 cpi.readPermission != null
7485 ? cpi.readPermission : cpi.writePermission);
7486 }
7487
7488 if (r != null && cpr.canRunHere(r)) {
7489 // This provider has been published or is in the process
7490 // of being published... but it is also allowed to run
7491 // in the caller's process, so don't make a connection
7492 // and just let the caller instantiate its own instance.
7493 if (cpr.provider != null) {
7494 // don't give caller the provider object, it needs
7495 // to make its own.
7496 cpr = new ContentProviderRecord(cpr);
7497 }
7498 return cpr;
7499 }
7500
7501 final long origId = Binder.clearCallingIdentity();
7502
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007503 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007504 // return it right away.
7505 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007506 if (DEBUG_PROVIDER) Log.v(TAG,
7507 "Adding provider requested by "
7508 + r.processName + " from process "
7509 + cpr.info.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007510 r.conProviders.add(cpr);
7511 cpr.clients.add(r);
7512 } else {
7513 cpr.externals++;
7514 }
7515
7516 if (cpr.app != null) {
7517 updateOomAdjLocked(cpr.app);
7518 }
7519
7520 Binder.restoreCallingIdentity(origId);
7521
7522 } else {
7523 try {
7524 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007525 resolveContentProvider(name,
7526 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007527 } catch (RemoteException ex) {
7528 }
7529 if (cpi == null) {
7530 return null;
7531 }
7532
7533 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7534 return new ContentProviderHolder(cpi,
7535 cpi.readPermission != null
7536 ? cpi.readPermission : cpi.writePermission);
7537 }
7538
7539 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7540 final boolean firstClass = cpr == null;
7541 if (firstClass) {
7542 try {
7543 ApplicationInfo ai =
7544 ActivityThread.getPackageManager().
7545 getApplicationInfo(
7546 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007547 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007548 if (ai == null) {
7549 Log.w(TAG, "No package info for content provider "
7550 + cpi.name);
7551 return null;
7552 }
7553 cpr = new ContentProviderRecord(cpi, ai);
7554 } catch (RemoteException ex) {
7555 // pm is in same process, this will never happen.
7556 }
7557 }
7558
7559 if (r != null && cpr.canRunHere(r)) {
7560 // If this is a multiprocess provider, then just return its
7561 // info and allow the caller to instantiate it. Only do
7562 // this if the provider is the same user as the caller's
7563 // process, or can run as root (so can be in any process).
7564 return cpr;
7565 }
7566
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007567 if (DEBUG_PROVIDER) {
7568 RuntimeException e = new RuntimeException("here");
7569 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7570 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007571 }
7572
7573 // This is single process, and our app is now connecting to it.
7574 // See if we are already in the process of launching this
7575 // provider.
7576 final int N = mLaunchingProviders.size();
7577 int i;
7578 for (i=0; i<N; i++) {
7579 if (mLaunchingProviders.get(i) == cpr) {
7580 break;
7581 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007582 }
7583
7584 // If the provider is not already being launched, then get it
7585 // started.
7586 if (i >= N) {
7587 final long origId = Binder.clearCallingIdentity();
7588 ProcessRecord proc = startProcessLocked(cpi.processName,
7589 cpr.appInfo, false, 0, "content provider",
7590 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007591 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007592 if (proc == null) {
7593 Log.w(TAG, "Unable to launch app "
7594 + cpi.applicationInfo.packageName + "/"
7595 + cpi.applicationInfo.uid + " for provider "
7596 + name + ": process is bad");
7597 return null;
7598 }
7599 cpr.launchingApp = proc;
7600 mLaunchingProviders.add(cpr);
7601 Binder.restoreCallingIdentity(origId);
7602 }
7603
7604 // Make sure the provider is published (the same provider class
7605 // may be published under multiple names).
7606 if (firstClass) {
7607 mProvidersByClass.put(cpi.name, cpr);
7608 }
7609 mProvidersByName.put(name, cpr);
7610
7611 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007612 if (DEBUG_PROVIDER) Log.v(TAG,
7613 "Adding provider requested by "
7614 + r.processName + " from process "
7615 + cpr.info.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007616 r.conProviders.add(cpr);
7617 cpr.clients.add(r);
7618 } else {
7619 cpr.externals++;
7620 }
7621 }
7622 }
7623
7624 // Wait for the provider to be published...
7625 synchronized (cpr) {
7626 while (cpr.provider == null) {
7627 if (cpr.launchingApp == null) {
7628 Log.w(TAG, "Unable to launch app "
7629 + cpi.applicationInfo.packageName + "/"
7630 + cpi.applicationInfo.uid + " for provider "
7631 + name + ": launching app became null");
7632 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7633 cpi.applicationInfo.packageName,
7634 cpi.applicationInfo.uid, name);
7635 return null;
7636 }
7637 try {
7638 cpr.wait();
7639 } catch (InterruptedException ex) {
7640 }
7641 }
7642 }
7643 return cpr;
7644 }
7645
7646 public final ContentProviderHolder getContentProvider(
7647 IApplicationThread caller, String name) {
7648 if (caller == null) {
7649 String msg = "null IApplicationThread when getting content provider "
7650 + name;
7651 Log.w(TAG, msg);
7652 throw new SecurityException(msg);
7653 }
7654
7655 return getContentProviderImpl(caller, name);
7656 }
7657
7658 private ContentProviderHolder getContentProviderExternal(String name) {
7659 return getContentProviderImpl(null, name);
7660 }
7661
7662 /**
7663 * Drop a content provider from a ProcessRecord's bookkeeping
7664 * @param cpr
7665 */
7666 public void removeContentProvider(IApplicationThread caller, String name) {
7667 synchronized (this) {
7668 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7669 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007670 // remove from mProvidersByClass
7671 if (DEBUG_PROVIDER) Log.v(TAG, name +
7672 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007673 return;
7674 }
7675 final ProcessRecord r = getRecordForAppLocked(caller);
7676 if (r == null) {
7677 throw new SecurityException(
7678 "Unable to find app for caller " + caller +
7679 " when removing content provider " + name);
7680 }
7681 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007682 ContentProviderRecord localCpr = (ContentProviderRecord)
7683 mProvidersByClass.get(cpr.info.name);
7684 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7685 + r.info.processName + " from process "
7686 + localCpr.appInfo.processName);
7687 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007688 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007689 Log.w(TAG, "removeContentProvider called on local provider: "
7690 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007691 return;
7692 } else {
7693 localCpr.clients.remove(r);
7694 r.conProviders.remove(localCpr);
7695 }
7696 updateOomAdjLocked();
7697 }
7698 }
7699
7700 private void removeContentProviderExternal(String name) {
7701 synchronized (this) {
7702 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7703 if(cpr == null) {
7704 //remove from mProvidersByClass
7705 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7706 return;
7707 }
7708
7709 //update content provider record entry info
7710 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7711 localCpr.externals--;
7712 if (localCpr.externals < 0) {
7713 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7714 }
7715 updateOomAdjLocked();
7716 }
7717 }
7718
7719 public final void publishContentProviders(IApplicationThread caller,
7720 List<ContentProviderHolder> providers) {
7721 if (providers == null) {
7722 return;
7723 }
7724
7725 synchronized(this) {
7726 final ProcessRecord r = getRecordForAppLocked(caller);
7727 if (r == null) {
7728 throw new SecurityException(
7729 "Unable to find app for caller " + caller
7730 + " (pid=" + Binder.getCallingPid()
7731 + ") when publishing content providers");
7732 }
7733
7734 final long origId = Binder.clearCallingIdentity();
7735
7736 final int N = providers.size();
7737 for (int i=0; i<N; i++) {
7738 ContentProviderHolder src = providers.get(i);
7739 if (src == null || src.info == null || src.provider == null) {
7740 continue;
7741 }
7742 ContentProviderRecord dst =
7743 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7744 if (dst != null) {
7745 mProvidersByClass.put(dst.info.name, dst);
7746 String names[] = dst.info.authority.split(";");
7747 for (int j = 0; j < names.length; j++) {
7748 mProvidersByName.put(names[j], dst);
7749 }
7750
7751 int NL = mLaunchingProviders.size();
7752 int j;
7753 for (j=0; j<NL; j++) {
7754 if (mLaunchingProviders.get(j) == dst) {
7755 mLaunchingProviders.remove(j);
7756 j--;
7757 NL--;
7758 }
7759 }
7760 synchronized (dst) {
7761 dst.provider = src.provider;
7762 dst.app = r;
7763 dst.notifyAll();
7764 }
7765 updateOomAdjLocked(r);
7766 }
7767 }
7768
7769 Binder.restoreCallingIdentity(origId);
7770 }
7771 }
7772
7773 public static final void installSystemProviders() {
7774 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7775 List providers = mSelf.generateApplicationProvidersLocked(app);
7776 mSystemThread.installSystemProviders(providers);
7777 }
7778
7779 // =========================================================
7780 // GLOBAL MANAGEMENT
7781 // =========================================================
7782
7783 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7784 ApplicationInfo info, String customProcess) {
7785 String proc = customProcess != null ? customProcess : info.processName;
7786 BatteryStatsImpl.Uid.Proc ps = null;
7787 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7788 synchronized (stats) {
7789 ps = stats.getProcessStatsLocked(info.uid, proc);
7790 }
7791 return new ProcessRecord(ps, thread, info, proc);
7792 }
7793
7794 final ProcessRecord addAppLocked(ApplicationInfo info) {
7795 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7796
7797 if (app == null) {
7798 app = newProcessRecordLocked(null, info, null);
7799 mProcessNames.put(info.processName, info.uid, app);
7800 updateLRUListLocked(app, true);
7801 }
7802
7803 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7804 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7805 app.persistent = true;
7806 app.maxAdj = CORE_SERVER_ADJ;
7807 }
7808 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7809 mPersistentStartingProcesses.add(app);
7810 startProcessLocked(app, "added application", app.processName);
7811 }
7812
7813 return app;
7814 }
7815
7816 public void unhandledBack() {
7817 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7818 "unhandledBack()");
7819
7820 synchronized(this) {
7821 int count = mHistory.size();
7822 if (Config.LOGD) Log.d(
7823 TAG, "Performing unhandledBack(): stack size = " + count);
7824 if (count > 1) {
7825 final long origId = Binder.clearCallingIdentity();
7826 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7827 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7828 Binder.restoreCallingIdentity(origId);
7829 }
7830 }
7831 }
7832
7833 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7834 String name = uri.getAuthority();
7835 ContentProviderHolder cph = getContentProviderExternal(name);
7836 ParcelFileDescriptor pfd = null;
7837 if (cph != null) {
7838 // We record the binder invoker's uid in thread-local storage before
7839 // going to the content provider to open the file. Later, in the code
7840 // that handles all permissions checks, we look for this uid and use
7841 // that rather than the Activity Manager's own uid. The effect is that
7842 // we do the check against the caller's permissions even though it looks
7843 // to the content provider like the Activity Manager itself is making
7844 // the request.
7845 sCallerIdentity.set(new Identity(
7846 Binder.getCallingPid(), Binder.getCallingUid()));
7847 try {
7848 pfd = cph.provider.openFile(uri, "r");
7849 } catch (FileNotFoundException e) {
7850 // do nothing; pfd will be returned null
7851 } finally {
7852 // Ensure that whatever happens, we clean up the identity state
7853 sCallerIdentity.remove();
7854 }
7855
7856 // We've got the fd now, so we're done with the provider.
7857 removeContentProviderExternal(name);
7858 } else {
7859 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7860 }
7861 return pfd;
7862 }
7863
7864 public void goingToSleep() {
7865 synchronized(this) {
7866 mSleeping = true;
7867 mWindowManager.setEventDispatching(false);
7868
7869 if (mResumedActivity != null) {
7870 pauseIfSleepingLocked();
7871 } else {
7872 Log.w(TAG, "goingToSleep with no resumed activity!");
7873 }
7874 }
7875 }
7876
Dianne Hackborn55280a92009-05-07 15:53:46 -07007877 public boolean shutdown(int timeout) {
7878 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7879 != PackageManager.PERMISSION_GRANTED) {
7880 throw new SecurityException("Requires permission "
7881 + android.Manifest.permission.SHUTDOWN);
7882 }
7883
7884 boolean timedout = false;
7885
7886 synchronized(this) {
7887 mShuttingDown = true;
7888 mWindowManager.setEventDispatching(false);
7889
7890 if (mResumedActivity != null) {
7891 pauseIfSleepingLocked();
7892 final long endTime = System.currentTimeMillis() + timeout;
7893 while (mResumedActivity != null || mPausingActivity != null) {
7894 long delay = endTime - System.currentTimeMillis();
7895 if (delay <= 0) {
7896 Log.w(TAG, "Activity manager shutdown timed out");
7897 timedout = true;
7898 break;
7899 }
7900 try {
7901 this.wait();
7902 } catch (InterruptedException e) {
7903 }
7904 }
7905 }
7906 }
7907
7908 mUsageStatsService.shutdown();
7909 mBatteryStatsService.shutdown();
7910
7911 return timedout;
7912 }
7913
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007914 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007915 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007916 if (!mGoingToSleep.isHeld()) {
7917 mGoingToSleep.acquire();
7918 if (mLaunchingActivity.isHeld()) {
7919 mLaunchingActivity.release();
7920 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7921 }
7922 }
7923
7924 // If we are not currently pausing an activity, get the current
7925 // one to pause. If we are pausing one, we will just let that stuff
7926 // run and release the wake lock when all done.
7927 if (mPausingActivity == null) {
7928 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7929 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7930 startPausingLocked(false, true);
7931 }
7932 }
7933 }
7934
7935 public void wakingUp() {
7936 synchronized(this) {
7937 if (mGoingToSleep.isHeld()) {
7938 mGoingToSleep.release();
7939 }
7940 mWindowManager.setEventDispatching(true);
7941 mSleeping = false;
7942 resumeTopActivityLocked(null);
7943 }
7944 }
7945
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007946 public void stopAppSwitches() {
7947 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7948 != PackageManager.PERMISSION_GRANTED) {
7949 throw new SecurityException("Requires permission "
7950 + android.Manifest.permission.STOP_APP_SWITCHES);
7951 }
7952
7953 synchronized(this) {
7954 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7955 + APP_SWITCH_DELAY_TIME;
7956 mDidAppSwitch = false;
7957 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7958 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7959 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7960 }
7961 }
7962
7963 public void resumeAppSwitches() {
7964 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7965 != PackageManager.PERMISSION_GRANTED) {
7966 throw new SecurityException("Requires permission "
7967 + android.Manifest.permission.STOP_APP_SWITCHES);
7968 }
7969
7970 synchronized(this) {
7971 // Note that we don't execute any pending app switches... we will
7972 // let those wait until either the timeout, or the next start
7973 // activity request.
7974 mAppSwitchesAllowedTime = 0;
7975 }
7976 }
7977
7978 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7979 String name) {
7980 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7981 return true;
7982 }
7983
7984 final int perm = checkComponentPermission(
7985 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7986 callingUid, -1);
7987 if (perm == PackageManager.PERMISSION_GRANTED) {
7988 return true;
7989 }
7990
7991 Log.w(TAG, name + " request from " + callingUid + " stopped");
7992 return false;
7993 }
7994
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007995 public void setDebugApp(String packageName, boolean waitForDebugger,
7996 boolean persistent) {
7997 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7998 "setDebugApp()");
7999
8000 // Note that this is not really thread safe if there are multiple
8001 // callers into it at the same time, but that's not a situation we
8002 // care about.
8003 if (persistent) {
8004 final ContentResolver resolver = mContext.getContentResolver();
8005 Settings.System.putString(
8006 resolver, Settings.System.DEBUG_APP,
8007 packageName);
8008 Settings.System.putInt(
8009 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8010 waitForDebugger ? 1 : 0);
8011 }
8012
8013 synchronized (this) {
8014 if (!persistent) {
8015 mOrigDebugApp = mDebugApp;
8016 mOrigWaitForDebugger = mWaitForDebugger;
8017 }
8018 mDebugApp = packageName;
8019 mWaitForDebugger = waitForDebugger;
8020 mDebugTransient = !persistent;
8021 if (packageName != null) {
8022 final long origId = Binder.clearCallingIdentity();
8023 uninstallPackageLocked(packageName, -1, false);
8024 Binder.restoreCallingIdentity(origId);
8025 }
8026 }
8027 }
8028
8029 public void setAlwaysFinish(boolean enabled) {
8030 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8031 "setAlwaysFinish()");
8032
8033 Settings.System.putInt(
8034 mContext.getContentResolver(),
8035 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8036
8037 synchronized (this) {
8038 mAlwaysFinishActivities = enabled;
8039 }
8040 }
8041
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008042 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008043 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008044 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008045 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008046 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008047 }
8048 }
8049
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008050 public void registerActivityWatcher(IActivityWatcher watcher) {
8051 mWatchers.register(watcher);
8052 }
8053
8054 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8055 mWatchers.unregister(watcher);
8056 }
8057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008058 public final void enterSafeMode() {
8059 synchronized(this) {
8060 // It only makes sense to do this before the system is ready
8061 // and started launching other packages.
8062 if (!mSystemReady) {
8063 try {
8064 ActivityThread.getPackageManager().enterSafeMode();
8065 } catch (RemoteException e) {
8066 }
8067
8068 View v = LayoutInflater.from(mContext).inflate(
8069 com.android.internal.R.layout.safe_mode, null);
8070 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8071 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8072 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8073 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8074 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8075 lp.format = v.getBackground().getOpacity();
8076 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8077 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8078 ((WindowManager)mContext.getSystemService(
8079 Context.WINDOW_SERVICE)).addView(v, lp);
8080 }
8081 }
8082 }
8083
8084 public void noteWakeupAlarm(IIntentSender sender) {
8085 if (!(sender instanceof PendingIntentRecord)) {
8086 return;
8087 }
8088 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8089 synchronized (stats) {
8090 if (mBatteryStatsService.isOnBattery()) {
8091 mBatteryStatsService.enforceCallingPermission();
8092 PendingIntentRecord rec = (PendingIntentRecord)sender;
8093 int MY_UID = Binder.getCallingUid();
8094 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8095 BatteryStatsImpl.Uid.Pkg pkg =
8096 stats.getPackageStatsLocked(uid, rec.key.packageName);
8097 pkg.incWakeupsLocked();
8098 }
8099 }
8100 }
8101
8102 public boolean killPidsForMemory(int[] pids) {
8103 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8104 throw new SecurityException("killPidsForMemory only available to the system");
8105 }
8106
8107 // XXX Note: don't acquire main activity lock here, because the window
8108 // manager calls in with its locks held.
8109
8110 boolean killed = false;
8111 synchronized (mPidsSelfLocked) {
8112 int[] types = new int[pids.length];
8113 int worstType = 0;
8114 for (int i=0; i<pids.length; i++) {
8115 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8116 if (proc != null) {
8117 int type = proc.setAdj;
8118 types[i] = type;
8119 if (type > worstType) {
8120 worstType = type;
8121 }
8122 }
8123 }
8124
8125 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8126 // then constrain it so we will kill all hidden procs.
8127 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8128 worstType = HIDDEN_APP_MIN_ADJ;
8129 }
8130 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8131 for (int i=0; i<pids.length; i++) {
8132 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8133 if (proc == null) {
8134 continue;
8135 }
8136 int adj = proc.setAdj;
8137 if (adj >= worstType) {
8138 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8139 + adj + ")");
8140 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
8141 proc.processName, adj);
8142 killed = true;
8143 Process.killProcess(pids[i]);
8144 }
8145 }
8146 }
8147 return killed;
8148 }
8149
8150 public void reportPss(IApplicationThread caller, int pss) {
8151 Watchdog.PssRequestor req;
8152 String name;
8153 ProcessRecord callerApp;
8154 synchronized (this) {
8155 if (caller == null) {
8156 return;
8157 }
8158 callerApp = getRecordForAppLocked(caller);
8159 if (callerApp == null) {
8160 return;
8161 }
8162 callerApp.lastPss = pss;
8163 req = callerApp;
8164 name = callerApp.processName;
8165 }
8166 Watchdog.getInstance().reportPss(req, name, pss);
8167 if (!callerApp.persistent) {
8168 removeRequestedPss(callerApp);
8169 }
8170 }
8171
8172 public void requestPss(Runnable completeCallback) {
8173 ArrayList<ProcessRecord> procs;
8174 synchronized (this) {
8175 mRequestPssCallback = completeCallback;
8176 mRequestPssList.clear();
8177 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8178 ProcessRecord proc = mLRUProcesses.get(i);
8179 if (!proc.persistent) {
8180 mRequestPssList.add(proc);
8181 }
8182 }
8183 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8184 }
8185
8186 int oldPri = Process.getThreadPriority(Process.myTid());
8187 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8188 for (int i=procs.size()-1; i>=0; i--) {
8189 ProcessRecord proc = procs.get(i);
8190 proc.lastPss = 0;
8191 proc.requestPss();
8192 }
8193 Process.setThreadPriority(oldPri);
8194 }
8195
8196 void removeRequestedPss(ProcessRecord proc) {
8197 Runnable callback = null;
8198 synchronized (this) {
8199 if (mRequestPssList.remove(proc)) {
8200 if (mRequestPssList.size() == 0) {
8201 callback = mRequestPssCallback;
8202 mRequestPssCallback = null;
8203 }
8204 }
8205 }
8206
8207 if (callback != null) {
8208 callback.run();
8209 }
8210 }
8211
8212 public void collectPss(Watchdog.PssStats stats) {
8213 stats.mEmptyPss = 0;
8214 stats.mEmptyCount = 0;
8215 stats.mBackgroundPss = 0;
8216 stats.mBackgroundCount = 0;
8217 stats.mServicePss = 0;
8218 stats.mServiceCount = 0;
8219 stats.mVisiblePss = 0;
8220 stats.mVisibleCount = 0;
8221 stats.mForegroundPss = 0;
8222 stats.mForegroundCount = 0;
8223 stats.mNoPssCount = 0;
8224 synchronized (this) {
8225 int i;
8226 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8227 ? mProcDeaths.length : stats.mProcDeaths.length;
8228 int aggr = 0;
8229 for (i=0; i<NPD; i++) {
8230 aggr += mProcDeaths[i];
8231 stats.mProcDeaths[i] = aggr;
8232 }
8233 while (i<stats.mProcDeaths.length) {
8234 stats.mProcDeaths[i] = 0;
8235 i++;
8236 }
8237
8238 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8239 ProcessRecord proc = mLRUProcesses.get(i);
8240 if (proc.persistent) {
8241 continue;
8242 }
8243 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8244 if (proc.lastPss == 0) {
8245 stats.mNoPssCount++;
8246 continue;
8247 }
8248 if (proc.setAdj == EMPTY_APP_ADJ) {
8249 stats.mEmptyPss += proc.lastPss;
8250 stats.mEmptyCount++;
8251 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8252 stats.mEmptyPss += proc.lastPss;
8253 stats.mEmptyCount++;
8254 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8255 stats.mBackgroundPss += proc.lastPss;
8256 stats.mBackgroundCount++;
8257 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8258 stats.mVisiblePss += proc.lastPss;
8259 stats.mVisibleCount++;
8260 } else {
8261 stats.mForegroundPss += proc.lastPss;
8262 stats.mForegroundCount++;
8263 }
8264 }
8265 }
8266 }
8267
8268 public final void startRunning(String pkg, String cls, String action,
8269 String data) {
8270 synchronized(this) {
8271 if (mStartRunning) {
8272 return;
8273 }
8274 mStartRunning = true;
8275 mTopComponent = pkg != null && cls != null
8276 ? new ComponentName(pkg, cls) : null;
8277 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8278 mTopData = data;
8279 if (!mSystemReady) {
8280 return;
8281 }
8282 }
8283
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008284 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008285 }
8286
8287 private void retrieveSettings() {
8288 final ContentResolver resolver = mContext.getContentResolver();
8289 String debugApp = Settings.System.getString(
8290 resolver, Settings.System.DEBUG_APP);
8291 boolean waitForDebugger = Settings.System.getInt(
8292 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8293 boolean alwaysFinishActivities = Settings.System.getInt(
8294 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8295
8296 Configuration configuration = new Configuration();
8297 Settings.System.getConfiguration(resolver, configuration);
8298
8299 synchronized (this) {
8300 mDebugApp = mOrigDebugApp = debugApp;
8301 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8302 mAlwaysFinishActivities = alwaysFinishActivities;
8303 // This happens before any activities are started, so we can
8304 // change mConfiguration in-place.
8305 mConfiguration.updateFrom(configuration);
8306 }
8307 }
8308
8309 public boolean testIsSystemReady() {
8310 // no need to synchronize(this) just to read & return the value
8311 return mSystemReady;
8312 }
8313
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008314 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008315 // In the simulator, startRunning will never have been called, which
8316 // normally sets a few crucial variables. Do it here instead.
8317 if (!Process.supportsProcesses()) {
8318 mStartRunning = true;
8319 mTopAction = Intent.ACTION_MAIN;
8320 }
8321
8322 synchronized(this) {
8323 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008324 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008325 return;
8326 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008327
8328 // Check to see if there are any update receivers to run.
8329 if (!mDidUpdate) {
8330 if (mWaitingUpdate) {
8331 return;
8332 }
8333 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8334 List<ResolveInfo> ris = null;
8335 try {
8336 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8337 intent, null, 0);
8338 } catch (RemoteException e) {
8339 }
8340 if (ris != null) {
8341 for (int i=ris.size()-1; i>=0; i--) {
8342 if ((ris.get(i).activityInfo.applicationInfo.flags
8343 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8344 ris.remove(i);
8345 }
8346 }
8347 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8348 for (int i=0; i<ris.size(); i++) {
8349 ActivityInfo ai = ris.get(i).activityInfo;
8350 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8351 IIntentReceiver finisher = null;
8352 if (i == 0) {
8353 finisher = new IIntentReceiver.Stub() {
8354 public void performReceive(Intent intent, int resultCode,
8355 String data, Bundle extras, boolean ordered)
8356 throws RemoteException {
8357 synchronized (ActivityManagerService.this) {
8358 mDidUpdate = true;
8359 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008360 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008361 }
8362 };
8363 }
8364 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8365 broadcastIntentLocked(null, null, intent, null, finisher,
8366 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8367 if (i == 0) {
8368 mWaitingUpdate = true;
8369 }
8370 }
8371 }
8372 if (mWaitingUpdate) {
8373 return;
8374 }
8375 mDidUpdate = true;
8376 }
8377
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008378 mSystemReady = true;
8379 if (!mStartRunning) {
8380 return;
8381 }
8382 }
8383
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008384 ArrayList<ProcessRecord> procsToKill = null;
8385 synchronized(mPidsSelfLocked) {
8386 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8387 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8388 if (!isAllowedWhileBooting(proc.info)){
8389 if (procsToKill == null) {
8390 procsToKill = new ArrayList<ProcessRecord>();
8391 }
8392 procsToKill.add(proc);
8393 }
8394 }
8395 }
8396
8397 if (procsToKill != null) {
8398 synchronized(this) {
8399 for (int i=procsToKill.size()-1; i>=0; i--) {
8400 ProcessRecord proc = procsToKill.get(i);
8401 Log.i(TAG, "Removing system update proc: " + proc);
8402 removeProcessLocked(proc, true);
8403 }
8404 }
8405 }
8406
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008407 Log.i(TAG, "System now ready");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008408 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8409 SystemClock.uptimeMillis());
8410
8411 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008412 // Make sure we have no pre-ready processes sitting around.
8413
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008414 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8415 ResolveInfo ri = mContext.getPackageManager()
8416 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008417 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008418 CharSequence errorMsg = null;
8419 if (ri != null) {
8420 ActivityInfo ai = ri.activityInfo;
8421 ApplicationInfo app = ai.applicationInfo;
8422 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8423 mTopAction = Intent.ACTION_FACTORY_TEST;
8424 mTopData = null;
8425 mTopComponent = new ComponentName(app.packageName,
8426 ai.name);
8427 } else {
8428 errorMsg = mContext.getResources().getText(
8429 com.android.internal.R.string.factorytest_not_system);
8430 }
8431 } else {
8432 errorMsg = mContext.getResources().getText(
8433 com.android.internal.R.string.factorytest_no_action);
8434 }
8435 if (errorMsg != null) {
8436 mTopAction = null;
8437 mTopData = null;
8438 mTopComponent = null;
8439 Message msg = Message.obtain();
8440 msg.what = SHOW_FACTORY_ERROR_MSG;
8441 msg.getData().putCharSequence("msg", errorMsg);
8442 mHandler.sendMessage(msg);
8443 }
8444 }
8445 }
8446
8447 retrieveSettings();
8448
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008449 if (goingCallback != null) goingCallback.run();
8450
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008451 synchronized (this) {
8452 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8453 try {
8454 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008455 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008456 if (apps != null) {
8457 int N = apps.size();
8458 int i;
8459 for (i=0; i<N; i++) {
8460 ApplicationInfo info
8461 = (ApplicationInfo)apps.get(i);
8462 if (info != null &&
8463 !info.packageName.equals("android")) {
8464 addAppLocked(info);
8465 }
8466 }
8467 }
8468 } catch (RemoteException ex) {
8469 // pm is in same process, this will never happen.
8470 }
8471 }
8472
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008473 // Start up initial activity.
8474 mBooting = true;
8475
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008476 try {
8477 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8478 Message msg = Message.obtain();
8479 msg.what = SHOW_UID_ERROR_MSG;
8480 mHandler.sendMessage(msg);
8481 }
8482 } catch (RemoteException e) {
8483 }
8484
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008485 resumeTopActivityLocked(null);
8486 }
8487 }
8488
8489 boolean makeAppCrashingLocked(ProcessRecord app,
8490 String tag, String shortMsg, String longMsg, byte[] crashData) {
8491 app.crashing = true;
8492 app.crashingReport = generateProcessError(app,
8493 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8494 startAppProblemLocked(app);
8495 app.stopFreezingAllLocked();
8496 return handleAppCrashLocked(app);
8497 }
8498
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008499 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Jacek Surazskia2339432009-09-18 15:01:26 +02008500 // check if error reporting is enabled in Gservices
8501 int enabled = Settings.Gservices.getInt(mContext.getContentResolver(),
8502 Settings.Gservices.SEND_ACTION_APP_ERROR, 0);
8503 if (enabled == 0) {
8504 return null;
8505 }
8506
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008507 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008508
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008509 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008510 // look for receiver in the installer package
8511 String candidate = pm.getInstallerPackageName(app.info.packageName);
8512 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8513 if (result != null) {
8514 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008515 }
8516
Jacek Surazski82a73df2009-06-17 14:33:18 +02008517 // if the error app is on the system image, look for system apps
8518 // error receiver
8519 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8520 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8521 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8522 if (result != null) {
8523 return result;
8524 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008525 }
8526
Jacek Surazski82a73df2009-06-17 14:33:18 +02008527 // if there is a default receiver, try that
8528 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8529 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008530 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008531 // should not happen
8532 Log.e(TAG, "error talking to PackageManager", e);
8533 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008534 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008535 }
8536
8537 /**
8538 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8539 *
8540 * @param pm PackageManager isntance
8541 * @param errorPackage package which caused the error
8542 * @param receiverPackage candidate package to receive the error
8543 * @return activity component within receiverPackage which handles
8544 * ACTION_APP_ERROR, or null if not found
8545 */
8546 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8547 String receiverPackage) throws RemoteException {
8548 if (receiverPackage == null || receiverPackage.length() == 0) {
8549 return null;
8550 }
8551
8552 // break the loop if it's the error report receiver package that crashed
8553 if (receiverPackage.equals(errorPackage)) {
8554 return null;
8555 }
8556
8557 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8558 intent.setPackage(receiverPackage);
8559 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8560 if (info == null || info.activityInfo == null) {
8561 return null;
8562 }
8563 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008564 }
8565
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008566 void makeAppNotRespondingLocked(ProcessRecord app,
8567 String tag, String shortMsg, String longMsg, byte[] crashData) {
8568 app.notResponding = true;
8569 app.notRespondingReport = generateProcessError(app,
8570 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8571 crashData);
8572 startAppProblemLocked(app);
8573 app.stopFreezingAllLocked();
8574 }
8575
8576 /**
8577 * Generate a process error record, suitable for attachment to a ProcessRecord.
8578 *
8579 * @param app The ProcessRecord in which the error occurred.
8580 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8581 * ActivityManager.AppErrorStateInfo
8582 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8583 * @param shortMsg Short message describing the crash.
8584 * @param longMsg Long message describing the crash.
8585 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8586 *
8587 * @return Returns a fully-formed AppErrorStateInfo record.
8588 */
8589 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8590 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8591 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8592
8593 report.condition = condition;
8594 report.processName = app.processName;
8595 report.pid = app.pid;
8596 report.uid = app.info.uid;
8597 report.tag = tag;
8598 report.shortMsg = shortMsg;
8599 report.longMsg = longMsg;
8600 report.crashData = crashData;
8601
8602 return report;
8603 }
8604
8605 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8606 boolean crashed) {
8607 synchronized (this) {
8608 app.crashing = false;
8609 app.crashingReport = null;
8610 app.notResponding = false;
8611 app.notRespondingReport = null;
8612 if (app.anrDialog == fromDialog) {
8613 app.anrDialog = null;
8614 }
8615 if (app.waitDialog == fromDialog) {
8616 app.waitDialog = null;
8617 }
8618 if (app.pid > 0 && app.pid != MY_PID) {
8619 if (crashed) {
8620 handleAppCrashLocked(app);
8621 }
8622 Log.i(ActivityManagerService.TAG, "Killing process "
8623 + app.processName
8624 + " (pid=" + app.pid + ") at user's request");
8625 Process.killProcess(app.pid);
8626 }
8627
8628 }
8629 }
8630
8631 boolean handleAppCrashLocked(ProcessRecord app) {
8632 long now = SystemClock.uptimeMillis();
8633
8634 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8635 app.info.uid);
8636 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8637 // This process loses!
8638 Log.w(TAG, "Process " + app.info.processName
8639 + " has crashed too many times: killing!");
8640 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8641 app.info.processName, app.info.uid);
8642 killServicesLocked(app, false);
8643 for (int i=mHistory.size()-1; i>=0; i--) {
8644 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8645 if (r.app == app) {
8646 if (Config.LOGD) Log.d(
8647 TAG, " Force finishing activity "
8648 + r.intent.getComponent().flattenToShortString());
8649 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8650 }
8651 }
8652 if (!app.persistent) {
8653 // We don't want to start this process again until the user
8654 // explicitly does so... but for persistent process, we really
8655 // need to keep it running. If a persistent process is actually
8656 // repeatedly crashing, then badness for everyone.
8657 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8658 app.info.processName);
8659 mBadProcesses.put(app.info.processName, app.info.uid, now);
8660 app.bad = true;
8661 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8662 app.removed = true;
8663 removeProcessLocked(app, false);
8664 return false;
8665 }
8666 }
8667
8668 // Bump up the crash count of any services currently running in the proc.
8669 if (app.services.size() != 0) {
8670 // Any services running in the application need to be placed
8671 // back in the pending list.
8672 Iterator it = app.services.iterator();
8673 while (it.hasNext()) {
8674 ServiceRecord sr = (ServiceRecord)it.next();
8675 sr.crashCount++;
8676 }
8677 }
8678
8679 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8680 return true;
8681 }
8682
8683 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008684 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008685 skipCurrentReceiverLocked(app);
8686 }
8687
8688 void skipCurrentReceiverLocked(ProcessRecord app) {
8689 boolean reschedule = false;
8690 BroadcastRecord r = app.curReceiver;
8691 if (r != null) {
8692 // The current broadcast is waiting for this app's receiver
8693 // to be finished. Looks like that's not going to happen, so
8694 // let the broadcast continue.
8695 logBroadcastReceiverDiscard(r);
8696 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8697 r.resultExtras, r.resultAbort, true);
8698 reschedule = true;
8699 }
8700 r = mPendingBroadcast;
8701 if (r != null && r.curApp == app) {
8702 if (DEBUG_BROADCAST) Log.v(TAG,
8703 "skip & discard pending app " + r);
8704 logBroadcastReceiverDiscard(r);
8705 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8706 r.resultExtras, r.resultAbort, true);
8707 reschedule = true;
8708 }
8709 if (reschedule) {
8710 scheduleBroadcastsLocked();
8711 }
8712 }
8713
8714 public int handleApplicationError(IBinder app, int flags,
8715 String tag, String shortMsg, String longMsg, byte[] crashData) {
8716 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008717 ProcessRecord r = null;
8718 synchronized (this) {
8719 if (app != null) {
8720 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8721 final int NA = apps.size();
8722 for (int ia=0; ia<NA; ia++) {
8723 ProcessRecord p = apps.valueAt(ia);
8724 if (p.thread != null && p.thread.asBinder() == app) {
8725 r = p;
8726 break;
8727 }
8728 }
8729 }
8730 }
8731
8732 if (r != null) {
8733 // The application has crashed. Send the SIGQUIT to the process so
8734 // that it can dump its state.
8735 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8736 //Log.i(TAG, "Current system threads:");
8737 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8738 }
8739
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008740 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008741 try {
8742 String name = r != null ? r.processName : null;
8743 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008744 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008745 shortMsg, longMsg, crashData)) {
8746 Log.w(TAG, "Force-killing crashed app " + name
8747 + " at watcher's request");
8748 Process.killProcess(pid);
8749 return 0;
8750 }
8751 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008752 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008753 }
8754 }
8755
8756 final long origId = Binder.clearCallingIdentity();
8757
8758 // If this process is running instrumentation, finish it.
8759 if (r != null && r.instrumentationClass != null) {
8760 Log.w(TAG, "Error in app " + r.processName
8761 + " running instrumentation " + r.instrumentationClass + ":");
8762 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8763 if (longMsg != null) Log.w(TAG, " " + longMsg);
8764 Bundle info = new Bundle();
8765 info.putString("shortMsg", shortMsg);
8766 info.putString("longMsg", longMsg);
8767 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8768 Binder.restoreCallingIdentity(origId);
8769 return 0;
8770 }
8771
8772 if (r != null) {
8773 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8774 return 0;
8775 }
8776 } else {
8777 Log.w(TAG, "Some application object " + app + " tag " + tag
8778 + " has crashed, but I don't know who it is.");
8779 Log.w(TAG, "ShortMsg:" + shortMsg);
8780 Log.w(TAG, "LongMsg:" + longMsg);
8781 Binder.restoreCallingIdentity(origId);
8782 return 0;
8783 }
8784
8785 Message msg = Message.obtain();
8786 msg.what = SHOW_ERROR_MSG;
8787 HashMap data = new HashMap();
8788 data.put("result", result);
8789 data.put("app", r);
8790 data.put("flags", flags);
8791 data.put("shortMsg", shortMsg);
8792 data.put("longMsg", longMsg);
8793 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8794 // For system processes, submit crash data to the server.
8795 data.put("crashData", crashData);
8796 }
8797 msg.obj = data;
8798 mHandler.sendMessage(msg);
8799
8800 Binder.restoreCallingIdentity(origId);
8801 }
8802
8803 int res = result.get();
8804
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008805 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008806 synchronized (this) {
8807 if (r != null) {
8808 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8809 SystemClock.uptimeMillis());
8810 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008811 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8812 appErrorIntent = createAppErrorIntentLocked(r);
8813 res = AppErrorDialog.FORCE_QUIT;
8814 }
8815 }
8816
8817 if (appErrorIntent != null) {
8818 try {
8819 mContext.startActivity(appErrorIntent);
8820 } catch (ActivityNotFoundException e) {
8821 Log.w(TAG, "bug report receiver dissappeared", e);
8822 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008823 }
8824
8825 return res;
8826 }
8827
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008828 Intent createAppErrorIntentLocked(ProcessRecord r) {
8829 ApplicationErrorReport report = createAppErrorReportLocked(r);
8830 if (report == null) {
8831 return null;
8832 }
8833 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8834 result.setComponent(r.errorReportReceiver);
8835 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8836 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8837 return result;
8838 }
8839
8840 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8841 if (r.errorReportReceiver == null) {
8842 return null;
8843 }
8844
8845 if (!r.crashing && !r.notResponding) {
8846 return null;
8847 }
8848
8849 try {
8850 ApplicationErrorReport report = new ApplicationErrorReport();
8851 report.packageName = r.info.packageName;
8852 report.installerPackageName = r.errorReportReceiver.getPackageName();
8853 report.processName = r.processName;
8854
8855 if (r.crashing) {
8856 report.type = ApplicationErrorReport.TYPE_CRASH;
8857 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8858
8859 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8860 r.crashingReport.crashData);
8861 DataInputStream dataStream = new DataInputStream(byteStream);
8862 CrashData crashData = new CrashData(dataStream);
8863 ThrowableData throwData = crashData.getThrowableData();
8864
8865 report.time = crashData.getTime();
8866 report.crashInfo.stackTrace = throwData.toString();
8867
Jacek Surazskif829a782009-06-11 22:47:02 +02008868 // Extract the source of the exception, useful for report
8869 // clustering. Also extract the "deepest" non-null exception
8870 // message.
8871 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008872 while (throwData.getCause() != null) {
8873 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008874 String msg = throwData.getMessage();
8875 if (msg != null && msg.length() > 0) {
8876 exceptionMessage = msg;
8877 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008878 }
8879 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008880 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008881 report.crashInfo.exceptionClassName = throwData.getType();
8882 report.crashInfo.throwFileName = trace.getFileName();
8883 report.crashInfo.throwClassName = trace.getClassName();
8884 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008885 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008886 } else if (r.notResponding) {
8887 report.type = ApplicationErrorReport.TYPE_ANR;
8888 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8889
8890 report.anrInfo.activity = r.notRespondingReport.tag;
8891 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8892 report.anrInfo.info = r.notRespondingReport.longMsg;
8893 }
8894
8895 return report;
8896 } catch (IOException e) {
8897 // we don't send it
8898 }
8899
8900 return null;
8901 }
8902
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008903 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8904 // assume our apps are happy - lazy create the list
8905 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8906
8907 synchronized (this) {
8908
8909 // iterate across all processes
8910 final int N = mLRUProcesses.size();
8911 for (int i = 0; i < N; i++) {
8912 ProcessRecord app = mLRUProcesses.get(i);
8913 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8914 // This one's in trouble, so we'll generate a report for it
8915 // crashes are higher priority (in case there's a crash *and* an anr)
8916 ActivityManager.ProcessErrorStateInfo report = null;
8917 if (app.crashing) {
8918 report = app.crashingReport;
8919 } else if (app.notResponding) {
8920 report = app.notRespondingReport;
8921 }
8922
8923 if (report != null) {
8924 if (errList == null) {
8925 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8926 }
8927 errList.add(report);
8928 } else {
8929 Log.w(TAG, "Missing app error report, app = " + app.processName +
8930 " crashing = " + app.crashing +
8931 " notResponding = " + app.notResponding);
8932 }
8933 }
8934 }
8935 }
8936
8937 return errList;
8938 }
8939
8940 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8941 // Lazy instantiation of list
8942 List<ActivityManager.RunningAppProcessInfo> runList = null;
8943 synchronized (this) {
8944 // Iterate across all processes
8945 final int N = mLRUProcesses.size();
8946 for (int i = 0; i < N; i++) {
8947 ProcessRecord app = mLRUProcesses.get(i);
8948 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8949 // Generate process state info for running application
8950 ActivityManager.RunningAppProcessInfo currApp =
8951 new ActivityManager.RunningAppProcessInfo(app.processName,
8952 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07008953 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008954 int adj = app.curAdj;
8955 if (adj >= CONTENT_PROVIDER_ADJ) {
8956 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8957 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8958 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008959 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8960 } else if (adj >= HOME_APP_ADJ) {
8961 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8962 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008963 } else if (adj >= SECONDARY_SERVER_ADJ) {
8964 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8965 } else if (adj >= VISIBLE_APP_ADJ) {
8966 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8967 } else {
8968 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8969 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07008970 currApp.importanceReasonCode = app.adjTypeCode;
8971 if (app.adjSource instanceof ProcessRecord) {
8972 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
8973 } else if (app.adjSource instanceof HistoryRecord) {
8974 HistoryRecord r = (HistoryRecord)app.adjSource;
8975 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
8976 }
8977 if (app.adjTarget instanceof ComponentName) {
8978 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
8979 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008980 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8981 // + " lru=" + currApp.lru);
8982 if (runList == null) {
8983 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8984 }
8985 runList.add(currApp);
8986 }
8987 }
8988 }
8989 return runList;
8990 }
8991
8992 @Override
8993 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8994 synchronized (this) {
8995 if (checkCallingPermission(android.Manifest.permission.DUMP)
8996 != PackageManager.PERMISSION_GRANTED) {
8997 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8998 + Binder.getCallingPid()
8999 + ", uid=" + Binder.getCallingUid()
9000 + " without permission "
9001 + android.Manifest.permission.DUMP);
9002 return;
9003 }
9004 if (args.length != 0 && "service".equals(args[0])) {
9005 dumpService(fd, pw, args);
9006 return;
9007 }
9008 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009009 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009010 pw.println(" ");
9011 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009012 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009013 if (mWaitingVisibleActivities.size() > 0) {
9014 pw.println(" ");
9015 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009016 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009017 }
9018 if (mStoppingActivities.size() > 0) {
9019 pw.println(" ");
9020 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009021 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009022 }
9023 if (mFinishingActivities.size() > 0) {
9024 pw.println(" ");
9025 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009026 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009027 }
9028
9029 pw.println(" ");
9030 pw.println(" mPausingActivity: " + mPausingActivity);
9031 pw.println(" mResumedActivity: " + mResumedActivity);
9032 pw.println(" mFocusedActivity: " + mFocusedActivity);
9033 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
9034
9035 if (mRecentTasks.size() > 0) {
9036 pw.println(" ");
9037 pw.println("Recent tasks in Current Activity Manager State:");
9038
9039 final int N = mRecentTasks.size();
9040 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009041 TaskRecord tr = mRecentTasks.get(i);
9042 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9043 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009044 mRecentTasks.get(i).dump(pw, " ");
9045 }
9046 }
9047
9048 pw.println(" ");
9049 pw.println(" mCurTask: " + mCurTask);
9050
9051 pw.println(" ");
9052 pw.println("Processes in Current Activity Manager State:");
9053
9054 boolean needSep = false;
9055 int numPers = 0;
9056
9057 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9058 final int NA = procs.size();
9059 for (int ia=0; ia<NA; ia++) {
9060 if (!needSep) {
9061 pw.println(" All known processes:");
9062 needSep = true;
9063 }
9064 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009065 pw.print(r.persistent ? " *PERS*" : " *APP*");
9066 pw.print(" UID "); pw.print(procs.keyAt(ia));
9067 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009068 r.dump(pw, " ");
9069 if (r.persistent) {
9070 numPers++;
9071 }
9072 }
9073 }
9074
9075 if (mLRUProcesses.size() > 0) {
9076 if (needSep) pw.println(" ");
9077 needSep = true;
9078 pw.println(" Running processes (most recent first):");
9079 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009080 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009081 needSep = true;
9082 }
9083
9084 synchronized (mPidsSelfLocked) {
9085 if (mPidsSelfLocked.size() > 0) {
9086 if (needSep) pw.println(" ");
9087 needSep = true;
9088 pw.println(" PID mappings:");
9089 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009090 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9091 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009092 }
9093 }
9094 }
9095
9096 if (mForegroundProcesses.size() > 0) {
9097 if (needSep) pw.println(" ");
9098 needSep = true;
9099 pw.println(" Foreground Processes:");
9100 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009101 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9102 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009103 }
9104 }
9105
9106 if (mPersistentStartingProcesses.size() > 0) {
9107 if (needSep) pw.println(" ");
9108 needSep = true;
9109 pw.println(" Persisent processes that are starting:");
9110 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009111 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009112 }
9113
9114 if (mStartingProcesses.size() > 0) {
9115 if (needSep) pw.println(" ");
9116 needSep = true;
9117 pw.println(" Processes that are starting:");
9118 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009119 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009120 }
9121
9122 if (mRemovedProcesses.size() > 0) {
9123 if (needSep) pw.println(" ");
9124 needSep = true;
9125 pw.println(" Processes that are being removed:");
9126 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009127 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009128 }
9129
9130 if (mProcessesOnHold.size() > 0) {
9131 if (needSep) pw.println(" ");
9132 needSep = true;
9133 pw.println(" Processes that are on old until the system is ready:");
9134 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009135 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009136 }
9137
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009138 if (mProcessesToGc.size() > 0) {
9139 if (needSep) pw.println(" ");
9140 needSep = true;
9141 pw.println(" Processes that are waiting to GC:");
9142 long now = SystemClock.uptimeMillis();
9143 for (int i=0; i<mProcessesToGc.size(); i++) {
9144 ProcessRecord proc = mProcessesToGc.get(i);
9145 pw.print(" Process "); pw.println(proc);
9146 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9147 pw.print(", last gced=");
9148 pw.print(now-proc.lastRequestedGc);
9149 pw.print(" ms ago, last lowMwm=");
9150 pw.print(now-proc.lastLowMemory);
9151 pw.println(" ms ago");
9152
9153 }
9154 }
9155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009156 if (mProcessCrashTimes.getMap().size() > 0) {
9157 if (needSep) pw.println(" ");
9158 needSep = true;
9159 pw.println(" Time since processes crashed:");
9160 long now = SystemClock.uptimeMillis();
9161 for (Map.Entry<String, SparseArray<Long>> procs
9162 : mProcessCrashTimes.getMap().entrySet()) {
9163 SparseArray<Long> uids = procs.getValue();
9164 final int N = uids.size();
9165 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009166 pw.print(" Process "); pw.print(procs.getKey());
9167 pw.print(" uid "); pw.print(uids.keyAt(i));
9168 pw.print(": last crashed ");
9169 pw.print((now-uids.valueAt(i)));
9170 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009171 }
9172 }
9173 }
9174
9175 if (mBadProcesses.getMap().size() > 0) {
9176 if (needSep) pw.println(" ");
9177 needSep = true;
9178 pw.println(" Bad processes:");
9179 for (Map.Entry<String, SparseArray<Long>> procs
9180 : mBadProcesses.getMap().entrySet()) {
9181 SparseArray<Long> uids = procs.getValue();
9182 final int N = uids.size();
9183 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009184 pw.print(" Bad process "); pw.print(procs.getKey());
9185 pw.print(" uid "); pw.print(uids.keyAt(i));
9186 pw.print(": crashed at time ");
9187 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009188 }
9189 }
9190 }
9191
9192 pw.println(" ");
9193 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009194 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009195 pw.println(" mConfiguration: " + mConfiguration);
9196 pw.println(" mStartRunning=" + mStartRunning
9197 + " mSystemReady=" + mSystemReady
9198 + " mBooting=" + mBooting
9199 + " mBooted=" + mBooted
9200 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009201 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009202 pw.println(" mGoingToSleep=" + mGoingToSleep);
9203 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9204 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9205 + " mDebugTransient=" + mDebugTransient
9206 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9207 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009208 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009209 }
9210 }
9211
9212 /**
9213 * There are three ways to call this:
9214 * - no service specified: dump all the services
9215 * - a flattened component name that matched an existing service was specified as the
9216 * first arg: dump that one service
9217 * - the first arg isn't the flattened component name of an existing service:
9218 * dump all services whose component contains the first arg as a substring
9219 */
9220 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9221 String[] newArgs;
9222 String componentNameString;
9223 ServiceRecord r;
9224 if (args.length == 1) {
9225 componentNameString = null;
9226 newArgs = EMPTY_STRING_ARRAY;
9227 r = null;
9228 } else {
9229 componentNameString = args[1];
9230 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9231 r = componentName != null ? mServices.get(componentName) : null;
9232 newArgs = new String[args.length - 2];
9233 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9234 }
9235
9236 if (r != null) {
9237 dumpService(fd, pw, r, newArgs);
9238 } else {
9239 for (ServiceRecord r1 : mServices.values()) {
9240 if (componentNameString == null
9241 || r1.name.flattenToString().contains(componentNameString)) {
9242 dumpService(fd, pw, r1, newArgs);
9243 }
9244 }
9245 }
9246 }
9247
9248 /**
9249 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9250 * there is a thread associated with the service.
9251 */
9252 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9253 pw.println(" Service " + r.name.flattenToString());
9254 if (r.app != null && r.app.thread != null) {
9255 try {
9256 // flush anything that is already in the PrintWriter since the thread is going
9257 // to write to the file descriptor directly
9258 pw.flush();
9259 r.app.thread.dumpService(fd, r, args);
9260 pw.print("\n");
9261 } catch (RemoteException e) {
9262 pw.println("got a RemoteException while dumping the service");
9263 }
9264 }
9265 }
9266
9267 void dumpBroadcasts(PrintWriter pw) {
9268 synchronized (this) {
9269 if (checkCallingPermission(android.Manifest.permission.DUMP)
9270 != PackageManager.PERMISSION_GRANTED) {
9271 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9272 + Binder.getCallingPid()
9273 + ", uid=" + Binder.getCallingUid()
9274 + " without permission "
9275 + android.Manifest.permission.DUMP);
9276 return;
9277 }
9278 pw.println("Broadcasts in Current Activity Manager State:");
9279
9280 if (mRegisteredReceivers.size() > 0) {
9281 pw.println(" ");
9282 pw.println(" Registered Receivers:");
9283 Iterator it = mRegisteredReceivers.values().iterator();
9284 while (it.hasNext()) {
9285 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009286 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009287 r.dump(pw, " ");
9288 }
9289 }
9290
9291 pw.println(" ");
9292 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009293 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009294
9295 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9296 || mPendingBroadcast != null) {
9297 if (mParallelBroadcasts.size() > 0) {
9298 pw.println(" ");
9299 pw.println(" Active broadcasts:");
9300 }
9301 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9302 pw.println(" Broadcast #" + i + ":");
9303 mParallelBroadcasts.get(i).dump(pw, " ");
9304 }
9305 if (mOrderedBroadcasts.size() > 0) {
9306 pw.println(" ");
9307 pw.println(" Active serialized broadcasts:");
9308 }
9309 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9310 pw.println(" Serialized Broadcast #" + i + ":");
9311 mOrderedBroadcasts.get(i).dump(pw, " ");
9312 }
9313 pw.println(" ");
9314 pw.println(" Pending broadcast:");
9315 if (mPendingBroadcast != null) {
9316 mPendingBroadcast.dump(pw, " ");
9317 } else {
9318 pw.println(" (null)");
9319 }
9320 }
9321
9322 pw.println(" ");
9323 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9324 if (mStickyBroadcasts != null) {
9325 pw.println(" ");
9326 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009327 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009328 for (Map.Entry<String, ArrayList<Intent>> ent
9329 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009330 pw.print(" * Sticky action "); pw.print(ent.getKey());
9331 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009332 ArrayList<Intent> intents = ent.getValue();
9333 final int N = intents.size();
9334 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009335 sb.setLength(0);
9336 sb.append(" Intent: ");
9337 intents.get(i).toShortString(sb, true, false);
9338 pw.println(sb.toString());
9339 Bundle bundle = intents.get(i).getExtras();
9340 if (bundle != null) {
9341 pw.print(" ");
9342 pw.println(bundle.toString());
9343 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009344 }
9345 }
9346 }
9347
9348 pw.println(" ");
9349 pw.println(" mHandler:");
9350 mHandler.dump(new PrintWriterPrinter(pw), " ");
9351 }
9352 }
9353
9354 void dumpServices(PrintWriter pw) {
9355 synchronized (this) {
9356 if (checkCallingPermission(android.Manifest.permission.DUMP)
9357 != PackageManager.PERMISSION_GRANTED) {
9358 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9359 + Binder.getCallingPid()
9360 + ", uid=" + Binder.getCallingUid()
9361 + " without permission "
9362 + android.Manifest.permission.DUMP);
9363 return;
9364 }
9365 pw.println("Services in Current Activity Manager State:");
9366
9367 boolean needSep = false;
9368
9369 if (mServices.size() > 0) {
9370 pw.println(" Active services:");
9371 Iterator<ServiceRecord> it = mServices.values().iterator();
9372 while (it.hasNext()) {
9373 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009374 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009375 r.dump(pw, " ");
9376 }
9377 needSep = true;
9378 }
9379
9380 if (mPendingServices.size() > 0) {
9381 if (needSep) pw.println(" ");
9382 pw.println(" Pending services:");
9383 for (int i=0; i<mPendingServices.size(); i++) {
9384 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009385 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009386 r.dump(pw, " ");
9387 }
9388 needSep = true;
9389 }
9390
9391 if (mRestartingServices.size() > 0) {
9392 if (needSep) pw.println(" ");
9393 pw.println(" Restarting services:");
9394 for (int i=0; i<mRestartingServices.size(); i++) {
9395 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009396 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009397 r.dump(pw, " ");
9398 }
9399 needSep = true;
9400 }
9401
9402 if (mStoppingServices.size() > 0) {
9403 if (needSep) pw.println(" ");
9404 pw.println(" Stopping services:");
9405 for (int i=0; i<mStoppingServices.size(); i++) {
9406 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009407 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009408 r.dump(pw, " ");
9409 }
9410 needSep = true;
9411 }
9412
9413 if (mServiceConnections.size() > 0) {
9414 if (needSep) pw.println(" ");
9415 pw.println(" Connection bindings to services:");
9416 Iterator<ConnectionRecord> it
9417 = mServiceConnections.values().iterator();
9418 while (it.hasNext()) {
9419 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009420 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009421 r.dump(pw, " ");
9422 }
9423 }
9424 }
9425 }
9426
9427 void dumpProviders(PrintWriter pw) {
9428 synchronized (this) {
9429 if (checkCallingPermission(android.Manifest.permission.DUMP)
9430 != PackageManager.PERMISSION_GRANTED) {
9431 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9432 + Binder.getCallingPid()
9433 + ", uid=" + Binder.getCallingUid()
9434 + " without permission "
9435 + android.Manifest.permission.DUMP);
9436 return;
9437 }
9438
9439 pw.println("Content Providers in Current Activity Manager State:");
9440
9441 boolean needSep = false;
9442
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009443 if (mProvidersByClass.size() > 0) {
9444 if (needSep) pw.println(" ");
9445 pw.println(" Published content providers (by class):");
9446 Iterator it = mProvidersByClass.entrySet().iterator();
9447 while (it.hasNext()) {
9448 Map.Entry e = (Map.Entry)it.next();
9449 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009450 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009451 r.dump(pw, " ");
9452 }
9453 needSep = true;
9454 }
9455
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009456 if (mProvidersByName.size() > 0) {
9457 pw.println(" ");
9458 pw.println(" Authority to provider mappings:");
9459 Iterator it = mProvidersByName.entrySet().iterator();
9460 while (it.hasNext()) {
9461 Map.Entry e = (Map.Entry)it.next();
9462 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9463 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9464 pw.println(r);
9465 }
9466 needSep = true;
9467 }
9468
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009469 if (mLaunchingProviders.size() > 0) {
9470 if (needSep) pw.println(" ");
9471 pw.println(" Launching content providers:");
9472 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009473 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9474 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009475 }
9476 needSep = true;
9477 }
9478
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009479 if (mGrantedUriPermissions.size() > 0) {
9480 pw.println();
9481 pw.println("Granted Uri Permissions:");
9482 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9483 int uid = mGrantedUriPermissions.keyAt(i);
9484 HashMap<Uri, UriPermission> perms
9485 = mGrantedUriPermissions.valueAt(i);
9486 pw.print(" * UID "); pw.print(uid);
9487 pw.println(" holds:");
9488 for (UriPermission perm : perms.values()) {
9489 pw.print(" "); pw.println(perm);
9490 perm.dump(pw, " ");
9491 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009492 }
9493 }
9494 }
9495 }
9496
9497 void dumpSenders(PrintWriter pw) {
9498 synchronized (this) {
9499 if (checkCallingPermission(android.Manifest.permission.DUMP)
9500 != PackageManager.PERMISSION_GRANTED) {
9501 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9502 + Binder.getCallingPid()
9503 + ", uid=" + Binder.getCallingUid()
9504 + " without permission "
9505 + android.Manifest.permission.DUMP);
9506 return;
9507 }
9508
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009509 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009510
9511 if (this.mIntentSenderRecords.size() > 0) {
9512 Iterator<WeakReference<PendingIntentRecord>> it
9513 = mIntentSenderRecords.values().iterator();
9514 while (it.hasNext()) {
9515 WeakReference<PendingIntentRecord> ref = it.next();
9516 PendingIntentRecord rec = ref != null ? ref.get(): null;
9517 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009518 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009519 rec.dump(pw, " ");
9520 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009521 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009522 }
9523 }
9524 }
9525 }
9526 }
9527
9528 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009529 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009530 TaskRecord lastTask = null;
9531 for (int i=list.size()-1; i>=0; i--) {
9532 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009533 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009534 if (lastTask != r.task) {
9535 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009536 pw.print(prefix);
9537 pw.print(full ? "* " : " ");
9538 pw.println(lastTask);
9539 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009540 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009541 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009542 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009543 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9544 pw.print(" #"); pw.print(i); pw.print(": ");
9545 pw.println(r);
9546 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009547 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009548 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009549 }
9550 }
9551
9552 private static final int dumpProcessList(PrintWriter pw, List list,
9553 String prefix, String normalLabel, String persistentLabel,
9554 boolean inclOomAdj) {
9555 int numPers = 0;
9556 for (int i=list.size()-1; i>=0; i--) {
9557 ProcessRecord r = (ProcessRecord)list.get(i);
9558 if (false) {
9559 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9560 + " #" + i + ":");
9561 r.dump(pw, prefix + " ");
9562 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009563 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009564 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009565 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9566 if (r.adjSource != null || r.adjTarget != null) {
9567 pw.println(prefix + " " + r.adjTarget
9568 + " used by " + r.adjSource);
9569 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009570 } else {
9571 pw.println(String.format("%s%s #%2d: %s",
9572 prefix, (r.persistent ? persistentLabel : normalLabel),
9573 i, r.toString()));
9574 }
9575 if (r.persistent) {
9576 numPers++;
9577 }
9578 }
9579 return numPers;
9580 }
9581
9582 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9583 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009584 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009585 long uptime = SystemClock.uptimeMillis();
9586 long realtime = SystemClock.elapsedRealtime();
9587
9588 if (isCheckinRequest) {
9589 // short checkin version
9590 pw.println(uptime + "," + realtime);
9591 pw.flush();
9592 } else {
9593 pw.println("Applications Memory Usage (kB):");
9594 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9595 }
9596 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9597 ProcessRecord r = (ProcessRecord)list.get(i);
9598 if (r.thread != null) {
9599 if (!isCheckinRequest) {
9600 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9601 pw.flush();
9602 }
9603 try {
9604 r.thread.asBinder().dump(fd, args);
9605 } catch (RemoteException e) {
9606 if (!isCheckinRequest) {
9607 pw.println("Got RemoteException!");
9608 pw.flush();
9609 }
9610 }
9611 }
9612 }
9613 }
9614
9615 /**
9616 * Searches array of arguments for the specified string
9617 * @param args array of argument strings
9618 * @param value value to search for
9619 * @return true if the value is contained in the array
9620 */
9621 private static boolean scanArgs(String[] args, String value) {
9622 if (args != null) {
9623 for (String arg : args) {
9624 if (value.equals(arg)) {
9625 return true;
9626 }
9627 }
9628 }
9629 return false;
9630 }
9631
Dianne Hackborn75b03852009-06-12 15:43:26 -07009632 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009633 int count = mHistory.size();
9634
9635 // convert the token to an entry in the history.
9636 HistoryRecord r = null;
9637 int index = -1;
9638 for (int i=count-1; i>=0; i--) {
9639 Object o = mHistory.get(i);
9640 if (o == token) {
9641 r = (HistoryRecord)o;
9642 index = i;
9643 break;
9644 }
9645 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009646
9647 return index;
9648 }
9649
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009650 private final void killServicesLocked(ProcessRecord app,
9651 boolean allowRestart) {
9652 // Report disconnected services.
9653 if (false) {
9654 // XXX we are letting the client link to the service for
9655 // death notifications.
9656 if (app.services.size() > 0) {
9657 Iterator it = app.services.iterator();
9658 while (it.hasNext()) {
9659 ServiceRecord r = (ServiceRecord)it.next();
9660 if (r.connections.size() > 0) {
9661 Iterator<ConnectionRecord> jt
9662 = r.connections.values().iterator();
9663 while (jt.hasNext()) {
9664 ConnectionRecord c = jt.next();
9665 if (c.binding.client != app) {
9666 try {
9667 //c.conn.connected(r.className, null);
9668 } catch (Exception e) {
9669 // todo: this should be asynchronous!
9670 Log.w(TAG, "Exception thrown disconnected servce "
9671 + r.shortName
9672 + " from app " + app.processName, e);
9673 }
9674 }
9675 }
9676 }
9677 }
9678 }
9679 }
9680
9681 // Clean up any connections this application has to other services.
9682 if (app.connections.size() > 0) {
9683 Iterator<ConnectionRecord> it = app.connections.iterator();
9684 while (it.hasNext()) {
9685 ConnectionRecord r = it.next();
9686 removeConnectionLocked(r, app, null);
9687 }
9688 }
9689 app.connections.clear();
9690
9691 if (app.services.size() != 0) {
9692 // Any services running in the application need to be placed
9693 // back in the pending list.
9694 Iterator it = app.services.iterator();
9695 while (it.hasNext()) {
9696 ServiceRecord sr = (ServiceRecord)it.next();
9697 synchronized (sr.stats.getBatteryStats()) {
9698 sr.stats.stopLaunchedLocked();
9699 }
9700 sr.app = null;
9701 sr.executeNesting = 0;
9702 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009703
9704 boolean hasClients = sr.bindings.size() > 0;
9705 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009706 Iterator<IntentBindRecord> bindings
9707 = sr.bindings.values().iterator();
9708 while (bindings.hasNext()) {
9709 IntentBindRecord b = bindings.next();
9710 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9711 + ": shouldUnbind=" + b.hasBound);
9712 b.binder = null;
9713 b.requested = b.received = b.hasBound = false;
9714 }
9715 }
9716
9717 if (sr.crashCount >= 2) {
9718 Log.w(TAG, "Service crashed " + sr.crashCount
9719 + " times, stopping: " + sr);
9720 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9721 sr.crashCount, sr.shortName, app.pid);
9722 bringDownServiceLocked(sr, true);
9723 } else if (!allowRestart) {
9724 bringDownServiceLocked(sr, true);
9725 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009726 boolean canceled = scheduleServiceRestartLocked(sr, true);
9727
9728 // Should the service remain running? Note that in the
9729 // extreme case of so many attempts to deliver a command
9730 // that it failed, that we also will stop it here.
9731 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9732 if (sr.pendingStarts.size() == 0) {
9733 sr.startRequested = false;
9734 if (!hasClients) {
9735 // Whoops, no reason to restart!
9736 bringDownServiceLocked(sr, true);
9737 }
9738 }
9739 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009740 }
9741 }
9742
9743 if (!allowRestart) {
9744 app.services.clear();
9745 }
9746 }
9747
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009748 // Make sure we have no more records on the stopping list.
9749 int i = mStoppingServices.size();
9750 while (i > 0) {
9751 i--;
9752 ServiceRecord sr = mStoppingServices.get(i);
9753 if (sr.app == app) {
9754 mStoppingServices.remove(i);
9755 }
9756 }
9757
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009758 app.executingServices.clear();
9759 }
9760
9761 private final void removeDyingProviderLocked(ProcessRecord proc,
9762 ContentProviderRecord cpr) {
9763 synchronized (cpr) {
9764 cpr.launchingApp = null;
9765 cpr.notifyAll();
9766 }
9767
9768 mProvidersByClass.remove(cpr.info.name);
9769 String names[] = cpr.info.authority.split(";");
9770 for (int j = 0; j < names.length; j++) {
9771 mProvidersByName.remove(names[j]);
9772 }
9773
9774 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9775 while (cit.hasNext()) {
9776 ProcessRecord capp = cit.next();
9777 if (!capp.persistent && capp.thread != null
9778 && capp.pid != 0
9779 && capp.pid != MY_PID) {
9780 Log.i(TAG, "Killing app " + capp.processName
9781 + " (pid " + capp.pid
9782 + ") because provider " + cpr.info.name
9783 + " is in dying process " + proc.processName);
9784 Process.killProcess(capp.pid);
9785 }
9786 }
9787
9788 mLaunchingProviders.remove(cpr);
9789 }
9790
9791 /**
9792 * Main code for cleaning up a process when it has gone away. This is
9793 * called both as a result of the process dying, or directly when stopping
9794 * a process when running in single process mode.
9795 */
9796 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9797 boolean restarting, int index) {
9798 if (index >= 0) {
9799 mLRUProcesses.remove(index);
9800 }
9801
9802 // Dismiss any open dialogs.
9803 if (app.crashDialog != null) {
9804 app.crashDialog.dismiss();
9805 app.crashDialog = null;
9806 }
9807 if (app.anrDialog != null) {
9808 app.anrDialog.dismiss();
9809 app.anrDialog = null;
9810 }
9811 if (app.waitDialog != null) {
9812 app.waitDialog.dismiss();
9813 app.waitDialog = null;
9814 }
9815
9816 app.crashing = false;
9817 app.notResponding = false;
9818
9819 app.resetPackageList();
9820 app.thread = null;
9821 app.forcingToForeground = null;
9822 app.foregroundServices = false;
9823
9824 killServicesLocked(app, true);
9825
9826 boolean restart = false;
9827
9828 int NL = mLaunchingProviders.size();
9829
9830 // Remove published content providers.
9831 if (!app.pubProviders.isEmpty()) {
9832 Iterator it = app.pubProviders.values().iterator();
9833 while (it.hasNext()) {
9834 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9835 cpr.provider = null;
9836 cpr.app = null;
9837
9838 // See if someone is waiting for this provider... in which
9839 // case we don't remove it, but just let it restart.
9840 int i = 0;
9841 if (!app.bad) {
9842 for (; i<NL; i++) {
9843 if (mLaunchingProviders.get(i) == cpr) {
9844 restart = true;
9845 break;
9846 }
9847 }
9848 } else {
9849 i = NL;
9850 }
9851
9852 if (i >= NL) {
9853 removeDyingProviderLocked(app, cpr);
9854 NL = mLaunchingProviders.size();
9855 }
9856 }
9857 app.pubProviders.clear();
9858 }
9859
9860 // Look through the content providers we are waiting to have launched,
9861 // and if any run in this process then either schedule a restart of
9862 // the process or kill the client waiting for it if this process has
9863 // gone bad.
9864 for (int i=0; i<NL; i++) {
9865 ContentProviderRecord cpr = (ContentProviderRecord)
9866 mLaunchingProviders.get(i);
9867 if (cpr.launchingApp == app) {
9868 if (!app.bad) {
9869 restart = true;
9870 } else {
9871 removeDyingProviderLocked(app, cpr);
9872 NL = mLaunchingProviders.size();
9873 }
9874 }
9875 }
9876
9877 // Unregister from connected content providers.
9878 if (!app.conProviders.isEmpty()) {
9879 Iterator it = app.conProviders.iterator();
9880 while (it.hasNext()) {
9881 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9882 cpr.clients.remove(app);
9883 }
9884 app.conProviders.clear();
9885 }
9886
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009887 // At this point there may be remaining entries in mLaunchingProviders
9888 // where we were the only one waiting, so they are no longer of use.
9889 // Look for these and clean up if found.
9890 // XXX Commented out for now. Trying to figure out a way to reproduce
9891 // the actual situation to identify what is actually going on.
9892 if (false) {
9893 for (int i=0; i<NL; i++) {
9894 ContentProviderRecord cpr = (ContentProviderRecord)
9895 mLaunchingProviders.get(i);
9896 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9897 synchronized (cpr) {
9898 cpr.launchingApp = null;
9899 cpr.notifyAll();
9900 }
9901 }
9902 }
9903 }
9904
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009905 skipCurrentReceiverLocked(app);
9906
9907 // Unregister any receivers.
9908 if (app.receivers.size() > 0) {
9909 Iterator<ReceiverList> it = app.receivers.iterator();
9910 while (it.hasNext()) {
9911 removeReceiverLocked(it.next());
9912 }
9913 app.receivers.clear();
9914 }
9915
Christopher Tate181fafa2009-05-14 11:12:14 -07009916 // If the app is undergoing backup, tell the backup manager about it
9917 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9918 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9919 try {
9920 IBackupManager bm = IBackupManager.Stub.asInterface(
9921 ServiceManager.getService(Context.BACKUP_SERVICE));
9922 bm.agentDisconnected(app.info.packageName);
9923 } catch (RemoteException e) {
9924 // can't happen; backup manager is local
9925 }
9926 }
9927
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009928 // If the caller is restarting this app, then leave it in its
9929 // current lists and let the caller take care of it.
9930 if (restarting) {
9931 return;
9932 }
9933
9934 if (!app.persistent) {
9935 if (DEBUG_PROCESSES) Log.v(TAG,
9936 "Removing non-persistent process during cleanup: " + app);
9937 mProcessNames.remove(app.processName, app.info.uid);
9938 } else if (!app.removed) {
9939 // This app is persistent, so we need to keep its record around.
9940 // If it is not already on the pending app list, add it there
9941 // and start a new process for it.
9942 app.thread = null;
9943 app.forcingToForeground = null;
9944 app.foregroundServices = false;
9945 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9946 mPersistentStartingProcesses.add(app);
9947 restart = true;
9948 }
9949 }
9950 mProcessesOnHold.remove(app);
9951
The Android Open Source Project4df24232009-03-05 14:34:35 -08009952 if (app == mHomeProcess) {
9953 mHomeProcess = null;
9954 }
9955
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009956 if (restart) {
9957 // We have components that still need to be running in the
9958 // process, so re-launch it.
9959 mProcessNames.put(app.processName, app.info.uid, app);
9960 startProcessLocked(app, "restart", app.processName);
9961 } else if (app.pid > 0 && app.pid != MY_PID) {
9962 // Goodbye!
9963 synchronized (mPidsSelfLocked) {
9964 mPidsSelfLocked.remove(app.pid);
9965 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9966 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009967 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009968 }
9969 }
9970
9971 // =========================================================
9972 // SERVICES
9973 // =========================================================
9974
9975 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9976 ActivityManager.RunningServiceInfo info =
9977 new ActivityManager.RunningServiceInfo();
9978 info.service = r.name;
9979 if (r.app != null) {
9980 info.pid = r.app.pid;
9981 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -07009982 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009983 info.process = r.processName;
9984 info.foreground = r.isForeground;
9985 info.activeSince = r.createTime;
9986 info.started = r.startRequested;
9987 info.clientCount = r.connections.size();
9988 info.crashCount = r.crashCount;
9989 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07009990 if (r.isForeground) {
9991 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
9992 }
9993 if (r.startRequested) {
9994 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
9995 }
9996 if (r.app != null && r.app.pid == Process.myPid()) {
9997 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
9998 }
9999 if (r.app != null && r.app.persistent) {
10000 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10001 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010002 for (ConnectionRecord conn : r.connections.values()) {
10003 if (conn.clientLabel != 0) {
10004 info.clientPackage = conn.binding.client.info.packageName;
10005 info.clientLabel = conn.clientLabel;
10006 break;
10007 }
10008 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010009 return info;
10010 }
10011
10012 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10013 int flags) {
10014 synchronized (this) {
10015 ArrayList<ActivityManager.RunningServiceInfo> res
10016 = new ArrayList<ActivityManager.RunningServiceInfo>();
10017
10018 if (mServices.size() > 0) {
10019 Iterator<ServiceRecord> it = mServices.values().iterator();
10020 while (it.hasNext() && res.size() < maxNum) {
10021 res.add(makeRunningServiceInfoLocked(it.next()));
10022 }
10023 }
10024
10025 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10026 ServiceRecord r = mRestartingServices.get(i);
10027 ActivityManager.RunningServiceInfo info =
10028 makeRunningServiceInfoLocked(r);
10029 info.restarting = r.nextRestartTime;
10030 res.add(info);
10031 }
10032
10033 return res;
10034 }
10035 }
10036
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010037 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10038 synchronized (this) {
10039 ServiceRecord r = mServices.get(name);
10040 if (r != null) {
10041 for (ConnectionRecord conn : r.connections.values()) {
10042 if (conn.clientIntent != null) {
10043 return conn.clientIntent;
10044 }
10045 }
10046 }
10047 }
10048 return null;
10049 }
10050
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010051 private final ServiceRecord findServiceLocked(ComponentName name,
10052 IBinder token) {
10053 ServiceRecord r = mServices.get(name);
10054 return r == token ? r : null;
10055 }
10056
10057 private final class ServiceLookupResult {
10058 final ServiceRecord record;
10059 final String permission;
10060
10061 ServiceLookupResult(ServiceRecord _record, String _permission) {
10062 record = _record;
10063 permission = _permission;
10064 }
10065 };
10066
10067 private ServiceLookupResult findServiceLocked(Intent service,
10068 String resolvedType) {
10069 ServiceRecord r = null;
10070 if (service.getComponent() != null) {
10071 r = mServices.get(service.getComponent());
10072 }
10073 if (r == null) {
10074 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10075 r = mServicesByIntent.get(filter);
10076 }
10077
10078 if (r == null) {
10079 try {
10080 ResolveInfo rInfo =
10081 ActivityThread.getPackageManager().resolveService(
10082 service, resolvedType, 0);
10083 ServiceInfo sInfo =
10084 rInfo != null ? rInfo.serviceInfo : null;
10085 if (sInfo == null) {
10086 return null;
10087 }
10088
10089 ComponentName name = new ComponentName(
10090 sInfo.applicationInfo.packageName, sInfo.name);
10091 r = mServices.get(name);
10092 } catch (RemoteException ex) {
10093 // pm is in same process, this will never happen.
10094 }
10095 }
10096 if (r != null) {
10097 int callingPid = Binder.getCallingPid();
10098 int callingUid = Binder.getCallingUid();
10099 if (checkComponentPermission(r.permission,
10100 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10101 != PackageManager.PERMISSION_GRANTED) {
10102 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10103 + " from pid=" + callingPid
10104 + ", uid=" + callingUid
10105 + " requires " + r.permission);
10106 return new ServiceLookupResult(null, r.permission);
10107 }
10108 return new ServiceLookupResult(r, null);
10109 }
10110 return null;
10111 }
10112
10113 private class ServiceRestarter implements Runnable {
10114 private ServiceRecord mService;
10115
10116 void setService(ServiceRecord service) {
10117 mService = service;
10118 }
10119
10120 public void run() {
10121 synchronized(ActivityManagerService.this) {
10122 performServiceRestartLocked(mService);
10123 }
10124 }
10125 }
10126
10127 private ServiceLookupResult retrieveServiceLocked(Intent service,
10128 String resolvedType, int callingPid, int callingUid) {
10129 ServiceRecord r = null;
10130 if (service.getComponent() != null) {
10131 r = mServices.get(service.getComponent());
10132 }
10133 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10134 r = mServicesByIntent.get(filter);
10135 if (r == null) {
10136 try {
10137 ResolveInfo rInfo =
10138 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010139 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010140 ServiceInfo sInfo =
10141 rInfo != null ? rInfo.serviceInfo : null;
10142 if (sInfo == null) {
10143 Log.w(TAG, "Unable to start service " + service +
10144 ": not found");
10145 return null;
10146 }
10147
10148 ComponentName name = new ComponentName(
10149 sInfo.applicationInfo.packageName, sInfo.name);
10150 r = mServices.get(name);
10151 if (r == null) {
10152 filter = new Intent.FilterComparison(service.cloneFilter());
10153 ServiceRestarter res = new ServiceRestarter();
10154 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10155 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10156 synchronized (stats) {
10157 ss = stats.getServiceStatsLocked(
10158 sInfo.applicationInfo.uid, sInfo.packageName,
10159 sInfo.name);
10160 }
10161 r = new ServiceRecord(ss, name, filter, sInfo, res);
10162 res.setService(r);
10163 mServices.put(name, r);
10164 mServicesByIntent.put(filter, r);
10165
10166 // Make sure this component isn't in the pending list.
10167 int N = mPendingServices.size();
10168 for (int i=0; i<N; i++) {
10169 ServiceRecord pr = mPendingServices.get(i);
10170 if (pr.name.equals(name)) {
10171 mPendingServices.remove(i);
10172 i--;
10173 N--;
10174 }
10175 }
10176 }
10177 } catch (RemoteException ex) {
10178 // pm is in same process, this will never happen.
10179 }
10180 }
10181 if (r != null) {
10182 if (checkComponentPermission(r.permission,
10183 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10184 != PackageManager.PERMISSION_GRANTED) {
10185 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10186 + " from pid=" + Binder.getCallingPid()
10187 + ", uid=" + Binder.getCallingUid()
10188 + " requires " + r.permission);
10189 return new ServiceLookupResult(null, r.permission);
10190 }
10191 return new ServiceLookupResult(r, null);
10192 }
10193 return null;
10194 }
10195
10196 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10197 long now = SystemClock.uptimeMillis();
10198 if (r.executeNesting == 0 && r.app != null) {
10199 if (r.app.executingServices.size() == 0) {
10200 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10201 msg.obj = r.app;
10202 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10203 }
10204 r.app.executingServices.add(r);
10205 }
10206 r.executeNesting++;
10207 r.executingStart = now;
10208 }
10209
10210 private final void sendServiceArgsLocked(ServiceRecord r,
10211 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010212 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010213 if (N == 0) {
10214 return;
10215 }
10216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010217 int i = 0;
10218 while (i < N) {
10219 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010220 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010221 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010222 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010223 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010224 // If somehow we got a dummy start at the front, then
10225 // just drop it here.
10226 i++;
10227 continue;
10228 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010229 bumpServiceExecutingLocked(r);
10230 if (!oomAdjusted) {
10231 oomAdjusted = true;
10232 updateOomAdjLocked(r.app);
10233 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010234 int flags = 0;
10235 if (si.deliveryCount > 0) {
10236 flags |= Service.START_FLAG_RETRY;
10237 }
10238 if (si.doneExecutingCount > 0) {
10239 flags |= Service.START_FLAG_REDELIVERY;
10240 }
10241 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10242 si.deliveredTime = SystemClock.uptimeMillis();
10243 r.deliveredStarts.add(si);
10244 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010245 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010246 } catch (RemoteException e) {
10247 // Remote process gone... we'll let the normal cleanup take
10248 // care of this.
10249 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010250 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010251 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010252 break;
10253 }
10254 }
10255 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010256 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010257 } else {
10258 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010259 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010260 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010261 }
10262 }
10263 }
10264
10265 private final boolean requestServiceBindingLocked(ServiceRecord r,
10266 IntentBindRecord i, boolean rebind) {
10267 if (r.app == null || r.app.thread == null) {
10268 // If service is not currently running, can't yet bind.
10269 return false;
10270 }
10271 if ((!i.requested || rebind) && i.apps.size() > 0) {
10272 try {
10273 bumpServiceExecutingLocked(r);
10274 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10275 + ": shouldUnbind=" + i.hasBound);
10276 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10277 if (!rebind) {
10278 i.requested = true;
10279 }
10280 i.hasBound = true;
10281 i.doRebind = false;
10282 } catch (RemoteException e) {
10283 return false;
10284 }
10285 }
10286 return true;
10287 }
10288
10289 private final void requestServiceBindingsLocked(ServiceRecord r) {
10290 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10291 while (bindings.hasNext()) {
10292 IntentBindRecord i = bindings.next();
10293 if (!requestServiceBindingLocked(r, i, false)) {
10294 break;
10295 }
10296 }
10297 }
10298
10299 private final void realStartServiceLocked(ServiceRecord r,
10300 ProcessRecord app) throws RemoteException {
10301 if (app.thread == null) {
10302 throw new RemoteException();
10303 }
10304
10305 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010306 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010307
10308 app.services.add(r);
10309 bumpServiceExecutingLocked(r);
10310 updateLRUListLocked(app, true);
10311
10312 boolean created = false;
10313 try {
10314 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10315 + r.name + " " + r.intent);
10316 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
10317 System.identityHashCode(r), r.shortName,
10318 r.intent.getIntent().toString(), r.app.pid);
10319 synchronized (r.stats.getBatteryStats()) {
10320 r.stats.startLaunchedLocked();
10321 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010322 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010323 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010324 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010325 created = true;
10326 } finally {
10327 if (!created) {
10328 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010329 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010330 }
10331 }
10332
10333 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010334
10335 // If the service is in the started state, and there are no
10336 // pending arguments, then fake up one so its onStartCommand() will
10337 // be called.
10338 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10339 r.lastStartId++;
10340 if (r.lastStartId < 1) {
10341 r.lastStartId = 1;
10342 }
10343 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10344 }
10345
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010346 sendServiceArgsLocked(r, true);
10347 }
10348
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010349 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10350 boolean allowCancel) {
10351 boolean canceled = false;
10352
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010353 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010354 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010355 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010356
10357 // Any delivered but not yet finished starts should be put back
10358 // on the pending list.
10359 final int N = r.deliveredStarts.size();
10360 if (N > 0) {
10361 for (int i=N-1; i>=0; i--) {
10362 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10363 if (si.intent == null) {
10364 // We'll generate this again if needed.
10365 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10366 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10367 r.pendingStarts.add(0, si);
10368 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10369 dur *= 2;
10370 if (minDuration < dur) minDuration = dur;
10371 if (resetTime < dur) resetTime = dur;
10372 } else {
10373 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10374 + r.name);
10375 canceled = true;
10376 }
10377 }
10378 r.deliveredStarts.clear();
10379 }
10380
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010381 r.totalRestartCount++;
10382 if (r.restartDelay == 0) {
10383 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010384 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010385 } else {
10386 // If it has been a "reasonably long time" since the service
10387 // was started, then reset our restart duration back to
10388 // the beginning, so we don't infinitely increase the duration
10389 // on a service that just occasionally gets killed (which is
10390 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010391 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010392 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010393 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010394 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010395 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010396 if (r.restartDelay < minDuration) {
10397 r.restartDelay = minDuration;
10398 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010399 }
10400 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010401
10402 r.nextRestartTime = now + r.restartDelay;
10403
10404 // Make sure that we don't end up restarting a bunch of services
10405 // all at the same time.
10406 boolean repeat;
10407 do {
10408 repeat = false;
10409 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10410 ServiceRecord r2 = mRestartingServices.get(i);
10411 if (r2 != r && r.nextRestartTime
10412 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10413 && r.nextRestartTime
10414 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10415 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10416 r.restartDelay = r.nextRestartTime - now;
10417 repeat = true;
10418 break;
10419 }
10420 }
10421 } while (repeat);
10422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010423 if (!mRestartingServices.contains(r)) {
10424 mRestartingServices.add(r);
10425 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010426
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010427 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010428
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010429 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010430 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010431 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10432 Log.w(TAG, "Scheduling restart of crashed service "
10433 + r.shortName + " in " + r.restartDelay + "ms");
10434 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10435 r.shortName, r.restartDelay);
10436
10437 Message msg = Message.obtain();
10438 msg.what = SERVICE_ERROR_MSG;
10439 msg.obj = r;
10440 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010441
10442 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010443 }
10444
10445 final void performServiceRestartLocked(ServiceRecord r) {
10446 if (!mRestartingServices.contains(r)) {
10447 return;
10448 }
10449 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10450 }
10451
10452 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10453 if (r.restartDelay == 0) {
10454 return false;
10455 }
10456 r.resetRestartCounter();
10457 mRestartingServices.remove(r);
10458 mHandler.removeCallbacks(r.restarter);
10459 return true;
10460 }
10461
10462 private final boolean bringUpServiceLocked(ServiceRecord r,
10463 int intentFlags, boolean whileRestarting) {
10464 //Log.i(TAG, "Bring up service:");
10465 //r.dump(" ");
10466
10467 if (r.app != null) {
10468 sendServiceArgsLocked(r, false);
10469 return true;
10470 }
10471
10472 if (!whileRestarting && r.restartDelay > 0) {
10473 // If waiting for a restart, then do nothing.
10474 return true;
10475 }
10476
10477 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10478 + " " + r.intent);
10479
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010480 // We are now bringing the service up, so no longer in the
10481 // restarting state.
10482 mRestartingServices.remove(r);
10483
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010484 final String appName = r.processName;
10485 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10486 if (app != null && app.thread != null) {
10487 try {
10488 realStartServiceLocked(r, app);
10489 return true;
10490 } catch (RemoteException e) {
10491 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10492 }
10493
10494 // If a dead object exception was thrown -- fall through to
10495 // restart the application.
10496 }
10497
10498 if (!mPendingServices.contains(r)) {
10499 // Not running -- get it started, and enqueue this service record
10500 // to be executed when the app comes up.
10501 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070010502 "service", r.name, false) == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010503 Log.w(TAG, "Unable to launch app "
10504 + r.appInfo.packageName + "/"
10505 + r.appInfo.uid + " for service "
10506 + r.intent.getIntent() + ": process is bad");
10507 bringDownServiceLocked(r, true);
10508 return false;
10509 }
10510 mPendingServices.add(r);
10511 }
10512 return true;
10513 }
10514
10515 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10516 //Log.i(TAG, "Bring down service:");
10517 //r.dump(" ");
10518
10519 // Does it still need to run?
10520 if (!force && r.startRequested) {
10521 return;
10522 }
10523 if (r.connections.size() > 0) {
10524 if (!force) {
10525 // XXX should probably keep a count of the number of auto-create
10526 // connections directly in the service.
10527 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10528 while (it.hasNext()) {
10529 ConnectionRecord cr = it.next();
10530 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10531 return;
10532 }
10533 }
10534 }
10535
10536 // Report to all of the connections that the service is no longer
10537 // available.
10538 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10539 while (it.hasNext()) {
10540 ConnectionRecord c = it.next();
10541 try {
10542 // todo: shouldn't be a synchronous call!
10543 c.conn.connected(r.name, null);
10544 } catch (Exception e) {
10545 Log.w(TAG, "Failure disconnecting service " + r.name +
10546 " to connection " + c.conn.asBinder() +
10547 " (in " + c.binding.client.processName + ")", e);
10548 }
10549 }
10550 }
10551
10552 // Tell the service that it has been unbound.
10553 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10554 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10555 while (it.hasNext()) {
10556 IntentBindRecord ibr = it.next();
10557 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10558 + ": hasBound=" + ibr.hasBound);
10559 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10560 try {
10561 bumpServiceExecutingLocked(r);
10562 updateOomAdjLocked(r.app);
10563 ibr.hasBound = false;
10564 r.app.thread.scheduleUnbindService(r,
10565 ibr.intent.getIntent());
10566 } catch (Exception e) {
10567 Log.w(TAG, "Exception when unbinding service "
10568 + r.shortName, e);
10569 serviceDoneExecutingLocked(r, true);
10570 }
10571 }
10572 }
10573 }
10574
10575 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10576 + " " + r.intent);
10577 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10578 System.identityHashCode(r), r.shortName,
10579 (r.app != null) ? r.app.pid : -1);
10580
10581 mServices.remove(r.name);
10582 mServicesByIntent.remove(r.intent);
10583 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10584 r.totalRestartCount = 0;
10585 unscheduleServiceRestartLocked(r);
10586
10587 // Also make sure it is not on the pending list.
10588 int N = mPendingServices.size();
10589 for (int i=0; i<N; i++) {
10590 if (mPendingServices.get(i) == r) {
10591 mPendingServices.remove(i);
10592 if (DEBUG_SERVICE) Log.v(
10593 TAG, "Removed pending service: " + r.shortName);
10594 i--;
10595 N--;
10596 }
10597 }
10598
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010599 r.cancelNotification();
10600 r.isForeground = false;
10601 r.foregroundId = 0;
10602 r.foregroundNoti = null;
10603
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010604 // Clear start entries.
10605 r.deliveredStarts.clear();
10606 r.pendingStarts.clear();
10607
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010608 if (r.app != null) {
10609 synchronized (r.stats.getBatteryStats()) {
10610 r.stats.stopLaunchedLocked();
10611 }
10612 r.app.services.remove(r);
10613 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010614 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010615 if (DEBUG_SERVICE) Log.v(TAG,
10616 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010617 bumpServiceExecutingLocked(r);
10618 mStoppingServices.add(r);
10619 updateOomAdjLocked(r.app);
10620 r.app.thread.scheduleStopService(r);
10621 } catch (Exception e) {
10622 Log.w(TAG, "Exception when stopping service "
10623 + r.shortName, e);
10624 serviceDoneExecutingLocked(r, true);
10625 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010626 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010627 } else {
10628 if (DEBUG_SERVICE) Log.v(
10629 TAG, "Removed service that has no process: " + r.shortName);
10630 }
10631 } else {
10632 if (DEBUG_SERVICE) Log.v(
10633 TAG, "Removed service that is not running: " + r.shortName);
10634 }
10635 }
10636
10637 ComponentName startServiceLocked(IApplicationThread caller,
10638 Intent service, String resolvedType,
10639 int callingPid, int callingUid) {
10640 synchronized(this) {
10641 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10642 + " type=" + resolvedType + " args=" + service.getExtras());
10643
10644 if (caller != null) {
10645 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10646 if (callerApp == null) {
10647 throw new SecurityException(
10648 "Unable to find app for caller " + caller
10649 + " (pid=" + Binder.getCallingPid()
10650 + ") when starting service " + service);
10651 }
10652 }
10653
10654 ServiceLookupResult res =
10655 retrieveServiceLocked(service, resolvedType,
10656 callingPid, callingUid);
10657 if (res == null) {
10658 return null;
10659 }
10660 if (res.record == null) {
10661 return new ComponentName("!", res.permission != null
10662 ? res.permission : "private to package");
10663 }
10664 ServiceRecord r = res.record;
10665 if (unscheduleServiceRestartLocked(r)) {
10666 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10667 + r.shortName);
10668 }
10669 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010670 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010671 r.lastStartId++;
10672 if (r.lastStartId < 1) {
10673 r.lastStartId = 1;
10674 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010675 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010676 r.lastActivity = SystemClock.uptimeMillis();
10677 synchronized (r.stats.getBatteryStats()) {
10678 r.stats.startRunningLocked();
10679 }
10680 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10681 return new ComponentName("!", "Service process is bad");
10682 }
10683 return r.name;
10684 }
10685 }
10686
10687 public ComponentName startService(IApplicationThread caller, Intent service,
10688 String resolvedType) {
10689 // Refuse possible leaked file descriptors
10690 if (service != null && service.hasFileDescriptors() == true) {
10691 throw new IllegalArgumentException("File descriptors passed in Intent");
10692 }
10693
10694 synchronized(this) {
10695 final int callingPid = Binder.getCallingPid();
10696 final int callingUid = Binder.getCallingUid();
10697 final long origId = Binder.clearCallingIdentity();
10698 ComponentName res = startServiceLocked(caller, service,
10699 resolvedType, callingPid, callingUid);
10700 Binder.restoreCallingIdentity(origId);
10701 return res;
10702 }
10703 }
10704
10705 ComponentName startServiceInPackage(int uid,
10706 Intent service, String resolvedType) {
10707 synchronized(this) {
10708 final long origId = Binder.clearCallingIdentity();
10709 ComponentName res = startServiceLocked(null, service,
10710 resolvedType, -1, uid);
10711 Binder.restoreCallingIdentity(origId);
10712 return res;
10713 }
10714 }
10715
10716 public int stopService(IApplicationThread caller, Intent service,
10717 String resolvedType) {
10718 // Refuse possible leaked file descriptors
10719 if (service != null && service.hasFileDescriptors() == true) {
10720 throw new IllegalArgumentException("File descriptors passed in Intent");
10721 }
10722
10723 synchronized(this) {
10724 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10725 + " type=" + resolvedType);
10726
10727 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10728 if (caller != null && callerApp == null) {
10729 throw new SecurityException(
10730 "Unable to find app for caller " + caller
10731 + " (pid=" + Binder.getCallingPid()
10732 + ") when stopping service " + service);
10733 }
10734
10735 // If this service is active, make sure it is stopped.
10736 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10737 if (r != null) {
10738 if (r.record != null) {
10739 synchronized (r.record.stats.getBatteryStats()) {
10740 r.record.stats.stopRunningLocked();
10741 }
10742 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010743 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010744 final long origId = Binder.clearCallingIdentity();
10745 bringDownServiceLocked(r.record, false);
10746 Binder.restoreCallingIdentity(origId);
10747 return 1;
10748 }
10749 return -1;
10750 }
10751 }
10752
10753 return 0;
10754 }
10755
10756 public IBinder peekService(Intent service, String resolvedType) {
10757 // Refuse possible leaked file descriptors
10758 if (service != null && service.hasFileDescriptors() == true) {
10759 throw new IllegalArgumentException("File descriptors passed in Intent");
10760 }
10761
10762 IBinder ret = null;
10763
10764 synchronized(this) {
10765 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10766
10767 if (r != null) {
10768 // r.record is null if findServiceLocked() failed the caller permission check
10769 if (r.record == null) {
10770 throw new SecurityException(
10771 "Permission Denial: Accessing service " + r.record.name
10772 + " from pid=" + Binder.getCallingPid()
10773 + ", uid=" + Binder.getCallingUid()
10774 + " requires " + r.permission);
10775 }
10776 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10777 if (ib != null) {
10778 ret = ib.binder;
10779 }
10780 }
10781 }
10782
10783 return ret;
10784 }
10785
10786 public boolean stopServiceToken(ComponentName className, IBinder token,
10787 int startId) {
10788 synchronized(this) {
10789 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10790 + " " + token + " startId=" + startId);
10791 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010792 if (r != null) {
10793 if (startId >= 0) {
10794 // Asked to only stop if done with all work. Note that
10795 // to avoid leaks, we will take this as dropping all
10796 // start items up to and including this one.
10797 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10798 if (si != null) {
10799 while (r.deliveredStarts.size() > 0) {
10800 if (r.deliveredStarts.remove(0) == si) {
10801 break;
10802 }
10803 }
10804 }
10805
10806 if (r.lastStartId != startId) {
10807 return false;
10808 }
10809
10810 if (r.deliveredStarts.size() > 0) {
10811 Log.w(TAG, "stopServiceToken startId " + startId
10812 + " is last, but have " + r.deliveredStarts.size()
10813 + " remaining args");
10814 }
10815 }
10816
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010817 synchronized (r.stats.getBatteryStats()) {
10818 r.stats.stopRunningLocked();
10819 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010820 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010821 }
10822 final long origId = Binder.clearCallingIdentity();
10823 bringDownServiceLocked(r, false);
10824 Binder.restoreCallingIdentity(origId);
10825 return true;
10826 }
10827 }
10828 return false;
10829 }
10830
10831 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010832 int id, Notification notification, boolean removeNotification) {
10833 final long origId = Binder.clearCallingIdentity();
10834 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010835 synchronized(this) {
10836 ServiceRecord r = findServiceLocked(className, token);
10837 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010838 if (id != 0) {
10839 if (notification == null) {
10840 throw new IllegalArgumentException("null notification");
10841 }
10842 if (r.foregroundId != id) {
10843 r.cancelNotification();
10844 r.foregroundId = id;
10845 }
10846 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10847 r.foregroundNoti = notification;
10848 r.isForeground = true;
10849 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010850 if (r.app != null) {
10851 updateServiceForegroundLocked(r.app, true);
10852 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010853 } else {
10854 if (r.isForeground) {
10855 r.isForeground = false;
10856 if (r.app != null) {
10857 updateServiceForegroundLocked(r.app, true);
10858 }
10859 }
10860 if (removeNotification) {
10861 r.cancelNotification();
10862 r.foregroundId = 0;
10863 r.foregroundNoti = null;
10864 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010865 }
10866 }
10867 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010868 } finally {
10869 Binder.restoreCallingIdentity(origId);
10870 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010871 }
10872
10873 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10874 boolean anyForeground = false;
10875 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10876 if (sr.isForeground) {
10877 anyForeground = true;
10878 break;
10879 }
10880 }
10881 if (anyForeground != proc.foregroundServices) {
10882 proc.foregroundServices = anyForeground;
10883 if (oomAdj) {
10884 updateOomAdjLocked();
10885 }
10886 }
10887 }
10888
10889 public int bindService(IApplicationThread caller, IBinder token,
10890 Intent service, String resolvedType,
10891 IServiceConnection connection, int flags) {
10892 // Refuse possible leaked file descriptors
10893 if (service != null && service.hasFileDescriptors() == true) {
10894 throw new IllegalArgumentException("File descriptors passed in Intent");
10895 }
10896
10897 synchronized(this) {
10898 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10899 + " type=" + resolvedType + " conn=" + connection.asBinder()
10900 + " flags=0x" + Integer.toHexString(flags));
10901 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10902 if (callerApp == null) {
10903 throw new SecurityException(
10904 "Unable to find app for caller " + caller
10905 + " (pid=" + Binder.getCallingPid()
10906 + ") when binding service " + service);
10907 }
10908
10909 HistoryRecord activity = null;
10910 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010911 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010912 if (aindex < 0) {
10913 Log.w(TAG, "Binding with unknown activity: " + token);
10914 return 0;
10915 }
10916 activity = (HistoryRecord)mHistory.get(aindex);
10917 }
10918
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010919 int clientLabel = 0;
10920 PendingIntent clientIntent = null;
10921
10922 if (callerApp.info.uid == Process.SYSTEM_UID) {
10923 // Hacky kind of thing -- allow system stuff to tell us
10924 // what they are, so we can report this elsewhere for
10925 // others to know why certain services are running.
10926 try {
10927 clientIntent = (PendingIntent)service.getParcelableExtra(
10928 Intent.EXTRA_CLIENT_INTENT);
10929 } catch (RuntimeException e) {
10930 }
10931 if (clientIntent != null) {
10932 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
10933 if (clientLabel != 0) {
10934 // There are no useful extras in the intent, trash them.
10935 // System code calling with this stuff just needs to know
10936 // this will happen.
10937 service = service.cloneFilter();
10938 }
10939 }
10940 }
10941
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010942 ServiceLookupResult res =
10943 retrieveServiceLocked(service, resolvedType,
10944 Binder.getCallingPid(), Binder.getCallingUid());
10945 if (res == null) {
10946 return 0;
10947 }
10948 if (res.record == null) {
10949 return -1;
10950 }
10951 ServiceRecord s = res.record;
10952
10953 final long origId = Binder.clearCallingIdentity();
10954
10955 if (unscheduleServiceRestartLocked(s)) {
10956 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10957 + s.shortName);
10958 }
10959
10960 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10961 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010962 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010963
10964 IBinder binder = connection.asBinder();
10965 s.connections.put(binder, c);
10966 b.connections.add(c);
10967 if (activity != null) {
10968 if (activity.connections == null) {
10969 activity.connections = new HashSet<ConnectionRecord>();
10970 }
10971 activity.connections.add(c);
10972 }
10973 b.client.connections.add(c);
10974 mServiceConnections.put(binder, c);
10975
10976 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10977 s.lastActivity = SystemClock.uptimeMillis();
10978 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10979 return 0;
10980 }
10981 }
10982
10983 if (s.app != null) {
10984 // This could have made the service more important.
10985 updateOomAdjLocked(s.app);
10986 }
10987
10988 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10989 + ": received=" + b.intent.received
10990 + " apps=" + b.intent.apps.size()
10991 + " doRebind=" + b.intent.doRebind);
10992
10993 if (s.app != null && b.intent.received) {
10994 // Service is already running, so we can immediately
10995 // publish the connection.
10996 try {
10997 c.conn.connected(s.name, b.intent.binder);
10998 } catch (Exception e) {
10999 Log.w(TAG, "Failure sending service " + s.shortName
11000 + " to connection " + c.conn.asBinder()
11001 + " (in " + c.binding.client.processName + ")", e);
11002 }
11003
11004 // If this is the first app connected back to this binding,
11005 // and the service had previously asked to be told when
11006 // rebound, then do so.
11007 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11008 requestServiceBindingLocked(s, b.intent, true);
11009 }
11010 } else if (!b.intent.requested) {
11011 requestServiceBindingLocked(s, b.intent, false);
11012 }
11013
11014 Binder.restoreCallingIdentity(origId);
11015 }
11016
11017 return 1;
11018 }
11019
11020 private void removeConnectionLocked(
11021 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11022 IBinder binder = c.conn.asBinder();
11023 AppBindRecord b = c.binding;
11024 ServiceRecord s = b.service;
11025 s.connections.remove(binder);
11026 b.connections.remove(c);
11027 if (c.activity != null && c.activity != skipAct) {
11028 if (c.activity.connections != null) {
11029 c.activity.connections.remove(c);
11030 }
11031 }
11032 if (b.client != skipApp) {
11033 b.client.connections.remove(c);
11034 }
11035 mServiceConnections.remove(binder);
11036
11037 if (b.connections.size() == 0) {
11038 b.intent.apps.remove(b.client);
11039 }
11040
11041 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11042 + ": shouldUnbind=" + b.intent.hasBound);
11043 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11044 && b.intent.hasBound) {
11045 try {
11046 bumpServiceExecutingLocked(s);
11047 updateOomAdjLocked(s.app);
11048 b.intent.hasBound = false;
11049 // Assume the client doesn't want to know about a rebind;
11050 // we will deal with that later if it asks for one.
11051 b.intent.doRebind = false;
11052 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11053 } catch (Exception e) {
11054 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11055 serviceDoneExecutingLocked(s, true);
11056 }
11057 }
11058
11059 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11060 bringDownServiceLocked(s, false);
11061 }
11062 }
11063
11064 public boolean unbindService(IServiceConnection connection) {
11065 synchronized (this) {
11066 IBinder binder = connection.asBinder();
11067 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11068 ConnectionRecord r = mServiceConnections.get(binder);
11069 if (r == null) {
11070 Log.w(TAG, "Unbind failed: could not find connection for "
11071 + connection.asBinder());
11072 return false;
11073 }
11074
11075 final long origId = Binder.clearCallingIdentity();
11076
11077 removeConnectionLocked(r, null, null);
11078
11079 if (r.binding.service.app != null) {
11080 // This could have made the service less important.
11081 updateOomAdjLocked(r.binding.service.app);
11082 }
11083
11084 Binder.restoreCallingIdentity(origId);
11085 }
11086
11087 return true;
11088 }
11089
11090 public void publishService(IBinder token, Intent intent, IBinder service) {
11091 // Refuse possible leaked file descriptors
11092 if (intent != null && intent.hasFileDescriptors() == true) {
11093 throw new IllegalArgumentException("File descriptors passed in Intent");
11094 }
11095
11096 synchronized(this) {
11097 if (!(token instanceof ServiceRecord)) {
11098 throw new IllegalArgumentException("Invalid service token");
11099 }
11100 ServiceRecord r = (ServiceRecord)token;
11101
11102 final long origId = Binder.clearCallingIdentity();
11103
11104 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11105 + " " + intent + ": " + service);
11106 if (r != null) {
11107 Intent.FilterComparison filter
11108 = new Intent.FilterComparison(intent);
11109 IntentBindRecord b = r.bindings.get(filter);
11110 if (b != null && !b.received) {
11111 b.binder = service;
11112 b.requested = true;
11113 b.received = true;
11114 if (r.connections.size() > 0) {
11115 Iterator<ConnectionRecord> it
11116 = r.connections.values().iterator();
11117 while (it.hasNext()) {
11118 ConnectionRecord c = it.next();
11119 if (!filter.equals(c.binding.intent.intent)) {
11120 if (DEBUG_SERVICE) Log.v(
11121 TAG, "Not publishing to: " + c);
11122 if (DEBUG_SERVICE) Log.v(
11123 TAG, "Bound intent: " + c.binding.intent.intent);
11124 if (DEBUG_SERVICE) Log.v(
11125 TAG, "Published intent: " + intent);
11126 continue;
11127 }
11128 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11129 try {
11130 c.conn.connected(r.name, service);
11131 } catch (Exception e) {
11132 Log.w(TAG, "Failure sending service " + r.name +
11133 " to connection " + c.conn.asBinder() +
11134 " (in " + c.binding.client.processName + ")", e);
11135 }
11136 }
11137 }
11138 }
11139
11140 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11141
11142 Binder.restoreCallingIdentity(origId);
11143 }
11144 }
11145 }
11146
11147 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11148 // Refuse possible leaked file descriptors
11149 if (intent != null && intent.hasFileDescriptors() == true) {
11150 throw new IllegalArgumentException("File descriptors passed in Intent");
11151 }
11152
11153 synchronized(this) {
11154 if (!(token instanceof ServiceRecord)) {
11155 throw new IllegalArgumentException("Invalid service token");
11156 }
11157 ServiceRecord r = (ServiceRecord)token;
11158
11159 final long origId = Binder.clearCallingIdentity();
11160
11161 if (r != null) {
11162 Intent.FilterComparison filter
11163 = new Intent.FilterComparison(intent);
11164 IntentBindRecord b = r.bindings.get(filter);
11165 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11166 + " at " + b + ": apps="
11167 + (b != null ? b.apps.size() : 0));
11168 if (b != null) {
11169 if (b.apps.size() > 0) {
11170 // Applications have already bound since the last
11171 // unbind, so just rebind right here.
11172 requestServiceBindingLocked(r, b, true);
11173 } else {
11174 // Note to tell the service the next time there is
11175 // a new client.
11176 b.doRebind = true;
11177 }
11178 }
11179
11180 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11181
11182 Binder.restoreCallingIdentity(origId);
11183 }
11184 }
11185 }
11186
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011187 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011188 synchronized(this) {
11189 if (!(token instanceof ServiceRecord)) {
11190 throw new IllegalArgumentException("Invalid service token");
11191 }
11192 ServiceRecord r = (ServiceRecord)token;
11193 boolean inStopping = mStoppingServices.contains(token);
11194 if (r != null) {
11195 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11196 + ": nesting=" + r.executeNesting
11197 + ", inStopping=" + inStopping);
11198 if (r != token) {
11199 Log.w(TAG, "Done executing service " + r.name
11200 + " with incorrect token: given " + token
11201 + ", expected " + r);
11202 return;
11203 }
11204
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011205 if (type == 1) {
11206 // This is a call from a service start... take care of
11207 // book-keeping.
11208 r.callStart = true;
11209 switch (res) {
11210 case Service.START_STICKY_COMPATIBILITY:
11211 case Service.START_STICKY: {
11212 // We are done with the associated start arguments.
11213 r.findDeliveredStart(startId, true);
11214 // Don't stop if killed.
11215 r.stopIfKilled = false;
11216 break;
11217 }
11218 case Service.START_NOT_STICKY: {
11219 // We are done with the associated start arguments.
11220 r.findDeliveredStart(startId, true);
11221 if (r.lastStartId == startId) {
11222 // There is no more work, and this service
11223 // doesn't want to hang around if killed.
11224 r.stopIfKilled = true;
11225 }
11226 break;
11227 }
11228 case Service.START_REDELIVER_INTENT: {
11229 // We'll keep this item until they explicitly
11230 // call stop for it, but keep track of the fact
11231 // that it was delivered.
11232 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11233 if (si != null) {
11234 si.deliveryCount = 0;
11235 si.doneExecutingCount++;
11236 // Don't stop if killed.
11237 r.stopIfKilled = true;
11238 }
11239 break;
11240 }
11241 default:
11242 throw new IllegalArgumentException(
11243 "Unknown service start result: " + res);
11244 }
11245 if (res == Service.START_STICKY_COMPATIBILITY) {
11246 r.callStart = false;
11247 }
11248 }
11249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011250 final long origId = Binder.clearCallingIdentity();
11251 serviceDoneExecutingLocked(r, inStopping);
11252 Binder.restoreCallingIdentity(origId);
11253 } else {
11254 Log.w(TAG, "Done executing unknown service " + r.name
11255 + " with token " + token);
11256 }
11257 }
11258 }
11259
11260 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11261 r.executeNesting--;
11262 if (r.executeNesting <= 0 && r.app != null) {
11263 r.app.executingServices.remove(r);
11264 if (r.app.executingServices.size() == 0) {
11265 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11266 }
11267 if (inStopping) {
11268 mStoppingServices.remove(r);
11269 }
11270 updateOomAdjLocked(r.app);
11271 }
11272 }
11273
11274 void serviceTimeout(ProcessRecord proc) {
11275 synchronized(this) {
11276 if (proc.executingServices.size() == 0 || proc.thread == null) {
11277 return;
11278 }
11279 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11280 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11281 ServiceRecord timeout = null;
11282 long nextTime = 0;
11283 while (it.hasNext()) {
11284 ServiceRecord sr = it.next();
11285 if (sr.executingStart < maxTime) {
11286 timeout = sr;
11287 break;
11288 }
11289 if (sr.executingStart > nextTime) {
11290 nextTime = sr.executingStart;
11291 }
11292 }
11293 if (timeout != null && mLRUProcesses.contains(proc)) {
11294 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011295 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011296 + timeout.name);
11297 } else {
11298 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11299 msg.obj = proc;
11300 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11301 }
11302 }
11303 }
11304
11305 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011306 // BACKUP AND RESTORE
11307 // =========================================================
11308
11309 // Cause the target app to be launched if necessary and its backup agent
11310 // instantiated. The backup agent will invoke backupAgentCreated() on the
11311 // activity manager to announce its creation.
11312 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11313 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11314 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11315
11316 synchronized(this) {
11317 // !!! TODO: currently no check here that we're already bound
11318 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11319 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11320 synchronized (stats) {
11321 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11322 }
11323
11324 BackupRecord r = new BackupRecord(ss, app, backupMode);
11325 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11326 // startProcessLocked() returns existing proc's record if it's already running
11327 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011328 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011329 if (proc == null) {
11330 Log.e(TAG, "Unable to start backup agent process " + r);
11331 return false;
11332 }
11333
11334 r.app = proc;
11335 mBackupTarget = r;
11336 mBackupAppName = app.packageName;
11337
Christopher Tate6fa95972009-06-05 18:43:55 -070011338 // Try not to kill the process during backup
11339 updateOomAdjLocked(proc);
11340
Christopher Tate181fafa2009-05-14 11:12:14 -070011341 // If the process is already attached, schedule the creation of the backup agent now.
11342 // If it is not yet live, this will be done when it attaches to the framework.
11343 if (proc.thread != null) {
11344 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11345 try {
11346 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11347 } catch (RemoteException e) {
11348 // !!! TODO: notify the backup manager that we crashed, or rely on
11349 // death notices, or...?
11350 }
11351 } else {
11352 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11353 }
11354 // Invariants: at this point, the target app process exists and the application
11355 // is either already running or in the process of coming up. mBackupTarget and
11356 // mBackupAppName describe the app, so that when it binds back to the AM we
11357 // know that it's scheduled for a backup-agent operation.
11358 }
11359
11360 return true;
11361 }
11362
11363 // A backup agent has just come up
11364 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11365 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11366 + " = " + agent);
11367
11368 synchronized(this) {
11369 if (!agentPackageName.equals(mBackupAppName)) {
11370 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11371 return;
11372 }
11373
Christopher Tate043dadc2009-06-02 16:11:00 -070011374 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011375 try {
11376 IBackupManager bm = IBackupManager.Stub.asInterface(
11377 ServiceManager.getService(Context.BACKUP_SERVICE));
11378 bm.agentConnected(agentPackageName, agent);
11379 } catch (RemoteException e) {
11380 // can't happen; the backup manager service is local
11381 } catch (Exception e) {
11382 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11383 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011384 } finally {
11385 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011386 }
11387 }
11388 }
11389
11390 // done with this agent
11391 public void unbindBackupAgent(ApplicationInfo appInfo) {
11392 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011393 if (appInfo == null) {
11394 Log.w(TAG, "unbind backup agent for null app");
11395 return;
11396 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011397
11398 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011399 if (mBackupAppName == null) {
11400 Log.w(TAG, "Unbinding backup agent with no active backup");
11401 return;
11402 }
11403
Christopher Tate181fafa2009-05-14 11:12:14 -070011404 if (!mBackupAppName.equals(appInfo.packageName)) {
11405 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11406 return;
11407 }
11408
Christopher Tate6fa95972009-06-05 18:43:55 -070011409 ProcessRecord proc = mBackupTarget.app;
11410 mBackupTarget = null;
11411 mBackupAppName = null;
11412
11413 // Not backing this app up any more; reset its OOM adjustment
11414 updateOomAdjLocked(proc);
11415
Christopher Tatec7b31e32009-06-10 15:49:30 -070011416 // If the app crashed during backup, 'thread' will be null here
11417 if (proc.thread != null) {
11418 try {
11419 proc.thread.scheduleDestroyBackupAgent(appInfo);
11420 } catch (Exception e) {
11421 Log.e(TAG, "Exception when unbinding backup agent:");
11422 e.printStackTrace();
11423 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011424 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011425 }
11426 }
11427 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011428 // BROADCASTS
11429 // =========================================================
11430
11431 private final List getStickies(String action, IntentFilter filter,
11432 List cur) {
11433 final ContentResolver resolver = mContext.getContentResolver();
11434 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11435 if (list == null) {
11436 return cur;
11437 }
11438 int N = list.size();
11439 for (int i=0; i<N; i++) {
11440 Intent intent = list.get(i);
11441 if (filter.match(resolver, intent, true, TAG) >= 0) {
11442 if (cur == null) {
11443 cur = new ArrayList<Intent>();
11444 }
11445 cur.add(intent);
11446 }
11447 }
11448 return cur;
11449 }
11450
11451 private final void scheduleBroadcastsLocked() {
11452 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11453 + mBroadcastsScheduled);
11454
11455 if (mBroadcastsScheduled) {
11456 return;
11457 }
11458 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11459 mBroadcastsScheduled = true;
11460 }
11461
11462 public Intent registerReceiver(IApplicationThread caller,
11463 IIntentReceiver receiver, IntentFilter filter, String permission) {
11464 synchronized(this) {
11465 ProcessRecord callerApp = null;
11466 if (caller != null) {
11467 callerApp = getRecordForAppLocked(caller);
11468 if (callerApp == null) {
11469 throw new SecurityException(
11470 "Unable to find app for caller " + caller
11471 + " (pid=" + Binder.getCallingPid()
11472 + ") when registering receiver " + receiver);
11473 }
11474 }
11475
11476 List allSticky = null;
11477
11478 // Look for any matching sticky broadcasts...
11479 Iterator actions = filter.actionsIterator();
11480 if (actions != null) {
11481 while (actions.hasNext()) {
11482 String action = (String)actions.next();
11483 allSticky = getStickies(action, filter, allSticky);
11484 }
11485 } else {
11486 allSticky = getStickies(null, filter, allSticky);
11487 }
11488
11489 // The first sticky in the list is returned directly back to
11490 // the client.
11491 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11492
11493 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11494 + ": " + sticky);
11495
11496 if (receiver == null) {
11497 return sticky;
11498 }
11499
11500 ReceiverList rl
11501 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11502 if (rl == null) {
11503 rl = new ReceiverList(this, callerApp,
11504 Binder.getCallingPid(),
11505 Binder.getCallingUid(), receiver);
11506 if (rl.app != null) {
11507 rl.app.receivers.add(rl);
11508 } else {
11509 try {
11510 receiver.asBinder().linkToDeath(rl, 0);
11511 } catch (RemoteException e) {
11512 return sticky;
11513 }
11514 rl.linkedToDeath = true;
11515 }
11516 mRegisteredReceivers.put(receiver.asBinder(), rl);
11517 }
11518 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11519 rl.add(bf);
11520 if (!bf.debugCheck()) {
11521 Log.w(TAG, "==> For Dynamic broadast");
11522 }
11523 mReceiverResolver.addFilter(bf);
11524
11525 // Enqueue broadcasts for all existing stickies that match
11526 // this filter.
11527 if (allSticky != null) {
11528 ArrayList receivers = new ArrayList();
11529 receivers.add(bf);
11530
11531 int N = allSticky.size();
11532 for (int i=0; i<N; i++) {
11533 Intent intent = (Intent)allSticky.get(i);
11534 BroadcastRecord r = new BroadcastRecord(intent, null,
11535 null, -1, -1, null, receivers, null, 0, null, null,
11536 false);
11537 if (mParallelBroadcasts.size() == 0) {
11538 scheduleBroadcastsLocked();
11539 }
11540 mParallelBroadcasts.add(r);
11541 }
11542 }
11543
11544 return sticky;
11545 }
11546 }
11547
11548 public void unregisterReceiver(IIntentReceiver receiver) {
11549 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11550
11551 boolean doNext = false;
11552
11553 synchronized(this) {
11554 ReceiverList rl
11555 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11556 if (rl != null) {
11557 if (rl.curBroadcast != null) {
11558 BroadcastRecord r = rl.curBroadcast;
11559 doNext = finishReceiverLocked(
11560 receiver.asBinder(), r.resultCode, r.resultData,
11561 r.resultExtras, r.resultAbort, true);
11562 }
11563
11564 if (rl.app != null) {
11565 rl.app.receivers.remove(rl);
11566 }
11567 removeReceiverLocked(rl);
11568 if (rl.linkedToDeath) {
11569 rl.linkedToDeath = false;
11570 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11571 }
11572 }
11573 }
11574
11575 if (!doNext) {
11576 return;
11577 }
11578
11579 final long origId = Binder.clearCallingIdentity();
11580 processNextBroadcast(false);
11581 trimApplications();
11582 Binder.restoreCallingIdentity(origId);
11583 }
11584
11585 void removeReceiverLocked(ReceiverList rl) {
11586 mRegisteredReceivers.remove(rl.receiver.asBinder());
11587 int N = rl.size();
11588 for (int i=0; i<N; i++) {
11589 mReceiverResolver.removeFilter(rl.get(i));
11590 }
11591 }
11592
11593 private final int broadcastIntentLocked(ProcessRecord callerApp,
11594 String callerPackage, Intent intent, String resolvedType,
11595 IIntentReceiver resultTo, int resultCode, String resultData,
11596 Bundle map, String requiredPermission,
11597 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11598 intent = new Intent(intent);
11599
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011600 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011601 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11602 + " ordered=" + ordered);
11603 if ((resultTo != null) && !ordered) {
11604 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11605 }
11606
11607 // Handle special intents: if this broadcast is from the package
11608 // manager about a package being removed, we need to remove all of
11609 // its activities from the history stack.
11610 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11611 intent.getAction());
11612 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11613 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11614 || uidRemoved) {
11615 if (checkComponentPermission(
11616 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11617 callingPid, callingUid, -1)
11618 == PackageManager.PERMISSION_GRANTED) {
11619 if (uidRemoved) {
11620 final Bundle intentExtras = intent.getExtras();
11621 final int uid = intentExtras != null
11622 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11623 if (uid >= 0) {
11624 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11625 synchronized (bs) {
11626 bs.removeUidStatsLocked(uid);
11627 }
11628 }
11629 } else {
11630 Uri data = intent.getData();
11631 String ssp;
11632 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11633 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11634 uninstallPackageLocked(ssp,
11635 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011636 AttributeCache ac = AttributeCache.instance();
11637 if (ac != null) {
11638 ac.removePackage(ssp);
11639 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011640 }
11641 }
11642 }
11643 } else {
11644 String msg = "Permission Denial: " + intent.getAction()
11645 + " broadcast from " + callerPackage + " (pid=" + callingPid
11646 + ", uid=" + callingUid + ")"
11647 + " requires "
11648 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11649 Log.w(TAG, msg);
11650 throw new SecurityException(msg);
11651 }
11652 }
11653
11654 /*
11655 * If this is the time zone changed action, queue up a message that will reset the timezone
11656 * of all currently running processes. This message will get queued up before the broadcast
11657 * happens.
11658 */
11659 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11660 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11661 }
11662
Dianne Hackborn854060af2009-07-09 18:14:31 -070011663 /*
11664 * Prevent non-system code (defined here to be non-persistent
11665 * processes) from sending protected broadcasts.
11666 */
11667 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11668 || callingUid == Process.SHELL_UID || callingUid == 0) {
11669 // Always okay.
11670 } else if (callerApp == null || !callerApp.persistent) {
11671 try {
11672 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11673 intent.getAction())) {
11674 String msg = "Permission Denial: not allowed to send broadcast "
11675 + intent.getAction() + " from pid="
11676 + callingPid + ", uid=" + callingUid;
11677 Log.w(TAG, msg);
11678 throw new SecurityException(msg);
11679 }
11680 } catch (RemoteException e) {
11681 Log.w(TAG, "Remote exception", e);
11682 return BROADCAST_SUCCESS;
11683 }
11684 }
11685
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011686 // Add to the sticky list if requested.
11687 if (sticky) {
11688 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11689 callingPid, callingUid)
11690 != PackageManager.PERMISSION_GRANTED) {
11691 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11692 + callingPid + ", uid=" + callingUid
11693 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11694 Log.w(TAG, msg);
11695 throw new SecurityException(msg);
11696 }
11697 if (requiredPermission != null) {
11698 Log.w(TAG, "Can't broadcast sticky intent " + intent
11699 + " and enforce permission " + requiredPermission);
11700 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11701 }
11702 if (intent.getComponent() != null) {
11703 throw new SecurityException(
11704 "Sticky broadcasts can't target a specific component");
11705 }
11706 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11707 if (list == null) {
11708 list = new ArrayList<Intent>();
11709 mStickyBroadcasts.put(intent.getAction(), list);
11710 }
11711 int N = list.size();
11712 int i;
11713 for (i=0; i<N; i++) {
11714 if (intent.filterEquals(list.get(i))) {
11715 // This sticky already exists, replace it.
11716 list.set(i, new Intent(intent));
11717 break;
11718 }
11719 }
11720 if (i >= N) {
11721 list.add(new Intent(intent));
11722 }
11723 }
11724
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011725 // Figure out who all will receive this broadcast.
11726 List receivers = null;
11727 List<BroadcastFilter> registeredReceivers = null;
11728 try {
11729 if (intent.getComponent() != null) {
11730 // Broadcast is going to one specific receiver class...
11731 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011732 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011733 if (ai != null) {
11734 receivers = new ArrayList();
11735 ResolveInfo ri = new ResolveInfo();
11736 ri.activityInfo = ai;
11737 receivers.add(ri);
11738 }
11739 } else {
11740 // Need to resolve the intent to interested receivers...
11741 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11742 == 0) {
11743 receivers =
11744 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011745 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011746 }
Mihai Preda074edef2009-05-18 17:13:31 +020011747 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011748 }
11749 } catch (RemoteException ex) {
11750 // pm is in same process, this will never happen.
11751 }
11752
11753 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11754 if (!ordered && NR > 0) {
11755 // If we are not serializing this broadcast, then send the
11756 // registered receivers separately so they don't wait for the
11757 // components to be launched.
11758 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11759 callerPackage, callingPid, callingUid, requiredPermission,
11760 registeredReceivers, resultTo, resultCode, resultData, map,
11761 ordered);
11762 if (DEBUG_BROADCAST) Log.v(
11763 TAG, "Enqueueing parallel broadcast " + r
11764 + ": prev had " + mParallelBroadcasts.size());
11765 mParallelBroadcasts.add(r);
11766 scheduleBroadcastsLocked();
11767 registeredReceivers = null;
11768 NR = 0;
11769 }
11770
11771 // Merge into one list.
11772 int ir = 0;
11773 if (receivers != null) {
11774 // A special case for PACKAGE_ADDED: do not allow the package
11775 // being added to see this broadcast. This prevents them from
11776 // using this as a back door to get run as soon as they are
11777 // installed. Maybe in the future we want to have a special install
11778 // broadcast or such for apps, but we'd like to deliberately make
11779 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011780 boolean skip = false;
11781 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011782 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011783 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11784 skip = true;
11785 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11786 skip = true;
11787 }
11788 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011789 ? intent.getData().getSchemeSpecificPart()
11790 : null;
11791 if (skipPackage != null && receivers != null) {
11792 int NT = receivers.size();
11793 for (int it=0; it<NT; it++) {
11794 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11795 if (curt.activityInfo.packageName.equals(skipPackage)) {
11796 receivers.remove(it);
11797 it--;
11798 NT--;
11799 }
11800 }
11801 }
11802
11803 int NT = receivers != null ? receivers.size() : 0;
11804 int it = 0;
11805 ResolveInfo curt = null;
11806 BroadcastFilter curr = null;
11807 while (it < NT && ir < NR) {
11808 if (curt == null) {
11809 curt = (ResolveInfo)receivers.get(it);
11810 }
11811 if (curr == null) {
11812 curr = registeredReceivers.get(ir);
11813 }
11814 if (curr.getPriority() >= curt.priority) {
11815 // Insert this broadcast record into the final list.
11816 receivers.add(it, curr);
11817 ir++;
11818 curr = null;
11819 it++;
11820 NT++;
11821 } else {
11822 // Skip to the next ResolveInfo in the final list.
11823 it++;
11824 curt = null;
11825 }
11826 }
11827 }
11828 while (ir < NR) {
11829 if (receivers == null) {
11830 receivers = new ArrayList();
11831 }
11832 receivers.add(registeredReceivers.get(ir));
11833 ir++;
11834 }
11835
11836 if ((receivers != null && receivers.size() > 0)
11837 || resultTo != null) {
11838 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11839 callerPackage, callingPid, callingUid, requiredPermission,
11840 receivers, resultTo, resultCode, resultData, map, ordered);
11841 if (DEBUG_BROADCAST) Log.v(
11842 TAG, "Enqueueing ordered broadcast " + r
11843 + ": prev had " + mOrderedBroadcasts.size());
11844 if (DEBUG_BROADCAST) {
11845 int seq = r.intent.getIntExtra("seq", -1);
11846 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11847 }
11848 mOrderedBroadcasts.add(r);
11849 scheduleBroadcastsLocked();
11850 }
11851
11852 return BROADCAST_SUCCESS;
11853 }
11854
11855 public final int broadcastIntent(IApplicationThread caller,
11856 Intent intent, String resolvedType, IIntentReceiver resultTo,
11857 int resultCode, String resultData, Bundle map,
11858 String requiredPermission, boolean serialized, boolean sticky) {
11859 // Refuse possible leaked file descriptors
11860 if (intent != null && intent.hasFileDescriptors() == true) {
11861 throw new IllegalArgumentException("File descriptors passed in Intent");
11862 }
11863
11864 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011865 int flags = intent.getFlags();
11866
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011867 if (!mSystemReady) {
11868 // if the caller really truly claims to know what they're doing, go
11869 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011870 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11871 intent = new Intent(intent);
11872 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11873 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11874 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11875 + " before boot completion");
11876 throw new IllegalStateException("Cannot broadcast before boot completed");
11877 }
11878 }
11879
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011880 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
11881 throw new IllegalArgumentException(
11882 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
11883 }
11884
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011885 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11886 final int callingPid = Binder.getCallingPid();
11887 final int callingUid = Binder.getCallingUid();
11888 final long origId = Binder.clearCallingIdentity();
11889 int res = broadcastIntentLocked(callerApp,
11890 callerApp != null ? callerApp.info.packageName : null,
11891 intent, resolvedType, resultTo,
11892 resultCode, resultData, map, requiredPermission, serialized,
11893 sticky, callingPid, callingUid);
11894 Binder.restoreCallingIdentity(origId);
11895 return res;
11896 }
11897 }
11898
11899 int broadcastIntentInPackage(String packageName, int uid,
11900 Intent intent, String resolvedType, IIntentReceiver resultTo,
11901 int resultCode, String resultData, Bundle map,
11902 String requiredPermission, boolean serialized, boolean sticky) {
11903 synchronized(this) {
11904 final long origId = Binder.clearCallingIdentity();
11905 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11906 resultTo, resultCode, resultData, map, requiredPermission,
11907 serialized, sticky, -1, uid);
11908 Binder.restoreCallingIdentity(origId);
11909 return res;
11910 }
11911 }
11912
11913 public final void unbroadcastIntent(IApplicationThread caller,
11914 Intent intent) {
11915 // Refuse possible leaked file descriptors
11916 if (intent != null && intent.hasFileDescriptors() == true) {
11917 throw new IllegalArgumentException("File descriptors passed in Intent");
11918 }
11919
11920 synchronized(this) {
11921 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11922 != PackageManager.PERMISSION_GRANTED) {
11923 String msg = "Permission Denial: unbroadcastIntent() from pid="
11924 + Binder.getCallingPid()
11925 + ", uid=" + Binder.getCallingUid()
11926 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11927 Log.w(TAG, msg);
11928 throw new SecurityException(msg);
11929 }
11930 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11931 if (list != null) {
11932 int N = list.size();
11933 int i;
11934 for (i=0; i<N; i++) {
11935 if (intent.filterEquals(list.get(i))) {
11936 list.remove(i);
11937 break;
11938 }
11939 }
11940 }
11941 }
11942 }
11943
11944 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11945 String resultData, Bundle resultExtras, boolean resultAbort,
11946 boolean explicit) {
11947 if (mOrderedBroadcasts.size() == 0) {
11948 if (explicit) {
11949 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11950 }
11951 return false;
11952 }
11953 BroadcastRecord r = mOrderedBroadcasts.get(0);
11954 if (r.receiver == null) {
11955 if (explicit) {
11956 Log.w(TAG, "finishReceiver called but none active");
11957 }
11958 return false;
11959 }
11960 if (r.receiver != receiver) {
11961 Log.w(TAG, "finishReceiver called but active receiver is different");
11962 return false;
11963 }
11964 int state = r.state;
11965 r.state = r.IDLE;
11966 if (state == r.IDLE) {
11967 if (explicit) {
11968 Log.w(TAG, "finishReceiver called but state is IDLE");
11969 }
11970 }
11971 r.receiver = null;
11972 r.intent.setComponent(null);
11973 if (r.curApp != null) {
11974 r.curApp.curReceiver = null;
11975 }
11976 if (r.curFilter != null) {
11977 r.curFilter.receiverList.curBroadcast = null;
11978 }
11979 r.curFilter = null;
11980 r.curApp = null;
11981 r.curComponent = null;
11982 r.curReceiver = null;
11983 mPendingBroadcast = null;
11984
11985 r.resultCode = resultCode;
11986 r.resultData = resultData;
11987 r.resultExtras = resultExtras;
11988 r.resultAbort = resultAbort;
11989
11990 // We will process the next receiver right now if this is finishing
11991 // an app receiver (which is always asynchronous) or after we have
11992 // come back from calling a receiver.
11993 return state == BroadcastRecord.APP_RECEIVE
11994 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11995 }
11996
11997 public void finishReceiver(IBinder who, int resultCode, String resultData,
11998 Bundle resultExtras, boolean resultAbort) {
11999 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12000
12001 // Refuse possible leaked file descriptors
12002 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12003 throw new IllegalArgumentException("File descriptors passed in Bundle");
12004 }
12005
12006 boolean doNext;
12007
12008 final long origId = Binder.clearCallingIdentity();
12009
12010 synchronized(this) {
12011 doNext = finishReceiverLocked(
12012 who, resultCode, resultData, resultExtras, resultAbort, true);
12013 }
12014
12015 if (doNext) {
12016 processNextBroadcast(false);
12017 }
12018 trimApplications();
12019
12020 Binder.restoreCallingIdentity(origId);
12021 }
12022
12023 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12024 if (r.nextReceiver > 0) {
12025 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12026 if (curReceiver instanceof BroadcastFilter) {
12027 BroadcastFilter bf = (BroadcastFilter) curReceiver;
12028 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
12029 System.identityHashCode(r),
12030 r.intent.getAction(),
12031 r.nextReceiver - 1,
12032 System.identityHashCode(bf));
12033 } else {
12034 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12035 System.identityHashCode(r),
12036 r.intent.getAction(),
12037 r.nextReceiver - 1,
12038 ((ResolveInfo)curReceiver).toString());
12039 }
12040 } else {
12041 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12042 + r);
12043 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12044 System.identityHashCode(r),
12045 r.intent.getAction(),
12046 r.nextReceiver,
12047 "NONE");
12048 }
12049 }
12050
12051 private final void broadcastTimeout() {
12052 synchronized (this) {
12053 if (mOrderedBroadcasts.size() == 0) {
12054 return;
12055 }
12056 long now = SystemClock.uptimeMillis();
12057 BroadcastRecord r = mOrderedBroadcasts.get(0);
12058 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
12059 if (DEBUG_BROADCAST) Log.v(TAG,
12060 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
12061 + (r.startTime + BROADCAST_TIMEOUT));
12062 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12063 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12064 return;
12065 }
12066
12067 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
12068 r.startTime = now;
12069 r.anrCount++;
12070
12071 // Current receiver has passed its expiration date.
12072 if (r.nextReceiver <= 0) {
12073 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12074 return;
12075 }
12076
12077 ProcessRecord app = null;
12078
12079 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12080 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12081 logBroadcastReceiverDiscard(r);
12082 if (curReceiver instanceof BroadcastFilter) {
12083 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12084 if (bf.receiverList.pid != 0
12085 && bf.receiverList.pid != MY_PID) {
12086 synchronized (this.mPidsSelfLocked) {
12087 app = this.mPidsSelfLocked.get(
12088 bf.receiverList.pid);
12089 }
12090 }
12091 } else {
12092 app = r.curApp;
12093 }
12094
12095 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070012096 appNotRespondingLocked(app, null, null,
12097 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012098 }
12099
12100 if (mPendingBroadcast == r) {
12101 mPendingBroadcast = null;
12102 }
12103
12104 // Move on to the next receiver.
12105 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12106 r.resultExtras, r.resultAbort, true);
12107 scheduleBroadcastsLocked();
12108 }
12109 }
12110
12111 private final void processCurBroadcastLocked(BroadcastRecord r,
12112 ProcessRecord app) throws RemoteException {
12113 if (app.thread == null) {
12114 throw new RemoteException();
12115 }
12116 r.receiver = app.thread.asBinder();
12117 r.curApp = app;
12118 app.curReceiver = r;
12119 updateLRUListLocked(app, true);
12120
12121 // Tell the application to launch this receiver.
12122 r.intent.setComponent(r.curComponent);
12123
12124 boolean started = false;
12125 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012126 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012127 "Delivering to component " + r.curComponent
12128 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012129 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012130 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12131 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12132 started = true;
12133 } finally {
12134 if (!started) {
12135 r.receiver = null;
12136 r.curApp = null;
12137 app.curReceiver = null;
12138 }
12139 }
12140
12141 }
12142
12143 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
12144 Intent intent, int resultCode, String data,
12145 Bundle extras, boolean ordered) throws RemoteException {
12146 if (app != null && app.thread != null) {
12147 // If we have an app thread, do the call through that so it is
12148 // correctly ordered with other one-way calls.
12149 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
12150 data, extras, ordered);
12151 } else {
12152 receiver.performReceive(intent, resultCode, data, extras, ordered);
12153 }
12154 }
12155
12156 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12157 BroadcastFilter filter, boolean ordered) {
12158 boolean skip = false;
12159 if (filter.requiredPermission != null) {
12160 int perm = checkComponentPermission(filter.requiredPermission,
12161 r.callingPid, r.callingUid, -1);
12162 if (perm != PackageManager.PERMISSION_GRANTED) {
12163 Log.w(TAG, "Permission Denial: broadcasting "
12164 + r.intent.toString()
12165 + " from " + r.callerPackage + " (pid="
12166 + r.callingPid + ", uid=" + r.callingUid + ")"
12167 + " requires " + filter.requiredPermission
12168 + " due to registered receiver " + filter);
12169 skip = true;
12170 }
12171 }
12172 if (r.requiredPermission != null) {
12173 int perm = checkComponentPermission(r.requiredPermission,
12174 filter.receiverList.pid, filter.receiverList.uid, -1);
12175 if (perm != PackageManager.PERMISSION_GRANTED) {
12176 Log.w(TAG, "Permission Denial: receiving "
12177 + r.intent.toString()
12178 + " to " + filter.receiverList.app
12179 + " (pid=" + filter.receiverList.pid
12180 + ", uid=" + filter.receiverList.uid + ")"
12181 + " requires " + r.requiredPermission
12182 + " due to sender " + r.callerPackage
12183 + " (uid " + r.callingUid + ")");
12184 skip = true;
12185 }
12186 }
12187
12188 if (!skip) {
12189 // If this is not being sent as an ordered broadcast, then we
12190 // don't want to touch the fields that keep track of the current
12191 // state of ordered broadcasts.
12192 if (ordered) {
12193 r.receiver = filter.receiverList.receiver.asBinder();
12194 r.curFilter = filter;
12195 filter.receiverList.curBroadcast = r;
12196 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012197 if (filter.receiverList.app != null) {
12198 // Bump hosting application to no longer be in background
12199 // scheduling class. Note that we can't do that if there
12200 // isn't an app... but we can only be in that case for
12201 // things that directly call the IActivityManager API, which
12202 // are already core system stuff so don't matter for this.
12203 r.curApp = filter.receiverList.app;
12204 filter.receiverList.app.curReceiver = r;
12205 updateOomAdjLocked();
12206 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012207 }
12208 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012209 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012210 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012211 Log.i(TAG, "Delivering to " + filter.receiverList.app
12212 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012213 }
12214 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12215 new Intent(r.intent), r.resultCode,
12216 r.resultData, r.resultExtras, r.ordered);
12217 if (ordered) {
12218 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12219 }
12220 } catch (RemoteException e) {
12221 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12222 if (ordered) {
12223 r.receiver = null;
12224 r.curFilter = null;
12225 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012226 if (filter.receiverList.app != null) {
12227 filter.receiverList.app.curReceiver = null;
12228 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012229 }
12230 }
12231 }
12232 }
12233
12234 private final void processNextBroadcast(boolean fromMsg) {
12235 synchronized(this) {
12236 BroadcastRecord r;
12237
12238 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12239 + mParallelBroadcasts.size() + " broadcasts, "
12240 + mOrderedBroadcasts.size() + " serialized broadcasts");
12241
12242 updateCpuStats();
12243
12244 if (fromMsg) {
12245 mBroadcastsScheduled = false;
12246 }
12247
12248 // First, deliver any non-serialized broadcasts right away.
12249 while (mParallelBroadcasts.size() > 0) {
12250 r = mParallelBroadcasts.remove(0);
12251 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012252 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12253 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012254 for (int i=0; i<N; i++) {
12255 Object target = r.receivers.get(i);
12256 if (DEBUG_BROADCAST) Log.v(TAG,
12257 "Delivering non-serialized to registered "
12258 + target + ": " + r);
12259 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12260 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012261 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12262 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012263 }
12264
12265 // Now take care of the next serialized one...
12266
12267 // If we are waiting for a process to come up to handle the next
12268 // broadcast, then do nothing at this point. Just in case, we
12269 // check that the process we're waiting for still exists.
12270 if (mPendingBroadcast != null) {
12271 Log.i(TAG, "processNextBroadcast: waiting for "
12272 + mPendingBroadcast.curApp);
12273
12274 boolean isDead;
12275 synchronized (mPidsSelfLocked) {
12276 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12277 }
12278 if (!isDead) {
12279 // It's still alive, so keep waiting
12280 return;
12281 } else {
12282 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12283 + " died before responding to broadcast");
12284 mPendingBroadcast = null;
12285 }
12286 }
12287
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012288 boolean looped = false;
12289
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012290 do {
12291 if (mOrderedBroadcasts.size() == 0) {
12292 // No more broadcasts pending, so all done!
12293 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012294 if (looped) {
12295 // If we had finished the last ordered broadcast, then
12296 // make sure all processes have correct oom and sched
12297 // adjustments.
12298 updateOomAdjLocked();
12299 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012300 return;
12301 }
12302 r = mOrderedBroadcasts.get(0);
12303 boolean forceReceive = false;
12304
12305 // Ensure that even if something goes awry with the timeout
12306 // detection, we catch "hung" broadcasts here, discard them,
12307 // and continue to make progress.
12308 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12309 long now = SystemClock.uptimeMillis();
12310 if (r.dispatchTime > 0) {
12311 if ((numReceivers > 0) &&
12312 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12313 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12314 + " now=" + now
12315 + " dispatchTime=" + r.dispatchTime
12316 + " startTime=" + r.startTime
12317 + " intent=" + r.intent
12318 + " numReceivers=" + numReceivers
12319 + " nextReceiver=" + r.nextReceiver
12320 + " state=" + r.state);
12321 broadcastTimeout(); // forcibly finish this broadcast
12322 forceReceive = true;
12323 r.state = BroadcastRecord.IDLE;
12324 }
12325 }
12326
12327 if (r.state != BroadcastRecord.IDLE) {
12328 if (DEBUG_BROADCAST) Log.d(TAG,
12329 "processNextBroadcast() called when not idle (state="
12330 + r.state + ")");
12331 return;
12332 }
12333
12334 if (r.receivers == null || r.nextReceiver >= numReceivers
12335 || r.resultAbort || forceReceive) {
12336 // No more receivers for this broadcast! Send the final
12337 // result if requested...
12338 if (r.resultTo != null) {
12339 try {
12340 if (DEBUG_BROADCAST) {
12341 int seq = r.intent.getIntExtra("seq", -1);
12342 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12343 + " seq=" + seq + " app=" + r.callerApp);
12344 }
12345 performReceive(r.callerApp, r.resultTo,
12346 new Intent(r.intent), r.resultCode,
12347 r.resultData, r.resultExtras, false);
12348 } catch (RemoteException e) {
12349 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12350 }
12351 }
12352
12353 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12354 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12355
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012356 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12357 + r);
12358
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012359 // ... and on to the next...
12360 mOrderedBroadcasts.remove(0);
12361 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012362 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012363 continue;
12364 }
12365 } while (r == null);
12366
12367 // Get the next receiver...
12368 int recIdx = r.nextReceiver++;
12369
12370 // Keep track of when this receiver started, and make sure there
12371 // is a timeout message pending to kill it if need be.
12372 r.startTime = SystemClock.uptimeMillis();
12373 if (recIdx == 0) {
12374 r.dispatchTime = r.startTime;
12375
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012376 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12377 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012378 if (DEBUG_BROADCAST) Log.v(TAG,
12379 "Submitting BROADCAST_TIMEOUT_MSG for "
12380 + (r.startTime + BROADCAST_TIMEOUT));
12381 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12382 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12383 }
12384
12385 Object nextReceiver = r.receivers.get(recIdx);
12386 if (nextReceiver instanceof BroadcastFilter) {
12387 // Simple case: this is a registered receiver who gets
12388 // a direct call.
12389 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12390 if (DEBUG_BROADCAST) Log.v(TAG,
12391 "Delivering serialized to registered "
12392 + filter + ": " + r);
12393 deliverToRegisteredReceiver(r, filter, r.ordered);
12394 if (r.receiver == null || !r.ordered) {
12395 // The receiver has already finished, so schedule to
12396 // process the next one.
12397 r.state = BroadcastRecord.IDLE;
12398 scheduleBroadcastsLocked();
12399 }
12400 return;
12401 }
12402
12403 // Hard case: need to instantiate the receiver, possibly
12404 // starting its application process to host it.
12405
12406 ResolveInfo info =
12407 (ResolveInfo)nextReceiver;
12408
12409 boolean skip = false;
12410 int perm = checkComponentPermission(info.activityInfo.permission,
12411 r.callingPid, r.callingUid,
12412 info.activityInfo.exported
12413 ? -1 : info.activityInfo.applicationInfo.uid);
12414 if (perm != PackageManager.PERMISSION_GRANTED) {
12415 Log.w(TAG, "Permission Denial: broadcasting "
12416 + r.intent.toString()
12417 + " from " + r.callerPackage + " (pid=" + r.callingPid
12418 + ", uid=" + r.callingUid + ")"
12419 + " requires " + info.activityInfo.permission
12420 + " due to receiver " + info.activityInfo.packageName
12421 + "/" + info.activityInfo.name);
12422 skip = true;
12423 }
12424 if (r.callingUid != Process.SYSTEM_UID &&
12425 r.requiredPermission != null) {
12426 try {
12427 perm = ActivityThread.getPackageManager().
12428 checkPermission(r.requiredPermission,
12429 info.activityInfo.applicationInfo.packageName);
12430 } catch (RemoteException e) {
12431 perm = PackageManager.PERMISSION_DENIED;
12432 }
12433 if (perm != PackageManager.PERMISSION_GRANTED) {
12434 Log.w(TAG, "Permission Denial: receiving "
12435 + r.intent + " to "
12436 + info.activityInfo.applicationInfo.packageName
12437 + " requires " + r.requiredPermission
12438 + " due to sender " + r.callerPackage
12439 + " (uid " + r.callingUid + ")");
12440 skip = true;
12441 }
12442 }
12443 if (r.curApp != null && r.curApp.crashing) {
12444 // If the target process is crashing, just skip it.
12445 skip = true;
12446 }
12447
12448 if (skip) {
12449 r.receiver = null;
12450 r.curFilter = null;
12451 r.state = BroadcastRecord.IDLE;
12452 scheduleBroadcastsLocked();
12453 return;
12454 }
12455
12456 r.state = BroadcastRecord.APP_RECEIVE;
12457 String targetProcess = info.activityInfo.processName;
12458 r.curComponent = new ComponentName(
12459 info.activityInfo.applicationInfo.packageName,
12460 info.activityInfo.name);
12461 r.curReceiver = info.activityInfo;
12462
12463 // Is this receiver's application already running?
12464 ProcessRecord app = getProcessRecordLocked(targetProcess,
12465 info.activityInfo.applicationInfo.uid);
12466 if (app != null && app.thread != null) {
12467 try {
12468 processCurBroadcastLocked(r, app);
12469 return;
12470 } catch (RemoteException e) {
12471 Log.w(TAG, "Exception when sending broadcast to "
12472 + r.curComponent, e);
12473 }
12474
12475 // If a dead object exception was thrown -- fall through to
12476 // restart the application.
12477 }
12478
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012479 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012480 if ((r.curApp=startProcessLocked(targetProcess,
12481 info.activityInfo.applicationInfo, true,
12482 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012483 "broadcast", r.curComponent,
12484 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12485 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012486 // Ah, this recipient is unavailable. Finish it if necessary,
12487 // and mark the broadcast record as ready for the next.
12488 Log.w(TAG, "Unable to launch app "
12489 + info.activityInfo.applicationInfo.packageName + "/"
12490 + info.activityInfo.applicationInfo.uid + " for broadcast "
12491 + r.intent + ": process is bad");
12492 logBroadcastReceiverDiscard(r);
12493 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12494 r.resultExtras, r.resultAbort, true);
12495 scheduleBroadcastsLocked();
12496 r.state = BroadcastRecord.IDLE;
12497 return;
12498 }
12499
12500 mPendingBroadcast = r;
12501 }
12502 }
12503
12504 // =========================================================
12505 // INSTRUMENTATION
12506 // =========================================================
12507
12508 public boolean startInstrumentation(ComponentName className,
12509 String profileFile, int flags, Bundle arguments,
12510 IInstrumentationWatcher watcher) {
12511 // Refuse possible leaked file descriptors
12512 if (arguments != null && arguments.hasFileDescriptors()) {
12513 throw new IllegalArgumentException("File descriptors passed in Bundle");
12514 }
12515
12516 synchronized(this) {
12517 InstrumentationInfo ii = null;
12518 ApplicationInfo ai = null;
12519 try {
12520 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012521 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012522 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012523 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012524 } catch (PackageManager.NameNotFoundException e) {
12525 }
12526 if (ii == null) {
12527 reportStartInstrumentationFailure(watcher, className,
12528 "Unable to find instrumentation info for: " + className);
12529 return false;
12530 }
12531 if (ai == null) {
12532 reportStartInstrumentationFailure(watcher, className,
12533 "Unable to find instrumentation target package: " + ii.targetPackage);
12534 return false;
12535 }
12536
12537 int match = mContext.getPackageManager().checkSignatures(
12538 ii.targetPackage, ii.packageName);
12539 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12540 String msg = "Permission Denial: starting instrumentation "
12541 + className + " from pid="
12542 + Binder.getCallingPid()
12543 + ", uid=" + Binder.getCallingPid()
12544 + " not allowed because package " + ii.packageName
12545 + " does not have a signature matching the target "
12546 + ii.targetPackage;
12547 reportStartInstrumentationFailure(watcher, className, msg);
12548 throw new SecurityException(msg);
12549 }
12550
12551 final long origId = Binder.clearCallingIdentity();
12552 uninstallPackageLocked(ii.targetPackage, -1, true);
12553 ProcessRecord app = addAppLocked(ai);
12554 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012555 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012556 app.instrumentationProfileFile = profileFile;
12557 app.instrumentationArguments = arguments;
12558 app.instrumentationWatcher = watcher;
12559 app.instrumentationResultClass = className;
12560 Binder.restoreCallingIdentity(origId);
12561 }
12562
12563 return true;
12564 }
12565
12566 /**
12567 * Report errors that occur while attempting to start Instrumentation. Always writes the
12568 * error to the logs, but if somebody is watching, send the report there too. This enables
12569 * the "am" command to report errors with more information.
12570 *
12571 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12572 * @param cn The component name of the instrumentation.
12573 * @param report The error report.
12574 */
12575 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12576 ComponentName cn, String report) {
12577 Log.w(TAG, report);
12578 try {
12579 if (watcher != null) {
12580 Bundle results = new Bundle();
12581 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12582 results.putString("Error", report);
12583 watcher.instrumentationStatus(cn, -1, results);
12584 }
12585 } catch (RemoteException e) {
12586 Log.w(TAG, e);
12587 }
12588 }
12589
12590 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12591 if (app.instrumentationWatcher != null) {
12592 try {
12593 // NOTE: IInstrumentationWatcher *must* be oneway here
12594 app.instrumentationWatcher.instrumentationFinished(
12595 app.instrumentationClass,
12596 resultCode,
12597 results);
12598 } catch (RemoteException e) {
12599 }
12600 }
12601 app.instrumentationWatcher = null;
12602 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012603 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012604 app.instrumentationProfileFile = null;
12605 app.instrumentationArguments = null;
12606
12607 uninstallPackageLocked(app.processName, -1, false);
12608 }
12609
12610 public void finishInstrumentation(IApplicationThread target,
12611 int resultCode, Bundle results) {
12612 // Refuse possible leaked file descriptors
12613 if (results != null && results.hasFileDescriptors()) {
12614 throw new IllegalArgumentException("File descriptors passed in Intent");
12615 }
12616
12617 synchronized(this) {
12618 ProcessRecord app = getRecordForAppLocked(target);
12619 if (app == null) {
12620 Log.w(TAG, "finishInstrumentation: no app for " + target);
12621 return;
12622 }
12623 final long origId = Binder.clearCallingIdentity();
12624 finishInstrumentationLocked(app, resultCode, results);
12625 Binder.restoreCallingIdentity(origId);
12626 }
12627 }
12628
12629 // =========================================================
12630 // CONFIGURATION
12631 // =========================================================
12632
12633 public ConfigurationInfo getDeviceConfigurationInfo() {
12634 ConfigurationInfo config = new ConfigurationInfo();
12635 synchronized (this) {
12636 config.reqTouchScreen = mConfiguration.touchscreen;
12637 config.reqKeyboardType = mConfiguration.keyboard;
12638 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012639 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12640 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012641 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12642 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012643 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12644 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012645 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12646 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012647 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012648 }
12649 return config;
12650 }
12651
12652 public Configuration getConfiguration() {
12653 Configuration ci;
12654 synchronized(this) {
12655 ci = new Configuration(mConfiguration);
12656 }
12657 return ci;
12658 }
12659
12660 public void updateConfiguration(Configuration values) {
12661 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12662 "updateConfiguration()");
12663
12664 synchronized(this) {
12665 if (values == null && mWindowManager != null) {
12666 // sentinel: fetch the current configuration from the window manager
12667 values = mWindowManager.computeNewConfiguration();
12668 }
12669
12670 final long origId = Binder.clearCallingIdentity();
12671 updateConfigurationLocked(values, null);
12672 Binder.restoreCallingIdentity(origId);
12673 }
12674 }
12675
12676 /**
12677 * Do either or both things: (1) change the current configuration, and (2)
12678 * make sure the given activity is running with the (now) current
12679 * configuration. Returns true if the activity has been left running, or
12680 * false if <var>starting</var> is being destroyed to match the new
12681 * configuration.
12682 */
12683 public boolean updateConfigurationLocked(Configuration values,
12684 HistoryRecord starting) {
12685 int changes = 0;
12686
12687 boolean kept = true;
12688
12689 if (values != null) {
12690 Configuration newConfig = new Configuration(mConfiguration);
12691 changes = newConfig.updateFrom(values);
12692 if (changes != 0) {
12693 if (DEBUG_SWITCH) {
12694 Log.i(TAG, "Updating configuration to: " + values);
12695 }
12696
12697 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12698
12699 if (values.locale != null) {
12700 saveLocaleLocked(values.locale,
12701 !values.locale.equals(mConfiguration.locale),
12702 values.userSetLocale);
12703 }
12704
12705 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012706 Log.i(TAG, "Config changed: " + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012707
12708 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12709 msg.obj = new Configuration(mConfiguration);
12710 mHandler.sendMessage(msg);
12711
12712 final int N = mLRUProcesses.size();
12713 for (int i=0; i<N; i++) {
12714 ProcessRecord app = mLRUProcesses.get(i);
12715 try {
12716 if (app.thread != null) {
12717 app.thread.scheduleConfigurationChanged(mConfiguration);
12718 }
12719 } catch (Exception e) {
12720 }
12721 }
12722 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12723 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12724 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012725
12726 AttributeCache ac = AttributeCache.instance();
12727 if (ac != null) {
12728 ac.updateConfiguration(mConfiguration);
12729 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012730 }
12731 }
12732
12733 if (changes != 0 && starting == null) {
12734 // If the configuration changed, and the caller is not already
12735 // in the process of starting an activity, then find the top
12736 // activity to check if its configuration needs to change.
12737 starting = topRunningActivityLocked(null);
12738 }
12739
12740 if (starting != null) {
12741 kept = ensureActivityConfigurationLocked(starting, changes);
12742 if (kept) {
12743 // If this didn't result in the starting activity being
12744 // destroyed, then we need to make sure at this point that all
12745 // other activities are made visible.
12746 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12747 + ", ensuring others are correct.");
12748 ensureActivitiesVisibleLocked(starting, changes);
12749 }
12750 }
12751
12752 return kept;
12753 }
12754
12755 private final boolean relaunchActivityLocked(HistoryRecord r,
12756 int changes, boolean andResume) {
12757 List<ResultInfo> results = null;
12758 List<Intent> newIntents = null;
12759 if (andResume) {
12760 results = r.results;
12761 newIntents = r.newIntents;
12762 }
12763 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12764 + " with results=" + results + " newIntents=" + newIntents
12765 + " andResume=" + andResume);
12766 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12767 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12768 r.task.taskId, r.shortComponentName);
12769
12770 r.startFreezingScreenLocked(r.app, 0);
12771
12772 try {
12773 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12774 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12775 changes, !andResume);
12776 // Note: don't need to call pauseIfSleepingLocked() here, because
12777 // the caller will only pass in 'andResume' if this activity is
12778 // currently resumed, which implies we aren't sleeping.
12779 } catch (RemoteException e) {
12780 return false;
12781 }
12782
12783 if (andResume) {
12784 r.results = null;
12785 r.newIntents = null;
12786 }
12787
12788 return true;
12789 }
12790
12791 /**
12792 * Make sure the given activity matches the current configuration. Returns
12793 * false if the activity had to be destroyed. Returns true if the
12794 * configuration is the same, or the activity will remain running as-is
12795 * for whatever reason. Ensures the HistoryRecord is updated with the
12796 * correct configuration and all other bookkeeping is handled.
12797 */
12798 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12799 int globalChanges) {
12800 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12801
12802 // Short circuit: if the two configurations are the exact same
12803 // object (the common case), then there is nothing to do.
12804 Configuration newConfig = mConfiguration;
12805 if (r.configuration == newConfig) {
12806 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12807 return true;
12808 }
12809
12810 // We don't worry about activities that are finishing.
12811 if (r.finishing) {
12812 if (DEBUG_SWITCH) Log.i(TAG,
12813 "Configuration doesn't matter in finishing " + r);
12814 r.stopFreezingScreenLocked(false);
12815 return true;
12816 }
12817
12818 // Okay we now are going to make this activity have the new config.
12819 // But then we need to figure out how it needs to deal with that.
12820 Configuration oldConfig = r.configuration;
12821 r.configuration = newConfig;
12822
12823 // If the activity isn't currently running, just leave the new
12824 // configuration and it will pick that up next time it starts.
12825 if (r.app == null || r.app.thread == null) {
12826 if (DEBUG_SWITCH) Log.i(TAG,
12827 "Configuration doesn't matter not running " + r);
12828 r.stopFreezingScreenLocked(false);
12829 return true;
12830 }
12831
12832 // If the activity isn't persistent, there is a chance we will
12833 // need to restart it.
12834 if (!r.persistent) {
12835
12836 // Figure out what has changed between the two configurations.
12837 int changes = oldConfig.diff(newConfig);
12838 if (DEBUG_SWITCH) {
12839 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12840 + Integer.toHexString(changes) + ", handles=0x"
12841 + Integer.toHexString(r.info.configChanges));
12842 }
12843 if ((changes&(~r.info.configChanges)) != 0) {
12844 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12845 r.configChangeFlags |= changes;
12846 r.startFreezingScreenLocked(r.app, globalChanges);
12847 if (r.app == null || r.app.thread == null) {
12848 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12849 destroyActivityLocked(r, true);
12850 } else if (r.state == ActivityState.PAUSING) {
12851 // A little annoying: we are waiting for this activity to
12852 // finish pausing. Let's not do anything now, but just
12853 // flag that it needs to be restarted when done pausing.
12854 r.configDestroy = true;
12855 return true;
12856 } else if (r.state == ActivityState.RESUMED) {
12857 // Try to optimize this case: the configuration is changing
12858 // and we need to restart the top, resumed activity.
12859 // Instead of doing the normal handshaking, just say
12860 // "restart!".
12861 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12862 relaunchActivityLocked(r, r.configChangeFlags, true);
12863 r.configChangeFlags = 0;
12864 } else {
12865 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12866 relaunchActivityLocked(r, r.configChangeFlags, false);
12867 r.configChangeFlags = 0;
12868 }
12869
12870 // All done... tell the caller we weren't able to keep this
12871 // activity around.
12872 return false;
12873 }
12874 }
12875
12876 // Default case: the activity can handle this new configuration, so
12877 // hand it over. Note that we don't need to give it the new
12878 // configuration, since we always send configuration changes to all
12879 // process when they happen so it can just use whatever configuration
12880 // it last got.
12881 if (r.app != null && r.app.thread != null) {
12882 try {
12883 r.app.thread.scheduleActivityConfigurationChanged(r);
12884 } catch (RemoteException e) {
12885 // If process died, whatever.
12886 }
12887 }
12888 r.stopFreezingScreenLocked(false);
12889
12890 return true;
12891 }
12892
12893 /**
12894 * Save the locale. You must be inside a synchronized (this) block.
12895 */
12896 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12897 if(isDiff) {
12898 SystemProperties.set("user.language", l.getLanguage());
12899 SystemProperties.set("user.region", l.getCountry());
12900 }
12901
12902 if(isPersist) {
12903 SystemProperties.set("persist.sys.language", l.getLanguage());
12904 SystemProperties.set("persist.sys.country", l.getCountry());
12905 SystemProperties.set("persist.sys.localevar", l.getVariant());
12906 }
12907 }
12908
12909 // =========================================================
12910 // LIFETIME MANAGEMENT
12911 // =========================================================
12912
12913 private final int computeOomAdjLocked(
12914 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12915 if (mAdjSeq == app.adjSeq) {
12916 // This adjustment has already been computed.
12917 return app.curAdj;
12918 }
12919
12920 if (app.thread == null) {
12921 app.adjSeq = mAdjSeq;
12922 return (app.curAdj=EMPTY_APP_ADJ);
12923 }
12924
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012925 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
12926 // The max adjustment doesn't allow this app to be anything
12927 // below foreground, so it is not worth doing work for it.
12928 app.adjType = "fixed";
12929 app.adjSeq = mAdjSeq;
12930 app.curRawAdj = app.maxAdj;
12931 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
12932 return (app.curAdj=app.maxAdj);
12933 }
12934
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070012935 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012936 app.adjSource = null;
12937 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012938
The Android Open Source Project4df24232009-03-05 14:34:35 -080012939 // Determine the importance of the process, starting with most
12940 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012941 int adj;
12942 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012943 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012944 // The last app on the list is the foreground app.
12945 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012946 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012947 } else if (app.instrumentationClass != null) {
12948 // Don't want to kill running instrumentation.
12949 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012950 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012951 } else if (app.persistentActivities > 0) {
12952 // Special persistent activities... shouldn't be used these days.
12953 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012954 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012955 } else if (app.curReceiver != null ||
12956 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12957 // An app that is currently receiving a broadcast also
12958 // counts as being in the foreground.
12959 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012960 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012961 } else if (app.executingServices.size() > 0) {
12962 // An app that is currently executing a service callback also
12963 // counts as being in the foreground.
12964 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012965 app.adjType = "exec-service";
12966 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012967 // The user is aware of this app, so make it visible.
12968 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012969 app.adjType = "foreground-service";
12970 } else if (app.forcingToForeground != null) {
12971 // The user is aware of this app, so make it visible.
12972 adj = VISIBLE_APP_ADJ;
12973 app.adjType = "force-foreground";
12974 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012975 } else if (app == mHomeProcess) {
12976 // This process is hosting what we currently consider to be the
12977 // home app, so we don't want to let it go into the background.
12978 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012979 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012980 } else if ((N=app.activities.size()) != 0) {
12981 // This app is in the background with paused activities.
12982 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012983 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012984 for (int j=0; j<N; j++) {
12985 if (((HistoryRecord)app.activities.get(j)).visible) {
12986 // This app has a visible activity!
12987 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012988 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012989 break;
12990 }
12991 }
12992 } else {
12993 // A very not-needed process.
12994 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012995 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012996 }
12997
The Android Open Source Project4df24232009-03-05 14:34:35 -080012998 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012999 // there are applications dependent on our services or providers, but
13000 // this gives us a baseline and makes sure we don't get into an
13001 // infinite recursion.
13002 app.adjSeq = mAdjSeq;
13003 app.curRawAdj = adj;
13004 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
13005
Christopher Tate6fa95972009-06-05 18:43:55 -070013006 if (mBackupTarget != null && app == mBackupTarget.app) {
13007 // If possible we want to avoid killing apps while they're being backed up
13008 if (adj > BACKUP_APP_ADJ) {
13009 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13010 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013011 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070013012 }
13013 }
13014
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013015 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013016 final long now = SystemClock.uptimeMillis();
13017 // This process is more important if the top activity is
13018 // bound to the service.
13019 Iterator jt = app.services.iterator();
13020 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13021 ServiceRecord s = (ServiceRecord)jt.next();
13022 if (s.startRequested) {
13023 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13024 // This service has seen some activity within
13025 // recent memory, so we will keep its process ahead
13026 // of the background processes.
13027 if (adj > SECONDARY_SERVER_ADJ) {
13028 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013029 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013030 }
13031 }
13032 }
13033 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
13034 Iterator<ConnectionRecord> kt
13035 = s.connections.values().iterator();
13036 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13037 // XXX should compute this based on the max of
13038 // all connected clients.
13039 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013040 if (cr.binding.client == app) {
13041 // Binding to ourself is not interesting.
13042 continue;
13043 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013044 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13045 ProcessRecord client = cr.binding.client;
13046 int myHiddenAdj = hiddenAdj;
13047 if (myHiddenAdj > client.hiddenAdj) {
13048 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13049 myHiddenAdj = client.hiddenAdj;
13050 } else {
13051 myHiddenAdj = VISIBLE_APP_ADJ;
13052 }
13053 }
13054 int clientAdj = computeOomAdjLocked(
13055 client, myHiddenAdj, TOP_APP);
13056 if (adj > clientAdj) {
13057 adj = clientAdj > VISIBLE_APP_ADJ
13058 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013059 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013060 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13061 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013062 app.adjSource = cr.binding.client;
13063 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013064 }
13065 }
13066 HistoryRecord a = cr.activity;
13067 //if (a != null) {
13068 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13069 //}
13070 if (a != null && adj > FOREGROUND_APP_ADJ &&
13071 (a.state == ActivityState.RESUMED
13072 || a.state == ActivityState.PAUSING)) {
13073 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013074 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013075 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13076 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013077 app.adjSource = a;
13078 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013079 }
13080 }
13081 }
13082 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013083
13084 // Finally, f this process has active services running in it, we
13085 // would like to avoid killing it unless it would prevent the current
13086 // application from running. By default we put the process in
13087 // with the rest of the background processes; as we scan through
13088 // its services we may bump it up from there.
13089 if (adj > hiddenAdj) {
13090 adj = hiddenAdj;
13091 app.adjType = "bg-services";
13092 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013093 }
13094
13095 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013096 Iterator jt = app.pubProviders.values().iterator();
13097 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13098 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13099 if (cpr.clients.size() != 0) {
13100 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13101 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13102 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013103 if (client == app) {
13104 // Being our own client is not interesting.
13105 continue;
13106 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013107 int myHiddenAdj = hiddenAdj;
13108 if (myHiddenAdj > client.hiddenAdj) {
13109 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13110 myHiddenAdj = client.hiddenAdj;
13111 } else {
13112 myHiddenAdj = FOREGROUND_APP_ADJ;
13113 }
13114 }
13115 int clientAdj = computeOomAdjLocked(
13116 client, myHiddenAdj, TOP_APP);
13117 if (adj > clientAdj) {
13118 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013119 ? clientAdj : FOREGROUND_APP_ADJ;
13120 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013121 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13122 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013123 app.adjSource = client;
13124 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013125 }
13126 }
13127 }
13128 // If the provider has external (non-framework) process
13129 // dependencies, ensure that its adjustment is at least
13130 // FOREGROUND_APP_ADJ.
13131 if (cpr.externals != 0) {
13132 if (adj > FOREGROUND_APP_ADJ) {
13133 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013134 app.adjType = "provider";
13135 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013136 }
13137 }
13138 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013139
13140 // Finally, if this process has published any content providers,
13141 // then its adjustment makes it at least as important as any of the
13142 // processes using those providers, and no less important than
13143 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
13144 if (adj > CONTENT_PROVIDER_ADJ) {
13145 adj = CONTENT_PROVIDER_ADJ;
13146 app.adjType = "pub-providers";
13147 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013148 }
13149
13150 app.curRawAdj = adj;
13151
13152 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13153 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13154 if (adj > app.maxAdj) {
13155 adj = app.maxAdj;
13156 }
13157
13158 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013159 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013160 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
13161 : Process.THREAD_GROUP_DEFAULT;
13162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013163 return adj;
13164 }
13165
13166 /**
13167 * Ask a given process to GC right now.
13168 */
13169 final void performAppGcLocked(ProcessRecord app) {
13170 try {
13171 app.lastRequestedGc = SystemClock.uptimeMillis();
13172 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013173 if (app.reportLowMemory) {
13174 app.reportLowMemory = false;
13175 app.thread.scheduleLowMemory();
13176 } else {
13177 app.thread.processInBackground();
13178 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013179 }
13180 } catch (Exception e) {
13181 // whatever.
13182 }
13183 }
13184
13185 /**
13186 * Returns true if things are idle enough to perform GCs.
13187 */
13188 private final boolean canGcNow() {
13189 return mParallelBroadcasts.size() == 0
13190 && mOrderedBroadcasts.size() == 0
13191 && (mSleeping || (mResumedActivity != null &&
13192 mResumedActivity.idle));
13193 }
13194
13195 /**
13196 * Perform GCs on all processes that are waiting for it, but only
13197 * if things are idle.
13198 */
13199 final void performAppGcsLocked() {
13200 final int N = mProcessesToGc.size();
13201 if (N <= 0) {
13202 return;
13203 }
13204 if (canGcNow()) {
13205 while (mProcessesToGc.size() > 0) {
13206 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013207 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13208 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13209 <= SystemClock.uptimeMillis()) {
13210 // To avoid spamming the system, we will GC processes one
13211 // at a time, waiting a few seconds between each.
13212 performAppGcLocked(proc);
13213 scheduleAppGcsLocked();
13214 return;
13215 } else {
13216 // It hasn't been long enough since we last GCed this
13217 // process... put it in the list to wait for its time.
13218 addProcessToGcListLocked(proc);
13219 break;
13220 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013221 }
13222 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013223
13224 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013225 }
13226 }
13227
13228 /**
13229 * If all looks good, perform GCs on all processes waiting for them.
13230 */
13231 final void performAppGcsIfAppropriateLocked() {
13232 if (canGcNow()) {
13233 performAppGcsLocked();
13234 return;
13235 }
13236 // Still not idle, wait some more.
13237 scheduleAppGcsLocked();
13238 }
13239
13240 /**
13241 * Schedule the execution of all pending app GCs.
13242 */
13243 final void scheduleAppGcsLocked() {
13244 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013245
13246 if (mProcessesToGc.size() > 0) {
13247 // Schedule a GC for the time to the next process.
13248 ProcessRecord proc = mProcessesToGc.get(0);
13249 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13250
13251 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13252 long now = SystemClock.uptimeMillis();
13253 if (when < (now+GC_TIMEOUT)) {
13254 when = now + GC_TIMEOUT;
13255 }
13256 mHandler.sendMessageAtTime(msg, when);
13257 }
13258 }
13259
13260 /**
13261 * Add a process to the array of processes waiting to be GCed. Keeps the
13262 * list in sorted order by the last GC time. The process can't already be
13263 * on the list.
13264 */
13265 final void addProcessToGcListLocked(ProcessRecord proc) {
13266 boolean added = false;
13267 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13268 if (mProcessesToGc.get(i).lastRequestedGc <
13269 proc.lastRequestedGc) {
13270 added = true;
13271 mProcessesToGc.add(i+1, proc);
13272 break;
13273 }
13274 }
13275 if (!added) {
13276 mProcessesToGc.add(0, proc);
13277 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013278 }
13279
13280 /**
13281 * Set up to ask a process to GC itself. This will either do it
13282 * immediately, or put it on the list of processes to gc the next
13283 * time things are idle.
13284 */
13285 final void scheduleAppGcLocked(ProcessRecord app) {
13286 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013287 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013288 return;
13289 }
13290 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013291 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013292 scheduleAppGcsLocked();
13293 }
13294 }
13295
13296 private final boolean updateOomAdjLocked(
13297 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13298 app.hiddenAdj = hiddenAdj;
13299
13300 if (app.thread == null) {
13301 return true;
13302 }
13303
13304 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
13305
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013306 if (app.pid != 0 && app.pid != MY_PID) {
13307 if (app.curRawAdj != app.setRawAdj) {
13308 if (app.curRawAdj > FOREGROUND_APP_ADJ
13309 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13310 // If this app is transitioning from foreground to
13311 // non-foreground, have it do a gc.
13312 scheduleAppGcLocked(app);
13313 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13314 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13315 // Likewise do a gc when an app is moving in to the
13316 // background (such as a service stopping).
13317 scheduleAppGcLocked(app);
13318 }
13319 app.setRawAdj = app.curRawAdj;
13320 }
13321 if (adj != app.setAdj) {
13322 if (Process.setOomAdj(app.pid, adj)) {
13323 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13324 TAG, "Set app " + app.processName +
13325 " oom adj to " + adj);
13326 app.setAdj = adj;
13327 } else {
13328 return false;
13329 }
13330 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013331 if (app.setSchedGroup != app.curSchedGroup) {
13332 app.setSchedGroup = app.curSchedGroup;
13333 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13334 "Setting process group of " + app.processName
13335 + " to " + app.curSchedGroup);
13336 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013337 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013338 try {
13339 Process.setProcessGroup(app.pid, app.curSchedGroup);
13340 } catch (Exception e) {
13341 Log.w(TAG, "Failed setting process group of " + app.pid
13342 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013343 e.printStackTrace();
13344 } finally {
13345 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013346 }
13347 }
13348 if (false) {
13349 if (app.thread != null) {
13350 try {
13351 app.thread.setSchedulingGroup(app.curSchedGroup);
13352 } catch (RemoteException e) {
13353 }
13354 }
13355 }
13356 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013357 }
13358
13359 return true;
13360 }
13361
13362 private final HistoryRecord resumedAppLocked() {
13363 HistoryRecord resumedActivity = mResumedActivity;
13364 if (resumedActivity == null || resumedActivity.app == null) {
13365 resumedActivity = mPausingActivity;
13366 if (resumedActivity == null || resumedActivity.app == null) {
13367 resumedActivity = topRunningActivityLocked(null);
13368 }
13369 }
13370 return resumedActivity;
13371 }
13372
13373 private final boolean updateOomAdjLocked(ProcessRecord app) {
13374 final HistoryRecord TOP_ACT = resumedAppLocked();
13375 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13376 int curAdj = app.curAdj;
13377 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13378 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13379
13380 mAdjSeq++;
13381
13382 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13383 if (res) {
13384 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13385 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13386 if (nowHidden != wasHidden) {
13387 // Changed to/from hidden state, so apps after it in the LRU
13388 // list may also be changed.
13389 updateOomAdjLocked();
13390 }
13391 }
13392 return res;
13393 }
13394
13395 private final boolean updateOomAdjLocked() {
13396 boolean didOomAdj = true;
13397 final HistoryRecord TOP_ACT = resumedAppLocked();
13398 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13399
13400 if (false) {
13401 RuntimeException e = new RuntimeException();
13402 e.fillInStackTrace();
13403 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13404 }
13405
13406 mAdjSeq++;
13407
13408 // First try updating the OOM adjustment for each of the
13409 // application processes based on their current state.
13410 int i = mLRUProcesses.size();
13411 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13412 while (i > 0) {
13413 i--;
13414 ProcessRecord app = mLRUProcesses.get(i);
13415 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13416 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13417 && app.curAdj == curHiddenAdj) {
13418 curHiddenAdj++;
13419 }
13420 } else {
13421 didOomAdj = false;
13422 }
13423 }
13424
13425 // todo: for now pretend like OOM ADJ didn't work, because things
13426 // aren't behaving as expected on Linux -- it's not killing processes.
13427 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13428 }
13429
13430 private final void trimApplications() {
13431 synchronized (this) {
13432 int i;
13433
13434 // First remove any unused application processes whose package
13435 // has been removed.
13436 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13437 final ProcessRecord app = mRemovedProcesses.get(i);
13438 if (app.activities.size() == 0
13439 && app.curReceiver == null && app.services.size() == 0) {
13440 Log.i(
13441 TAG, "Exiting empty application process "
13442 + app.processName + " ("
13443 + (app.thread != null ? app.thread.asBinder() : null)
13444 + ")\n");
13445 if (app.pid > 0 && app.pid != MY_PID) {
13446 Process.killProcess(app.pid);
13447 } else {
13448 try {
13449 app.thread.scheduleExit();
13450 } catch (Exception e) {
13451 // Ignore exceptions.
13452 }
13453 }
13454 cleanUpApplicationRecordLocked(app, false, -1);
13455 mRemovedProcesses.remove(i);
13456
13457 if (app.persistent) {
13458 if (app.persistent) {
13459 addAppLocked(app.info);
13460 }
13461 }
13462 }
13463 }
13464
13465 // Now try updating the OOM adjustment for each of the
13466 // application processes based on their current state.
13467 // If the setOomAdj() API is not supported, then go with our
13468 // back-up plan...
13469 if (!updateOomAdjLocked()) {
13470
13471 // Count how many processes are running services.
13472 int numServiceProcs = 0;
13473 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13474 final ProcessRecord app = mLRUProcesses.get(i);
13475
13476 if (app.persistent || app.services.size() != 0
13477 || app.curReceiver != null
13478 || app.persistentActivities > 0) {
13479 // Don't count processes holding services against our
13480 // maximum process count.
13481 if (localLOGV) Log.v(
13482 TAG, "Not trimming app " + app + " with services: "
13483 + app.services);
13484 numServiceProcs++;
13485 }
13486 }
13487
13488 int curMaxProcs = mProcessLimit;
13489 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13490 if (mAlwaysFinishActivities) {
13491 curMaxProcs = 1;
13492 }
13493 curMaxProcs += numServiceProcs;
13494
13495 // Quit as many processes as we can to get down to the desired
13496 // process count. First remove any processes that no longer
13497 // have activites running in them.
13498 for ( i=0;
13499 i<mLRUProcesses.size()
13500 && mLRUProcesses.size() > curMaxProcs;
13501 i++) {
13502 final ProcessRecord app = mLRUProcesses.get(i);
13503 // Quit an application only if it is not currently
13504 // running any activities.
13505 if (!app.persistent && app.activities.size() == 0
13506 && app.curReceiver == null && app.services.size() == 0) {
13507 Log.i(
13508 TAG, "Exiting empty application process "
13509 + app.processName + " ("
13510 + (app.thread != null ? app.thread.asBinder() : null)
13511 + ")\n");
13512 if (app.pid > 0 && app.pid != MY_PID) {
13513 Process.killProcess(app.pid);
13514 } else {
13515 try {
13516 app.thread.scheduleExit();
13517 } catch (Exception e) {
13518 // Ignore exceptions.
13519 }
13520 }
13521 // todo: For now we assume the application is not buggy
13522 // or evil, and will quit as a result of our request.
13523 // Eventually we need to drive this off of the death
13524 // notification, and kill the process if it takes too long.
13525 cleanUpApplicationRecordLocked(app, false, i);
13526 i--;
13527 }
13528 }
13529
13530 // If we still have too many processes, now from the least
13531 // recently used process we start finishing activities.
13532 if (Config.LOGV) Log.v(
13533 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13534 " of " + curMaxProcs + " processes");
13535 for ( i=0;
13536 i<mLRUProcesses.size()
13537 && mLRUProcesses.size() > curMaxProcs;
13538 i++) {
13539 final ProcessRecord app = mLRUProcesses.get(i);
13540 // Quit the application only if we have a state saved for
13541 // all of its activities.
13542 boolean canQuit = !app.persistent && app.curReceiver == null
13543 && app.services.size() == 0
13544 && app.persistentActivities == 0;
13545 int NUMA = app.activities.size();
13546 int j;
13547 if (Config.LOGV) Log.v(
13548 TAG, "Looking to quit " + app.processName);
13549 for (j=0; j<NUMA && canQuit; j++) {
13550 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13551 if (Config.LOGV) Log.v(
13552 TAG, " " + r.intent.getComponent().flattenToShortString()
13553 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13554 canQuit = (r.haveState || !r.stateNotNeeded)
13555 && !r.visible && r.stopped;
13556 }
13557 if (canQuit) {
13558 // Finish all of the activities, and then the app itself.
13559 for (j=0; j<NUMA; j++) {
13560 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13561 if (!r.finishing) {
13562 destroyActivityLocked(r, false);
13563 }
13564 r.resultTo = null;
13565 }
13566 Log.i(TAG, "Exiting application process "
13567 + app.processName + " ("
13568 + (app.thread != null ? app.thread.asBinder() : null)
13569 + ")\n");
13570 if (app.pid > 0 && app.pid != MY_PID) {
13571 Process.killProcess(app.pid);
13572 } else {
13573 try {
13574 app.thread.scheduleExit();
13575 } catch (Exception e) {
13576 // Ignore exceptions.
13577 }
13578 }
13579 // todo: For now we assume the application is not buggy
13580 // or evil, and will quit as a result of our request.
13581 // Eventually we need to drive this off of the death
13582 // notification, and kill the process if it takes too long.
13583 cleanUpApplicationRecordLocked(app, false, i);
13584 i--;
13585 //dump();
13586 }
13587 }
13588
13589 }
13590
13591 int curMaxActivities = MAX_ACTIVITIES;
13592 if (mAlwaysFinishActivities) {
13593 curMaxActivities = 1;
13594 }
13595
13596 // Finally, if there are too many activities now running, try to
13597 // finish as many as we can to get back down to the limit.
13598 for ( i=0;
13599 i<mLRUActivities.size()
13600 && mLRUActivities.size() > curMaxActivities;
13601 i++) {
13602 final HistoryRecord r
13603 = (HistoryRecord)mLRUActivities.get(i);
13604
13605 // We can finish this one if we have its icicle saved and
13606 // it is not persistent.
13607 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13608 && r.stopped && !r.persistent && !r.finishing) {
13609 final int origSize = mLRUActivities.size();
13610 destroyActivityLocked(r, true);
13611
13612 // This will remove it from the LRU list, so keep
13613 // our index at the same value. Note that this check to
13614 // see if the size changes is just paranoia -- if
13615 // something unexpected happens, we don't want to end up
13616 // in an infinite loop.
13617 if (origSize > mLRUActivities.size()) {
13618 i--;
13619 }
13620 }
13621 }
13622 }
13623 }
13624
13625 /** This method sends the specified signal to each of the persistent apps */
13626 public void signalPersistentProcesses(int sig) throws RemoteException {
13627 if (sig != Process.SIGNAL_USR1) {
13628 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13629 }
13630
13631 synchronized (this) {
13632 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13633 != PackageManager.PERMISSION_GRANTED) {
13634 throw new SecurityException("Requires permission "
13635 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13636 }
13637
13638 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13639 ProcessRecord r = mLRUProcesses.get(i);
13640 if (r.thread != null && r.persistent) {
13641 Process.sendSignal(r.pid, sig);
13642 }
13643 }
13644 }
13645 }
13646
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013647 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013648 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013649
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013650 try {
13651 synchronized (this) {
13652 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13653 // its own permission.
13654 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13655 != PackageManager.PERMISSION_GRANTED) {
13656 throw new SecurityException("Requires permission "
13657 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013658 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013659
13660 if (start && fd == null) {
13661 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013662 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013663
13664 ProcessRecord proc = null;
13665 try {
13666 int pid = Integer.parseInt(process);
13667 synchronized (mPidsSelfLocked) {
13668 proc = mPidsSelfLocked.get(pid);
13669 }
13670 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013671 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013672
13673 if (proc == null) {
13674 HashMap<String, SparseArray<ProcessRecord>> all
13675 = mProcessNames.getMap();
13676 SparseArray<ProcessRecord> procs = all.get(process);
13677 if (procs != null && procs.size() > 0) {
13678 proc = procs.valueAt(0);
13679 }
13680 }
13681
13682 if (proc == null || proc.thread == null) {
13683 throw new IllegalArgumentException("Unknown process: " + process);
13684 }
13685
13686 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13687 if (isSecure) {
13688 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13689 throw new SecurityException("Process not debuggable: " + proc);
13690 }
13691 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013692
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013693 proc.thread.profilerControl(start, path, fd);
13694 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013695 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013696 }
13697 } catch (RemoteException e) {
13698 throw new IllegalStateException("Process disappeared");
13699 } finally {
13700 if (fd != null) {
13701 try {
13702 fd.close();
13703 } catch (IOException e) {
13704 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013705 }
13706 }
13707 }
13708
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013709 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13710 public void monitor() {
13711 synchronized (this) { }
13712 }
13713}