blob: 66ef55722472c97d9c8d6178ac20aa31bad622f0 [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;
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070036import android.app.IActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.app.IActivityWatcher;
38import android.app.IApplicationThread;
39import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.app.IServiceConnection;
41import android.app.IThumbnailReceiver;
42import android.app.Instrumentation;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070043import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.app.PendingIntent;
45import android.app.ResultInfo;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070046import android.app.Service;
Christopher Tate181fafa2009-05-14 11:12:14 -070047import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020048import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.content.ComponentName;
50import android.content.ContentResolver;
51import android.content.Context;
52import android.content.Intent;
53import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070054import android.content.IIntentReceiver;
55import android.content.IIntentSender;
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 /**
461 * List of intents that were used to start the most recent tasks.
462 */
463 final ArrayList<TaskRecord> mRecentTasks
464 = new ArrayList<TaskRecord>();
465
466 /**
467 * List of activities that are ready to be finished, but waiting
468 * for the previous activity to settle down before doing so. It contains
469 * HistoryRecord objects.
470 */
471 final ArrayList mFinishingActivities = new ArrayList();
472
473 /**
474 * All of the applications we currently have running organized by name.
475 * The keys are strings of the application package name (as
476 * returned by the package manager), and the keys are ApplicationRecord
477 * objects.
478 */
479 final ProcessMap<ProcessRecord> mProcessNames
480 = new ProcessMap<ProcessRecord>();
481
482 /**
483 * The last time that various processes have crashed.
484 */
485 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
486
487 /**
488 * Set of applications that we consider to be bad, and will reject
489 * incoming broadcasts from (which the user has no control over).
490 * Processes are added to this set when they have crashed twice within
491 * a minimum amount of time; they are removed from it when they are
492 * later restarted (hopefully due to some user action). The value is the
493 * time it was added to the list.
494 */
495 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
496
497 /**
498 * All of the processes we currently have running organized by pid.
499 * The keys are the pid running the application.
500 *
501 * <p>NOTE: This object is protected by its own lock, NOT the global
502 * activity manager lock!
503 */
504 final SparseArray<ProcessRecord> mPidsSelfLocked
505 = new SparseArray<ProcessRecord>();
506
507 /**
508 * All of the processes that have been forced to be foreground. The key
509 * is the pid of the caller who requested it (we hold a death
510 * link on it).
511 */
512 abstract class ForegroundToken implements IBinder.DeathRecipient {
513 int pid;
514 IBinder token;
515 }
516 final SparseArray<ForegroundToken> mForegroundProcesses
517 = new SparseArray<ForegroundToken>();
518
519 /**
520 * List of records for processes that someone had tried to start before the
521 * system was ready. We don't start them at that point, but ensure they
522 * are started by the time booting is complete.
523 */
524 final ArrayList<ProcessRecord> mProcessesOnHold
525 = new ArrayList<ProcessRecord>();
526
527 /**
528 * List of records for processes that we have started and are waiting
529 * for them to call back. This is really only needed when running in
530 * single processes mode, in which case we do not have a unique pid for
531 * each process.
532 */
533 final ArrayList<ProcessRecord> mStartingProcesses
534 = new ArrayList<ProcessRecord>();
535
536 /**
537 * List of persistent applications that are in the process
538 * of being started.
539 */
540 final ArrayList<ProcessRecord> mPersistentStartingProcesses
541 = new ArrayList<ProcessRecord>();
542
543 /**
544 * Processes that are being forcibly torn down.
545 */
546 final ArrayList<ProcessRecord> mRemovedProcesses
547 = new ArrayList<ProcessRecord>();
548
549 /**
550 * List of running applications, sorted by recent usage.
551 * The first entry in the list is the least recently used.
552 * It contains ApplicationRecord objects. This list does NOT include
553 * any persistent application records (since we never want to exit them).
554 */
555 final ArrayList<ProcessRecord> mLRUProcesses
556 = new ArrayList<ProcessRecord>();
557
558 /**
559 * List of processes that should gc as soon as things are idle.
560 */
561 final ArrayList<ProcessRecord> mProcessesToGc
562 = new ArrayList<ProcessRecord>();
563
564 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800565 * This is the process holding what we currently consider to be
566 * the "home" activity.
567 */
568 private ProcessRecord mHomeProcess;
569
570 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 * List of running activities, sorted by recent usage.
572 * The first entry in the list is the least recently used.
573 * It contains HistoryRecord objects.
574 */
575 private final ArrayList mLRUActivities = new ArrayList();
576
577 /**
578 * Set of PendingResultRecord objects that are currently active.
579 */
580 final HashSet mPendingResultRecords = new HashSet();
581
582 /**
583 * Set of IntentSenderRecord objects that are currently active.
584 */
585 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
586 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
587
588 /**
589 * Intent broadcast that we have tried to start, but are
590 * waiting for its application's process to be created. We only
591 * need one (instead of a list) because we always process broadcasts
592 * one at a time, so no others can be started while waiting for this
593 * one.
594 */
595 BroadcastRecord mPendingBroadcast = null;
596
597 /**
598 * Keeps track of all IIntentReceivers that have been registered for
599 * broadcasts. Hash keys are the receiver IBinder, hash value is
600 * a ReceiverList.
601 */
602 final HashMap mRegisteredReceivers = new HashMap();
603
604 /**
605 * Resolver for broadcast intents to registered receivers.
606 * Holds BroadcastFilter (subclass of IntentFilter).
607 */
608 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
609 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
610 @Override
611 protected boolean allowFilterResult(
612 BroadcastFilter filter, List<BroadcastFilter> dest) {
613 IBinder target = filter.receiverList.receiver.asBinder();
614 for (int i=dest.size()-1; i>=0; i--) {
615 if (dest.get(i).receiverList.receiver.asBinder() == target) {
616 return false;
617 }
618 }
619 return true;
620 }
621 };
622
623 /**
624 * State of all active sticky broadcasts. Keys are the action of the
625 * sticky Intent, values are an ArrayList of all broadcasted intents with
626 * that action (which should usually be one).
627 */
628 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
629 new HashMap<String, ArrayList<Intent>>();
630
631 /**
632 * All currently running services.
633 */
634 final HashMap<ComponentName, ServiceRecord> mServices =
635 new HashMap<ComponentName, ServiceRecord>();
636
637 /**
638 * All currently running services indexed by the Intent used to start them.
639 */
640 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
641 new HashMap<Intent.FilterComparison, ServiceRecord>();
642
643 /**
644 * All currently bound service connections. Keys are the IBinder of
645 * the client's IServiceConnection.
646 */
647 final HashMap<IBinder, ConnectionRecord> mServiceConnections
648 = new HashMap<IBinder, ConnectionRecord>();
649
650 /**
651 * List of services that we have been asked to start,
652 * but haven't yet been able to. It is used to hold start requests
653 * while waiting for their corresponding application thread to get
654 * going.
655 */
656 final ArrayList<ServiceRecord> mPendingServices
657 = new ArrayList<ServiceRecord>();
658
659 /**
660 * List of services that are scheduled to restart following a crash.
661 */
662 final ArrayList<ServiceRecord> mRestartingServices
663 = new ArrayList<ServiceRecord>();
664
665 /**
666 * List of services that are in the process of being stopped.
667 */
668 final ArrayList<ServiceRecord> mStoppingServices
669 = new ArrayList<ServiceRecord>();
670
671 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700672 * Backup/restore process management
673 */
674 String mBackupAppName = null;
675 BackupRecord mBackupTarget = null;
676
677 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 * List of PendingThumbnailsRecord objects of clients who are still
679 * waiting to receive all of the thumbnails for a task.
680 */
681 final ArrayList mPendingThumbnails = new ArrayList();
682
683 /**
684 * List of HistoryRecord objects that have been finished and must
685 * still report back to a pending thumbnail receiver.
686 */
687 final ArrayList mCancelledThumbnails = new ArrayList();
688
689 /**
690 * All of the currently running global content providers. Keys are a
691 * string containing the provider name and values are a
692 * ContentProviderRecord object containing the data about it. Note
693 * that a single provider may be published under multiple names, so
694 * there may be multiple entries here for a single one in mProvidersByClass.
695 */
696 final HashMap mProvidersByName = new HashMap();
697
698 /**
699 * All of the currently running global content providers. Keys are a
700 * string containing the provider's implementation class and values are a
701 * ContentProviderRecord object containing the data about it.
702 */
703 final HashMap mProvidersByClass = new HashMap();
704
705 /**
706 * List of content providers who have clients waiting for them. The
707 * application is currently being launched and the provider will be
708 * removed from this list once it is published.
709 */
710 final ArrayList mLaunchingProviders = new ArrayList();
711
712 /**
713 * Global set of specific Uri permissions that have been granted.
714 */
715 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
716 = new SparseArray<HashMap<Uri, UriPermission>>();
717
718 /**
719 * Thread-local storage used to carry caller permissions over through
720 * indirect content-provider access.
721 * @see #ActivityManagerService.openContentUri()
722 */
723 private class Identity {
724 public int pid;
725 public int uid;
726
727 Identity(int _pid, int _uid) {
728 pid = _pid;
729 uid = _uid;
730 }
731 }
732 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
733
734 /**
735 * All information we have collected about the runtime performance of
736 * any user id that can impact battery performance.
737 */
738 final BatteryStatsService mBatteryStatsService;
739
740 /**
741 * information about component usage
742 */
743 final UsageStatsService mUsageStatsService;
744
745 /**
746 * Current configuration information. HistoryRecord objects are given
747 * a reference to this object to indicate which configuration they are
748 * currently running in, so this object must be kept immutable.
749 */
750 Configuration mConfiguration = new Configuration();
751
752 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700753 * Hardware-reported OpenGLES version.
754 */
755 final int GL_ES_VERSION;
756
757 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 * List of initialization arguments to pass to all processes when binding applications to them.
759 * For example, references to the commonly used services.
760 */
761 HashMap<String, IBinder> mAppBindArgs;
762
763 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700764 * Temporary to avoid allocations. Protected by main lock.
765 */
766 final StringBuilder mStringBuilder = new StringBuilder(256);
767
768 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 * Used to control how we initialize the service.
770 */
771 boolean mStartRunning = false;
772 ComponentName mTopComponent;
773 String mTopAction;
774 String mTopData;
775 boolean mSystemReady = false;
776 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700777 boolean mWaitingUpdate = false;
778 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779
780 Context mContext;
781
782 int mFactoryTest;
783
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700784 boolean mCheckedForSetup;
785
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700787 * The time at which we will allow normal application switches again,
788 * after a call to {@link #stopAppSwitches()}.
789 */
790 long mAppSwitchesAllowedTime;
791
792 /**
793 * This is set to true after the first switch after mAppSwitchesAllowedTime
794 * is set; any switches after that will clear the time.
795 */
796 boolean mDidAppSwitch;
797
798 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 * Set while we are wanting to sleep, to prevent any
800 * activities from being started/resumed.
801 */
802 boolean mSleeping = false;
803
804 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700805 * Set if we are shutting down the system, similar to sleeping.
806 */
807 boolean mShuttingDown = false;
808
809 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 * Set when the system is going to sleep, until we have
811 * successfully paused the current activity and released our wake lock.
812 * At that point the system is allowed to actually sleep.
813 */
814 PowerManager.WakeLock mGoingToSleep;
815
816 /**
817 * We don't want to allow the device to go to sleep while in the process
818 * of launching an activity. This is primarily to allow alarm intent
819 * receivers to launch an activity and get that to run before the device
820 * goes back to sleep.
821 */
822 PowerManager.WakeLock mLaunchingActivity;
823
824 /**
825 * Task identifier that activities are currently being started
826 * in. Incremented each time a new task is created.
827 * todo: Replace this with a TokenSpace class that generates non-repeating
828 * integers that won't wrap.
829 */
830 int mCurTask = 1;
831
832 /**
833 * Current sequence id for oom_adj computation traversal.
834 */
835 int mAdjSeq = 0;
836
837 /**
838 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
839 * is set, indicating the user wants processes started in such a way
840 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
841 * running in each process (thus no pre-initialized process, etc).
842 */
843 boolean mSimpleProcessManagement = false;
844
845 /**
846 * System monitoring: number of processes that died since the last
847 * N procs were started.
848 */
849 int[] mProcDeaths = new int[20];
850
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700851 /**
852 * This is set if we had to do a delayed dexopt of an app before launching
853 * it, to increasing the ANR timeouts in that case.
854 */
855 boolean mDidDexOpt;
856
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 String mDebugApp = null;
858 boolean mWaitForDebugger = false;
859 boolean mDebugTransient = false;
860 String mOrigDebugApp = null;
861 boolean mOrigWaitForDebugger = false;
862 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700863 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700865 final RemoteCallbackList<IActivityWatcher> mWatchers
866 = new RemoteCallbackList<IActivityWatcher>();
867
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 /**
869 * Callback of last caller to {@link #requestPss}.
870 */
871 Runnable mRequestPssCallback;
872
873 /**
874 * Remaining processes for which we are waiting results from the last
875 * call to {@link #requestPss}.
876 */
877 final ArrayList<ProcessRecord> mRequestPssList
878 = new ArrayList<ProcessRecord>();
879
880 /**
881 * Runtime statistics collection thread. This object's lock is used to
882 * protect all related state.
883 */
884 final Thread mProcessStatsThread;
885
886 /**
887 * Used to collect process stats when showing not responding dialog.
888 * Protected by mProcessStatsThread.
889 */
890 final ProcessStats mProcessStats = new ProcessStats(
891 MONITOR_THREAD_CPU_USAGE);
892 long mLastCpuTime = 0;
893 long mLastWriteTime = 0;
894
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700895 long mInitialStartTime = 0;
896
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 /**
898 * Set to true after the system has finished booting.
899 */
900 boolean mBooted = false;
901
902 int mProcessLimit = 0;
903
904 WindowManagerService mWindowManager;
905
906 static ActivityManagerService mSelf;
907 static ActivityThread mSystemThread;
908
909 private final class AppDeathRecipient implements IBinder.DeathRecipient {
910 final ProcessRecord mApp;
911 final int mPid;
912 final IApplicationThread mAppThread;
913
914 AppDeathRecipient(ProcessRecord app, int pid,
915 IApplicationThread thread) {
916 if (localLOGV) Log.v(
917 TAG, "New death recipient " + this
918 + " for thread " + thread.asBinder());
919 mApp = app;
920 mPid = pid;
921 mAppThread = thread;
922 }
923
924 public void binderDied() {
925 if (localLOGV) Log.v(
926 TAG, "Death received in " + this
927 + " for thread " + mAppThread.asBinder());
928 removeRequestedPss(mApp);
929 synchronized(ActivityManagerService.this) {
930 appDiedLocked(mApp, mPid, mAppThread);
931 }
932 }
933 }
934
935 static final int SHOW_ERROR_MSG = 1;
936 static final int SHOW_NOT_RESPONDING_MSG = 2;
937 static final int SHOW_FACTORY_ERROR_MSG = 3;
938 static final int UPDATE_CONFIGURATION_MSG = 4;
939 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
940 static final int WAIT_FOR_DEBUGGER_MSG = 6;
941 static final int BROADCAST_INTENT_MSG = 7;
942 static final int BROADCAST_TIMEOUT_MSG = 8;
943 static final int PAUSE_TIMEOUT_MSG = 9;
944 static final int IDLE_TIMEOUT_MSG = 10;
945 static final int IDLE_NOW_MSG = 11;
946 static final int SERVICE_TIMEOUT_MSG = 12;
947 static final int UPDATE_TIME_ZONE = 13;
948 static final int SHOW_UID_ERROR_MSG = 14;
949 static final int IM_FEELING_LUCKY_MSG = 15;
950 static final int LAUNCH_TIMEOUT_MSG = 16;
951 static final int DESTROY_TIMEOUT_MSG = 17;
952 static final int SERVICE_ERROR_MSG = 18;
953 static final int RESUME_TOP_ACTIVITY_MSG = 19;
954 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700955 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700956 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957
958 AlertDialog mUidAlert;
959
960 final Handler mHandler = new Handler() {
961 //public Handler() {
962 // if (localLOGV) Log.v(TAG, "Handler started!");
963 //}
964
965 public void handleMessage(Message msg) {
966 switch (msg.what) {
967 case SHOW_ERROR_MSG: {
968 HashMap data = (HashMap) msg.obj;
969 byte[] crashData = (byte[])data.get("crashData");
970 if (crashData != null) {
971 // This needs to be *un*synchronized to avoid deadlock.
972 ContentResolver resolver = mContext.getContentResolver();
973 Checkin.reportCrash(resolver, crashData);
974 }
975 synchronized (ActivityManagerService.this) {
976 ProcessRecord proc = (ProcessRecord)data.get("app");
977 if (proc != null && proc.crashDialog != null) {
978 Log.e(TAG, "App already has crash dialog: " + proc);
979 return;
980 }
981 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700982 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 Dialog d = new AppErrorDialog(
984 mContext, res, proc,
985 (Integer)data.get("flags"),
986 (String)data.get("shortMsg"),
987 (String)data.get("longMsg"));
988 d.show();
989 proc.crashDialog = d;
990 } else {
991 // The device is asleep, so just pretend that the user
992 // saw a crash dialog and hit "force quit".
993 res.set(0);
994 }
995 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700996
997 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 } break;
999 case SHOW_NOT_RESPONDING_MSG: {
1000 synchronized (ActivityManagerService.this) {
1001 HashMap data = (HashMap) msg.obj;
1002 ProcessRecord proc = (ProcessRecord)data.get("app");
1003 if (proc != null && proc.anrDialog != null) {
1004 Log.e(TAG, "App already has anr dialog: " + proc);
1005 return;
1006 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001007
1008 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1009 null, null, 0, null, null, null,
1010 false, false, MY_PID, Process.SYSTEM_UID);
1011
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1013 mContext, proc, (HistoryRecord)data.get("activity"));
1014 d.show();
1015 proc.anrDialog = d;
1016 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001017
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001018 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 } break;
1020 case SHOW_FACTORY_ERROR_MSG: {
1021 Dialog d = new FactoryErrorDialog(
1022 mContext, msg.getData().getCharSequence("msg"));
1023 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001024 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 } break;
1026 case UPDATE_CONFIGURATION_MSG: {
1027 final ContentResolver resolver = mContext.getContentResolver();
1028 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1029 } break;
1030 case GC_BACKGROUND_PROCESSES_MSG: {
1031 synchronized (ActivityManagerService.this) {
1032 performAppGcsIfAppropriateLocked();
1033 }
1034 } break;
1035 case WAIT_FOR_DEBUGGER_MSG: {
1036 synchronized (ActivityManagerService.this) {
1037 ProcessRecord app = (ProcessRecord)msg.obj;
1038 if (msg.arg1 != 0) {
1039 if (!app.waitedForDebugger) {
1040 Dialog d = new AppWaitingForDebuggerDialog(
1041 ActivityManagerService.this,
1042 mContext, app);
1043 app.waitDialog = d;
1044 app.waitedForDebugger = true;
1045 d.show();
1046 }
1047 } else {
1048 if (app.waitDialog != null) {
1049 app.waitDialog.dismiss();
1050 app.waitDialog = null;
1051 }
1052 }
1053 }
1054 } break;
1055 case BROADCAST_INTENT_MSG: {
1056 if (DEBUG_BROADCAST) Log.v(
1057 TAG, "Received BROADCAST_INTENT_MSG");
1058 processNextBroadcast(true);
1059 } break;
1060 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001061 if (mDidDexOpt) {
1062 mDidDexOpt = false;
1063 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1064 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1065 return;
1066 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 broadcastTimeout();
1068 } break;
1069 case PAUSE_TIMEOUT_MSG: {
1070 IBinder token = (IBinder)msg.obj;
1071 // We don't at this point know if the activity is fullscreen,
1072 // so we need to be conservative and assume it isn't.
1073 Log.w(TAG, "Activity pause timeout for " + token);
1074 activityPaused(token, null, true);
1075 } break;
1076 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001077 if (mDidDexOpt) {
1078 mDidDexOpt = false;
1079 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1080 nmsg.obj = msg.obj;
1081 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1082 return;
1083 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001084 // We don't at this point know if the activity is fullscreen,
1085 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001086 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 Log.w(TAG, "Activity idle timeout for " + token);
1088 activityIdleInternal(token, true);
1089 } break;
1090 case DESTROY_TIMEOUT_MSG: {
1091 IBinder token = (IBinder)msg.obj;
1092 // We don't at this point know if the activity is fullscreen,
1093 // so we need to be conservative and assume it isn't.
1094 Log.w(TAG, "Activity destroy timeout for " + token);
1095 activityDestroyed(token);
1096 } break;
1097 case IDLE_NOW_MSG: {
1098 IBinder token = (IBinder)msg.obj;
1099 activityIdle(token);
1100 } break;
1101 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001102 if (mDidDexOpt) {
1103 mDidDexOpt = false;
1104 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1105 nmsg.obj = msg.obj;
1106 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1107 return;
1108 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 serviceTimeout((ProcessRecord)msg.obj);
1110 } break;
1111 case UPDATE_TIME_ZONE: {
1112 synchronized (ActivityManagerService.this) {
1113 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1114 ProcessRecord r = mLRUProcesses.get(i);
1115 if (r.thread != null) {
1116 try {
1117 r.thread.updateTimeZone();
1118 } catch (RemoteException ex) {
1119 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1120 }
1121 }
1122 }
1123 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001124 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 case SHOW_UID_ERROR_MSG: {
1126 // XXX This is a temporary dialog, no need to localize.
1127 AlertDialog d = new BaseErrorDialog(mContext);
1128 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1129 d.setCancelable(false);
1130 d.setTitle("System UIDs Inconsistent");
1131 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1132 d.setButton("I'm Feeling Lucky",
1133 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1134 mUidAlert = d;
1135 d.show();
1136 } break;
1137 case IM_FEELING_LUCKY_MSG: {
1138 if (mUidAlert != null) {
1139 mUidAlert.dismiss();
1140 mUidAlert = null;
1141 }
1142 } break;
1143 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001144 if (mDidDexOpt) {
1145 mDidDexOpt = false;
1146 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1147 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1148 return;
1149 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 synchronized (ActivityManagerService.this) {
1151 if (mLaunchingActivity.isHeld()) {
1152 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1153 mLaunchingActivity.release();
1154 }
1155 }
1156 } break;
1157 case SERVICE_ERROR_MSG: {
1158 ServiceRecord srv = (ServiceRecord)msg.obj;
1159 // This needs to be *un*synchronized to avoid deadlock.
1160 Checkin.logEvent(mContext.getContentResolver(),
1161 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1162 srv.name.toShortString());
1163 } break;
1164 case RESUME_TOP_ACTIVITY_MSG: {
1165 synchronized (ActivityManagerService.this) {
1166 resumeTopActivityLocked(null);
1167 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001168 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001170 if (mDidDexOpt) {
1171 mDidDexOpt = false;
1172 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1173 nmsg.obj = msg.obj;
1174 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1175 return;
1176 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177 ProcessRecord app = (ProcessRecord)msg.obj;
1178 synchronized (ActivityManagerService.this) {
1179 processStartTimedOutLocked(app);
1180 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001181 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001182 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1183 synchronized (ActivityManagerService.this) {
1184 doPendingActivityLaunchesLocked(true);
1185 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001186 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001187 case KILL_APPLICATION_MSG: {
1188 synchronized (ActivityManagerService.this) {
1189 int uid = msg.arg1;
1190 boolean restart = (msg.arg2 == 1);
1191 String pkg = (String) msg.obj;
1192 uninstallPackageLocked(pkg, uid, restart);
1193 }
1194 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195 }
1196 }
1197 };
1198
1199 public static void setSystemProcess() {
1200 try {
1201 ActivityManagerService m = mSelf;
1202
1203 ServiceManager.addService("activity", m);
1204 ServiceManager.addService("meminfo", new MemBinder(m));
1205 if (MONITOR_CPU_USAGE) {
1206 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1207 }
1208 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1209 ServiceManager.addService("activity.services", new ServicesBinder(m));
1210 ServiceManager.addService("activity.senders", new SendersBinder(m));
1211 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1212 ServiceManager.addService("permission", new PermissionController(m));
1213
1214 ApplicationInfo info =
1215 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001216 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217 synchronized (mSelf) {
1218 ProcessRecord app = mSelf.newProcessRecordLocked(
1219 mSystemThread.getApplicationThread(), info,
1220 info.processName);
1221 app.persistent = true;
1222 app.pid = Process.myPid();
1223 app.maxAdj = SYSTEM_ADJ;
1224 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1225 synchronized (mSelf.mPidsSelfLocked) {
1226 mSelf.mPidsSelfLocked.put(app.pid, app);
1227 }
1228 mSelf.updateLRUListLocked(app, true);
1229 }
1230 } catch (PackageManager.NameNotFoundException e) {
1231 throw new RuntimeException(
1232 "Unable to find android system package", e);
1233 }
1234 }
1235
1236 public void setWindowManager(WindowManagerService wm) {
1237 mWindowManager = wm;
1238 }
1239
1240 public static final Context main(int factoryTest) {
1241 AThread thr = new AThread();
1242 thr.start();
1243
1244 synchronized (thr) {
1245 while (thr.mService == null) {
1246 try {
1247 thr.wait();
1248 } catch (InterruptedException e) {
1249 }
1250 }
1251 }
1252
1253 ActivityManagerService m = thr.mService;
1254 mSelf = m;
1255 ActivityThread at = ActivityThread.systemMain();
1256 mSystemThread = at;
1257 Context context = at.getSystemContext();
1258 m.mContext = context;
1259 m.mFactoryTest = factoryTest;
1260 PowerManager pm =
1261 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1262 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1263 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1264 m.mLaunchingActivity.setReferenceCounted(false);
1265
1266 m.mBatteryStatsService.publish(context);
1267 m.mUsageStatsService.publish(context);
1268
1269 synchronized (thr) {
1270 thr.mReady = true;
1271 thr.notifyAll();
1272 }
1273
1274 m.startRunning(null, null, null, null);
1275
1276 return context;
1277 }
1278
1279 public static ActivityManagerService self() {
1280 return mSelf;
1281 }
1282
1283 static class AThread extends Thread {
1284 ActivityManagerService mService;
1285 boolean mReady = false;
1286
1287 public AThread() {
1288 super("ActivityManager");
1289 }
1290
1291 public void run() {
1292 Looper.prepare();
1293
1294 android.os.Process.setThreadPriority(
1295 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1296
1297 ActivityManagerService m = new ActivityManagerService();
1298
1299 synchronized (this) {
1300 mService = m;
1301 notifyAll();
1302 }
1303
1304 synchronized (this) {
1305 while (!mReady) {
1306 try {
1307 wait();
1308 } catch (InterruptedException e) {
1309 }
1310 }
1311 }
1312
1313 Looper.loop();
1314 }
1315 }
1316
1317 static class BroadcastsBinder extends Binder {
1318 ActivityManagerService mActivityManagerService;
1319 BroadcastsBinder(ActivityManagerService activityManagerService) {
1320 mActivityManagerService = activityManagerService;
1321 }
1322
1323 @Override
1324 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1325 mActivityManagerService.dumpBroadcasts(pw);
1326 }
1327 }
1328
1329 static class ServicesBinder extends Binder {
1330 ActivityManagerService mActivityManagerService;
1331 ServicesBinder(ActivityManagerService activityManagerService) {
1332 mActivityManagerService = activityManagerService;
1333 }
1334
1335 @Override
1336 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1337 mActivityManagerService.dumpServices(pw);
1338 }
1339 }
1340
1341 static class SendersBinder extends Binder {
1342 ActivityManagerService mActivityManagerService;
1343 SendersBinder(ActivityManagerService activityManagerService) {
1344 mActivityManagerService = activityManagerService;
1345 }
1346
1347 @Override
1348 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1349 mActivityManagerService.dumpSenders(pw);
1350 }
1351 }
1352
1353 static class ProvidersBinder extends Binder {
1354 ActivityManagerService mActivityManagerService;
1355 ProvidersBinder(ActivityManagerService activityManagerService) {
1356 mActivityManagerService = activityManagerService;
1357 }
1358
1359 @Override
1360 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1361 mActivityManagerService.dumpProviders(pw);
1362 }
1363 }
1364
1365 static class MemBinder extends Binder {
1366 ActivityManagerService mActivityManagerService;
1367 MemBinder(ActivityManagerService activityManagerService) {
1368 mActivityManagerService = activityManagerService;
1369 }
1370
1371 @Override
1372 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1373 ActivityManagerService service = mActivityManagerService;
1374 ArrayList<ProcessRecord> procs;
1375 synchronized (mActivityManagerService) {
1376 if (args != null && args.length > 0
1377 && args[0].charAt(0) != '-') {
1378 procs = new ArrayList<ProcessRecord>();
1379 int pid = -1;
1380 try {
1381 pid = Integer.parseInt(args[0]);
1382 } catch (NumberFormatException e) {
1383
1384 }
1385 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1386 ProcessRecord proc = service.mLRUProcesses.get(i);
1387 if (proc.pid == pid) {
1388 procs.add(proc);
1389 } else if (proc.processName.equals(args[0])) {
1390 procs.add(proc);
1391 }
1392 }
1393 if (procs.size() <= 0) {
1394 pw.println("No process found for: " + args[0]);
1395 return;
1396 }
1397 } else {
1398 procs = service.mLRUProcesses;
1399 }
1400 }
1401 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1402 }
1403 }
1404
1405 static class CpuBinder extends Binder {
1406 ActivityManagerService mActivityManagerService;
1407 CpuBinder(ActivityManagerService activityManagerService) {
1408 mActivityManagerService = activityManagerService;
1409 }
1410
1411 @Override
1412 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1413 synchronized (mActivityManagerService.mProcessStatsThread) {
1414 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1415 }
1416 }
1417 }
1418
1419 private ActivityManagerService() {
1420 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1421 if (v != null && Integer.getInteger(v) != 0) {
1422 mSimpleProcessManagement = true;
1423 }
1424 v = System.getenv("ANDROID_DEBUG_APP");
1425 if (v != null) {
1426 mSimpleProcessManagement = true;
1427 }
1428
1429 MY_PID = Process.myPid();
1430
1431 File dataDir = Environment.getDataDirectory();
1432 File systemDir = new File(dataDir, "system");
1433 systemDir.mkdirs();
1434 mBatteryStatsService = new BatteryStatsService(new File(
1435 systemDir, "batterystats.bin").toString());
1436 mBatteryStatsService.getActiveStatistics().readLocked();
1437 mBatteryStatsService.getActiveStatistics().writeLocked();
1438
1439 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001440 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001441
Jack Palevichb90d28c2009-07-22 15:35:24 -07001442 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1443 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001445 mConfiguration.makeDefault();
1446 mProcessStats.init();
1447
1448 // Add ourself to the Watchdog monitors.
1449 Watchdog.getInstance().addMonitor(this);
1450
1451 // These values are set in system/rootdir/init.rc on startup.
1452 FOREGROUND_APP_ADJ =
1453 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1454 VISIBLE_APP_ADJ =
1455 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1456 SECONDARY_SERVER_ADJ =
1457 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001458 BACKUP_APP_ADJ =
1459 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001460 HOME_APP_ADJ =
1461 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001462 HIDDEN_APP_MIN_ADJ =
1463 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1464 CONTENT_PROVIDER_ADJ =
1465 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1466 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1467 EMPTY_APP_ADJ =
1468 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1469 FOREGROUND_APP_MEM =
1470 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1471 VISIBLE_APP_MEM =
1472 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1473 SECONDARY_SERVER_MEM =
1474 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001475 BACKUP_APP_MEM =
1476 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001477 HOME_APP_MEM =
1478 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001479 HIDDEN_APP_MEM =
1480 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1481 EMPTY_APP_MEM =
1482 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1483
1484 mProcessStatsThread = new Thread("ProcessStats") {
1485 public void run() {
1486 while (true) {
1487 try {
1488 try {
1489 synchronized(this) {
1490 final long now = SystemClock.uptimeMillis();
1491 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1492 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1493 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1494 // + ", write delay=" + nextWriteDelay);
1495 if (nextWriteDelay < nextCpuDelay) {
1496 nextCpuDelay = nextWriteDelay;
1497 }
1498 if (nextCpuDelay > 0) {
1499 this.wait(nextCpuDelay);
1500 }
1501 }
1502 } catch (InterruptedException e) {
1503 }
1504
1505 updateCpuStatsNow();
1506 } catch (Exception e) {
1507 Log.e(TAG, "Unexpected exception collecting process stats", e);
1508 }
1509 }
1510 }
1511 };
1512 mProcessStatsThread.start();
1513 }
1514
1515 @Override
1516 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1517 throws RemoteException {
1518 try {
1519 return super.onTransact(code, data, reply, flags);
1520 } catch (RuntimeException e) {
1521 // The activity manager only throws security exceptions, so let's
1522 // log all others.
1523 if (!(e instanceof SecurityException)) {
1524 Log.e(TAG, "Activity Manager Crash", e);
1525 }
1526 throw e;
1527 }
1528 }
1529
1530 void updateCpuStats() {
1531 synchronized (mProcessStatsThread) {
1532 final long now = SystemClock.uptimeMillis();
1533 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1534 mProcessStatsThread.notify();
1535 }
1536 }
1537 }
1538
1539 void updateCpuStatsNow() {
1540 synchronized (mProcessStatsThread) {
1541 final long now = SystemClock.uptimeMillis();
1542 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001544 if (MONITOR_CPU_USAGE &&
1545 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1546 mLastCpuTime = now;
1547 haveNewCpuStats = true;
1548 mProcessStats.update();
1549 //Log.i(TAG, mProcessStats.printCurrentState());
1550 //Log.i(TAG, "Total CPU usage: "
1551 // + mProcessStats.getTotalCpuPercent() + "%");
1552
1553 // Log the cpu usage if the property is set.
1554 if ("true".equals(SystemProperties.get("events.cpu"))) {
1555 int user = mProcessStats.getLastUserTime();
1556 int system = mProcessStats.getLastSystemTime();
1557 int iowait = mProcessStats.getLastIoWaitTime();
1558 int irq = mProcessStats.getLastIrqTime();
1559 int softIrq = mProcessStats.getLastSoftIrqTime();
1560 int idle = mProcessStats.getLastIdleTime();
1561
1562 int total = user + system + iowait + irq + softIrq + idle;
1563 if (total == 0) total = 1;
1564
1565 EventLog.writeEvent(LOG_CPU,
1566 ((user+system+iowait+irq+softIrq) * 100) / total,
1567 (user * 100) / total,
1568 (system * 100) / total,
1569 (iowait * 100) / total,
1570 (irq * 100) / total,
1571 (softIrq * 100) / total);
1572 }
1573 }
1574
Amith Yamasani819f9282009-06-24 23:18:15 -07001575 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001576 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001577 synchronized(mPidsSelfLocked) {
1578 if (haveNewCpuStats) {
1579 if (mBatteryStatsService.isOnBattery()) {
1580 final int N = mProcessStats.countWorkingStats();
1581 for (int i=0; i<N; i++) {
1582 ProcessStats.Stats st
1583 = mProcessStats.getWorkingStats(i);
1584 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1585 if (pr != null) {
1586 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1587 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001588 } else {
1589 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001590 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001591 if (ps != null) {
1592 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1593 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001594 }
1595 }
1596 }
1597 }
1598 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001599
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001600 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1601 mLastWriteTime = now;
1602 mBatteryStatsService.getActiveStatistics().writeLocked();
1603 }
1604 }
1605 }
1606 }
1607
1608 /**
1609 * Initialize the application bind args. These are passed to each
1610 * process when the bindApplication() IPC is sent to the process. They're
1611 * lazily setup to make sure the services are running when they're asked for.
1612 */
1613 private HashMap<String, IBinder> getCommonServicesLocked() {
1614 if (mAppBindArgs == null) {
1615 mAppBindArgs = new HashMap<String, IBinder>();
1616
1617 // Setup the application init args
1618 mAppBindArgs.put("package", ServiceManager.getService("package"));
1619 mAppBindArgs.put("window", ServiceManager.getService("window"));
1620 mAppBindArgs.put(Context.ALARM_SERVICE,
1621 ServiceManager.getService(Context.ALARM_SERVICE));
1622 }
1623 return mAppBindArgs;
1624 }
1625
1626 private final void setFocusedActivityLocked(HistoryRecord r) {
1627 if (mFocusedActivity != r) {
1628 mFocusedActivity = r;
1629 mWindowManager.setFocusedApp(r, true);
1630 }
1631 }
1632
1633 private final void updateLRUListLocked(ProcessRecord app,
1634 boolean oomAdj) {
1635 // put it on the LRU to keep track of when it should be exited.
1636 int lrui = mLRUProcesses.indexOf(app);
1637 if (lrui >= 0) mLRUProcesses.remove(lrui);
1638 mLRUProcesses.add(app);
1639 //Log.i(TAG, "Putting proc to front: " + app.processName);
1640 if (oomAdj) {
1641 updateOomAdjLocked();
1642 }
1643 }
1644
1645 private final boolean updateLRUListLocked(HistoryRecord r) {
1646 final boolean hadit = mLRUActivities.remove(r);
1647 mLRUActivities.add(r);
1648 return hadit;
1649 }
1650
1651 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1652 int i = mHistory.size()-1;
1653 while (i >= 0) {
1654 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1655 if (!r.finishing && r != notTop) {
1656 return r;
1657 }
1658 i--;
1659 }
1660 return null;
1661 }
1662
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001663 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1664 int i = mHistory.size()-1;
1665 while (i >= 0) {
1666 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1667 if (!r.finishing && !r.delayedResume && r != notTop) {
1668 return r;
1669 }
1670 i--;
1671 }
1672 return null;
1673 }
1674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001675 /**
1676 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001677 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001678 *
1679 * @param token If non-null, any history records matching this token will be skipped.
1680 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1681 *
1682 * @return Returns the HistoryRecord of the next activity on the stack.
1683 */
1684 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1685 int i = mHistory.size()-1;
1686 while (i >= 0) {
1687 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1688 // Note: the taskId check depends on real taskId fields being non-zero
1689 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1690 return r;
1691 }
1692 i--;
1693 }
1694 return null;
1695 }
1696
1697 private final ProcessRecord getProcessRecordLocked(
1698 String processName, int uid) {
1699 if (uid == Process.SYSTEM_UID) {
1700 // The system gets to run in any process. If there are multiple
1701 // processes with the same uid, just pick the first (this
1702 // should never happen).
1703 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1704 processName);
1705 return procs != null ? procs.valueAt(0) : null;
1706 }
1707 ProcessRecord proc = mProcessNames.get(processName, uid);
1708 return proc;
1709 }
1710
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001711 private void ensurePackageDexOpt(String packageName) {
1712 IPackageManager pm = ActivityThread.getPackageManager();
1713 try {
1714 if (pm.performDexOpt(packageName)) {
1715 mDidDexOpt = true;
1716 }
1717 } catch (RemoteException e) {
1718 }
1719 }
1720
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001721 private boolean isNextTransitionForward() {
1722 int transit = mWindowManager.getPendingAppTransition();
1723 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1724 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1725 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1726 }
1727
1728 private final boolean realStartActivityLocked(HistoryRecord r,
1729 ProcessRecord app, boolean andResume, boolean checkConfig)
1730 throws RemoteException {
1731
1732 r.startFreezingScreenLocked(app, 0);
1733 mWindowManager.setAppVisibility(r, true);
1734
1735 // Have the window manager re-evaluate the orientation of
1736 // the screen based on the new activity order. Note that
1737 // as a result of this, it can call back into the activity
1738 // manager with a new orientation. We don't care about that,
1739 // because the activity is not currently running so we are
1740 // just restarting it anyway.
1741 if (checkConfig) {
1742 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001743 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001744 r.mayFreezeScreenLocked(app) ? r : null);
1745 updateConfigurationLocked(config, r);
1746 }
1747
1748 r.app = app;
1749
1750 if (localLOGV) Log.v(TAG, "Launching: " + r);
1751
1752 int idx = app.activities.indexOf(r);
1753 if (idx < 0) {
1754 app.activities.add(r);
1755 }
1756 updateLRUListLocked(app, true);
1757
1758 try {
1759 if (app.thread == null) {
1760 throw new RemoteException();
1761 }
1762 List<ResultInfo> results = null;
1763 List<Intent> newIntents = null;
1764 if (andResume) {
1765 results = r.results;
1766 newIntents = r.newIntents;
1767 }
1768 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1769 + " icicle=" + r.icicle
1770 + " with results=" + results + " newIntents=" + newIntents
1771 + " andResume=" + andResume);
1772 if (andResume) {
1773 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1774 System.identityHashCode(r),
1775 r.task.taskId, r.shortComponentName);
1776 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001777 if (r.isHomeActivity) {
1778 mHomeProcess = app;
1779 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001780 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001781 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001782 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001783 r.info, r.icicle, results, newIntents, !andResume,
1784 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001785 } catch (RemoteException e) {
1786 if (r.launchFailed) {
1787 // This is the second time we failed -- finish activity
1788 // and give up.
1789 Log.e(TAG, "Second failure launching "
1790 + r.intent.getComponent().flattenToShortString()
1791 + ", giving up", e);
1792 appDiedLocked(app, app.pid, app.thread);
1793 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1794 "2nd-crash");
1795 return false;
1796 }
1797
1798 // This is the first time we failed -- restart process and
1799 // retry.
1800 app.activities.remove(r);
1801 throw e;
1802 }
1803
1804 r.launchFailed = false;
1805 if (updateLRUListLocked(r)) {
1806 Log.w(TAG, "Activity " + r
1807 + " being launched, but already in LRU list");
1808 }
1809
1810 if (andResume) {
1811 // As part of the process of launching, ActivityThread also performs
1812 // a resume.
1813 r.state = ActivityState.RESUMED;
1814 r.icicle = null;
1815 r.haveState = false;
1816 r.stopped = false;
1817 mResumedActivity = r;
1818 r.task.touchActiveTime();
1819 completeResumeLocked(r);
1820 pauseIfSleepingLocked();
1821 } else {
1822 // This activity is not starting in the resumed state... which
1823 // should look like we asked it to pause+stop (but remain visible),
1824 // and it has done so and reported back the current icicle and
1825 // other state.
1826 r.state = ActivityState.STOPPED;
1827 r.stopped = true;
1828 }
1829
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001830 // Launch the new version setup screen if needed. We do this -after-
1831 // launching the initial activity (that is, home), so that it can have
1832 // a chance to initialize itself while in the background, making the
1833 // switch back to it faster and look better.
1834 startSetupActivityLocked();
1835
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001836 return true;
1837 }
1838
1839 private final void startSpecificActivityLocked(HistoryRecord r,
1840 boolean andResume, boolean checkConfig) {
1841 // Is this activity's application already running?
1842 ProcessRecord app = getProcessRecordLocked(r.processName,
1843 r.info.applicationInfo.uid);
1844
1845 if (r.startTime == 0) {
1846 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001847 if (mInitialStartTime == 0) {
1848 mInitialStartTime = r.startTime;
1849 }
1850 } else if (mInitialStartTime == 0) {
1851 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001852 }
1853
1854 if (app != null && app.thread != null) {
1855 try {
1856 realStartActivityLocked(r, app, andResume, checkConfig);
1857 return;
1858 } catch (RemoteException e) {
1859 Log.w(TAG, "Exception when starting activity "
1860 + r.intent.getComponent().flattenToShortString(), e);
1861 }
1862
1863 // If a dead object exception was thrown -- fall through to
1864 // restart the application.
1865 }
1866
1867 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001868 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001869 }
1870
1871 private final ProcessRecord startProcessLocked(String processName,
1872 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001873 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001874 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1875 // We don't have to do anything more if:
1876 // (1) There is an existing application record; and
1877 // (2) The caller doesn't think it is dead, OR there is no thread
1878 // object attached to it so we know it couldn't have crashed; and
1879 // (3) There is a pid assigned to it, so it is either starting or
1880 // already running.
1881 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1882 + " app=" + app + " knownToBeDead=" + knownToBeDead
1883 + " thread=" + (app != null ? app.thread : null)
1884 + " pid=" + (app != null ? app.pid : -1));
1885 if (app != null &&
1886 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1887 return app;
1888 }
1889
1890 String hostingNameStr = hostingName != null
1891 ? hostingName.flattenToShortString() : null;
1892
1893 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1894 // If we are in the background, then check to see if this process
1895 // is bad. If so, we will just silently fail.
1896 if (mBadProcesses.get(info.processName, info.uid) != null) {
1897 return null;
1898 }
1899 } else {
1900 // When the user is explicitly starting a process, then clear its
1901 // crash count so that we won't make it bad until they see at
1902 // least one crash dialog again, and make the process good again
1903 // if it had been bad.
1904 mProcessCrashTimes.remove(info.processName, info.uid);
1905 if (mBadProcesses.get(info.processName, info.uid) != null) {
1906 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1907 info.processName);
1908 mBadProcesses.remove(info.processName, info.uid);
1909 if (app != null) {
1910 app.bad = false;
1911 }
1912 }
1913 }
1914
1915 if (app == null) {
1916 app = newProcessRecordLocked(null, info, processName);
1917 mProcessNames.put(processName, info.uid, app);
1918 } else {
1919 // If this is a new package in the process, add the package to the list
1920 app.addPackage(info.packageName);
1921 }
1922
1923 // If the system is not ready yet, then hold off on starting this
1924 // process until it is.
1925 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001926 && !isAllowedWhileBooting(info)
1927 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001928 if (!mProcessesOnHold.contains(app)) {
1929 mProcessesOnHold.add(app);
1930 }
1931 return app;
1932 }
1933
1934 startProcessLocked(app, hostingType, hostingNameStr);
1935 return (app.pid != 0) ? app : null;
1936 }
1937
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001938 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1939 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1940 }
1941
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001942 private final void startProcessLocked(ProcessRecord app,
1943 String hostingType, String hostingNameStr) {
1944 if (app.pid > 0 && app.pid != MY_PID) {
1945 synchronized (mPidsSelfLocked) {
1946 mPidsSelfLocked.remove(app.pid);
1947 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1948 }
1949 app.pid = 0;
1950 }
1951
1952 mProcessesOnHold.remove(app);
1953
1954 updateCpuStats();
1955
1956 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1957 mProcDeaths[0] = 0;
1958
1959 try {
1960 int uid = app.info.uid;
1961 int[] gids = null;
1962 try {
1963 gids = mContext.getPackageManager().getPackageGids(
1964 app.info.packageName);
1965 } catch (PackageManager.NameNotFoundException e) {
1966 Log.w(TAG, "Unable to retrieve gids", e);
1967 }
1968 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1969 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1970 && mTopComponent != null
1971 && app.processName.equals(mTopComponent.getPackageName())) {
1972 uid = 0;
1973 }
1974 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1975 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1976 uid = 0;
1977 }
1978 }
1979 int debugFlags = 0;
1980 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1981 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1982 }
1983 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1984 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1985 }
1986 if ("1".equals(SystemProperties.get("debug.assert"))) {
1987 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1988 }
1989 int pid = Process.start("android.app.ActivityThread",
1990 mSimpleProcessManagement ? app.processName : null, uid, uid,
1991 gids, debugFlags, null);
1992 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1993 synchronized (bs) {
1994 if (bs.isOnBattery()) {
1995 app.batteryStats.incStartsLocked();
1996 }
1997 }
1998
1999 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
2000 app.processName, hostingType,
2001 hostingNameStr != null ? hostingNameStr : "");
2002
2003 if (app.persistent) {
2004 Watchdog.getInstance().processStarted(app, app.processName, pid);
2005 }
2006
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07002007 StringBuilder buf = mStringBuilder;
2008 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002009 buf.append("Start proc ");
2010 buf.append(app.processName);
2011 buf.append(" for ");
2012 buf.append(hostingType);
2013 if (hostingNameStr != null) {
2014 buf.append(" ");
2015 buf.append(hostingNameStr);
2016 }
2017 buf.append(": pid=");
2018 buf.append(pid);
2019 buf.append(" uid=");
2020 buf.append(uid);
2021 buf.append(" gids={");
2022 if (gids != null) {
2023 for (int gi=0; gi<gids.length; gi++) {
2024 if (gi != 0) buf.append(", ");
2025 buf.append(gids[gi]);
2026
2027 }
2028 }
2029 buf.append("}");
2030 Log.i(TAG, buf.toString());
2031 if (pid == 0 || pid == MY_PID) {
2032 // Processes are being emulated with threads.
2033 app.pid = MY_PID;
2034 app.removed = false;
2035 mStartingProcesses.add(app);
2036 } else if (pid > 0) {
2037 app.pid = pid;
2038 app.removed = false;
2039 synchronized (mPidsSelfLocked) {
2040 this.mPidsSelfLocked.put(pid, app);
2041 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2042 msg.obj = app;
2043 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2044 }
2045 } else {
2046 app.pid = 0;
2047 RuntimeException e = new RuntimeException(
2048 "Failure starting process " + app.processName
2049 + ": returned pid=" + pid);
2050 Log.e(TAG, e.getMessage(), e);
2051 }
2052 } catch (RuntimeException e) {
2053 // XXX do better error recovery.
2054 app.pid = 0;
2055 Log.e(TAG, "Failure starting process " + app.processName, e);
2056 }
2057 }
2058
2059 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2060 if (mPausingActivity != null) {
2061 RuntimeException e = new RuntimeException();
2062 Log.e(TAG, "Trying to pause when pause is already pending for "
2063 + mPausingActivity, e);
2064 }
2065 HistoryRecord prev = mResumedActivity;
2066 if (prev == null) {
2067 RuntimeException e = new RuntimeException();
2068 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2069 resumeTopActivityLocked(null);
2070 return;
2071 }
2072 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2073 mResumedActivity = null;
2074 mPausingActivity = prev;
2075 mLastPausedActivity = prev;
2076 prev.state = ActivityState.PAUSING;
2077 prev.task.touchActiveTime();
2078
2079 updateCpuStats();
2080
2081 if (prev.app != null && prev.app.thread != null) {
2082 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2083 try {
2084 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2085 System.identityHashCode(prev),
2086 prev.shortComponentName);
2087 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2088 prev.configChangeFlags);
2089 updateUsageStats(prev, false);
2090 } catch (Exception e) {
2091 // Ignore exception, if process died other code will cleanup.
2092 Log.w(TAG, "Exception thrown during pause", e);
2093 mPausingActivity = null;
2094 mLastPausedActivity = null;
2095 }
2096 } else {
2097 mPausingActivity = null;
2098 mLastPausedActivity = null;
2099 }
2100
2101 // If we are not going to sleep, we want to ensure the device is
2102 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002103 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002104 mLaunchingActivity.acquire();
2105 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2106 // To be safe, don't allow the wake lock to be held for too long.
2107 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2108 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2109 }
2110 }
2111
2112
2113 if (mPausingActivity != null) {
2114 // Have the window manager pause its key dispatching until the new
2115 // activity has started. If we're pausing the activity just because
2116 // the screen is being turned off and the UI is sleeping, don't interrupt
2117 // key dispatch; the same activity will pick it up again on wakeup.
2118 if (!uiSleeping) {
2119 prev.pauseKeyDispatchingLocked();
2120 } else {
2121 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2122 }
2123
2124 // Schedule a pause timeout in case the app doesn't respond.
2125 // We don't give it much time because this directly impacts the
2126 // responsiveness seen by the user.
2127 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2128 msg.obj = prev;
2129 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2130 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2131 } else {
2132 // This activity failed to schedule the
2133 // pause, so just treat it as being paused now.
2134 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2135 resumeTopActivityLocked(null);
2136 }
2137 }
2138
2139 private final void completePauseLocked() {
2140 HistoryRecord prev = mPausingActivity;
2141 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2142
2143 if (prev != null) {
2144 if (prev.finishing) {
2145 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2146 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2147 } else if (prev.app != null) {
2148 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2149 if (prev.waitingVisible) {
2150 prev.waitingVisible = false;
2151 mWaitingVisibleActivities.remove(prev);
2152 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2153 TAG, "Complete pause, no longer waiting: " + prev);
2154 }
2155 if (prev.configDestroy) {
2156 // The previous is being paused because the configuration
2157 // is changing, which means it is actually stopping...
2158 // To juggle the fact that we are also starting a new
2159 // instance right now, we need to first completely stop
2160 // the current instance before starting the new one.
2161 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2162 destroyActivityLocked(prev, true);
2163 } else {
2164 mStoppingActivities.add(prev);
2165 if (mStoppingActivities.size() > 3) {
2166 // If we already have a few activities waiting to stop,
2167 // then give up on things going idle and start clearing
2168 // them out.
2169 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2170 Message msg = Message.obtain();
2171 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2172 mHandler.sendMessage(msg);
2173 }
2174 }
2175 } else {
2176 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2177 prev = null;
2178 }
2179 mPausingActivity = null;
2180 }
2181
Dianne Hackborn55280a92009-05-07 15:53:46 -07002182 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002183 resumeTopActivityLocked(prev);
2184 } else {
2185 if (mGoingToSleep.isHeld()) {
2186 mGoingToSleep.release();
2187 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002188 if (mShuttingDown) {
2189 notifyAll();
2190 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002191 }
2192
2193 if (prev != null) {
2194 prev.resumeKeyDispatchingLocked();
2195 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002196
2197 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2198 long diff = 0;
2199 synchronized (mProcessStatsThread) {
2200 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2201 }
2202 if (diff > 0) {
2203 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2204 synchronized (bsi) {
2205 BatteryStatsImpl.Uid.Proc ps =
2206 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2207 prev.info.packageName);
2208 if (ps != null) {
2209 ps.addForegroundTimeLocked(diff);
2210 }
2211 }
2212 }
2213 }
2214 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002215 }
2216
2217 /**
2218 * Once we know that we have asked an application to put an activity in
2219 * the resumed state (either by launching it or explicitly telling it),
2220 * this function updates the rest of our state to match that fact.
2221 */
2222 private final void completeResumeLocked(HistoryRecord next) {
2223 next.idle = false;
2224 next.results = null;
2225 next.newIntents = null;
2226
2227 // schedule an idle timeout in case the app doesn't do it for us.
2228 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2229 msg.obj = next;
2230 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2231
2232 if (false) {
2233 // The activity was never told to pause, so just keep
2234 // things going as-is. To maintain our own state,
2235 // we need to emulate it coming back and saying it is
2236 // idle.
2237 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2238 msg.obj = next;
2239 mHandler.sendMessage(msg);
2240 }
2241
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002242 reportResumedActivity(next);
2243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002244 next.thumbnail = null;
2245 setFocusedActivityLocked(next);
2246 next.resumeKeyDispatchingLocked();
2247 ensureActivitiesVisibleLocked(null, 0);
2248 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002249
2250 // Mark the point when the activity is resuming
2251 // TODO: To be more accurate, the mark should be before the onCreate,
2252 // not after the onResume. But for subsequent starts, onResume is fine.
2253 if (next.app != null) {
2254 synchronized (mProcessStatsThread) {
2255 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2256 }
2257 } else {
2258 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2259 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002260 }
2261
2262 /**
2263 * Make sure that all activities that need to be visible (that is, they
2264 * currently can be seen by the user) actually are.
2265 */
2266 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2267 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2268 if (DEBUG_VISBILITY) Log.v(
2269 TAG, "ensureActivitiesVisible behind " + top
2270 + " configChanges=0x" + Integer.toHexString(configChanges));
2271
2272 // If the top activity is not fullscreen, then we need to
2273 // make sure any activities under it are now visible.
2274 final int count = mHistory.size();
2275 int i = count-1;
2276 while (mHistory.get(i) != top) {
2277 i--;
2278 }
2279 HistoryRecord r;
2280 boolean behindFullscreen = false;
2281 for (; i>=0; i--) {
2282 r = (HistoryRecord)mHistory.get(i);
2283 if (DEBUG_VISBILITY) Log.v(
2284 TAG, "Make visible? " + r + " finishing=" + r.finishing
2285 + " state=" + r.state);
2286 if (r.finishing) {
2287 continue;
2288 }
2289
2290 final boolean doThisProcess = onlyThisProcess == null
2291 || onlyThisProcess.equals(r.processName);
2292
2293 // First: if this is not the current activity being started, make
2294 // sure it matches the current configuration.
2295 if (r != starting && doThisProcess) {
2296 ensureActivityConfigurationLocked(r, 0);
2297 }
2298
2299 if (r.app == null || r.app.thread == null) {
2300 if (onlyThisProcess == null
2301 || onlyThisProcess.equals(r.processName)) {
2302 // This activity needs to be visible, but isn't even
2303 // running... get it started, but don't resume it
2304 // at this point.
2305 if (DEBUG_VISBILITY) Log.v(
2306 TAG, "Start and freeze screen for " + r);
2307 if (r != starting) {
2308 r.startFreezingScreenLocked(r.app, configChanges);
2309 }
2310 if (!r.visible) {
2311 if (DEBUG_VISBILITY) Log.v(
2312 TAG, "Starting and making visible: " + r);
2313 mWindowManager.setAppVisibility(r, true);
2314 }
2315 if (r != starting) {
2316 startSpecificActivityLocked(r, false, false);
2317 }
2318 }
2319
2320 } else if (r.visible) {
2321 // If this activity is already visible, then there is nothing
2322 // else to do here.
2323 if (DEBUG_VISBILITY) Log.v(
2324 TAG, "Skipping: already visible at " + r);
2325 r.stopFreezingScreenLocked(false);
2326
2327 } else if (onlyThisProcess == null) {
2328 // This activity is not currently visible, but is running.
2329 // Tell it to become visible.
2330 r.visible = true;
2331 if (r.state != ActivityState.RESUMED && r != starting) {
2332 // If this activity is paused, tell it
2333 // to now show its window.
2334 if (DEBUG_VISBILITY) Log.v(
2335 TAG, "Making visible and scheduling visibility: " + r);
2336 try {
2337 mWindowManager.setAppVisibility(r, true);
2338 r.app.thread.scheduleWindowVisibility(r, true);
2339 r.stopFreezingScreenLocked(false);
2340 } catch (Exception e) {
2341 // Just skip on any failure; we'll make it
2342 // visible when it next restarts.
2343 Log.w(TAG, "Exception thrown making visibile: "
2344 + r.intent.getComponent(), e);
2345 }
2346 }
2347 }
2348
2349 // Aggregate current change flags.
2350 configChanges |= r.configChangeFlags;
2351
2352 if (r.fullscreen) {
2353 // At this point, nothing else needs to be shown
2354 if (DEBUG_VISBILITY) Log.v(
2355 TAG, "Stopping: fullscreen at " + r);
2356 behindFullscreen = true;
2357 i--;
2358 break;
2359 }
2360 }
2361
2362 // Now for any activities that aren't visible to the user, make
2363 // sure they no longer are keeping the screen frozen.
2364 while (i >= 0) {
2365 r = (HistoryRecord)mHistory.get(i);
2366 if (DEBUG_VISBILITY) Log.v(
2367 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2368 + " state=" + r.state
2369 + " behindFullscreen=" + behindFullscreen);
2370 if (!r.finishing) {
2371 if (behindFullscreen) {
2372 if (r.visible) {
2373 if (DEBUG_VISBILITY) Log.v(
2374 TAG, "Making invisible: " + r);
2375 r.visible = false;
2376 try {
2377 mWindowManager.setAppVisibility(r, false);
2378 if ((r.state == ActivityState.STOPPING
2379 || r.state == ActivityState.STOPPED)
2380 && r.app != null && r.app.thread != null) {
2381 if (DEBUG_VISBILITY) Log.v(
2382 TAG, "Scheduling invisibility: " + r);
2383 r.app.thread.scheduleWindowVisibility(r, false);
2384 }
2385 } catch (Exception e) {
2386 // Just skip on any failure; we'll make it
2387 // visible when it next restarts.
2388 Log.w(TAG, "Exception thrown making hidden: "
2389 + r.intent.getComponent(), e);
2390 }
2391 } else {
2392 if (DEBUG_VISBILITY) Log.v(
2393 TAG, "Already invisible: " + r);
2394 }
2395 } else if (r.fullscreen) {
2396 if (DEBUG_VISBILITY) Log.v(
2397 TAG, "Now behindFullscreen: " + r);
2398 behindFullscreen = true;
2399 }
2400 }
2401 i--;
2402 }
2403 }
2404
2405 /**
2406 * Version of ensureActivitiesVisible that can easily be called anywhere.
2407 */
2408 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2409 int configChanges) {
2410 HistoryRecord r = topRunningActivityLocked(null);
2411 if (r != null) {
2412 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2413 }
2414 }
2415
2416 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2417 if (resumed) {
2418 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2419 } else {
2420 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2421 }
2422 }
2423
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002424 private boolean startHomeActivityLocked() {
2425 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2426 && mTopAction == null) {
2427 // We are running in factory test mode, but unable to find
2428 // the factory test app, so just sit around displaying the
2429 // error message and don't try to start anything.
2430 return false;
2431 }
2432 Intent intent = new Intent(
2433 mTopAction,
2434 mTopData != null ? Uri.parse(mTopData) : null);
2435 intent.setComponent(mTopComponent);
2436 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2437 intent.addCategory(Intent.CATEGORY_HOME);
2438 }
2439 ActivityInfo aInfo =
2440 intent.resolveActivityInfo(mContext.getPackageManager(),
2441 STOCK_PM_FLAGS);
2442 if (aInfo != null) {
2443 intent.setComponent(new ComponentName(
2444 aInfo.applicationInfo.packageName, aInfo.name));
2445 // Don't do this if the home app is currently being
2446 // instrumented.
2447 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2448 aInfo.applicationInfo.uid);
2449 if (app == null || app.instrumentationClass == null) {
2450 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2451 startActivityLocked(null, intent, null, null, 0, aInfo,
2452 null, null, 0, 0, 0, false, false);
2453 }
2454 }
2455
2456
2457 return true;
2458 }
2459
2460 /**
2461 * Starts the "new version setup screen" if appropriate.
2462 */
2463 private void startSetupActivityLocked() {
2464 // Only do this once per boot.
2465 if (mCheckedForSetup) {
2466 return;
2467 }
2468
2469 // We will show this screen if the current one is a different
2470 // version than the last one shown, and we are not running in
2471 // low-level factory test mode.
2472 final ContentResolver resolver = mContext.getContentResolver();
2473 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2474 Settings.Secure.getInt(resolver,
2475 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2476 mCheckedForSetup = true;
2477
2478 // See if we should be showing the platform update setup UI.
2479 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2480 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2481 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2482
2483 // We don't allow third party apps to replace this.
2484 ResolveInfo ri = null;
2485 for (int i=0; ris != null && i<ris.size(); i++) {
2486 if ((ris.get(i).activityInfo.applicationInfo.flags
2487 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2488 ri = ris.get(i);
2489 break;
2490 }
2491 }
2492
2493 if (ri != null) {
2494 String vers = ri.activityInfo.metaData != null
2495 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2496 : null;
2497 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2498 vers = ri.activityInfo.applicationInfo.metaData.getString(
2499 Intent.METADATA_SETUP_VERSION);
2500 }
2501 String lastVers = Settings.Secure.getString(
2502 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2503 if (vers != null && !vers.equals(lastVers)) {
2504 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2505 intent.setComponent(new ComponentName(
2506 ri.activityInfo.packageName, ri.activityInfo.name));
2507 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2508 null, null, 0, 0, 0, false, false);
2509 }
2510 }
2511 }
2512 }
2513
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002514 private void reportResumedActivity(HistoryRecord r) {
2515 //Log.i(TAG, "**** REPORT RESUME: " + r);
2516
2517 final int identHash = System.identityHashCode(r);
2518 updateUsageStats(r, true);
2519
2520 int i = mWatchers.beginBroadcast();
2521 while (i > 0) {
2522 i--;
2523 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2524 if (w != null) {
2525 try {
2526 w.activityResuming(identHash);
2527 } catch (RemoteException e) {
2528 }
2529 }
2530 }
2531 mWatchers.finishBroadcast();
2532 }
2533
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002534 /**
2535 * Ensure that the top activity in the stack is resumed.
2536 *
2537 * @param prev The previously resumed activity, for when in the process
2538 * of pausing; can be null to call from elsewhere.
2539 *
2540 * @return Returns true if something is being resumed, or false if
2541 * nothing happened.
2542 */
2543 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2544 // Find the first activity that is not finishing.
2545 HistoryRecord next = topRunningActivityLocked(null);
2546
2547 // Remember how we'll process this pause/resume situation, and ensure
2548 // that the state is reset however we wind up proceeding.
2549 final boolean userLeaving = mUserLeaving;
2550 mUserLeaving = false;
2551
2552 if (next == null) {
2553 // There are no more activities! Let's just start up the
2554 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002555 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002556 }
2557
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002558 next.delayedResume = false;
2559
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002560 // If the top activity is the resumed one, nothing to do.
2561 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2562 // Make sure we have executed any pending transitions, since there
2563 // should be nothing left to do at this point.
2564 mWindowManager.executeAppTransition();
2565 return false;
2566 }
2567
2568 // If we are sleeping, and there is no resumed activity, and the top
2569 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002570 if ((mSleeping || mShuttingDown)
2571 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002572 // Make sure we have executed any pending transitions, since there
2573 // should be nothing left to do at this point.
2574 mWindowManager.executeAppTransition();
2575 return false;
2576 }
2577
2578 // The activity may be waiting for stop, but that is no longer
2579 // appropriate for it.
2580 mStoppingActivities.remove(next);
2581 mWaitingVisibleActivities.remove(next);
2582
2583 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2584
2585 // If we are currently pausing an activity, then don't do anything
2586 // until that is done.
2587 if (mPausingActivity != null) {
2588 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2589 return false;
2590 }
2591
2592 // We need to start pausing the current activity so the top one
2593 // can be resumed...
2594 if (mResumedActivity != null) {
2595 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2596 startPausingLocked(userLeaving, false);
2597 return true;
2598 }
2599
2600 if (prev != null && prev != next) {
2601 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2602 prev.waitingVisible = true;
2603 mWaitingVisibleActivities.add(prev);
2604 if (DEBUG_SWITCH) Log.v(
2605 TAG, "Resuming top, waiting visible to hide: " + prev);
2606 } else {
2607 // The next activity is already visible, so hide the previous
2608 // activity's windows right now so we can show the new one ASAP.
2609 // We only do this if the previous is finishing, which should mean
2610 // it is on top of the one being resumed so hiding it quickly
2611 // is good. Otherwise, we want to do the normal route of allowing
2612 // the resumed activity to be shown so we can decide if the
2613 // previous should actually be hidden depending on whether the
2614 // new one is found to be full-screen or not.
2615 if (prev.finishing) {
2616 mWindowManager.setAppVisibility(prev, false);
2617 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2618 + prev + ", waitingVisible="
2619 + (prev != null ? prev.waitingVisible : null)
2620 + ", nowVisible=" + next.nowVisible);
2621 } else {
2622 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2623 + prev + ", waitingVisible="
2624 + (prev != null ? prev.waitingVisible : null)
2625 + ", nowVisible=" + next.nowVisible);
2626 }
2627 }
2628 }
2629
2630 // We are starting up the next activity, so tell the window manager
2631 // that the previous one will be hidden soon. This way it can know
2632 // to ignore it when computing the desired screen orientation.
2633 if (prev != null) {
2634 if (prev.finishing) {
2635 if (DEBUG_TRANSITION) Log.v(TAG,
2636 "Prepare close transition: prev=" + prev);
2637 mWindowManager.prepareAppTransition(prev.task == next.task
2638 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2639 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2640 mWindowManager.setAppWillBeHidden(prev);
2641 mWindowManager.setAppVisibility(prev, false);
2642 } else {
2643 if (DEBUG_TRANSITION) Log.v(TAG,
2644 "Prepare open transition: prev=" + prev);
2645 mWindowManager.prepareAppTransition(prev.task == next.task
2646 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2647 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2648 }
2649 if (false) {
2650 mWindowManager.setAppWillBeHidden(prev);
2651 mWindowManager.setAppVisibility(prev, false);
2652 }
2653 } else if (mHistory.size() > 1) {
2654 if (DEBUG_TRANSITION) Log.v(TAG,
2655 "Prepare open transition: no previous");
2656 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2657 }
2658
2659 if (next.app != null && next.app.thread != null) {
2660 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2661
2662 // This activity is now becoming visible.
2663 mWindowManager.setAppVisibility(next, true);
2664
2665 HistoryRecord lastResumedActivity = mResumedActivity;
2666 ActivityState lastState = next.state;
2667
2668 updateCpuStats();
2669
2670 next.state = ActivityState.RESUMED;
2671 mResumedActivity = next;
2672 next.task.touchActiveTime();
2673 updateLRUListLocked(next.app, true);
2674 updateLRUListLocked(next);
2675
2676 // Have the window manager re-evaluate the orientation of
2677 // the screen based on the new activity order.
2678 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002679 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002680 next.mayFreezeScreenLocked(next.app) ? next : null);
2681 if (config != null) {
2682 next.frozenBeforeDestroy = true;
2683 }
2684 if (!updateConfigurationLocked(config, next)) {
2685 // The configuration update wasn't able to keep the existing
2686 // instance of the activity, and instead started a new one.
2687 // We should be all done, but let's just make sure our activity
2688 // is still at the top and schedule another run if something
2689 // weird happened.
2690 HistoryRecord nextNext = topRunningActivityLocked(null);
2691 if (DEBUG_SWITCH) Log.i(TAG,
2692 "Activity config changed during resume: " + next
2693 + ", new next: " + nextNext);
2694 if (nextNext != next) {
2695 // Do over!
2696 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2697 }
2698 mWindowManager.executeAppTransition();
2699 return true;
2700 }
2701
2702 try {
2703 // Deliver all pending results.
2704 ArrayList a = next.results;
2705 if (a != null) {
2706 final int N = a.size();
2707 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002708 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002709 TAG, "Delivering results to " + next
2710 + ": " + a);
2711 next.app.thread.scheduleSendResult(next, a);
2712 }
2713 }
2714
2715 if (next.newIntents != null) {
2716 next.app.thread.scheduleNewIntent(next.newIntents, next);
2717 }
2718
2719 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2720 System.identityHashCode(next),
2721 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002722
2723 next.app.thread.scheduleResumeActivity(next,
2724 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002725
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002726 pauseIfSleepingLocked();
2727
2728 } catch (Exception e) {
2729 // Whoops, need to restart this activity!
2730 next.state = lastState;
2731 mResumedActivity = lastResumedActivity;
2732 if (Config.LOGD) Log.d(TAG,
2733 "Restarting because process died: " + next);
2734 if (!next.hasBeenLaunched) {
2735 next.hasBeenLaunched = true;
2736 } else {
2737 if (SHOW_APP_STARTING_ICON) {
2738 mWindowManager.setAppStartingWindow(
2739 next, next.packageName, next.theme,
2740 next.nonLocalizedLabel,
2741 next.labelRes, next.icon, null, true);
2742 }
2743 }
2744 startSpecificActivityLocked(next, true, false);
2745 return true;
2746 }
2747
2748 // From this point on, if something goes wrong there is no way
2749 // to recover the activity.
2750 try {
2751 next.visible = true;
2752 completeResumeLocked(next);
2753 } catch (Exception e) {
2754 // If any exception gets thrown, toss away this
2755 // activity and try the next one.
2756 Log.w(TAG, "Exception thrown during resume of " + next, e);
2757 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2758 "resume-exception");
2759 return true;
2760 }
2761
2762 // Didn't need to use the icicle, and it is now out of date.
2763 next.icicle = null;
2764 next.haveState = false;
2765 next.stopped = false;
2766
2767 } else {
2768 // Whoops, need to restart this activity!
2769 if (!next.hasBeenLaunched) {
2770 next.hasBeenLaunched = true;
2771 } else {
2772 if (SHOW_APP_STARTING_ICON) {
2773 mWindowManager.setAppStartingWindow(
2774 next, next.packageName, next.theme,
2775 next.nonLocalizedLabel,
2776 next.labelRes, next.icon, null, true);
2777 }
2778 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2779 }
2780 startSpecificActivityLocked(next, true, true);
2781 }
2782
2783 return true;
2784 }
2785
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002786 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2787 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002788 final int NH = mHistory.size();
2789
2790 int addPos = -1;
2791
2792 if (!newTask) {
2793 // If starting in an existing task, find where that is...
2794 HistoryRecord next = null;
2795 boolean startIt = true;
2796 for (int i = NH-1; i >= 0; i--) {
2797 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2798 if (p.finishing) {
2799 continue;
2800 }
2801 if (p.task == r.task) {
2802 // Here it is! Now, if this is not yet visible to the
2803 // user, then just add it without starting; it will
2804 // get started when the user navigates back to it.
2805 addPos = i+1;
2806 if (!startIt) {
2807 mHistory.add(addPos, r);
2808 r.inHistory = true;
2809 r.task.numActivities++;
2810 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2811 r.info.screenOrientation, r.fullscreen);
2812 if (VALIDATE_TOKENS) {
2813 mWindowManager.validateAppTokens(mHistory);
2814 }
2815 return;
2816 }
2817 break;
2818 }
2819 if (p.fullscreen) {
2820 startIt = false;
2821 }
2822 next = p;
2823 }
2824 }
2825
2826 // Place a new activity at top of stack, so it is next to interact
2827 // with the user.
2828 if (addPos < 0) {
2829 addPos = mHistory.size();
2830 }
2831
2832 // If we are not placing the new activity frontmost, we do not want
2833 // to deliver the onUserLeaving callback to the actual frontmost
2834 // activity
2835 if (addPos < NH) {
2836 mUserLeaving = false;
2837 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2838 }
2839
2840 // Slot the activity into the history stack and proceed
2841 mHistory.add(addPos, r);
2842 r.inHistory = true;
2843 r.frontOfTask = newTask;
2844 r.task.numActivities++;
2845 if (NH > 0) {
2846 // We want to show the starting preview window if we are
2847 // switching to a new task, or the next activity's process is
2848 // not currently running.
2849 boolean showStartingIcon = newTask;
2850 ProcessRecord proc = r.app;
2851 if (proc == null) {
2852 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2853 }
2854 if (proc == null || proc.thread == null) {
2855 showStartingIcon = true;
2856 }
2857 if (DEBUG_TRANSITION) Log.v(TAG,
2858 "Prepare open transition: starting " + r);
2859 mWindowManager.prepareAppTransition(newTask
2860 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2861 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2862 mWindowManager.addAppToken(
2863 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2864 boolean doShow = true;
2865 if (newTask) {
2866 // Even though this activity is starting fresh, we still need
2867 // to reset it to make sure we apply affinities to move any
2868 // existing activities from other tasks in to it.
2869 // If the caller has requested that the target task be
2870 // reset, then do so.
2871 if ((r.intent.getFlags()
2872 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2873 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002874 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002875 }
2876 }
2877 if (SHOW_APP_STARTING_ICON && doShow) {
2878 // Figure out if we are transitioning from another activity that is
2879 // "has the same starting icon" as the next one. This allows the
2880 // window manager to keep the previous window it had previously
2881 // created, if it still had one.
2882 HistoryRecord prev = mResumedActivity;
2883 if (prev != null) {
2884 // We don't want to reuse the previous starting preview if:
2885 // (1) The current activity is in a different task.
2886 if (prev.task != r.task) prev = null;
2887 // (2) The current activity is already displayed.
2888 else if (prev.nowVisible) prev = null;
2889 }
2890 mWindowManager.setAppStartingWindow(
2891 r, r.packageName, r.theme, r.nonLocalizedLabel,
2892 r.labelRes, r.icon, prev, showStartingIcon);
2893 }
2894 } else {
2895 // If this is the first activity, don't do any fancy animations,
2896 // because there is nothing for it to animate on top of.
2897 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2898 r.info.screenOrientation, r.fullscreen);
2899 }
2900 if (VALIDATE_TOKENS) {
2901 mWindowManager.validateAppTokens(mHistory);
2902 }
2903
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002904 if (doResume) {
2905 resumeTopActivityLocked(null);
2906 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002907 }
2908
2909 /**
2910 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002911 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2912 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002913 * an instance of that activity in the stack and, if found, finish all
2914 * activities on top of it and return the instance.
2915 *
2916 * @param newR Description of the new activity being started.
2917 * @return Returns the old activity that should be continue to be used,
2918 * or null if none was found.
2919 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002920 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002921 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002922 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002923
2924 // First find the requested task.
2925 while (i > 0) {
2926 i--;
2927 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2928 if (r.task.taskId == taskId) {
2929 i++;
2930 break;
2931 }
2932 }
2933
2934 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002935 while (i > 0) {
2936 i--;
2937 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2938 if (r.finishing) {
2939 continue;
2940 }
2941 if (r.task.taskId != taskId) {
2942 return null;
2943 }
2944 if (r.realActivity.equals(newR.realActivity)) {
2945 // Here it is! Now finish everything in front...
2946 HistoryRecord ret = r;
2947 if (doClear) {
2948 while (i < (mHistory.size()-1)) {
2949 i++;
2950 r = (HistoryRecord)mHistory.get(i);
2951 if (r.finishing) {
2952 continue;
2953 }
2954 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2955 null, "clear")) {
2956 i--;
2957 }
2958 }
2959 }
2960
2961 // Finally, if this is a normal launch mode (that is, not
2962 // expecting onNewIntent()), then we will finish the current
2963 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002964 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
2965 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002966 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002967 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002968 if (index >= 0) {
2969 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2970 null, "clear");
2971 }
2972 return null;
2973 }
2974 }
2975
2976 return ret;
2977 }
2978 }
2979
2980 return null;
2981 }
2982
2983 /**
2984 * Find the activity in the history stack within the given task. Returns
2985 * the index within the history at which it's found, or < 0 if not found.
2986 */
2987 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2988 int i = mHistory.size();
2989 while (i > 0) {
2990 i--;
2991 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2992 if (candidate.task.taskId != task) {
2993 break;
2994 }
2995 if (candidate.realActivity.equals(r.realActivity)) {
2996 return i;
2997 }
2998 }
2999
3000 return -1;
3001 }
3002
3003 /**
3004 * Reorder the history stack so that the activity at the given index is
3005 * brought to the front.
3006 */
3007 private final HistoryRecord moveActivityToFrontLocked(int where) {
3008 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3009 int top = mHistory.size();
3010 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3011 mHistory.add(top, newTop);
3012 oldTop.frontOfTask = false;
3013 newTop.frontOfTask = true;
3014 return newTop;
3015 }
3016
3017 /**
3018 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3019 * method will be called at the proper time.
3020 */
3021 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3022 boolean sent = false;
3023 if (r.state == ActivityState.RESUMED
3024 && r.app != null && r.app.thread != null) {
3025 try {
3026 ArrayList<Intent> ar = new ArrayList<Intent>();
3027 ar.add(new Intent(intent));
3028 r.app.thread.scheduleNewIntent(ar, r);
3029 sent = true;
3030 } catch (Exception e) {
3031 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3032 }
3033 }
3034 if (!sent) {
3035 r.addNewIntentLocked(new Intent(intent));
3036 }
3037 }
3038
3039 private final void logStartActivity(int tag, HistoryRecord r,
3040 TaskRecord task) {
3041 EventLog.writeEvent(tag,
3042 System.identityHashCode(r), task.taskId,
3043 r.shortComponentName, r.intent.getAction(),
3044 r.intent.getType(), r.intent.getDataString(),
3045 r.intent.getFlags());
3046 }
3047
3048 private final int startActivityLocked(IApplicationThread caller,
3049 Intent intent, String resolvedType,
3050 Uri[] grantedUriPermissions,
3051 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3052 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003053 int callingPid, int callingUid, boolean onlyIfNeeded,
3054 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003055 Log.i(TAG, "Starting activity: " + intent);
3056
3057 HistoryRecord sourceRecord = null;
3058 HistoryRecord resultRecord = null;
3059 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003060 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003061 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003062 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3063 if (index >= 0) {
3064 sourceRecord = (HistoryRecord)mHistory.get(index);
3065 if (requestCode >= 0 && !sourceRecord.finishing) {
3066 resultRecord = sourceRecord;
3067 }
3068 }
3069 }
3070
3071 int launchFlags = intent.getFlags();
3072
3073 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3074 && sourceRecord != null) {
3075 // Transfer the result target from the source activity to the new
3076 // one being started, including any failures.
3077 if (requestCode >= 0) {
3078 return START_FORWARD_AND_REQUEST_CONFLICT;
3079 }
3080 resultRecord = sourceRecord.resultTo;
3081 resultWho = sourceRecord.resultWho;
3082 requestCode = sourceRecord.requestCode;
3083 sourceRecord.resultTo = null;
3084 if (resultRecord != null) {
3085 resultRecord.removeResultsLocked(
3086 sourceRecord, resultWho, requestCode);
3087 }
3088 }
3089
3090 int err = START_SUCCESS;
3091
3092 if (intent.getComponent() == null) {
3093 // We couldn't find a class that can handle the given Intent.
3094 // That's the end of that!
3095 err = START_INTENT_NOT_RESOLVED;
3096 }
3097
3098 if (err == START_SUCCESS && aInfo == null) {
3099 // We couldn't find the specific class specified in the Intent.
3100 // Also the end of the line.
3101 err = START_CLASS_NOT_FOUND;
3102 }
3103
3104 ProcessRecord callerApp = null;
3105 if (err == START_SUCCESS && caller != null) {
3106 callerApp = getRecordForAppLocked(caller);
3107 if (callerApp != null) {
3108 callingPid = callerApp.pid;
3109 callingUid = callerApp.info.uid;
3110 } else {
3111 Log.w(TAG, "Unable to find app for caller " + caller
3112 + " (pid=" + callingPid + ") when starting: "
3113 + intent.toString());
3114 err = START_PERMISSION_DENIED;
3115 }
3116 }
3117
3118 if (err != START_SUCCESS) {
3119 if (resultRecord != null) {
3120 sendActivityResultLocked(-1,
3121 resultRecord, resultWho, requestCode,
3122 Activity.RESULT_CANCELED, null);
3123 }
3124 return err;
3125 }
3126
3127 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3128 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3129 if (perm != PackageManager.PERMISSION_GRANTED) {
3130 if (resultRecord != null) {
3131 sendActivityResultLocked(-1,
3132 resultRecord, resultWho, requestCode,
3133 Activity.RESULT_CANCELED, null);
3134 }
3135 String msg = "Permission Denial: starting " + intent.toString()
3136 + " from " + callerApp + " (pid=" + callingPid
3137 + ", uid=" + callingUid + ")"
3138 + " requires " + aInfo.permission;
3139 Log.w(TAG, msg);
3140 throw new SecurityException(msg);
3141 }
3142
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003143 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003144 boolean abort = false;
3145 try {
3146 // The Intent we give to the watcher has the extra data
3147 // stripped off, since it can contain private information.
3148 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003149 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003150 aInfo.applicationInfo.packageName);
3151 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003152 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003153 }
3154
3155 if (abort) {
3156 if (resultRecord != null) {
3157 sendActivityResultLocked(-1,
3158 resultRecord, resultWho, requestCode,
3159 Activity.RESULT_CANCELED, null);
3160 }
3161 // We pretend to the caller that it was really started, but
3162 // they will just get a cancel result.
3163 return START_SUCCESS;
3164 }
3165 }
3166
3167 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3168 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003169 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003170
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003171 if (mResumedActivity == null
3172 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3173 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3174 PendingActivityLaunch pal = new PendingActivityLaunch();
3175 pal.r = r;
3176 pal.sourceRecord = sourceRecord;
3177 pal.grantedUriPermissions = grantedUriPermissions;
3178 pal.grantedMode = grantedMode;
3179 pal.onlyIfNeeded = onlyIfNeeded;
3180 mPendingActivityLaunches.add(pal);
3181 return START_SWITCHES_CANCELED;
3182 }
3183 }
3184
3185 if (mDidAppSwitch) {
3186 // This is the second allowed switch since we stopped switches,
3187 // so now just generally allow switches. Use case: user presses
3188 // home (switches disabled, switch to home, mDidAppSwitch now true);
3189 // user taps a home icon (coming from home so allowed, we hit here
3190 // and now allow anyone to switch again).
3191 mAppSwitchesAllowedTime = 0;
3192 } else {
3193 mDidAppSwitch = true;
3194 }
3195
3196 doPendingActivityLaunchesLocked(false);
3197
3198 return startActivityUncheckedLocked(r, sourceRecord,
3199 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3200 }
3201
3202 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3203 final int N = mPendingActivityLaunches.size();
3204 if (N <= 0) {
3205 return;
3206 }
3207 for (int i=0; i<N; i++) {
3208 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3209 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3210 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3211 doResume && i == (N-1));
3212 }
3213 mPendingActivityLaunches.clear();
3214 }
3215
3216 private final int startActivityUncheckedLocked(HistoryRecord r,
3217 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3218 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3219 final Intent intent = r.intent;
3220 final int callingUid = r.launchedFromUid;
3221
3222 int launchFlags = intent.getFlags();
3223
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003224 // We'll invoke onUserLeaving before onPause only if the launching
3225 // activity did not explicitly state that this is an automated launch.
3226 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3227 if (DEBUG_USER_LEAVING) Log.v(TAG,
3228 "startActivity() => mUserLeaving=" + mUserLeaving);
3229
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003230 // If the caller has asked not to resume at this point, we make note
3231 // of this in the record so that we can skip it when trying to find
3232 // the top running activity.
3233 if (!doResume) {
3234 r.delayedResume = true;
3235 }
3236
3237 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3238 != 0 ? r : null;
3239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003240 // If the onlyIfNeeded flag is set, then we can do this if the activity
3241 // being launched is the same as the one making the call... or, as
3242 // a special case, if we do not know the caller then we count the
3243 // current top activity as the caller.
3244 if (onlyIfNeeded) {
3245 HistoryRecord checkedCaller = sourceRecord;
3246 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003247 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003248 }
3249 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3250 // Caller is not the same as launcher, so always needed.
3251 onlyIfNeeded = false;
3252 }
3253 }
3254
3255 if (grantedUriPermissions != null && callingUid > 0) {
3256 for (int i=0; i<grantedUriPermissions.length; i++) {
3257 grantUriPermissionLocked(callingUid, r.packageName,
3258 grantedUriPermissions[i], grantedMode, r);
3259 }
3260 }
3261
3262 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3263 intent, r);
3264
3265 if (sourceRecord == null) {
3266 // This activity is not being started from another... in this
3267 // case we -always- start a new task.
3268 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3269 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3270 + intent);
3271 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3272 }
3273 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3274 // The original activity who is starting us is running as a single
3275 // instance... this new activity it is starting must go on its
3276 // own task.
3277 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3278 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3279 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3280 // The activity being started is a single instance... it always
3281 // gets launched into its own task.
3282 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3283 }
3284
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003285 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003286 // For whatever reason this activity is being launched into a new
3287 // task... yet the caller has requested a result back. Well, that
3288 // is pretty messed up, so instead immediately send back a cancel
3289 // and let the new task continue launched as normal without a
3290 // dependency on its originator.
3291 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3292 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003293 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003294 Activity.RESULT_CANCELED, null);
3295 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003296 }
3297
3298 boolean addingToTask = false;
3299 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3300 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3301 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3302 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3303 // If bring to front is requested, and no result is requested, and
3304 // we can find a task that was started with this same
3305 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003306 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003307 // See if there is a task to bring to the front. If this is
3308 // a SINGLE_INSTANCE activity, there can be one and only one
3309 // instance of it in the history, and it is always in its own
3310 // unique task, so we do a special search.
3311 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3312 ? findTaskLocked(intent, r.info)
3313 : findActivityLocked(intent, r.info);
3314 if (taskTop != null) {
3315 if (taskTop.task.intent == null) {
3316 // This task was started because of movement of
3317 // the activity based on affinity... now that we
3318 // are actually launching it, we can assign the
3319 // base intent.
3320 taskTop.task.setIntent(intent, r.info);
3321 }
3322 // If the target task is not in the front, then we need
3323 // to bring it to the front... except... well, with
3324 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3325 // to have the same behavior as if a new instance was
3326 // being started, which means not bringing it to the front
3327 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003328 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003329 if (curTop.task != taskTop.task) {
3330 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3331 boolean callerAtFront = sourceRecord == null
3332 || curTop.task == sourceRecord.task;
3333 if (callerAtFront) {
3334 // We really do want to push this one into the
3335 // user's face, right now.
3336 moveTaskToFrontLocked(taskTop.task);
3337 }
3338 }
3339 // If the caller has requested that the target task be
3340 // reset, then do so.
3341 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3342 taskTop = resetTaskIfNeededLocked(taskTop, r);
3343 }
3344 if (onlyIfNeeded) {
3345 // We don't need to start a new activity, and
3346 // the client said not to do anything if that
3347 // is the case, so this is it! And for paranoia, make
3348 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003349 if (doResume) {
3350 resumeTopActivityLocked(null);
3351 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003352 return START_RETURN_INTENT_TO_CALLER;
3353 }
3354 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3355 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3356 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3357 // In this situation we want to remove all activities
3358 // from the task up to the one being started. In most
3359 // cases this means we are resetting the task to its
3360 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003361 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003362 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003363 if (top != null) {
3364 if (top.frontOfTask) {
3365 // Activity aliases may mean we use different
3366 // intents for the top activity, so make sure
3367 // the task now has the identity of the new
3368 // intent.
3369 top.task.setIntent(r.intent, r.info);
3370 }
3371 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3372 deliverNewIntentLocked(top, r.intent);
3373 } else {
3374 // A special case: we need to
3375 // start the activity because it is not currently
3376 // running, and the caller has asked to clear the
3377 // current task to have this activity at the top.
3378 addingToTask = true;
3379 // Now pretend like this activity is being started
3380 // by the top of its task, so it is put in the
3381 // right place.
3382 sourceRecord = taskTop;
3383 }
3384 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3385 // In this case the top activity on the task is the
3386 // same as the one being launched, so we take that
3387 // as a request to bring the task to the foreground.
3388 // If the top activity in the task is the root
3389 // activity, deliver this new intent to it if it
3390 // desires.
3391 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3392 && taskTop.realActivity.equals(r.realActivity)) {
3393 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3394 if (taskTop.frontOfTask) {
3395 taskTop.task.setIntent(r.intent, r.info);
3396 }
3397 deliverNewIntentLocked(taskTop, r.intent);
3398 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3399 // In this case we are launching the root activity
3400 // of the task, but with a different intent. We
3401 // should start a new instance on top.
3402 addingToTask = true;
3403 sourceRecord = taskTop;
3404 }
3405 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3406 // In this case an activity is being launched in to an
3407 // existing task, without resetting that task. This
3408 // is typically the situation of launching an activity
3409 // from a notification or shortcut. We want to place
3410 // the new activity on top of the current task.
3411 addingToTask = true;
3412 sourceRecord = taskTop;
3413 } else if (!taskTop.task.rootWasReset) {
3414 // In this case we are launching in to an existing task
3415 // that has not yet been started from its front door.
3416 // The current task has been brought to the front.
3417 // Ideally, we'd probably like to place this new task
3418 // at the bottom of its stack, but that's a little hard
3419 // to do with the current organization of the code so
3420 // for now we'll just drop it.
3421 taskTop.task.setIntent(r.intent, r.info);
3422 }
3423 if (!addingToTask) {
3424 // We didn't do anything... but it was needed (a.k.a., client
3425 // don't use that intent!) And for paranoia, make
3426 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003427 if (doResume) {
3428 resumeTopActivityLocked(null);
3429 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003430 return START_TASK_TO_FRONT;
3431 }
3432 }
3433 }
3434 }
3435
3436 //String uri = r.intent.toURI();
3437 //Intent intent2 = new Intent(uri);
3438 //Log.i(TAG, "Given intent: " + r.intent);
3439 //Log.i(TAG, "URI is: " + uri);
3440 //Log.i(TAG, "To intent: " + intent2);
3441
3442 if (r.packageName != null) {
3443 // If the activity being launched is the same as the one currently
3444 // at the top, then we need to check if it should only be launched
3445 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003446 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3447 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003448 if (top.realActivity.equals(r.realActivity)) {
3449 if (top.app != null && top.app.thread != null) {
3450 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3451 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3452 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3453 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3454 // For paranoia, make sure we have correctly
3455 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003456 if (doResume) {
3457 resumeTopActivityLocked(null);
3458 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003459 if (onlyIfNeeded) {
3460 // We don't need to start a new activity, and
3461 // the client said not to do anything if that
3462 // is the case, so this is it!
3463 return START_RETURN_INTENT_TO_CALLER;
3464 }
3465 deliverNewIntentLocked(top, r.intent);
3466 return START_DELIVERED_TO_TOP;
3467 }
3468 }
3469 }
3470 }
3471
3472 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003473 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003474 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003475 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003476 Activity.RESULT_CANCELED, null);
3477 }
3478 return START_CLASS_NOT_FOUND;
3479 }
3480
3481 boolean newTask = false;
3482
3483 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003484 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003485 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3486 // todo: should do better management of integers.
3487 mCurTask++;
3488 if (mCurTask <= 0) {
3489 mCurTask = 1;
3490 }
3491 r.task = new TaskRecord(mCurTask, r.info, intent,
3492 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3493 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3494 + " in new task " + r.task);
3495 newTask = true;
3496 addRecentTask(r.task);
3497
3498 } else if (sourceRecord != null) {
3499 if (!addingToTask &&
3500 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3501 // In this case, we are adding the activity to an existing
3502 // task, but the caller has asked to clear that task if the
3503 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003504 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003505 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003506 if (top != null) {
3507 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3508 deliverNewIntentLocked(top, r.intent);
3509 // For paranoia, make sure we have correctly
3510 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003511 if (doResume) {
3512 resumeTopActivityLocked(null);
3513 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003514 return START_DELIVERED_TO_TOP;
3515 }
3516 } else if (!addingToTask &&
3517 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3518 // In this case, we are launching an activity in our own task
3519 // that may already be running somewhere in the history, and
3520 // we want to shuffle it to the front of the stack if so.
3521 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3522 if (where >= 0) {
3523 HistoryRecord top = moveActivityToFrontLocked(where);
3524 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3525 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003526 if (doResume) {
3527 resumeTopActivityLocked(null);
3528 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003529 return START_DELIVERED_TO_TOP;
3530 }
3531 }
3532 // An existing activity is starting this new activity, so we want
3533 // to keep the new one in the same task as the one that is starting
3534 // it.
3535 r.task = sourceRecord.task;
3536 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3537 + " in existing task " + r.task);
3538
3539 } else {
3540 // This not being started from an existing activity, and not part
3541 // of a new task... just put it in the top task, though these days
3542 // this case should never happen.
3543 final int N = mHistory.size();
3544 HistoryRecord prev =
3545 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3546 r.task = prev != null
3547 ? prev.task
3548 : new TaskRecord(mCurTask, r.info, intent,
3549 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3550 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3551 + " in new guessed " + r.task);
3552 }
3553 if (newTask) {
3554 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3555 }
3556 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003557 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003558 return START_SUCCESS;
3559 }
3560
3561 public final int startActivity(IApplicationThread caller,
3562 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3563 int grantedMode, IBinder resultTo,
3564 String resultWho, int requestCode, boolean onlyIfNeeded,
3565 boolean debug) {
3566 // Refuse possible leaked file descriptors
3567 if (intent != null && intent.hasFileDescriptors()) {
3568 throw new IllegalArgumentException("File descriptors passed in Intent");
3569 }
3570
The Android Open Source Project4df24232009-03-05 14:34:35 -08003571 final boolean componentSpecified = intent.getComponent() != null;
3572
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003573 // Don't modify the client's object!
3574 intent = new Intent(intent);
3575
3576 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003577 ActivityInfo aInfo;
3578 try {
3579 ResolveInfo rInfo =
3580 ActivityThread.getPackageManager().resolveIntent(
3581 intent, resolvedType,
3582 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003583 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003584 aInfo = rInfo != null ? rInfo.activityInfo : null;
3585 } catch (RemoteException e) {
3586 aInfo = null;
3587 }
3588
3589 if (aInfo != null) {
3590 // Store the found target back into the intent, because now that
3591 // we have it we never want to do this again. For example, if the
3592 // user navigates back to this point in the history, we should
3593 // always restart the exact same activity.
3594 intent.setComponent(new ComponentName(
3595 aInfo.applicationInfo.packageName, aInfo.name));
3596
3597 // Don't debug things in the system process
3598 if (debug) {
3599 if (!aInfo.processName.equals("system")) {
3600 setDebugApp(aInfo.processName, true, false);
3601 }
3602 }
3603 }
3604
3605 synchronized(this) {
3606 final long origId = Binder.clearCallingIdentity();
3607 int res = startActivityLocked(caller, intent, resolvedType,
3608 grantedUriPermissions, grantedMode, aInfo,
3609 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003610 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003611 Binder.restoreCallingIdentity(origId);
3612 return res;
3613 }
3614 }
3615
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003616 public int startActivityPendingIntent(IApplicationThread caller,
3617 PendingIntent intent, Intent fillInIntent, String resolvedType,
3618 IBinder resultTo, String resultWho, int requestCode,
3619 int flagsMask, int flagsValues) {
3620 // Refuse possible leaked file descriptors
3621 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3622 throw new IllegalArgumentException("File descriptors passed in Intent");
3623 }
3624
3625 IIntentSender sender = intent.getTarget();
3626 if (!(sender instanceof PendingIntentRecord)) {
3627 throw new IllegalArgumentException("Bad PendingIntent object");
3628 }
3629
3630 PendingIntentRecord pir = (PendingIntentRecord)sender;
3631 if (pir.key.type != IActivityManager.INTENT_SENDER_ACTIVITY) {
3632 return START_NOT_ACTIVITY;
3633 }
3634
3635 return pir.sendInner(0, fillInIntent, resolvedType,
3636 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3637 }
3638
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003639 public boolean startNextMatchingActivity(IBinder callingActivity,
3640 Intent intent) {
3641 // Refuse possible leaked file descriptors
3642 if (intent != null && intent.hasFileDescriptors() == true) {
3643 throw new IllegalArgumentException("File descriptors passed in Intent");
3644 }
3645
3646 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003647 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003648 if (index < 0) {
3649 return false;
3650 }
3651 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3652 if (r.app == null || r.app.thread == null) {
3653 // The caller is not running... d'oh!
3654 return false;
3655 }
3656 intent = new Intent(intent);
3657 // The caller is not allowed to change the data.
3658 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3659 // And we are resetting to find the next component...
3660 intent.setComponent(null);
3661
3662 ActivityInfo aInfo = null;
3663 try {
3664 List<ResolveInfo> resolves =
3665 ActivityThread.getPackageManager().queryIntentActivities(
3666 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003667 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003668
3669 // Look for the original activity in the list...
3670 final int N = resolves != null ? resolves.size() : 0;
3671 for (int i=0; i<N; i++) {
3672 ResolveInfo rInfo = resolves.get(i);
3673 if (rInfo.activityInfo.packageName.equals(r.packageName)
3674 && rInfo.activityInfo.name.equals(r.info.name)) {
3675 // We found the current one... the next matching is
3676 // after it.
3677 i++;
3678 if (i<N) {
3679 aInfo = resolves.get(i).activityInfo;
3680 }
3681 break;
3682 }
3683 }
3684 } catch (RemoteException e) {
3685 }
3686
3687 if (aInfo == null) {
3688 // Nobody who is next!
3689 return false;
3690 }
3691
3692 intent.setComponent(new ComponentName(
3693 aInfo.applicationInfo.packageName, aInfo.name));
3694 intent.setFlags(intent.getFlags()&~(
3695 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3696 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3697 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3698 Intent.FLAG_ACTIVITY_NEW_TASK));
3699
3700 // Okay now we need to start the new activity, replacing the
3701 // currently running activity. This is a little tricky because
3702 // we want to start the new one as if the current one is finished,
3703 // but not finish the current one first so that there is no flicker.
3704 // And thus...
3705 final boolean wasFinishing = r.finishing;
3706 r.finishing = true;
3707
3708 // Propagate reply information over to the new activity.
3709 final HistoryRecord resultTo = r.resultTo;
3710 final String resultWho = r.resultWho;
3711 final int requestCode = r.requestCode;
3712 r.resultTo = null;
3713 if (resultTo != null) {
3714 resultTo.removeResultsLocked(r, resultWho, requestCode);
3715 }
3716
3717 final long origId = Binder.clearCallingIdentity();
3718 // XXX we are not dealing with propagating grantedUriPermissions...
3719 // those are not yet exposed to user code, so there is no need.
3720 int res = startActivityLocked(r.app.thread, intent,
3721 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003722 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003723 Binder.restoreCallingIdentity(origId);
3724
3725 r.finishing = wasFinishing;
3726 if (res != START_SUCCESS) {
3727 return false;
3728 }
3729 return true;
3730 }
3731 }
3732
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003733 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003734 Intent intent, String resolvedType, IBinder resultTo,
3735 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003736
3737 // This is so super not safe, that only the system (or okay root)
3738 // can do it.
3739 final int callingUid = Binder.getCallingUid();
3740 if (callingUid != 0 && callingUid != Process.myUid()) {
3741 throw new SecurityException(
3742 "startActivityInPackage only available to the system");
3743 }
3744
The Android Open Source Project4df24232009-03-05 14:34:35 -08003745 final boolean componentSpecified = intent.getComponent() != null;
3746
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003747 // Don't modify the client's object!
3748 intent = new Intent(intent);
3749
3750 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003751 ActivityInfo aInfo;
3752 try {
3753 ResolveInfo rInfo =
3754 ActivityThread.getPackageManager().resolveIntent(
3755 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003756 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003757 aInfo = rInfo != null ? rInfo.activityInfo : null;
3758 } catch (RemoteException e) {
3759 aInfo = null;
3760 }
3761
3762 if (aInfo != null) {
3763 // Store the found target back into the intent, because now that
3764 // we have it we never want to do this again. For example, if the
3765 // user navigates back to this point in the history, we should
3766 // always restart the exact same activity.
3767 intent.setComponent(new ComponentName(
3768 aInfo.applicationInfo.packageName, aInfo.name));
3769 }
3770
3771 synchronized(this) {
3772 return startActivityLocked(null, intent, resolvedType,
3773 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003774 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003775 }
3776 }
3777
3778 private final void addRecentTask(TaskRecord task) {
3779 // Remove any existing entries that are the same kind of task.
3780 int N = mRecentTasks.size();
3781 for (int i=0; i<N; i++) {
3782 TaskRecord tr = mRecentTasks.get(i);
3783 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3784 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3785 mRecentTasks.remove(i);
3786 i--;
3787 N--;
3788 if (task.intent == null) {
3789 // If the new recent task we are adding is not fully
3790 // specified, then replace it with the existing recent task.
3791 task = tr;
3792 }
3793 }
3794 }
3795 if (N >= MAX_RECENT_TASKS) {
3796 mRecentTasks.remove(N-1);
3797 }
3798 mRecentTasks.add(0, task);
3799 }
3800
3801 public void setRequestedOrientation(IBinder token,
3802 int requestedOrientation) {
3803 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003804 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003805 if (index < 0) {
3806 return;
3807 }
3808 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3809 final long origId = Binder.clearCallingIdentity();
3810 mWindowManager.setAppOrientation(r, requestedOrientation);
3811 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003812 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003813 r.mayFreezeScreenLocked(r.app) ? r : null);
3814 if (config != null) {
3815 r.frozenBeforeDestroy = true;
3816 if (!updateConfigurationLocked(config, r)) {
3817 resumeTopActivityLocked(null);
3818 }
3819 }
3820 Binder.restoreCallingIdentity(origId);
3821 }
3822 }
3823
3824 public int getRequestedOrientation(IBinder token) {
3825 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003826 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003827 if (index < 0) {
3828 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3829 }
3830 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3831 return mWindowManager.getAppOrientation(r);
3832 }
3833 }
3834
3835 private final void stopActivityLocked(HistoryRecord r) {
3836 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3837 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3838 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3839 if (!r.finishing) {
3840 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3841 "no-history");
3842 }
3843 } else if (r.app != null && r.app.thread != null) {
3844 if (mFocusedActivity == r) {
3845 setFocusedActivityLocked(topRunningActivityLocked(null));
3846 }
3847 r.resumeKeyDispatchingLocked();
3848 try {
3849 r.stopped = false;
3850 r.state = ActivityState.STOPPING;
3851 if (DEBUG_VISBILITY) Log.v(
3852 TAG, "Stopping visible=" + r.visible + " for " + r);
3853 if (!r.visible) {
3854 mWindowManager.setAppVisibility(r, false);
3855 }
3856 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3857 } catch (Exception e) {
3858 // Maybe just ignore exceptions here... if the process
3859 // has crashed, our death notification will clean things
3860 // up.
3861 Log.w(TAG, "Exception thrown during pause", e);
3862 // Just in case, assume it to be stopped.
3863 r.stopped = true;
3864 r.state = ActivityState.STOPPED;
3865 if (r.configDestroy) {
3866 destroyActivityLocked(r, true);
3867 }
3868 }
3869 }
3870 }
3871
3872 /**
3873 * @return Returns true if the activity is being finished, false if for
3874 * some reason it is being left as-is.
3875 */
3876 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3877 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003878 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003879 TAG, "Finishing activity: token=" + token
3880 + ", result=" + resultCode + ", data=" + resultData);
3881
Dianne Hackborn75b03852009-06-12 15:43:26 -07003882 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003883 if (index < 0) {
3884 return false;
3885 }
3886 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3887
3888 // Is this the last activity left?
3889 boolean lastActivity = true;
3890 for (int i=mHistory.size()-1; i>=0; i--) {
3891 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3892 if (!p.finishing && p != r) {
3893 lastActivity = false;
3894 break;
3895 }
3896 }
3897
3898 // If this is the last activity, but it is the home activity, then
3899 // just don't finish it.
3900 if (lastActivity) {
3901 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3902 return false;
3903 }
3904 }
3905
3906 finishActivityLocked(r, index, resultCode, resultData, reason);
3907 return true;
3908 }
3909
3910 /**
3911 * @return Returns true if this activity has been removed from the history
3912 * list, or false if it is still in the list and will be removed later.
3913 */
3914 private final boolean finishActivityLocked(HistoryRecord r, int index,
3915 int resultCode, Intent resultData, String reason) {
3916 if (r.finishing) {
3917 Log.w(TAG, "Duplicate finish request for " + r);
3918 return false;
3919 }
3920
3921 r.finishing = true;
3922 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3923 System.identityHashCode(r),
3924 r.task.taskId, r.shortComponentName, reason);
3925 r.task.numActivities--;
3926 if (r.frontOfTask && index < (mHistory.size()-1)) {
3927 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3928 if (next.task == r.task) {
3929 next.frontOfTask = true;
3930 }
3931 }
3932
3933 r.pauseKeyDispatchingLocked();
3934 if (mFocusedActivity == r) {
3935 setFocusedActivityLocked(topRunningActivityLocked(null));
3936 }
3937
3938 // send the result
3939 HistoryRecord resultTo = r.resultTo;
3940 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003941 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3942 + " who=" + r.resultWho + " req=" + r.requestCode
3943 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003944 if (r.info.applicationInfo.uid > 0) {
3945 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3946 r.packageName, resultData, r);
3947 }
3948 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3949 resultData);
3950 r.resultTo = null;
3951 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003952 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003953
3954 // Make sure this HistoryRecord is not holding on to other resources,
3955 // because clients have remote IPC references to this object so we
3956 // can't assume that will go away and want to avoid circular IPC refs.
3957 r.results = null;
3958 r.pendingResults = null;
3959 r.newIntents = null;
3960 r.icicle = null;
3961
3962 if (mPendingThumbnails.size() > 0) {
3963 // There are clients waiting to receive thumbnails so, in case
3964 // this is an activity that someone is waiting for, add it
3965 // to the pending list so we can correctly update the clients.
3966 mCancelledThumbnails.add(r);
3967 }
3968
3969 if (mResumedActivity == r) {
3970 boolean endTask = index <= 0
3971 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3972 if (DEBUG_TRANSITION) Log.v(TAG,
3973 "Prepare close transition: finishing " + r);
3974 mWindowManager.prepareAppTransition(endTask
3975 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3976 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3977
3978 // Tell window manager to prepare for this one to be removed.
3979 mWindowManager.setAppVisibility(r, false);
3980
3981 if (mPausingActivity == null) {
3982 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3983 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3984 startPausingLocked(false, false);
3985 }
3986
3987 } else if (r.state != ActivityState.PAUSING) {
3988 // If the activity is PAUSING, we will complete the finish once
3989 // it is done pausing; else we can just directly finish it here.
3990 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3991 return finishCurrentActivityLocked(r, index,
3992 FINISH_AFTER_PAUSE) == null;
3993 } else {
3994 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3995 }
3996
3997 return false;
3998 }
3999
4000 private static final int FINISH_IMMEDIATELY = 0;
4001 private static final int FINISH_AFTER_PAUSE = 1;
4002 private static final int FINISH_AFTER_VISIBLE = 2;
4003
4004 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4005 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004006 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004007 if (index < 0) {
4008 return null;
4009 }
4010
4011 return finishCurrentActivityLocked(r, index, mode);
4012 }
4013
4014 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4015 int index, int mode) {
4016 // First things first: if this activity is currently visible,
4017 // and the resumed activity is not yet visible, then hold off on
4018 // finishing until the resumed one becomes visible.
4019 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4020 if (!mStoppingActivities.contains(r)) {
4021 mStoppingActivities.add(r);
4022 if (mStoppingActivities.size() > 3) {
4023 // If we already have a few activities waiting to stop,
4024 // then give up on things going idle and start clearing
4025 // them out.
4026 Message msg = Message.obtain();
4027 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4028 mHandler.sendMessage(msg);
4029 }
4030 }
4031 r.state = ActivityState.STOPPING;
4032 updateOomAdjLocked();
4033 return r;
4034 }
4035
4036 // make sure the record is cleaned out of other places.
4037 mStoppingActivities.remove(r);
4038 mWaitingVisibleActivities.remove(r);
4039 if (mResumedActivity == r) {
4040 mResumedActivity = null;
4041 }
4042 final ActivityState prevState = r.state;
4043 r.state = ActivityState.FINISHING;
4044
4045 if (mode == FINISH_IMMEDIATELY
4046 || prevState == ActivityState.STOPPED
4047 || prevState == ActivityState.INITIALIZING) {
4048 // If this activity is already stopped, we can just finish
4049 // it right now.
4050 return destroyActivityLocked(r, true) ? null : r;
4051 } else {
4052 // Need to go through the full pause cycle to get this
4053 // activity into the stopped state and then finish it.
4054 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4055 mFinishingActivities.add(r);
4056 resumeTopActivityLocked(null);
4057 }
4058 return r;
4059 }
4060
4061 /**
4062 * This is the internal entry point for handling Activity.finish().
4063 *
4064 * @param token The Binder token referencing the Activity we want to finish.
4065 * @param resultCode Result code, if any, from this Activity.
4066 * @param resultData Result data (Intent), if any, from this Activity.
4067 *
4068 * @result Returns true if the activity successfully finished, or false if it is still running.
4069 */
4070 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4071 // Refuse possible leaked file descriptors
4072 if (resultData != null && resultData.hasFileDescriptors() == true) {
4073 throw new IllegalArgumentException("File descriptors passed in Intent");
4074 }
4075
4076 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004077 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004078 // Find the first activity that is not finishing.
4079 HistoryRecord next = topRunningActivityLocked(token, 0);
4080 if (next != null) {
4081 // ask watcher if this is allowed
4082 boolean resumeOK = true;
4083 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004084 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004085 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004086 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004087 }
4088
4089 if (!resumeOK) {
4090 return false;
4091 }
4092 }
4093 }
4094 final long origId = Binder.clearCallingIdentity();
4095 boolean res = requestFinishActivityLocked(token, resultCode,
4096 resultData, "app-request");
4097 Binder.restoreCallingIdentity(origId);
4098 return res;
4099 }
4100 }
4101
4102 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4103 String resultWho, int requestCode, int resultCode, Intent data) {
4104
4105 if (callingUid > 0) {
4106 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4107 data, r);
4108 }
4109
The Android Open Source Project10592532009-03-18 17:39:46 -07004110 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4111 + " : who=" + resultWho + " req=" + requestCode
4112 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004113 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4114 try {
4115 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4116 list.add(new ResultInfo(resultWho, requestCode,
4117 resultCode, data));
4118 r.app.thread.scheduleSendResult(r, list);
4119 return;
4120 } catch (Exception e) {
4121 Log.w(TAG, "Exception thrown sending result to " + r, e);
4122 }
4123 }
4124
4125 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4126 }
4127
4128 public final void finishSubActivity(IBinder token, String resultWho,
4129 int requestCode) {
4130 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004131 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004132 if (index < 0) {
4133 return;
4134 }
4135 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4136
4137 final long origId = Binder.clearCallingIdentity();
4138
4139 int i;
4140 for (i=mHistory.size()-1; i>=0; i--) {
4141 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4142 if (r.resultTo == self && r.requestCode == requestCode) {
4143 if ((r.resultWho == null && resultWho == null) ||
4144 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4145 finishActivityLocked(r, i,
4146 Activity.RESULT_CANCELED, null, "request-sub");
4147 }
4148 }
4149 }
4150
4151 Binder.restoreCallingIdentity(origId);
4152 }
4153 }
4154
4155 /**
4156 * Perform clean-up of service connections in an activity record.
4157 */
4158 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4159 // Throw away any services that have been bound by this activity.
4160 if (r.connections != null) {
4161 Iterator<ConnectionRecord> it = r.connections.iterator();
4162 while (it.hasNext()) {
4163 ConnectionRecord c = it.next();
4164 removeConnectionLocked(c, null, r);
4165 }
4166 r.connections = null;
4167 }
4168 }
4169
4170 /**
4171 * Perform the common clean-up of an activity record. This is called both
4172 * as part of destroyActivityLocked() (when destroying the client-side
4173 * representation) and cleaning things up as a result of its hosting
4174 * processing going away, in which case there is no remaining client-side
4175 * state to destroy so only the cleanup here is needed.
4176 */
4177 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4178 if (mResumedActivity == r) {
4179 mResumedActivity = null;
4180 }
4181 if (mFocusedActivity == r) {
4182 mFocusedActivity = null;
4183 }
4184
4185 r.configDestroy = false;
4186 r.frozenBeforeDestroy = false;
4187
4188 // Make sure this record is no longer in the pending finishes list.
4189 // This could happen, for example, if we are trimming activities
4190 // down to the max limit while they are still waiting to finish.
4191 mFinishingActivities.remove(r);
4192 mWaitingVisibleActivities.remove(r);
4193
4194 // Remove any pending results.
4195 if (r.finishing && r.pendingResults != null) {
4196 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4197 PendingIntentRecord rec = apr.get();
4198 if (rec != null) {
4199 cancelIntentSenderLocked(rec, false);
4200 }
4201 }
4202 r.pendingResults = null;
4203 }
4204
4205 if (cleanServices) {
4206 cleanUpActivityServicesLocked(r);
4207 }
4208
4209 if (mPendingThumbnails.size() > 0) {
4210 // There are clients waiting to receive thumbnails so, in case
4211 // this is an activity that someone is waiting for, add it
4212 // to the pending list so we can correctly update the clients.
4213 mCancelledThumbnails.add(r);
4214 }
4215
4216 // Get rid of any pending idle timeouts.
4217 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4218 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4219 }
4220
4221 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4222 if (r.state != ActivityState.DESTROYED) {
4223 mHistory.remove(r);
4224 r.inHistory = false;
4225 r.state = ActivityState.DESTROYED;
4226 mWindowManager.removeAppToken(r);
4227 if (VALIDATE_TOKENS) {
4228 mWindowManager.validateAppTokens(mHistory);
4229 }
4230 cleanUpActivityServicesLocked(r);
4231 removeActivityUriPermissionsLocked(r);
4232 }
4233 }
4234
4235 /**
4236 * Destroy the current CLIENT SIDE instance of an activity. This may be
4237 * called both when actually finishing an activity, or when performing
4238 * a configuration switch where we destroy the current client-side object
4239 * but then create a new client-side object for this same HistoryRecord.
4240 */
4241 private final boolean destroyActivityLocked(HistoryRecord r,
4242 boolean removeFromApp) {
4243 if (DEBUG_SWITCH) Log.v(
4244 TAG, "Removing activity: token=" + r
4245 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4246 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4247 System.identityHashCode(r),
4248 r.task.taskId, r.shortComponentName);
4249
4250 boolean removedFromHistory = false;
4251
4252 cleanUpActivityLocked(r, false);
4253
4254 if (r.app != null) {
4255 if (removeFromApp) {
4256 int idx = r.app.activities.indexOf(r);
4257 if (idx >= 0) {
4258 r.app.activities.remove(idx);
4259 }
4260 if (r.persistent) {
4261 decPersistentCountLocked(r.app);
4262 }
4263 }
4264
4265 boolean skipDestroy = false;
4266
4267 try {
4268 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4269 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4270 r.configChangeFlags);
4271 } catch (Exception e) {
4272 // We can just ignore exceptions here... if the process
4273 // has crashed, our death notification will clean things
4274 // up.
4275 //Log.w(TAG, "Exception thrown during finish", e);
4276 if (r.finishing) {
4277 removeActivityFromHistoryLocked(r);
4278 removedFromHistory = true;
4279 skipDestroy = true;
4280 }
4281 }
4282
4283 r.app = null;
4284 r.nowVisible = false;
4285
4286 if (r.finishing && !skipDestroy) {
4287 r.state = ActivityState.DESTROYING;
4288 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4289 msg.obj = r;
4290 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4291 } else {
4292 r.state = ActivityState.DESTROYED;
4293 }
4294 } else {
4295 // remove this record from the history.
4296 if (r.finishing) {
4297 removeActivityFromHistoryLocked(r);
4298 removedFromHistory = true;
4299 } else {
4300 r.state = ActivityState.DESTROYED;
4301 }
4302 }
4303
4304 r.configChangeFlags = 0;
4305
4306 if (!mLRUActivities.remove(r)) {
4307 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4308 }
4309
4310 return removedFromHistory;
4311 }
4312
4313 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4314 ProcessRecord app)
4315 {
4316 int i = list.size();
4317 if (localLOGV) Log.v(
4318 TAG, "Removing app " + app + " from list " + list
4319 + " with " + i + " entries");
4320 while (i > 0) {
4321 i--;
4322 HistoryRecord r = (HistoryRecord)list.get(i);
4323 if (localLOGV) Log.v(
4324 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4325 if (r.app == app) {
4326 if (localLOGV) Log.v(TAG, "Removing this entry!");
4327 list.remove(i);
4328 }
4329 }
4330 }
4331
4332 /**
4333 * Main function for removing an existing process from the activity manager
4334 * as a result of that process going away. Clears out all connections
4335 * to the process.
4336 */
4337 private final void handleAppDiedLocked(ProcessRecord app,
4338 boolean restarting) {
4339 cleanUpApplicationRecordLocked(app, restarting, -1);
4340 if (!restarting) {
4341 mLRUProcesses.remove(app);
4342 }
4343
4344 // Just in case...
4345 if (mPausingActivity != null && mPausingActivity.app == app) {
4346 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4347 mPausingActivity = null;
4348 }
4349 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4350 mLastPausedActivity = null;
4351 }
4352
4353 // Remove this application's activities from active lists.
4354 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4355 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4356 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4357 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4358
4359 boolean atTop = true;
4360 boolean hasVisibleActivities = false;
4361
4362 // Clean out the history list.
4363 int i = mHistory.size();
4364 if (localLOGV) Log.v(
4365 TAG, "Removing app " + app + " from history with " + i + " entries");
4366 while (i > 0) {
4367 i--;
4368 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4369 if (localLOGV) Log.v(
4370 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4371 if (r.app == app) {
4372 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4373 if (localLOGV) Log.v(
4374 TAG, "Removing this entry! frozen=" + r.haveState
4375 + " finishing=" + r.finishing);
4376 mHistory.remove(i);
4377
4378 r.inHistory = false;
4379 mWindowManager.removeAppToken(r);
4380 if (VALIDATE_TOKENS) {
4381 mWindowManager.validateAppTokens(mHistory);
4382 }
4383 removeActivityUriPermissionsLocked(r);
4384
4385 } else {
4386 // We have the current state for this activity, so
4387 // it can be restarted later when needed.
4388 if (localLOGV) Log.v(
4389 TAG, "Keeping entry, setting app to null");
4390 if (r.visible) {
4391 hasVisibleActivities = true;
4392 }
4393 r.app = null;
4394 r.nowVisible = false;
4395 if (!r.haveState) {
4396 r.icicle = null;
4397 }
4398 }
4399
4400 cleanUpActivityLocked(r, true);
4401 r.state = ActivityState.STOPPED;
4402 }
4403 atTop = false;
4404 }
4405
4406 app.activities.clear();
4407
4408 if (app.instrumentationClass != null) {
4409 Log.w(TAG, "Crash of app " + app.processName
4410 + " running instrumentation " + app.instrumentationClass);
4411 Bundle info = new Bundle();
4412 info.putString("shortMsg", "Process crashed.");
4413 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4414 }
4415
4416 if (!restarting) {
4417 if (!resumeTopActivityLocked(null)) {
4418 // If there was nothing to resume, and we are not already
4419 // restarting this process, but there is a visible activity that
4420 // is hosted by the process... then make sure all visible
4421 // activities are running, taking care of restarting this
4422 // process.
4423 if (hasVisibleActivities) {
4424 ensureActivitiesVisibleLocked(null, 0);
4425 }
4426 }
4427 }
4428 }
4429
4430 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4431 IBinder threadBinder = thread.asBinder();
4432
4433 // Find the application record.
4434 int count = mLRUProcesses.size();
4435 int i;
4436 for (i=0; i<count; i++) {
4437 ProcessRecord rec = mLRUProcesses.get(i);
4438 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4439 return i;
4440 }
4441 }
4442 return -1;
4443 }
4444
4445 private final ProcessRecord getRecordForAppLocked(
4446 IApplicationThread thread) {
4447 if (thread == null) {
4448 return null;
4449 }
4450
4451 int appIndex = getLRURecordIndexForAppLocked(thread);
4452 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4453 }
4454
4455 private final void appDiedLocked(ProcessRecord app, int pid,
4456 IApplicationThread thread) {
4457
4458 mProcDeaths[0]++;
4459
4460 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4461 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4462 + ") has died.");
4463 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4464 if (localLOGV) Log.v(
4465 TAG, "Dying app: " + app + ", pid: " + pid
4466 + ", thread: " + thread.asBinder());
4467 boolean doLowMem = app.instrumentationClass == null;
4468 handleAppDiedLocked(app, false);
4469
4470 if (doLowMem) {
4471 // If there are no longer any background processes running,
4472 // and the app that died was not running instrumentation,
4473 // then tell everyone we are now low on memory.
4474 boolean haveBg = false;
4475 int count = mLRUProcesses.size();
4476 int i;
4477 for (i=0; i<count; i++) {
4478 ProcessRecord rec = mLRUProcesses.get(i);
4479 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4480 haveBg = true;
4481 break;
4482 }
4483 }
4484
4485 if (!haveBg) {
4486 Log.i(TAG, "Low Memory: No more background processes.");
4487 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004488 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004489 for (i=0; i<count; i++) {
4490 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004491 if (rec.thread != null &&
4492 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4493 // The low memory report is overriding any current
4494 // state for a GC request. Make sure to do
4495 // visible/foreground processes first.
4496 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4497 rec.lastRequestedGc = 0;
4498 } else {
4499 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004500 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004501 rec.reportLowMemory = true;
4502 rec.lastLowMemory = now;
4503 mProcessesToGc.remove(rec);
4504 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004505 }
4506 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004507 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004508 }
4509 }
4510 } else if (Config.LOGD) {
4511 Log.d(TAG, "Received spurious death notification for thread "
4512 + thread.asBinder());
4513 }
4514 }
4515
4516 final String readFile(String filename) {
4517 try {
4518 FileInputStream fs = new FileInputStream(filename);
4519 byte[] inp = new byte[8192];
4520 int size = fs.read(inp);
4521 fs.close();
4522 return new String(inp, 0, 0, size);
4523 } catch (java.io.IOException e) {
4524 }
4525 return "";
4526 }
4527
4528 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004529 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004530 if (app.notResponding || app.crashing) {
4531 return;
4532 }
4533
4534 // Log the ANR to the event log.
4535 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4536
4537 // If we are on a secure build and the application is not interesting to the user (it is
4538 // not visible or in the background), just kill it instead of displaying a dialog.
4539 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4540 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4541 Process.killProcess(app.pid);
4542 return;
4543 }
4544
4545 // DeviceMonitor.start();
4546
4547 String processInfo = null;
4548 if (MONITOR_CPU_USAGE) {
4549 updateCpuStatsNow();
4550 synchronized (mProcessStatsThread) {
4551 processInfo = mProcessStats.printCurrentState();
4552 }
4553 }
4554
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004555 StringBuilder info = mStringBuilder;
4556 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004557 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004558 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004559 if (reportedActivity != null && reportedActivity.app != null) {
4560 info.append(" (last in ");
4561 info.append(reportedActivity.app.processName);
4562 info.append(")");
4563 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004564 if (annotation != null) {
4565 info.append("\nAnnotation: ");
4566 info.append(annotation);
4567 }
4568 if (MONITOR_CPU_USAGE) {
4569 info.append("\nCPU usage:\n");
4570 info.append(processInfo);
4571 }
4572 Log.i(TAG, info.toString());
4573
4574 // The application is not responding. Dump as many thread traces as we can.
4575 boolean fileDump = prepareTraceFile(true);
4576 if (!fileDump) {
4577 // Dumping traces to the log, just dump the process that isn't responding so
4578 // we don't overflow the log
4579 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4580 } else {
4581 // Dumping traces to a file so dump all active processes we know about
4582 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004583 // First, these are the most important processes.
4584 final int[] imppids = new int[3];
4585 int i=0;
4586 imppids[0] = app.pid;
4587 i++;
4588 if (reportedActivity != null && reportedActivity.app != null
4589 && reportedActivity.app.thread != null
4590 && reportedActivity.app.pid != app.pid) {
4591 imppids[i] = reportedActivity.app.pid;
4592 i++;
4593 }
4594 imppids[i] = Process.myPid();
4595 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4596 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4597 synchronized (this) {
4598 try {
4599 wait(200);
4600 } catch (InterruptedException e) {
4601 }
4602 }
4603 }
4604 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004605 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004606 boolean done = false;
4607 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4608 if (imppids[j] == r.pid) {
4609 done = true;
4610 break;
4611 }
4612 }
4613 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004614 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004615 synchronized (this) {
4616 try {
4617 wait(200);
4618 } catch (InterruptedException e) {
4619 }
4620 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004621 }
4622 }
4623 }
4624 }
4625
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004626 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004627 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004628 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004629 app.pid, info.toString());
4630 if (res != 0) {
4631 if (res < 0) {
4632 // wait until the SIGQUIT has had a chance to process before killing the
4633 // process.
4634 try {
4635 wait(2000);
4636 } catch (InterruptedException e) {
4637 }
4638
4639 Process.killProcess(app.pid);
4640 return;
4641 }
4642 }
4643 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004644 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004645 }
4646 }
4647
4648 makeAppNotRespondingLocked(app,
4649 activity != null ? activity.shortComponentName : null,
4650 annotation != null ? "ANR " + annotation : "ANR",
4651 info.toString(), null);
4652 Message msg = Message.obtain();
4653 HashMap map = new HashMap();
4654 msg.what = SHOW_NOT_RESPONDING_MSG;
4655 msg.obj = map;
4656 map.put("app", app);
4657 if (activity != null) {
4658 map.put("activity", activity);
4659 }
4660
4661 mHandler.sendMessage(msg);
4662 return;
4663 }
4664
4665 /**
4666 * If a stack trace file has been configured, prepare the filesystem
4667 * by creating the directory if it doesn't exist and optionally
4668 * removing the old trace file.
4669 *
4670 * @param removeExisting If set, the existing trace file will be removed.
4671 * @return Returns true if the trace file preparations succeeded
4672 */
4673 public static boolean prepareTraceFile(boolean removeExisting) {
4674 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4675 boolean fileReady = false;
4676 if (!TextUtils.isEmpty(tracesPath)) {
4677 File f = new File(tracesPath);
4678 if (!f.exists()) {
4679 // Ensure the enclosing directory exists
4680 File dir = f.getParentFile();
4681 if (!dir.exists()) {
4682 fileReady = dir.mkdirs();
4683 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004684 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004685 } else if (dir.isDirectory()) {
4686 fileReady = true;
4687 }
4688 } else if (removeExisting) {
4689 // Remove the previous traces file, so we don't fill the disk.
4690 // The VM will recreate it
4691 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4692 fileReady = f.delete();
4693 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004694
4695 if (removeExisting) {
4696 try {
4697 f.createNewFile();
4698 FileUtils.setPermissions(f.getAbsolutePath(),
4699 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4700 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4701 fileReady = true;
4702 } catch (IOException e) {
4703 Log.w(TAG, "Unable to make ANR traces file", e);
4704 }
4705 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004706 }
4707
4708 return fileReady;
4709 }
4710
4711
4712 private final void decPersistentCountLocked(ProcessRecord app)
4713 {
4714 app.persistentActivities--;
4715 if (app.persistentActivities > 0) {
4716 // Still more of 'em...
4717 return;
4718 }
4719 if (app.persistent) {
4720 // Ah, but the application itself is persistent. Whatever!
4721 return;
4722 }
4723
4724 // App is no longer persistent... make sure it and the ones
4725 // following it in the LRU list have the correc oom_adj.
4726 updateOomAdjLocked();
4727 }
4728
4729 public void setPersistent(IBinder token, boolean isPersistent) {
4730 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4731 != PackageManager.PERMISSION_GRANTED) {
4732 String msg = "Permission Denial: setPersistent() from pid="
4733 + Binder.getCallingPid()
4734 + ", uid=" + Binder.getCallingUid()
4735 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4736 Log.w(TAG, msg);
4737 throw new SecurityException(msg);
4738 }
4739
4740 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004741 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004742 if (index < 0) {
4743 return;
4744 }
4745 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4746 ProcessRecord app = r.app;
4747
4748 if (localLOGV) Log.v(
4749 TAG, "Setting persistence " + isPersistent + ": " + r);
4750
4751 if (isPersistent) {
4752 if (r.persistent) {
4753 // Okay okay, I heard you already!
4754 if (localLOGV) Log.v(TAG, "Already persistent!");
4755 return;
4756 }
4757 r.persistent = true;
4758 app.persistentActivities++;
4759 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4760 if (app.persistentActivities > 1) {
4761 // We aren't the first...
4762 if (localLOGV) Log.v(TAG, "Not the first!");
4763 return;
4764 }
4765 if (app.persistent) {
4766 // This would be redundant.
4767 if (localLOGV) Log.v(TAG, "App is persistent!");
4768 return;
4769 }
4770
4771 // App is now persistent... make sure it and the ones
4772 // following it now have the correct oom_adj.
4773 final long origId = Binder.clearCallingIdentity();
4774 updateOomAdjLocked();
4775 Binder.restoreCallingIdentity(origId);
4776
4777 } else {
4778 if (!r.persistent) {
4779 // Okay okay, I heard you already!
4780 return;
4781 }
4782 r.persistent = false;
4783 final long origId = Binder.clearCallingIdentity();
4784 decPersistentCountLocked(app);
4785 Binder.restoreCallingIdentity(origId);
4786
4787 }
4788 }
4789 }
4790
4791 public boolean clearApplicationUserData(final String packageName,
4792 final IPackageDataObserver observer) {
4793 int uid = Binder.getCallingUid();
4794 int pid = Binder.getCallingPid();
4795 long callingId = Binder.clearCallingIdentity();
4796 try {
4797 IPackageManager pm = ActivityThread.getPackageManager();
4798 int pkgUid = -1;
4799 synchronized(this) {
4800 try {
4801 pkgUid = pm.getPackageUid(packageName);
4802 } catch (RemoteException e) {
4803 }
4804 if (pkgUid == -1) {
4805 Log.w(TAG, "Invalid packageName:" + packageName);
4806 return false;
4807 }
4808 if (uid == pkgUid || checkComponentPermission(
4809 android.Manifest.permission.CLEAR_APP_USER_DATA,
4810 pid, uid, -1)
4811 == PackageManager.PERMISSION_GRANTED) {
4812 restartPackageLocked(packageName, pkgUid);
4813 } else {
4814 throw new SecurityException(pid+" does not have permission:"+
4815 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4816 "for process:"+packageName);
4817 }
4818 }
4819
4820 try {
4821 //clear application user data
4822 pm.clearApplicationUserData(packageName, observer);
4823 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4824 Uri.fromParts("package", packageName, null));
4825 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4826 broadcastIntentLocked(null, null, intent,
4827 null, null, 0, null, null, null,
4828 false, false, MY_PID, Process.SYSTEM_UID);
4829 } catch (RemoteException e) {
4830 }
4831 } finally {
4832 Binder.restoreCallingIdentity(callingId);
4833 }
4834 return true;
4835 }
4836
4837 public void restartPackage(final String packageName) {
4838 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4839 != PackageManager.PERMISSION_GRANTED) {
4840 String msg = "Permission Denial: restartPackage() from pid="
4841 + Binder.getCallingPid()
4842 + ", uid=" + Binder.getCallingUid()
4843 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4844 Log.w(TAG, msg);
4845 throw new SecurityException(msg);
4846 }
4847
4848 long callingId = Binder.clearCallingIdentity();
4849 try {
4850 IPackageManager pm = ActivityThread.getPackageManager();
4851 int pkgUid = -1;
4852 synchronized(this) {
4853 try {
4854 pkgUid = pm.getPackageUid(packageName);
4855 } catch (RemoteException e) {
4856 }
4857 if (pkgUid == -1) {
4858 Log.w(TAG, "Invalid packageName: " + packageName);
4859 return;
4860 }
4861 restartPackageLocked(packageName, pkgUid);
4862 }
4863 } finally {
4864 Binder.restoreCallingIdentity(callingId);
4865 }
4866 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004867
4868 /*
4869 * The pkg name and uid have to be specified.
4870 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4871 */
4872 public void killApplicationWithUid(String pkg, int uid) {
4873 if (pkg == null) {
4874 return;
4875 }
4876 // Make sure the uid is valid.
4877 if (uid < 0) {
4878 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4879 return;
4880 }
4881 int callerUid = Binder.getCallingUid();
4882 // Only the system server can kill an application
4883 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004884 // Post an aysnc message to kill the application
4885 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4886 msg.arg1 = uid;
4887 msg.arg2 = 0;
4888 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004889 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004890 } else {
4891 throw new SecurityException(callerUid + " cannot kill pkg: " +
4892 pkg);
4893 }
4894 }
4895
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004896 public void closeSystemDialogs(String reason) {
4897 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4898 if (reason != null) {
4899 intent.putExtra("reason", reason);
4900 }
4901
4902 final int uid = Binder.getCallingUid();
4903 final long origId = Binder.clearCallingIdentity();
4904 synchronized (this) {
4905 int i = mWatchers.beginBroadcast();
4906 while (i > 0) {
4907 i--;
4908 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4909 if (w != null) {
4910 try {
4911 w.closingSystemDialogs(reason);
4912 } catch (RemoteException e) {
4913 }
4914 }
4915 }
4916 mWatchers.finishBroadcast();
4917
4918 broadcastIntentLocked(null, null, intent, null,
4919 null, 0, null, null, null, false, false, -1, uid);
4920 }
4921 Binder.restoreCallingIdentity(origId);
4922 }
4923
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004924 public void getProcessMemoryInfo(int pid, Debug.MemoryInfo mi)
4925 throws RemoteException {
4926 ProcessRecord proc;
4927 synchronized (mPidsSelfLocked) {
4928 proc = mPidsSelfLocked.get(pid);
4929 }
4930
4931 if (proc == null) {
4932 throw new RemoteException();
4933 }
4934
4935 IApplicationThread thread = proc.thread;
4936 if (thread == null) {
4937 throw new RemoteException();
4938 }
4939
4940 thread.getMemoryInfo(mi);
4941 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07004942
4943 public void killApplicationProcess(String processName, int uid) {
4944 if (processName == null) {
4945 return;
4946 }
4947
4948 int callerUid = Binder.getCallingUid();
4949 // Only the system server can kill an application
4950 if (callerUid == Process.SYSTEM_UID) {
4951 synchronized (this) {
4952 ProcessRecord app = getProcessRecordLocked(processName, uid);
4953 if (app != null) {
4954 try {
4955 app.thread.scheduleSuicide();
4956 } catch (RemoteException e) {
4957 // If the other end already died, then our work here is done.
4958 }
4959 } else {
4960 Log.w(TAG, "Process/uid not found attempting kill of "
4961 + processName + " / " + uid);
4962 }
4963 }
4964 } else {
4965 throw new SecurityException(callerUid + " cannot kill app process: " +
4966 processName);
4967 }
4968 }
4969
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004970 private void restartPackageLocked(final String packageName, int uid) {
4971 uninstallPackageLocked(packageName, uid, false);
4972 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4973 Uri.fromParts("package", packageName, null));
4974 intent.putExtra(Intent.EXTRA_UID, uid);
4975 broadcastIntentLocked(null, null, intent,
4976 null, null, 0, null, null, null,
4977 false, false, MY_PID, Process.SYSTEM_UID);
4978 }
4979
4980 private final void uninstallPackageLocked(String name, int uid,
4981 boolean callerWillRestart) {
4982 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4983
4984 int i, N;
4985
4986 final String procNamePrefix = name + ":";
4987 if (uid < 0) {
4988 try {
4989 uid = ActivityThread.getPackageManager().getPackageUid(name);
4990 } catch (RemoteException e) {
4991 }
4992 }
4993
4994 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4995 while (badApps.hasNext()) {
4996 SparseArray<Long> ba = badApps.next();
4997 if (ba.get(uid) != null) {
4998 badApps.remove();
4999 }
5000 }
5001
5002 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
5003
5004 // Remove all processes this package may have touched: all with the
5005 // same UID (except for the system or root user), and all whose name
5006 // matches the package name.
5007 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5008 final int NA = apps.size();
5009 for (int ia=0; ia<NA; ia++) {
5010 ProcessRecord app = apps.valueAt(ia);
5011 if (app.removed) {
5012 procs.add(app);
5013 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5014 || app.processName.equals(name)
5015 || app.processName.startsWith(procNamePrefix)) {
5016 app.removed = true;
5017 procs.add(app);
5018 }
5019 }
5020 }
5021
5022 N = procs.size();
5023 for (i=0; i<N; i++) {
5024 removeProcessLocked(procs.get(i), callerWillRestart);
5025 }
5026
5027 for (i=mHistory.size()-1; i>=0; i--) {
5028 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5029 if (r.packageName.equals(name)) {
5030 if (Config.LOGD) Log.d(
5031 TAG, " Force finishing activity "
5032 + r.intent.getComponent().flattenToShortString());
5033 if (r.app != null) {
5034 r.app.removed = true;
5035 }
5036 r.app = null;
5037 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5038 }
5039 }
5040
5041 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5042 for (ServiceRecord service : mServices.values()) {
5043 if (service.packageName.equals(name)) {
5044 if (service.app != null) {
5045 service.app.removed = true;
5046 }
5047 service.app = null;
5048 services.add(service);
5049 }
5050 }
5051
5052 N = services.size();
5053 for (i=0; i<N; i++) {
5054 bringDownServiceLocked(services.get(i), true);
5055 }
5056
5057 resumeTopActivityLocked(null);
5058 }
5059
5060 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5061 final String name = app.processName;
5062 final int uid = app.info.uid;
5063 if (Config.LOGD) Log.d(
5064 TAG, "Force removing process " + app + " (" + name
5065 + "/" + uid + ")");
5066
5067 mProcessNames.remove(name, uid);
5068 boolean needRestart = false;
5069 if (app.pid > 0 && app.pid != MY_PID) {
5070 int pid = app.pid;
5071 synchronized (mPidsSelfLocked) {
5072 mPidsSelfLocked.remove(pid);
5073 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5074 }
5075 handleAppDiedLocked(app, true);
5076 mLRUProcesses.remove(app);
5077 Process.killProcess(pid);
5078
5079 if (app.persistent) {
5080 if (!callerWillRestart) {
5081 addAppLocked(app.info);
5082 } else {
5083 needRestart = true;
5084 }
5085 }
5086 } else {
5087 mRemovedProcesses.add(app);
5088 }
5089
5090 return needRestart;
5091 }
5092
5093 private final void processStartTimedOutLocked(ProcessRecord app) {
5094 final int pid = app.pid;
5095 boolean gone = false;
5096 synchronized (mPidsSelfLocked) {
5097 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5098 if (knownApp != null && knownApp.thread == null) {
5099 mPidsSelfLocked.remove(pid);
5100 gone = true;
5101 }
5102 }
5103
5104 if (gone) {
5105 Log.w(TAG, "Process " + app + " failed to attach");
5106 mProcessNames.remove(app.processName, app.info.uid);
5107 Process.killProcess(pid);
5108 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5109 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5110 mPendingBroadcast = null;
5111 scheduleBroadcastsLocked();
5112 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005113 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5114 Log.w(TAG, "Unattached app died before backup, skipping");
5115 try {
5116 IBackupManager bm = IBackupManager.Stub.asInterface(
5117 ServiceManager.getService(Context.BACKUP_SERVICE));
5118 bm.agentDisconnected(app.info.packageName);
5119 } catch (RemoteException e) {
5120 // Can't happen; the backup manager is local
5121 }
5122 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005123 } else {
5124 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5125 }
5126 }
5127
5128 private final boolean attachApplicationLocked(IApplicationThread thread,
5129 int pid) {
5130
5131 // Find the application record that is being attached... either via
5132 // the pid if we are running in multiple processes, or just pull the
5133 // next app record if we are emulating process with anonymous threads.
5134 ProcessRecord app;
5135 if (pid != MY_PID && pid >= 0) {
5136 synchronized (mPidsSelfLocked) {
5137 app = mPidsSelfLocked.get(pid);
5138 }
5139 } else if (mStartingProcesses.size() > 0) {
5140 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005141 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005142 } else {
5143 app = null;
5144 }
5145
5146 if (app == null) {
5147 Log.w(TAG, "No pending application record for pid " + pid
5148 + " (IApplicationThread " + thread + "); dropping process");
5149 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5150 if (pid > 0 && pid != MY_PID) {
5151 Process.killProcess(pid);
5152 } else {
5153 try {
5154 thread.scheduleExit();
5155 } catch (Exception e) {
5156 // Ignore exceptions.
5157 }
5158 }
5159 return false;
5160 }
5161
5162 // If this application record is still attached to a previous
5163 // process, clean it up now.
5164 if (app.thread != null) {
5165 handleAppDiedLocked(app, true);
5166 }
5167
5168 // Tell the process all about itself.
5169
5170 if (localLOGV) Log.v(
5171 TAG, "Binding process pid " + pid + " to record " + app);
5172
5173 String processName = app.processName;
5174 try {
5175 thread.asBinder().linkToDeath(new AppDeathRecipient(
5176 app, pid, thread), 0);
5177 } catch (RemoteException e) {
5178 app.resetPackageList();
5179 startProcessLocked(app, "link fail", processName);
5180 return false;
5181 }
5182
5183 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5184
5185 app.thread = thread;
5186 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005187 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005188 app.forcingToForeground = null;
5189 app.foregroundServices = false;
5190 app.debugging = false;
5191
5192 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5193
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005194 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5195 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005196
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005197 if (!normalMode) {
5198 Log.i(TAG, "Launching preboot mode app: " + app);
5199 }
5200
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005201 if (localLOGV) Log.v(
5202 TAG, "New app record " + app
5203 + " thread=" + thread.asBinder() + " pid=" + pid);
5204 try {
5205 int testMode = IApplicationThread.DEBUG_OFF;
5206 if (mDebugApp != null && mDebugApp.equals(processName)) {
5207 testMode = mWaitForDebugger
5208 ? IApplicationThread.DEBUG_WAIT
5209 : IApplicationThread.DEBUG_ON;
5210 app.debugging = true;
5211 if (mDebugTransient) {
5212 mDebugApp = mOrigDebugApp;
5213 mWaitForDebugger = mOrigWaitForDebugger;
5214 }
5215 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005216
Christopher Tate181fafa2009-05-14 11:12:14 -07005217 // If the app is being launched for restore or full backup, set it up specially
5218 boolean isRestrictedBackupMode = false;
5219 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5220 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5221 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5222 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005223
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005224 ensurePackageDexOpt(app.instrumentationInfo != null
5225 ? app.instrumentationInfo.packageName
5226 : app.info.packageName);
5227 if (app.instrumentationClass != null) {
5228 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005229 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07005230 thread.bindApplication(processName, app.instrumentationInfo != null
5231 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005232 app.instrumentationClass, app.instrumentationProfileFile,
5233 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005234 isRestrictedBackupMode || !normalMode,
5235 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005236 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005237 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005238 } catch (Exception e) {
5239 // todo: Yikes! What should we do? For now we will try to
5240 // start another process, but that could easily get us in
5241 // an infinite loop of restarting processes...
5242 Log.w(TAG, "Exception thrown during bind!", e);
5243
5244 app.resetPackageList();
5245 startProcessLocked(app, "bind fail", processName);
5246 return false;
5247 }
5248
5249 // Remove this record from the list of starting applications.
5250 mPersistentStartingProcesses.remove(app);
5251 mProcessesOnHold.remove(app);
5252
5253 boolean badApp = false;
5254 boolean didSomething = false;
5255
5256 // See if the top visible activity is waiting to run in this process...
5257 HistoryRecord hr = topRunningActivityLocked(null);
5258 if (hr != null) {
5259 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5260 && processName.equals(hr.processName)) {
5261 try {
5262 if (realStartActivityLocked(hr, app, true, true)) {
5263 didSomething = true;
5264 }
5265 } catch (Exception e) {
5266 Log.w(TAG, "Exception in new application when starting activity "
5267 + hr.intent.getComponent().flattenToShortString(), e);
5268 badApp = true;
5269 }
5270 } else {
5271 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5272 }
5273 }
5274
5275 // Find any services that should be running in this process...
5276 if (!badApp && mPendingServices.size() > 0) {
5277 ServiceRecord sr = null;
5278 try {
5279 for (int i=0; i<mPendingServices.size(); i++) {
5280 sr = mPendingServices.get(i);
5281 if (app.info.uid != sr.appInfo.uid
5282 || !processName.equals(sr.processName)) {
5283 continue;
5284 }
5285
5286 mPendingServices.remove(i);
5287 i--;
5288 realStartServiceLocked(sr, app);
5289 didSomething = true;
5290 }
5291 } catch (Exception e) {
5292 Log.w(TAG, "Exception in new application when starting service "
5293 + sr.shortName, e);
5294 badApp = true;
5295 }
5296 }
5297
5298 // Check if the next broadcast receiver is in this process...
5299 BroadcastRecord br = mPendingBroadcast;
5300 if (!badApp && br != null && br.curApp == app) {
5301 try {
5302 mPendingBroadcast = null;
5303 processCurBroadcastLocked(br, app);
5304 didSomething = true;
5305 } catch (Exception e) {
5306 Log.w(TAG, "Exception in new application when starting receiver "
5307 + br.curComponent.flattenToShortString(), e);
5308 badApp = true;
5309 logBroadcastReceiverDiscard(br);
5310 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5311 br.resultExtras, br.resultAbort, true);
5312 scheduleBroadcastsLocked();
5313 }
5314 }
5315
Christopher Tate181fafa2009-05-14 11:12:14 -07005316 // Check whether the next backup agent is in this process...
5317 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5318 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005319 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005320 try {
5321 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5322 } catch (Exception e) {
5323 Log.w(TAG, "Exception scheduling backup agent creation: ");
5324 e.printStackTrace();
5325 }
5326 }
5327
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005328 if (badApp) {
5329 // todo: Also need to kill application to deal with all
5330 // kinds of exceptions.
5331 handleAppDiedLocked(app, false);
5332 return false;
5333 }
5334
5335 if (!didSomething) {
5336 updateOomAdjLocked();
5337 }
5338
5339 return true;
5340 }
5341
5342 public final void attachApplication(IApplicationThread thread) {
5343 synchronized (this) {
5344 int callingPid = Binder.getCallingPid();
5345 final long origId = Binder.clearCallingIdentity();
5346 attachApplicationLocked(thread, callingPid);
5347 Binder.restoreCallingIdentity(origId);
5348 }
5349 }
5350
5351 public final void activityIdle(IBinder token) {
5352 final long origId = Binder.clearCallingIdentity();
5353 activityIdleInternal(token, false);
5354 Binder.restoreCallingIdentity(origId);
5355 }
5356
5357 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5358 boolean remove) {
5359 int N = mStoppingActivities.size();
5360 if (N <= 0) return null;
5361
5362 ArrayList<HistoryRecord> stops = null;
5363
5364 final boolean nowVisible = mResumedActivity != null
5365 && mResumedActivity.nowVisible
5366 && !mResumedActivity.waitingVisible;
5367 for (int i=0; i<N; i++) {
5368 HistoryRecord s = mStoppingActivities.get(i);
5369 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5370 + nowVisible + " waitingVisible=" + s.waitingVisible
5371 + " finishing=" + s.finishing);
5372 if (s.waitingVisible && nowVisible) {
5373 mWaitingVisibleActivities.remove(s);
5374 s.waitingVisible = false;
5375 if (s.finishing) {
5376 // If this activity is finishing, it is sitting on top of
5377 // everyone else but we now know it is no longer needed...
5378 // so get rid of it. Otherwise, we need to go through the
5379 // normal flow and hide it once we determine that it is
5380 // hidden by the activities in front of it.
5381 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5382 mWindowManager.setAppVisibility(s, false);
5383 }
5384 }
5385 if (!s.waitingVisible && remove) {
5386 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5387 if (stops == null) {
5388 stops = new ArrayList<HistoryRecord>();
5389 }
5390 stops.add(s);
5391 mStoppingActivities.remove(i);
5392 N--;
5393 i--;
5394 }
5395 }
5396
5397 return stops;
5398 }
5399
5400 void enableScreenAfterBoot() {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005401 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5402 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005403 mWindowManager.enableScreenAfterBoot();
5404 }
5405
5406 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5407 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5408
5409 ArrayList<HistoryRecord> stops = null;
5410 ArrayList<HistoryRecord> finishes = null;
5411 ArrayList<HistoryRecord> thumbnails = null;
5412 int NS = 0;
5413 int NF = 0;
5414 int NT = 0;
5415 IApplicationThread sendThumbnail = null;
5416 boolean booting = false;
5417 boolean enableScreen = false;
5418
5419 synchronized (this) {
5420 if (token != null) {
5421 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5422 }
5423
5424 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005425 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005426 if (index >= 0) {
5427 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5428
5429 // No longer need to keep the device awake.
5430 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5431 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5432 mLaunchingActivity.release();
5433 }
5434
5435 // We are now idle. If someone is waiting for a thumbnail from
5436 // us, we can now deliver.
5437 r.idle = true;
5438 scheduleAppGcsLocked();
5439 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5440 sendThumbnail = r.app.thread;
5441 r.thumbnailNeeded = false;
5442 }
5443
5444 // If this activity is fullscreen, set up to hide those under it.
5445
5446 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5447 ensureActivitiesVisibleLocked(null, 0);
5448
5449 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5450 if (!mBooted && !fromTimeout) {
5451 mBooted = true;
5452 enableScreen = true;
5453 }
5454 }
5455
5456 // Atomically retrieve all of the other things to do.
5457 stops = processStoppingActivitiesLocked(true);
5458 NS = stops != null ? stops.size() : 0;
5459 if ((NF=mFinishingActivities.size()) > 0) {
5460 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5461 mFinishingActivities.clear();
5462 }
5463 if ((NT=mCancelledThumbnails.size()) > 0) {
5464 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5465 mCancelledThumbnails.clear();
5466 }
5467
5468 booting = mBooting;
5469 mBooting = false;
5470 }
5471
5472 int i;
5473
5474 // Send thumbnail if requested.
5475 if (sendThumbnail != null) {
5476 try {
5477 sendThumbnail.requestThumbnail(token);
5478 } catch (Exception e) {
5479 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5480 sendPendingThumbnail(null, token, null, null, true);
5481 }
5482 }
5483
5484 // Stop any activities that are scheduled to do so but have been
5485 // waiting for the next one to start.
5486 for (i=0; i<NS; i++) {
5487 HistoryRecord r = (HistoryRecord)stops.get(i);
5488 synchronized (this) {
5489 if (r.finishing) {
5490 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5491 } else {
5492 stopActivityLocked(r);
5493 }
5494 }
5495 }
5496
5497 // Finish any activities that are scheduled to do so but have been
5498 // waiting for the next one to start.
5499 for (i=0; i<NF; i++) {
5500 HistoryRecord r = (HistoryRecord)finishes.get(i);
5501 synchronized (this) {
5502 destroyActivityLocked(r, true);
5503 }
5504 }
5505
5506 // Report back to any thumbnail receivers.
5507 for (i=0; i<NT; i++) {
5508 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5509 sendPendingThumbnail(r, null, null, null, true);
5510 }
5511
5512 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005513 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005514 }
5515
5516 trimApplications();
5517 //dump();
5518 //mWindowManager.dump();
5519
5520 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005521 enableScreenAfterBoot();
5522 }
5523 }
5524
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005525 final void finishBooting() {
5526 // Ensure that any processes we had put on hold are now started
5527 // up.
5528 final int NP = mProcessesOnHold.size();
5529 if (NP > 0) {
5530 ArrayList<ProcessRecord> procs =
5531 new ArrayList<ProcessRecord>(mProcessesOnHold);
5532 for (int ip=0; ip<NP; ip++) {
5533 this.startProcessLocked(procs.get(ip), "on-hold", null);
5534 }
5535 }
5536 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5537 // Tell anyone interested that we are done booting!
5538 synchronized (this) {
5539 broadcastIntentLocked(null, null,
5540 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5541 null, null, 0, null, null,
5542 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5543 false, false, MY_PID, Process.SYSTEM_UID);
5544 }
5545 }
5546 }
5547
5548 final void ensureBootCompleted() {
5549 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005550 boolean enableScreen;
5551 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005552 booting = mBooting;
5553 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005554 enableScreen = !mBooted;
5555 mBooted = true;
5556 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005557
5558 if (booting) {
5559 finishBooting();
5560 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005561
5562 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005563 enableScreenAfterBoot();
5564 }
5565 }
5566
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005567 public final void activityPaused(IBinder token, Bundle icicle) {
5568 // Refuse possible leaked file descriptors
5569 if (icicle != null && icicle.hasFileDescriptors()) {
5570 throw new IllegalArgumentException("File descriptors passed in Bundle");
5571 }
5572
5573 final long origId = Binder.clearCallingIdentity();
5574 activityPaused(token, icicle, false);
5575 Binder.restoreCallingIdentity(origId);
5576 }
5577
5578 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5579 if (DEBUG_PAUSE) Log.v(
5580 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5581 + ", timeout=" + timeout);
5582
5583 HistoryRecord r = null;
5584
5585 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005586 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005587 if (index >= 0) {
5588 r = (HistoryRecord)mHistory.get(index);
5589 if (!timeout) {
5590 r.icicle = icicle;
5591 r.haveState = true;
5592 }
5593 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5594 if (mPausingActivity == r) {
5595 r.state = ActivityState.PAUSED;
5596 completePauseLocked();
5597 } else {
5598 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5599 System.identityHashCode(r), r.shortComponentName,
5600 mPausingActivity != null
5601 ? mPausingActivity.shortComponentName : "(none)");
5602 }
5603 }
5604 }
5605 }
5606
5607 public final void activityStopped(IBinder token, Bitmap thumbnail,
5608 CharSequence description) {
5609 if (localLOGV) Log.v(
5610 TAG, "Activity stopped: token=" + token);
5611
5612 HistoryRecord r = null;
5613
5614 final long origId = Binder.clearCallingIdentity();
5615
5616 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005617 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005618 if (index >= 0) {
5619 r = (HistoryRecord)mHistory.get(index);
5620 r.thumbnail = thumbnail;
5621 r.description = description;
5622 r.stopped = true;
5623 r.state = ActivityState.STOPPED;
5624 if (!r.finishing) {
5625 if (r.configDestroy) {
5626 destroyActivityLocked(r, true);
5627 resumeTopActivityLocked(null);
5628 }
5629 }
5630 }
5631 }
5632
5633 if (r != null) {
5634 sendPendingThumbnail(r, null, null, null, false);
5635 }
5636
5637 trimApplications();
5638
5639 Binder.restoreCallingIdentity(origId);
5640 }
5641
5642 public final void activityDestroyed(IBinder token) {
5643 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5644 synchronized (this) {
5645 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5646
Dianne Hackborn75b03852009-06-12 15:43:26 -07005647 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005648 if (index >= 0) {
5649 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5650 if (r.state == ActivityState.DESTROYING) {
5651 final long origId = Binder.clearCallingIdentity();
5652 removeActivityFromHistoryLocked(r);
5653 Binder.restoreCallingIdentity(origId);
5654 }
5655 }
5656 }
5657 }
5658
5659 public String getCallingPackage(IBinder token) {
5660 synchronized (this) {
5661 HistoryRecord r = getCallingRecordLocked(token);
5662 return r != null && r.app != null ? r.app.processName : null;
5663 }
5664 }
5665
5666 public ComponentName getCallingActivity(IBinder token) {
5667 synchronized (this) {
5668 HistoryRecord r = getCallingRecordLocked(token);
5669 return r != null ? r.intent.getComponent() : null;
5670 }
5671 }
5672
5673 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005674 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005675 if (index >= 0) {
5676 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5677 if (r != null) {
5678 return r.resultTo;
5679 }
5680 }
5681 return null;
5682 }
5683
5684 public ComponentName getActivityClassForToken(IBinder token) {
5685 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005686 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005687 if (index >= 0) {
5688 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5689 return r.intent.getComponent();
5690 }
5691 return null;
5692 }
5693 }
5694
5695 public String getPackageForToken(IBinder token) {
5696 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005697 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005698 if (index >= 0) {
5699 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5700 return r.packageName;
5701 }
5702 return null;
5703 }
5704 }
5705
5706 public IIntentSender getIntentSender(int type,
5707 String packageName, IBinder token, String resultWho,
5708 int requestCode, Intent intent, String resolvedType, int flags) {
5709 // Refuse possible leaked file descriptors
5710 if (intent != null && intent.hasFileDescriptors() == true) {
5711 throw new IllegalArgumentException("File descriptors passed in Intent");
5712 }
5713
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005714 if (type == INTENT_SENDER_BROADCAST) {
5715 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5716 throw new IllegalArgumentException(
5717 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5718 }
5719 }
5720
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005721 synchronized(this) {
5722 int callingUid = Binder.getCallingUid();
5723 try {
5724 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5725 Process.supportsProcesses()) {
5726 int uid = ActivityThread.getPackageManager()
5727 .getPackageUid(packageName);
5728 if (uid != Binder.getCallingUid()) {
5729 String msg = "Permission Denial: getIntentSender() from pid="
5730 + Binder.getCallingPid()
5731 + ", uid=" + Binder.getCallingUid()
5732 + ", (need uid=" + uid + ")"
5733 + " is not allowed to send as package " + packageName;
5734 Log.w(TAG, msg);
5735 throw new SecurityException(msg);
5736 }
5737 }
5738 } catch (RemoteException e) {
5739 throw new SecurityException(e);
5740 }
5741 HistoryRecord activity = null;
5742 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005743 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005744 if (index < 0) {
5745 return null;
5746 }
5747 activity = (HistoryRecord)mHistory.get(index);
5748 if (activity.finishing) {
5749 return null;
5750 }
5751 }
5752
5753 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5754 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5755 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5756 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5757 |PendingIntent.FLAG_UPDATE_CURRENT);
5758
5759 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5760 type, packageName, activity, resultWho,
5761 requestCode, intent, resolvedType, flags);
5762 WeakReference<PendingIntentRecord> ref;
5763 ref = mIntentSenderRecords.get(key);
5764 PendingIntentRecord rec = ref != null ? ref.get() : null;
5765 if (rec != null) {
5766 if (!cancelCurrent) {
5767 if (updateCurrent) {
5768 rec.key.requestIntent.replaceExtras(intent);
5769 }
5770 return rec;
5771 }
5772 rec.canceled = true;
5773 mIntentSenderRecords.remove(key);
5774 }
5775 if (noCreate) {
5776 return rec;
5777 }
5778 rec = new PendingIntentRecord(this, key, callingUid);
5779 mIntentSenderRecords.put(key, rec.ref);
5780 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5781 if (activity.pendingResults == null) {
5782 activity.pendingResults
5783 = new HashSet<WeakReference<PendingIntentRecord>>();
5784 }
5785 activity.pendingResults.add(rec.ref);
5786 }
5787 return rec;
5788 }
5789 }
5790
5791 public void cancelIntentSender(IIntentSender sender) {
5792 if (!(sender instanceof PendingIntentRecord)) {
5793 return;
5794 }
5795 synchronized(this) {
5796 PendingIntentRecord rec = (PendingIntentRecord)sender;
5797 try {
5798 int uid = ActivityThread.getPackageManager()
5799 .getPackageUid(rec.key.packageName);
5800 if (uid != Binder.getCallingUid()) {
5801 String msg = "Permission Denial: cancelIntentSender() from pid="
5802 + Binder.getCallingPid()
5803 + ", uid=" + Binder.getCallingUid()
5804 + " is not allowed to cancel packges "
5805 + rec.key.packageName;
5806 Log.w(TAG, msg);
5807 throw new SecurityException(msg);
5808 }
5809 } catch (RemoteException e) {
5810 throw new SecurityException(e);
5811 }
5812 cancelIntentSenderLocked(rec, true);
5813 }
5814 }
5815
5816 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5817 rec.canceled = true;
5818 mIntentSenderRecords.remove(rec.key);
5819 if (cleanActivity && rec.key.activity != null) {
5820 rec.key.activity.pendingResults.remove(rec.ref);
5821 }
5822 }
5823
5824 public String getPackageForIntentSender(IIntentSender pendingResult) {
5825 if (!(pendingResult instanceof PendingIntentRecord)) {
5826 return null;
5827 }
5828 synchronized(this) {
5829 try {
5830 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5831 return res.key.packageName;
5832 } catch (ClassCastException e) {
5833 }
5834 }
5835 return null;
5836 }
5837
5838 public void setProcessLimit(int max) {
5839 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5840 "setProcessLimit()");
5841 mProcessLimit = max;
5842 }
5843
5844 public int getProcessLimit() {
5845 return mProcessLimit;
5846 }
5847
5848 void foregroundTokenDied(ForegroundToken token) {
5849 synchronized (ActivityManagerService.this) {
5850 synchronized (mPidsSelfLocked) {
5851 ForegroundToken cur
5852 = mForegroundProcesses.get(token.pid);
5853 if (cur != token) {
5854 return;
5855 }
5856 mForegroundProcesses.remove(token.pid);
5857 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5858 if (pr == null) {
5859 return;
5860 }
5861 pr.forcingToForeground = null;
5862 pr.foregroundServices = false;
5863 }
5864 updateOomAdjLocked();
5865 }
5866 }
5867
5868 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5869 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5870 "setProcessForeground()");
5871 synchronized(this) {
5872 boolean changed = false;
5873
5874 synchronized (mPidsSelfLocked) {
5875 ProcessRecord pr = mPidsSelfLocked.get(pid);
5876 if (pr == null) {
5877 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5878 return;
5879 }
5880 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5881 if (oldToken != null) {
5882 oldToken.token.unlinkToDeath(oldToken, 0);
5883 mForegroundProcesses.remove(pid);
5884 pr.forcingToForeground = null;
5885 changed = true;
5886 }
5887 if (isForeground && token != null) {
5888 ForegroundToken newToken = new ForegroundToken() {
5889 public void binderDied() {
5890 foregroundTokenDied(this);
5891 }
5892 };
5893 newToken.pid = pid;
5894 newToken.token = token;
5895 try {
5896 token.linkToDeath(newToken, 0);
5897 mForegroundProcesses.put(pid, newToken);
5898 pr.forcingToForeground = token;
5899 changed = true;
5900 } catch (RemoteException e) {
5901 // If the process died while doing this, we will later
5902 // do the cleanup with the process death link.
5903 }
5904 }
5905 }
5906
5907 if (changed) {
5908 updateOomAdjLocked();
5909 }
5910 }
5911 }
5912
5913 // =========================================================
5914 // PERMISSIONS
5915 // =========================================================
5916
5917 static class PermissionController extends IPermissionController.Stub {
5918 ActivityManagerService mActivityManagerService;
5919 PermissionController(ActivityManagerService activityManagerService) {
5920 mActivityManagerService = activityManagerService;
5921 }
5922
5923 public boolean checkPermission(String permission, int pid, int uid) {
5924 return mActivityManagerService.checkPermission(permission, pid,
5925 uid) == PackageManager.PERMISSION_GRANTED;
5926 }
5927 }
5928
5929 /**
5930 * This can be called with or without the global lock held.
5931 */
5932 int checkComponentPermission(String permission, int pid, int uid,
5933 int reqUid) {
5934 // We might be performing an operation on behalf of an indirect binder
5935 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5936 // client identity accordingly before proceeding.
5937 Identity tlsIdentity = sCallerIdentity.get();
5938 if (tlsIdentity != null) {
5939 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5940 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5941 uid = tlsIdentity.uid;
5942 pid = tlsIdentity.pid;
5943 }
5944
5945 // Root, system server and our own process get to do everything.
5946 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5947 !Process.supportsProcesses()) {
5948 return PackageManager.PERMISSION_GRANTED;
5949 }
5950 // If the target requires a specific UID, always fail for others.
5951 if (reqUid >= 0 && uid != reqUid) {
5952 return PackageManager.PERMISSION_DENIED;
5953 }
5954 if (permission == null) {
5955 return PackageManager.PERMISSION_GRANTED;
5956 }
5957 try {
5958 return ActivityThread.getPackageManager()
5959 .checkUidPermission(permission, uid);
5960 } catch (RemoteException e) {
5961 // Should never happen, but if it does... deny!
5962 Log.e(TAG, "PackageManager is dead?!?", e);
5963 }
5964 return PackageManager.PERMISSION_DENIED;
5965 }
5966
5967 /**
5968 * As the only public entry point for permissions checking, this method
5969 * can enforce the semantic that requesting a check on a null global
5970 * permission is automatically denied. (Internally a null permission
5971 * string is used when calling {@link #checkComponentPermission} in cases
5972 * when only uid-based security is needed.)
5973 *
5974 * This can be called with or without the global lock held.
5975 */
5976 public int checkPermission(String permission, int pid, int uid) {
5977 if (permission == null) {
5978 return PackageManager.PERMISSION_DENIED;
5979 }
5980 return checkComponentPermission(permission, pid, uid, -1);
5981 }
5982
5983 /**
5984 * Binder IPC calls go through the public entry point.
5985 * This can be called with or without the global lock held.
5986 */
5987 int checkCallingPermission(String permission) {
5988 return checkPermission(permission,
5989 Binder.getCallingPid(),
5990 Binder.getCallingUid());
5991 }
5992
5993 /**
5994 * This can be called with or without the global lock held.
5995 */
5996 void enforceCallingPermission(String permission, String func) {
5997 if (checkCallingPermission(permission)
5998 == PackageManager.PERMISSION_GRANTED) {
5999 return;
6000 }
6001
6002 String msg = "Permission Denial: " + func + " from pid="
6003 + Binder.getCallingPid()
6004 + ", uid=" + Binder.getCallingUid()
6005 + " requires " + permission;
6006 Log.w(TAG, msg);
6007 throw new SecurityException(msg);
6008 }
6009
6010 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6011 ProviderInfo pi, int uid, int modeFlags) {
6012 try {
6013 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6014 if ((pi.readPermission != null) &&
6015 (pm.checkUidPermission(pi.readPermission, uid)
6016 != PackageManager.PERMISSION_GRANTED)) {
6017 return false;
6018 }
6019 }
6020 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6021 if ((pi.writePermission != null) &&
6022 (pm.checkUidPermission(pi.writePermission, uid)
6023 != PackageManager.PERMISSION_GRANTED)) {
6024 return false;
6025 }
6026 }
6027 return true;
6028 } catch (RemoteException e) {
6029 return false;
6030 }
6031 }
6032
6033 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6034 int modeFlags) {
6035 // Root gets to do everything.
6036 if (uid == 0 || !Process.supportsProcesses()) {
6037 return true;
6038 }
6039 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6040 if (perms == null) return false;
6041 UriPermission perm = perms.get(uri);
6042 if (perm == null) return false;
6043 return (modeFlags&perm.modeFlags) == modeFlags;
6044 }
6045
6046 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6047 // Another redirected-binder-call permissions check as in
6048 // {@link checkComponentPermission}.
6049 Identity tlsIdentity = sCallerIdentity.get();
6050 if (tlsIdentity != null) {
6051 uid = tlsIdentity.uid;
6052 pid = tlsIdentity.pid;
6053 }
6054
6055 // Our own process gets to do everything.
6056 if (pid == MY_PID) {
6057 return PackageManager.PERMISSION_GRANTED;
6058 }
6059 synchronized(this) {
6060 return checkUriPermissionLocked(uri, uid, modeFlags)
6061 ? PackageManager.PERMISSION_GRANTED
6062 : PackageManager.PERMISSION_DENIED;
6063 }
6064 }
6065
6066 private void grantUriPermissionLocked(int callingUid,
6067 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6068 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6069 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6070 if (modeFlags == 0) {
6071 return;
6072 }
6073
6074 final IPackageManager pm = ActivityThread.getPackageManager();
6075
6076 // If this is not a content: uri, we can't do anything with it.
6077 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6078 return;
6079 }
6080
6081 String name = uri.getAuthority();
6082 ProviderInfo pi = null;
6083 ContentProviderRecord cpr
6084 = (ContentProviderRecord)mProvidersByName.get(name);
6085 if (cpr != null) {
6086 pi = cpr.info;
6087 } else {
6088 try {
6089 pi = pm.resolveContentProvider(name,
6090 PackageManager.GET_URI_PERMISSION_PATTERNS);
6091 } catch (RemoteException ex) {
6092 }
6093 }
6094 if (pi == null) {
6095 Log.w(TAG, "No content provider found for: " + name);
6096 return;
6097 }
6098
6099 int targetUid;
6100 try {
6101 targetUid = pm.getPackageUid(targetPkg);
6102 if (targetUid < 0) {
6103 return;
6104 }
6105 } catch (RemoteException ex) {
6106 return;
6107 }
6108
6109 // First... does the target actually need this permission?
6110 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6111 // No need to grant the target this permission.
6112 return;
6113 }
6114
6115 // Second... maybe someone else has already granted the
6116 // permission?
6117 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6118 // No need to grant the target this permission.
6119 return;
6120 }
6121
6122 // Third... is the provider allowing granting of URI permissions?
6123 if (!pi.grantUriPermissions) {
6124 throw new SecurityException("Provider " + pi.packageName
6125 + "/" + pi.name
6126 + " does not allow granting of Uri permissions (uri "
6127 + uri + ")");
6128 }
6129 if (pi.uriPermissionPatterns != null) {
6130 final int N = pi.uriPermissionPatterns.length;
6131 boolean allowed = false;
6132 for (int i=0; i<N; i++) {
6133 if (pi.uriPermissionPatterns[i] != null
6134 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6135 allowed = true;
6136 break;
6137 }
6138 }
6139 if (!allowed) {
6140 throw new SecurityException("Provider " + pi.packageName
6141 + "/" + pi.name
6142 + " does not allow granting of permission to path of Uri "
6143 + uri);
6144 }
6145 }
6146
6147 // Fourth... does the caller itself have permission to access
6148 // this uri?
6149 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6150 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6151 throw new SecurityException("Uid " + callingUid
6152 + " does not have permission to uri " + uri);
6153 }
6154 }
6155
6156 // Okay! So here we are: the caller has the assumed permission
6157 // to the uri, and the target doesn't. Let's now give this to
6158 // the target.
6159
6160 HashMap<Uri, UriPermission> targetUris
6161 = mGrantedUriPermissions.get(targetUid);
6162 if (targetUris == null) {
6163 targetUris = new HashMap<Uri, UriPermission>();
6164 mGrantedUriPermissions.put(targetUid, targetUris);
6165 }
6166
6167 UriPermission perm = targetUris.get(uri);
6168 if (perm == null) {
6169 perm = new UriPermission(targetUid, uri);
6170 targetUris.put(uri, perm);
6171
6172 }
6173 perm.modeFlags |= modeFlags;
6174 if (activity == null) {
6175 perm.globalModeFlags |= modeFlags;
6176 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6177 perm.readActivities.add(activity);
6178 if (activity.readUriPermissions == null) {
6179 activity.readUriPermissions = new HashSet<UriPermission>();
6180 }
6181 activity.readUriPermissions.add(perm);
6182 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6183 perm.writeActivities.add(activity);
6184 if (activity.writeUriPermissions == null) {
6185 activity.writeUriPermissions = new HashSet<UriPermission>();
6186 }
6187 activity.writeUriPermissions.add(perm);
6188 }
6189 }
6190
6191 private void grantUriPermissionFromIntentLocked(int callingUid,
6192 String targetPkg, Intent intent, HistoryRecord activity) {
6193 if (intent == null) {
6194 return;
6195 }
6196 Uri data = intent.getData();
6197 if (data == null) {
6198 return;
6199 }
6200 grantUriPermissionLocked(callingUid, targetPkg, data,
6201 intent.getFlags(), activity);
6202 }
6203
6204 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6205 Uri uri, int modeFlags) {
6206 synchronized(this) {
6207 final ProcessRecord r = getRecordForAppLocked(caller);
6208 if (r == null) {
6209 throw new SecurityException("Unable to find app for caller "
6210 + caller
6211 + " when granting permission to uri " + uri);
6212 }
6213 if (targetPkg == null) {
6214 Log.w(TAG, "grantUriPermission: null target");
6215 return;
6216 }
6217 if (uri == null) {
6218 Log.w(TAG, "grantUriPermission: null uri");
6219 return;
6220 }
6221
6222 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6223 null);
6224 }
6225 }
6226
6227 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6228 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6229 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6230 HashMap<Uri, UriPermission> perms
6231 = mGrantedUriPermissions.get(perm.uid);
6232 if (perms != null) {
6233 perms.remove(perm.uri);
6234 if (perms.size() == 0) {
6235 mGrantedUriPermissions.remove(perm.uid);
6236 }
6237 }
6238 }
6239 }
6240
6241 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6242 if (activity.readUriPermissions != null) {
6243 for (UriPermission perm : activity.readUriPermissions) {
6244 perm.readActivities.remove(activity);
6245 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6246 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6247 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6248 removeUriPermissionIfNeededLocked(perm);
6249 }
6250 }
6251 }
6252 if (activity.writeUriPermissions != null) {
6253 for (UriPermission perm : activity.writeUriPermissions) {
6254 perm.writeActivities.remove(activity);
6255 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6256 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6257 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6258 removeUriPermissionIfNeededLocked(perm);
6259 }
6260 }
6261 }
6262 }
6263
6264 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6265 int modeFlags) {
6266 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6267 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6268 if (modeFlags == 0) {
6269 return;
6270 }
6271
6272 final IPackageManager pm = ActivityThread.getPackageManager();
6273
6274 final String authority = uri.getAuthority();
6275 ProviderInfo pi = null;
6276 ContentProviderRecord cpr
6277 = (ContentProviderRecord)mProvidersByName.get(authority);
6278 if (cpr != null) {
6279 pi = cpr.info;
6280 } else {
6281 try {
6282 pi = pm.resolveContentProvider(authority,
6283 PackageManager.GET_URI_PERMISSION_PATTERNS);
6284 } catch (RemoteException ex) {
6285 }
6286 }
6287 if (pi == null) {
6288 Log.w(TAG, "No content provider found for: " + authority);
6289 return;
6290 }
6291
6292 // Does the caller have this permission on the URI?
6293 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6294 // Right now, if you are not the original owner of the permission,
6295 // you are not allowed to revoke it.
6296 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6297 throw new SecurityException("Uid " + callingUid
6298 + " does not have permission to uri " + uri);
6299 //}
6300 }
6301
6302 // Go through all of the permissions and remove any that match.
6303 final List<String> SEGMENTS = uri.getPathSegments();
6304 if (SEGMENTS != null) {
6305 final int NS = SEGMENTS.size();
6306 int N = mGrantedUriPermissions.size();
6307 for (int i=0; i<N; i++) {
6308 HashMap<Uri, UriPermission> perms
6309 = mGrantedUriPermissions.valueAt(i);
6310 Iterator<UriPermission> it = perms.values().iterator();
6311 toploop:
6312 while (it.hasNext()) {
6313 UriPermission perm = it.next();
6314 Uri targetUri = perm.uri;
6315 if (!authority.equals(targetUri.getAuthority())) {
6316 continue;
6317 }
6318 List<String> targetSegments = targetUri.getPathSegments();
6319 if (targetSegments == null) {
6320 continue;
6321 }
6322 if (targetSegments.size() < NS) {
6323 continue;
6324 }
6325 for (int j=0; j<NS; j++) {
6326 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6327 continue toploop;
6328 }
6329 }
6330 perm.clearModes(modeFlags);
6331 if (perm.modeFlags == 0) {
6332 it.remove();
6333 }
6334 }
6335 if (perms.size() == 0) {
6336 mGrantedUriPermissions.remove(
6337 mGrantedUriPermissions.keyAt(i));
6338 N--;
6339 i--;
6340 }
6341 }
6342 }
6343 }
6344
6345 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6346 int modeFlags) {
6347 synchronized(this) {
6348 final ProcessRecord r = getRecordForAppLocked(caller);
6349 if (r == null) {
6350 throw new SecurityException("Unable to find app for caller "
6351 + caller
6352 + " when revoking permission to uri " + uri);
6353 }
6354 if (uri == null) {
6355 Log.w(TAG, "revokeUriPermission: null uri");
6356 return;
6357 }
6358
6359 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6360 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6361 if (modeFlags == 0) {
6362 return;
6363 }
6364
6365 final IPackageManager pm = ActivityThread.getPackageManager();
6366
6367 final String authority = uri.getAuthority();
6368 ProviderInfo pi = null;
6369 ContentProviderRecord cpr
6370 = (ContentProviderRecord)mProvidersByName.get(authority);
6371 if (cpr != null) {
6372 pi = cpr.info;
6373 } else {
6374 try {
6375 pi = pm.resolveContentProvider(authority,
6376 PackageManager.GET_URI_PERMISSION_PATTERNS);
6377 } catch (RemoteException ex) {
6378 }
6379 }
6380 if (pi == null) {
6381 Log.w(TAG, "No content provider found for: " + authority);
6382 return;
6383 }
6384
6385 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6386 }
6387 }
6388
6389 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6390 synchronized (this) {
6391 ProcessRecord app =
6392 who != null ? getRecordForAppLocked(who) : null;
6393 if (app == null) return;
6394
6395 Message msg = Message.obtain();
6396 msg.what = WAIT_FOR_DEBUGGER_MSG;
6397 msg.obj = app;
6398 msg.arg1 = waiting ? 1 : 0;
6399 mHandler.sendMessage(msg);
6400 }
6401 }
6402
6403 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6404 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006405 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006406 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006407 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006408 }
6409
6410 // =========================================================
6411 // TASK MANAGEMENT
6412 // =========================================================
6413
6414 public List getTasks(int maxNum, int flags,
6415 IThumbnailReceiver receiver) {
6416 ArrayList list = new ArrayList();
6417
6418 PendingThumbnailsRecord pending = null;
6419 IApplicationThread topThumbnail = null;
6420 HistoryRecord topRecord = null;
6421
6422 synchronized(this) {
6423 if (localLOGV) Log.v(
6424 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6425 + ", receiver=" + receiver);
6426
6427 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6428 != PackageManager.PERMISSION_GRANTED) {
6429 if (receiver != null) {
6430 // If the caller wants to wait for pending thumbnails,
6431 // it ain't gonna get them.
6432 try {
6433 receiver.finished();
6434 } catch (RemoteException ex) {
6435 }
6436 }
6437 String msg = "Permission Denial: getTasks() from pid="
6438 + Binder.getCallingPid()
6439 + ", uid=" + Binder.getCallingUid()
6440 + " requires " + android.Manifest.permission.GET_TASKS;
6441 Log.w(TAG, msg);
6442 throw new SecurityException(msg);
6443 }
6444
6445 int pos = mHistory.size()-1;
6446 HistoryRecord next =
6447 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6448 HistoryRecord top = null;
6449 CharSequence topDescription = null;
6450 TaskRecord curTask = null;
6451 int numActivities = 0;
6452 int numRunning = 0;
6453 while (pos >= 0 && maxNum > 0) {
6454 final HistoryRecord r = next;
6455 pos--;
6456 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6457
6458 // Initialize state for next task if needed.
6459 if (top == null ||
6460 (top.state == ActivityState.INITIALIZING
6461 && top.task == r.task)) {
6462 top = r;
6463 topDescription = r.description;
6464 curTask = r.task;
6465 numActivities = numRunning = 0;
6466 }
6467
6468 // Add 'r' into the current task.
6469 numActivities++;
6470 if (r.app != null && r.app.thread != null) {
6471 numRunning++;
6472 }
6473 if (topDescription == null) {
6474 topDescription = r.description;
6475 }
6476
6477 if (localLOGV) Log.v(
6478 TAG, r.intent.getComponent().flattenToShortString()
6479 + ": task=" + r.task);
6480
6481 // If the next one is a different task, generate a new
6482 // TaskInfo entry for what we have.
6483 if (next == null || next.task != curTask) {
6484 ActivityManager.RunningTaskInfo ci
6485 = new ActivityManager.RunningTaskInfo();
6486 ci.id = curTask.taskId;
6487 ci.baseActivity = r.intent.getComponent();
6488 ci.topActivity = top.intent.getComponent();
6489 ci.thumbnail = top.thumbnail;
6490 ci.description = topDescription;
6491 ci.numActivities = numActivities;
6492 ci.numRunning = numRunning;
6493 //System.out.println(
6494 // "#" + maxNum + ": " + " descr=" + ci.description);
6495 if (ci.thumbnail == null && receiver != null) {
6496 if (localLOGV) Log.v(
6497 TAG, "State=" + top.state + "Idle=" + top.idle
6498 + " app=" + top.app
6499 + " thr=" + (top.app != null ? top.app.thread : null));
6500 if (top.state == ActivityState.RESUMED
6501 || top.state == ActivityState.PAUSING) {
6502 if (top.idle && top.app != null
6503 && top.app.thread != null) {
6504 topRecord = top;
6505 topThumbnail = top.app.thread;
6506 } else {
6507 top.thumbnailNeeded = true;
6508 }
6509 }
6510 if (pending == null) {
6511 pending = new PendingThumbnailsRecord(receiver);
6512 }
6513 pending.pendingRecords.add(top);
6514 }
6515 list.add(ci);
6516 maxNum--;
6517 top = null;
6518 }
6519 }
6520
6521 if (pending != null) {
6522 mPendingThumbnails.add(pending);
6523 }
6524 }
6525
6526 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6527
6528 if (topThumbnail != null) {
6529 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6530 try {
6531 topThumbnail.requestThumbnail(topRecord);
6532 } catch (Exception e) {
6533 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6534 sendPendingThumbnail(null, topRecord, null, null, true);
6535 }
6536 }
6537
6538 if (pending == null && receiver != null) {
6539 // In this case all thumbnails were available and the client
6540 // is being asked to be told when the remaining ones come in...
6541 // which is unusually, since the top-most currently running
6542 // activity should never have a canned thumbnail! Oh well.
6543 try {
6544 receiver.finished();
6545 } catch (RemoteException ex) {
6546 }
6547 }
6548
6549 return list;
6550 }
6551
6552 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6553 int flags) {
6554 synchronized (this) {
6555 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6556 "getRecentTasks()");
6557
6558 final int N = mRecentTasks.size();
6559 ArrayList<ActivityManager.RecentTaskInfo> res
6560 = new ArrayList<ActivityManager.RecentTaskInfo>(
6561 maxNum < N ? maxNum : N);
6562 for (int i=0; i<N && maxNum > 0; i++) {
6563 TaskRecord tr = mRecentTasks.get(i);
6564 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6565 || (tr.intent == null)
6566 || ((tr.intent.getFlags()
6567 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6568 ActivityManager.RecentTaskInfo rti
6569 = new ActivityManager.RecentTaskInfo();
6570 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6571 rti.baseIntent = new Intent(
6572 tr.intent != null ? tr.intent : tr.affinityIntent);
6573 rti.origActivity = tr.origActivity;
6574 res.add(rti);
6575 maxNum--;
6576 }
6577 }
6578 return res;
6579 }
6580 }
6581
6582 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6583 int j;
6584 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6585 TaskRecord jt = startTask;
6586
6587 // First look backwards
6588 for (j=startIndex-1; j>=0; j--) {
6589 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6590 if (r.task != jt) {
6591 jt = r.task;
6592 if (affinity.equals(jt.affinity)) {
6593 return j;
6594 }
6595 }
6596 }
6597
6598 // Now look forwards
6599 final int N = mHistory.size();
6600 jt = startTask;
6601 for (j=startIndex+1; j<N; j++) {
6602 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6603 if (r.task != jt) {
6604 if (affinity.equals(jt.affinity)) {
6605 return j;
6606 }
6607 jt = r.task;
6608 }
6609 }
6610
6611 // Might it be at the top?
6612 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6613 return N-1;
6614 }
6615
6616 return -1;
6617 }
6618
6619 /**
6620 * Perform a reset of the given task, if needed as part of launching it.
6621 * Returns the new HistoryRecord at the top of the task.
6622 */
6623 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6624 HistoryRecord newActivity) {
6625 boolean forceReset = (newActivity.info.flags
6626 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6627 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6628 if ((newActivity.info.flags
6629 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6630 forceReset = true;
6631 }
6632 }
6633
6634 final TaskRecord task = taskTop.task;
6635
6636 // We are going to move through the history list so that we can look
6637 // at each activity 'target' with 'below' either the interesting
6638 // activity immediately below it in the stack or null.
6639 HistoryRecord target = null;
6640 int targetI = 0;
6641 int taskTopI = -1;
6642 int replyChainEnd = -1;
6643 int lastReparentPos = -1;
6644 for (int i=mHistory.size()-1; i>=-1; i--) {
6645 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6646
6647 if (below != null && below.finishing) {
6648 continue;
6649 }
6650 if (target == null) {
6651 target = below;
6652 targetI = i;
6653 // If we were in the middle of a reply chain before this
6654 // task, it doesn't appear like the root of the chain wants
6655 // anything interesting, so drop it.
6656 replyChainEnd = -1;
6657 continue;
6658 }
6659
6660 final int flags = target.info.flags;
6661
6662 final boolean finishOnTaskLaunch =
6663 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6664 final boolean allowTaskReparenting =
6665 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6666
6667 if (target.task == task) {
6668 // We are inside of the task being reset... we'll either
6669 // finish this activity, push it out for another task,
6670 // or leave it as-is. We only do this
6671 // for activities that are not the root of the task (since
6672 // if we finish the root, we may no longer have the task!).
6673 if (taskTopI < 0) {
6674 taskTopI = targetI;
6675 }
6676 if (below != null && below.task == task) {
6677 final boolean clearWhenTaskReset =
6678 (target.intent.getFlags()
6679 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006680 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006681 // If this activity is sending a reply to a previous
6682 // activity, we can't do anything with it now until
6683 // we reach the start of the reply chain.
6684 // XXX note that we are assuming the result is always
6685 // to the previous activity, which is almost always
6686 // the case but we really shouldn't count on.
6687 if (replyChainEnd < 0) {
6688 replyChainEnd = targetI;
6689 }
Ed Heyl73798232009-03-24 21:32:21 -07006690 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006691 && target.taskAffinity != null
6692 && !target.taskAffinity.equals(task.affinity)) {
6693 // If this activity has an affinity for another
6694 // task, then we need to move it out of here. We will
6695 // move it as far out of the way as possible, to the
6696 // bottom of the activity stack. This also keeps it
6697 // correctly ordered with any activities we previously
6698 // moved.
6699 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6700 if (target.taskAffinity != null
6701 && target.taskAffinity.equals(p.task.affinity)) {
6702 // If the activity currently at the bottom has the
6703 // same task affinity as the one we are moving,
6704 // then merge it into the same task.
6705 target.task = p.task;
6706 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6707 + " out to bottom task " + p.task);
6708 } else {
6709 mCurTask++;
6710 if (mCurTask <= 0) {
6711 mCurTask = 1;
6712 }
6713 target.task = new TaskRecord(mCurTask, target.info, null,
6714 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6715 target.task.affinityIntent = target.intent;
6716 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6717 + " out to new task " + target.task);
6718 }
6719 mWindowManager.setAppGroupId(target, task.taskId);
6720 if (replyChainEnd < 0) {
6721 replyChainEnd = targetI;
6722 }
6723 int dstPos = 0;
6724 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6725 p = (HistoryRecord)mHistory.get(srcPos);
6726 if (p.finishing) {
6727 continue;
6728 }
6729 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6730 + " out to target's task " + target.task);
6731 task.numActivities--;
6732 p.task = target.task;
6733 target.task.numActivities++;
6734 mHistory.remove(srcPos);
6735 mHistory.add(dstPos, p);
6736 mWindowManager.moveAppToken(dstPos, p);
6737 mWindowManager.setAppGroupId(p, p.task.taskId);
6738 dstPos++;
6739 if (VALIDATE_TOKENS) {
6740 mWindowManager.validateAppTokens(mHistory);
6741 }
6742 i++;
6743 }
6744 if (taskTop == p) {
6745 taskTop = below;
6746 }
6747 if (taskTopI == replyChainEnd) {
6748 taskTopI = -1;
6749 }
6750 replyChainEnd = -1;
6751 addRecentTask(target.task);
6752 } else if (forceReset || finishOnTaskLaunch
6753 || clearWhenTaskReset) {
6754 // If the activity should just be removed -- either
6755 // because it asks for it, or the task should be
6756 // cleared -- then finish it and anything that is
6757 // part of its reply chain.
6758 if (clearWhenTaskReset) {
6759 // In this case, we want to finish this activity
6760 // and everything above it, so be sneaky and pretend
6761 // like these are all in the reply chain.
6762 replyChainEnd = targetI+1;
6763 while (replyChainEnd < mHistory.size() &&
6764 ((HistoryRecord)mHistory.get(
6765 replyChainEnd)).task == task) {
6766 replyChainEnd++;
6767 }
6768 replyChainEnd--;
6769 } else if (replyChainEnd < 0) {
6770 replyChainEnd = targetI;
6771 }
6772 HistoryRecord p = null;
6773 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6774 p = (HistoryRecord)mHistory.get(srcPos);
6775 if (p.finishing) {
6776 continue;
6777 }
6778 if (finishActivityLocked(p, srcPos,
6779 Activity.RESULT_CANCELED, null, "reset")) {
6780 replyChainEnd--;
6781 srcPos--;
6782 }
6783 }
6784 if (taskTop == p) {
6785 taskTop = below;
6786 }
6787 if (taskTopI == replyChainEnd) {
6788 taskTopI = -1;
6789 }
6790 replyChainEnd = -1;
6791 } else {
6792 // If we were in the middle of a chain, well the
6793 // activity that started it all doesn't want anything
6794 // special, so leave it all as-is.
6795 replyChainEnd = -1;
6796 }
6797 } else {
6798 // Reached the bottom of the task -- any reply chain
6799 // should be left as-is.
6800 replyChainEnd = -1;
6801 }
6802
6803 } else if (target.resultTo != null) {
6804 // If this activity is sending a reply to a previous
6805 // activity, we can't do anything with it now until
6806 // we reach the start of the reply chain.
6807 // XXX note that we are assuming the result is always
6808 // to the previous activity, which is almost always
6809 // the case but we really shouldn't count on.
6810 if (replyChainEnd < 0) {
6811 replyChainEnd = targetI;
6812 }
6813
6814 } else if (taskTopI >= 0 && allowTaskReparenting
6815 && task.affinity != null
6816 && task.affinity.equals(target.taskAffinity)) {
6817 // We are inside of another task... if this activity has
6818 // an affinity for our task, then either remove it if we are
6819 // clearing or move it over to our task. Note that
6820 // we currently punt on the case where we are resetting a
6821 // task that is not at the top but who has activities above
6822 // with an affinity to it... this is really not a normal
6823 // case, and we will need to later pull that task to the front
6824 // and usually at that point we will do the reset and pick
6825 // up those remaining activities. (This only happens if
6826 // someone starts an activity in a new task from an activity
6827 // in a task that is not currently on top.)
6828 if (forceReset || finishOnTaskLaunch) {
6829 if (replyChainEnd < 0) {
6830 replyChainEnd = targetI;
6831 }
6832 HistoryRecord p = null;
6833 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6834 p = (HistoryRecord)mHistory.get(srcPos);
6835 if (p.finishing) {
6836 continue;
6837 }
6838 if (finishActivityLocked(p, srcPos,
6839 Activity.RESULT_CANCELED, null, "reset")) {
6840 taskTopI--;
6841 lastReparentPos--;
6842 replyChainEnd--;
6843 srcPos--;
6844 }
6845 }
6846 replyChainEnd = -1;
6847 } else {
6848 if (replyChainEnd < 0) {
6849 replyChainEnd = targetI;
6850 }
6851 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6852 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6853 if (p.finishing) {
6854 continue;
6855 }
6856 if (lastReparentPos < 0) {
6857 lastReparentPos = taskTopI;
6858 taskTop = p;
6859 } else {
6860 lastReparentPos--;
6861 }
6862 mHistory.remove(srcPos);
6863 p.task.numActivities--;
6864 p.task = task;
6865 mHistory.add(lastReparentPos, p);
6866 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6867 + " in to resetting task " + task);
6868 task.numActivities++;
6869 mWindowManager.moveAppToken(lastReparentPos, p);
6870 mWindowManager.setAppGroupId(p, p.task.taskId);
6871 if (VALIDATE_TOKENS) {
6872 mWindowManager.validateAppTokens(mHistory);
6873 }
6874 }
6875 replyChainEnd = -1;
6876
6877 // Now we've moved it in to place... but what if this is
6878 // a singleTop activity and we have put it on top of another
6879 // instance of the same activity? Then we drop the instance
6880 // below so it remains singleTop.
6881 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6882 for (int j=lastReparentPos-1; j>=0; j--) {
6883 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6884 if (p.finishing) {
6885 continue;
6886 }
6887 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6888 if (finishActivityLocked(p, j,
6889 Activity.RESULT_CANCELED, null, "replace")) {
6890 taskTopI--;
6891 lastReparentPos--;
6892 }
6893 }
6894 }
6895 }
6896 }
6897 }
6898
6899 target = below;
6900 targetI = i;
6901 }
6902
6903 return taskTop;
6904 }
6905
6906 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006907 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006908 */
6909 public void moveTaskToFront(int task) {
6910 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6911 "moveTaskToFront()");
6912
6913 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006914 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6915 Binder.getCallingUid(), "Task to front")) {
6916 return;
6917 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006918 final long origId = Binder.clearCallingIdentity();
6919 try {
6920 int N = mRecentTasks.size();
6921 for (int i=0; i<N; i++) {
6922 TaskRecord tr = mRecentTasks.get(i);
6923 if (tr.taskId == task) {
6924 moveTaskToFrontLocked(tr);
6925 return;
6926 }
6927 }
6928 for (int i=mHistory.size()-1; i>=0; i--) {
6929 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6930 if (hr.task.taskId == task) {
6931 moveTaskToFrontLocked(hr.task);
6932 return;
6933 }
6934 }
6935 } finally {
6936 Binder.restoreCallingIdentity(origId);
6937 }
6938 }
6939 }
6940
6941 private final void moveTaskToFrontLocked(TaskRecord tr) {
6942 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6943
6944 final int task = tr.taskId;
6945 int top = mHistory.size()-1;
6946
6947 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6948 // nothing to do!
6949 return;
6950 }
6951
6952 if (DEBUG_TRANSITION) Log.v(TAG,
6953 "Prepare to front transition: task=" + tr);
6954 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6955
6956 ArrayList moved = new ArrayList();
6957
6958 // Applying the affinities may have removed entries from the history,
6959 // so get the size again.
6960 top = mHistory.size()-1;
6961 int pos = top;
6962
6963 // Shift all activities with this task up to the top
6964 // of the stack, keeping them in the same internal order.
6965 while (pos >= 0) {
6966 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6967 if (localLOGV) Log.v(
6968 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6969 boolean first = true;
6970 if (r.task.taskId == task) {
6971 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6972 mHistory.remove(pos);
6973 mHistory.add(top, r);
6974 moved.add(0, r);
6975 top--;
6976 if (first) {
6977 addRecentTask(r.task);
6978 first = false;
6979 }
6980 }
6981 pos--;
6982 }
6983
6984 mWindowManager.moveAppTokensToTop(moved);
6985 if (VALIDATE_TOKENS) {
6986 mWindowManager.validateAppTokens(mHistory);
6987 }
6988
6989 finishTaskMove(task);
6990 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6991 }
6992
6993 private final void finishTaskMove(int task) {
6994 resumeTopActivityLocked(null);
6995 }
6996
6997 public void moveTaskToBack(int task) {
6998 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6999 "moveTaskToBack()");
7000
7001 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007002 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7003 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7004 Binder.getCallingUid(), "Task to back")) {
7005 return;
7006 }
7007 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007008 final long origId = Binder.clearCallingIdentity();
7009 moveTaskToBackLocked(task);
7010 Binder.restoreCallingIdentity(origId);
7011 }
7012 }
7013
7014 /**
7015 * Moves an activity, and all of the other activities within the same task, to the bottom
7016 * of the history stack. The activity's order within the task is unchanged.
7017 *
7018 * @param token A reference to the activity we wish to move
7019 * @param nonRoot If false then this only works if the activity is the root
7020 * of a task; if true it will work for any activity in a task.
7021 * @return Returns true if the move completed, false if not.
7022 */
7023 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7024 synchronized(this) {
7025 final long origId = Binder.clearCallingIdentity();
7026 int taskId = getTaskForActivityLocked(token, !nonRoot);
7027 if (taskId >= 0) {
7028 return moveTaskToBackLocked(taskId);
7029 }
7030 Binder.restoreCallingIdentity(origId);
7031 }
7032 return false;
7033 }
7034
7035 /**
7036 * Worker method for rearranging history stack. Implements the function of moving all
7037 * activities for a specific task (gathering them if disjoint) into a single group at the
7038 * bottom of the stack.
7039 *
7040 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7041 * to premeptively cancel the move.
7042 *
7043 * @param task The taskId to collect and move to the bottom.
7044 * @return Returns true if the move completed, false if not.
7045 */
7046 private final boolean moveTaskToBackLocked(int task) {
7047 Log.i(TAG, "moveTaskToBack: " + task);
7048
7049 // If we have a watcher, preflight the move before committing to it. First check
7050 // for *other* available tasks, but if none are available, then try again allowing the
7051 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007052 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007053 HistoryRecord next = topRunningActivityLocked(null, task);
7054 if (next == null) {
7055 next = topRunningActivityLocked(null, 0);
7056 }
7057 if (next != null) {
7058 // ask watcher if this is allowed
7059 boolean moveOK = true;
7060 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007061 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007062 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007063 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007064 }
7065 if (!moveOK) {
7066 return false;
7067 }
7068 }
7069 }
7070
7071 ArrayList moved = new ArrayList();
7072
7073 if (DEBUG_TRANSITION) Log.v(TAG,
7074 "Prepare to back transition: task=" + task);
7075 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
7076
7077 final int N = mHistory.size();
7078 int bottom = 0;
7079 int pos = 0;
7080
7081 // Shift all activities with this task down to the bottom
7082 // of the stack, keeping them in the same internal order.
7083 while (pos < N) {
7084 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7085 if (localLOGV) Log.v(
7086 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7087 if (r.task.taskId == task) {
7088 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7089 mHistory.remove(pos);
7090 mHistory.add(bottom, r);
7091 moved.add(r);
7092 bottom++;
7093 }
7094 pos++;
7095 }
7096
7097 mWindowManager.moveAppTokensToBottom(moved);
7098 if (VALIDATE_TOKENS) {
7099 mWindowManager.validateAppTokens(mHistory);
7100 }
7101
7102 finishTaskMove(task);
7103 return true;
7104 }
7105
7106 public void moveTaskBackwards(int task) {
7107 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7108 "moveTaskBackwards()");
7109
7110 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007111 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7112 Binder.getCallingUid(), "Task backwards")) {
7113 return;
7114 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007115 final long origId = Binder.clearCallingIdentity();
7116 moveTaskBackwardsLocked(task);
7117 Binder.restoreCallingIdentity(origId);
7118 }
7119 }
7120
7121 private final void moveTaskBackwardsLocked(int task) {
7122 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7123 }
7124
7125 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7126 synchronized(this) {
7127 return getTaskForActivityLocked(token, onlyRoot);
7128 }
7129 }
7130
7131 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7132 final int N = mHistory.size();
7133 TaskRecord lastTask = null;
7134 for (int i=0; i<N; i++) {
7135 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7136 if (r == token) {
7137 if (!onlyRoot || lastTask != r.task) {
7138 return r.task.taskId;
7139 }
7140 return -1;
7141 }
7142 lastTask = r.task;
7143 }
7144
7145 return -1;
7146 }
7147
7148 /**
7149 * Returns the top activity in any existing task matching the given
7150 * Intent. Returns null if no such task is found.
7151 */
7152 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7153 ComponentName cls = intent.getComponent();
7154 if (info.targetActivity != null) {
7155 cls = new ComponentName(info.packageName, info.targetActivity);
7156 }
7157
7158 TaskRecord cp = null;
7159
7160 final int N = mHistory.size();
7161 for (int i=(N-1); i>=0; i--) {
7162 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7163 if (!r.finishing && r.task != cp
7164 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7165 cp = r.task;
7166 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7167 // + "/aff=" + r.task.affinity + " to new cls="
7168 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7169 if (r.task.affinity != null) {
7170 if (r.task.affinity.equals(info.taskAffinity)) {
7171 //Log.i(TAG, "Found matching affinity!");
7172 return r;
7173 }
7174 } else if (r.task.intent != null
7175 && r.task.intent.getComponent().equals(cls)) {
7176 //Log.i(TAG, "Found matching class!");
7177 //dump();
7178 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7179 return r;
7180 } else if (r.task.affinityIntent != null
7181 && r.task.affinityIntent.getComponent().equals(cls)) {
7182 //Log.i(TAG, "Found matching class!");
7183 //dump();
7184 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7185 return r;
7186 }
7187 }
7188 }
7189
7190 return null;
7191 }
7192
7193 /**
7194 * Returns the first activity (starting from the top of the stack) that
7195 * is the same as the given activity. Returns null if no such activity
7196 * is found.
7197 */
7198 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7199 ComponentName cls = intent.getComponent();
7200 if (info.targetActivity != null) {
7201 cls = new ComponentName(info.packageName, info.targetActivity);
7202 }
7203
7204 final int N = mHistory.size();
7205 for (int i=(N-1); i>=0; i--) {
7206 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7207 if (!r.finishing) {
7208 if (r.intent.getComponent().equals(cls)) {
7209 //Log.i(TAG, "Found matching class!");
7210 //dump();
7211 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7212 return r;
7213 }
7214 }
7215 }
7216
7217 return null;
7218 }
7219
7220 public void finishOtherInstances(IBinder token, ComponentName className) {
7221 synchronized(this) {
7222 final long origId = Binder.clearCallingIdentity();
7223
7224 int N = mHistory.size();
7225 TaskRecord lastTask = null;
7226 for (int i=0; i<N; i++) {
7227 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7228 if (r.realActivity.equals(className)
7229 && r != token && lastTask != r.task) {
7230 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7231 null, "others")) {
7232 i--;
7233 N--;
7234 }
7235 }
7236 lastTask = r.task;
7237 }
7238
7239 Binder.restoreCallingIdentity(origId);
7240 }
7241 }
7242
7243 // =========================================================
7244 // THUMBNAILS
7245 // =========================================================
7246
7247 public void reportThumbnail(IBinder token,
7248 Bitmap thumbnail, CharSequence description) {
7249 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7250 final long origId = Binder.clearCallingIdentity();
7251 sendPendingThumbnail(null, token, thumbnail, description, true);
7252 Binder.restoreCallingIdentity(origId);
7253 }
7254
7255 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7256 Bitmap thumbnail, CharSequence description, boolean always) {
7257 TaskRecord task = null;
7258 ArrayList receivers = null;
7259
7260 //System.out.println("Send pending thumbnail: " + r);
7261
7262 synchronized(this) {
7263 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007264 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007265 if (index < 0) {
7266 return;
7267 }
7268 r = (HistoryRecord)mHistory.get(index);
7269 }
7270 if (thumbnail == null) {
7271 thumbnail = r.thumbnail;
7272 description = r.description;
7273 }
7274 if (thumbnail == null && !always) {
7275 // If there is no thumbnail, and this entry is not actually
7276 // going away, then abort for now and pick up the next
7277 // thumbnail we get.
7278 return;
7279 }
7280 task = r.task;
7281
7282 int N = mPendingThumbnails.size();
7283 int i=0;
7284 while (i<N) {
7285 PendingThumbnailsRecord pr =
7286 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7287 //System.out.println("Looking in " + pr.pendingRecords);
7288 if (pr.pendingRecords.remove(r)) {
7289 if (receivers == null) {
7290 receivers = new ArrayList();
7291 }
7292 receivers.add(pr);
7293 if (pr.pendingRecords.size() == 0) {
7294 pr.finished = true;
7295 mPendingThumbnails.remove(i);
7296 N--;
7297 continue;
7298 }
7299 }
7300 i++;
7301 }
7302 }
7303
7304 if (receivers != null) {
7305 final int N = receivers.size();
7306 for (int i=0; i<N; i++) {
7307 try {
7308 PendingThumbnailsRecord pr =
7309 (PendingThumbnailsRecord)receivers.get(i);
7310 pr.receiver.newThumbnail(
7311 task != null ? task.taskId : -1, thumbnail, description);
7312 if (pr.finished) {
7313 pr.receiver.finished();
7314 }
7315 } catch (Exception e) {
7316 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7317 }
7318 }
7319 }
7320 }
7321
7322 // =========================================================
7323 // CONTENT PROVIDERS
7324 // =========================================================
7325
7326 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7327 List providers = null;
7328 try {
7329 providers = ActivityThread.getPackageManager().
7330 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007331 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007332 } catch (RemoteException ex) {
7333 }
7334 if (providers != null) {
7335 final int N = providers.size();
7336 for (int i=0; i<N; i++) {
7337 ProviderInfo cpi =
7338 (ProviderInfo)providers.get(i);
7339 ContentProviderRecord cpr =
7340 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7341 if (cpr == null) {
7342 cpr = new ContentProviderRecord(cpi, app.info);
7343 mProvidersByClass.put(cpi.name, cpr);
7344 }
7345 app.pubProviders.put(cpi.name, cpr);
7346 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007347 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007348 }
7349 }
7350 return providers;
7351 }
7352
7353 private final String checkContentProviderPermissionLocked(
7354 ProviderInfo cpi, ProcessRecord r, int mode) {
7355 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7356 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7357 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7358 cpi.exported ? -1 : cpi.applicationInfo.uid)
7359 == PackageManager.PERMISSION_GRANTED
7360 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7361 return null;
7362 }
7363 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7364 cpi.exported ? -1 : cpi.applicationInfo.uid)
7365 == PackageManager.PERMISSION_GRANTED) {
7366 return null;
7367 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007368
7369 PathPermission[] pps = cpi.pathPermissions;
7370 if (pps != null) {
7371 int i = pps.length;
7372 while (i > 0) {
7373 i--;
7374 PathPermission pp = pps[i];
7375 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7376 cpi.exported ? -1 : cpi.applicationInfo.uid)
7377 == PackageManager.PERMISSION_GRANTED
7378 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7379 return null;
7380 }
7381 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7382 cpi.exported ? -1 : cpi.applicationInfo.uid)
7383 == PackageManager.PERMISSION_GRANTED) {
7384 return null;
7385 }
7386 }
7387 }
7388
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007389 String msg = "Permission Denial: opening provider " + cpi.name
7390 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7391 + ", uid=" + callingUid + ") requires "
7392 + cpi.readPermission + " or " + cpi.writePermission;
7393 Log.w(TAG, msg);
7394 return msg;
7395 }
7396
7397 private final ContentProviderHolder getContentProviderImpl(
7398 IApplicationThread caller, String name) {
7399 ContentProviderRecord cpr;
7400 ProviderInfo cpi = null;
7401
7402 synchronized(this) {
7403 ProcessRecord r = null;
7404 if (caller != null) {
7405 r = getRecordForAppLocked(caller);
7406 if (r == null) {
7407 throw new SecurityException(
7408 "Unable to find app for caller " + caller
7409 + " (pid=" + Binder.getCallingPid()
7410 + ") when getting content provider " + name);
7411 }
7412 }
7413
7414 // First check if this content provider has been published...
7415 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7416 if (cpr != null) {
7417 cpi = cpr.info;
7418 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7419 return new ContentProviderHolder(cpi,
7420 cpi.readPermission != null
7421 ? cpi.readPermission : cpi.writePermission);
7422 }
7423
7424 if (r != null && cpr.canRunHere(r)) {
7425 // This provider has been published or is in the process
7426 // of being published... but it is also allowed to run
7427 // in the caller's process, so don't make a connection
7428 // and just let the caller instantiate its own instance.
7429 if (cpr.provider != null) {
7430 // don't give caller the provider object, it needs
7431 // to make its own.
7432 cpr = new ContentProviderRecord(cpr);
7433 }
7434 return cpr;
7435 }
7436
7437 final long origId = Binder.clearCallingIdentity();
7438
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007439 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007440 // return it right away.
7441 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007442 if (DEBUG_PROVIDER) Log.v(TAG,
7443 "Adding provider requested by "
7444 + r.processName + " from process "
7445 + cpr.info.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007446 r.conProviders.add(cpr);
7447 cpr.clients.add(r);
7448 } else {
7449 cpr.externals++;
7450 }
7451
7452 if (cpr.app != null) {
7453 updateOomAdjLocked(cpr.app);
7454 }
7455
7456 Binder.restoreCallingIdentity(origId);
7457
7458 } else {
7459 try {
7460 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007461 resolveContentProvider(name,
7462 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007463 } catch (RemoteException ex) {
7464 }
7465 if (cpi == null) {
7466 return null;
7467 }
7468
7469 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7470 return new ContentProviderHolder(cpi,
7471 cpi.readPermission != null
7472 ? cpi.readPermission : cpi.writePermission);
7473 }
7474
7475 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7476 final boolean firstClass = cpr == null;
7477 if (firstClass) {
7478 try {
7479 ApplicationInfo ai =
7480 ActivityThread.getPackageManager().
7481 getApplicationInfo(
7482 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007483 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007484 if (ai == null) {
7485 Log.w(TAG, "No package info for content provider "
7486 + cpi.name);
7487 return null;
7488 }
7489 cpr = new ContentProviderRecord(cpi, ai);
7490 } catch (RemoteException ex) {
7491 // pm is in same process, this will never happen.
7492 }
7493 }
7494
7495 if (r != null && cpr.canRunHere(r)) {
7496 // If this is a multiprocess provider, then just return its
7497 // info and allow the caller to instantiate it. Only do
7498 // this if the provider is the same user as the caller's
7499 // process, or can run as root (so can be in any process).
7500 return cpr;
7501 }
7502
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007503 if (DEBUG_PROVIDER) {
7504 RuntimeException e = new RuntimeException("here");
7505 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7506 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007507 }
7508
7509 // This is single process, and our app is now connecting to it.
7510 // See if we are already in the process of launching this
7511 // provider.
7512 final int N = mLaunchingProviders.size();
7513 int i;
7514 for (i=0; i<N; i++) {
7515 if (mLaunchingProviders.get(i) == cpr) {
7516 break;
7517 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007518 }
7519
7520 // If the provider is not already being launched, then get it
7521 // started.
7522 if (i >= N) {
7523 final long origId = Binder.clearCallingIdentity();
7524 ProcessRecord proc = startProcessLocked(cpi.processName,
7525 cpr.appInfo, false, 0, "content provider",
7526 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007527 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007528 if (proc == null) {
7529 Log.w(TAG, "Unable to launch app "
7530 + cpi.applicationInfo.packageName + "/"
7531 + cpi.applicationInfo.uid + " for provider "
7532 + name + ": process is bad");
7533 return null;
7534 }
7535 cpr.launchingApp = proc;
7536 mLaunchingProviders.add(cpr);
7537 Binder.restoreCallingIdentity(origId);
7538 }
7539
7540 // Make sure the provider is published (the same provider class
7541 // may be published under multiple names).
7542 if (firstClass) {
7543 mProvidersByClass.put(cpi.name, cpr);
7544 }
7545 mProvidersByName.put(name, cpr);
7546
7547 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007548 if (DEBUG_PROVIDER) Log.v(TAG,
7549 "Adding provider requested by "
7550 + r.processName + " from process "
7551 + cpr.info.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007552 r.conProviders.add(cpr);
7553 cpr.clients.add(r);
7554 } else {
7555 cpr.externals++;
7556 }
7557 }
7558 }
7559
7560 // Wait for the provider to be published...
7561 synchronized (cpr) {
7562 while (cpr.provider == null) {
7563 if (cpr.launchingApp == null) {
7564 Log.w(TAG, "Unable to launch app "
7565 + cpi.applicationInfo.packageName + "/"
7566 + cpi.applicationInfo.uid + " for provider "
7567 + name + ": launching app became null");
7568 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7569 cpi.applicationInfo.packageName,
7570 cpi.applicationInfo.uid, name);
7571 return null;
7572 }
7573 try {
7574 cpr.wait();
7575 } catch (InterruptedException ex) {
7576 }
7577 }
7578 }
7579 return cpr;
7580 }
7581
7582 public final ContentProviderHolder getContentProvider(
7583 IApplicationThread caller, String name) {
7584 if (caller == null) {
7585 String msg = "null IApplicationThread when getting content provider "
7586 + name;
7587 Log.w(TAG, msg);
7588 throw new SecurityException(msg);
7589 }
7590
7591 return getContentProviderImpl(caller, name);
7592 }
7593
7594 private ContentProviderHolder getContentProviderExternal(String name) {
7595 return getContentProviderImpl(null, name);
7596 }
7597
7598 /**
7599 * Drop a content provider from a ProcessRecord's bookkeeping
7600 * @param cpr
7601 */
7602 public void removeContentProvider(IApplicationThread caller, String name) {
7603 synchronized (this) {
7604 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7605 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007606 // remove from mProvidersByClass
7607 if (DEBUG_PROVIDER) Log.v(TAG, name +
7608 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007609 return;
7610 }
7611 final ProcessRecord r = getRecordForAppLocked(caller);
7612 if (r == null) {
7613 throw new SecurityException(
7614 "Unable to find app for caller " + caller +
7615 " when removing content provider " + name);
7616 }
7617 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007618 ContentProviderRecord localCpr = (ContentProviderRecord)
7619 mProvidersByClass.get(cpr.info.name);
7620 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7621 + r.info.processName + " from process "
7622 + localCpr.appInfo.processName);
7623 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007624 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007625 Log.w(TAG, "removeContentProvider called on local provider: "
7626 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007627 return;
7628 } else {
7629 localCpr.clients.remove(r);
7630 r.conProviders.remove(localCpr);
7631 }
7632 updateOomAdjLocked();
7633 }
7634 }
7635
7636 private void removeContentProviderExternal(String name) {
7637 synchronized (this) {
7638 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7639 if(cpr == null) {
7640 //remove from mProvidersByClass
7641 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7642 return;
7643 }
7644
7645 //update content provider record entry info
7646 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7647 localCpr.externals--;
7648 if (localCpr.externals < 0) {
7649 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7650 }
7651 updateOomAdjLocked();
7652 }
7653 }
7654
7655 public final void publishContentProviders(IApplicationThread caller,
7656 List<ContentProviderHolder> providers) {
7657 if (providers == null) {
7658 return;
7659 }
7660
7661 synchronized(this) {
7662 final ProcessRecord r = getRecordForAppLocked(caller);
7663 if (r == null) {
7664 throw new SecurityException(
7665 "Unable to find app for caller " + caller
7666 + " (pid=" + Binder.getCallingPid()
7667 + ") when publishing content providers");
7668 }
7669
7670 final long origId = Binder.clearCallingIdentity();
7671
7672 final int N = providers.size();
7673 for (int i=0; i<N; i++) {
7674 ContentProviderHolder src = providers.get(i);
7675 if (src == null || src.info == null || src.provider == null) {
7676 continue;
7677 }
7678 ContentProviderRecord dst =
7679 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7680 if (dst != null) {
7681 mProvidersByClass.put(dst.info.name, dst);
7682 String names[] = dst.info.authority.split(";");
7683 for (int j = 0; j < names.length; j++) {
7684 mProvidersByName.put(names[j], dst);
7685 }
7686
7687 int NL = mLaunchingProviders.size();
7688 int j;
7689 for (j=0; j<NL; j++) {
7690 if (mLaunchingProviders.get(j) == dst) {
7691 mLaunchingProviders.remove(j);
7692 j--;
7693 NL--;
7694 }
7695 }
7696 synchronized (dst) {
7697 dst.provider = src.provider;
7698 dst.app = r;
7699 dst.notifyAll();
7700 }
7701 updateOomAdjLocked(r);
7702 }
7703 }
7704
7705 Binder.restoreCallingIdentity(origId);
7706 }
7707 }
7708
7709 public static final void installSystemProviders() {
7710 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7711 List providers = mSelf.generateApplicationProvidersLocked(app);
7712 mSystemThread.installSystemProviders(providers);
7713 }
7714
7715 // =========================================================
7716 // GLOBAL MANAGEMENT
7717 // =========================================================
7718
7719 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7720 ApplicationInfo info, String customProcess) {
7721 String proc = customProcess != null ? customProcess : info.processName;
7722 BatteryStatsImpl.Uid.Proc ps = null;
7723 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7724 synchronized (stats) {
7725 ps = stats.getProcessStatsLocked(info.uid, proc);
7726 }
7727 return new ProcessRecord(ps, thread, info, proc);
7728 }
7729
7730 final ProcessRecord addAppLocked(ApplicationInfo info) {
7731 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7732
7733 if (app == null) {
7734 app = newProcessRecordLocked(null, info, null);
7735 mProcessNames.put(info.processName, info.uid, app);
7736 updateLRUListLocked(app, true);
7737 }
7738
7739 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7740 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7741 app.persistent = true;
7742 app.maxAdj = CORE_SERVER_ADJ;
7743 }
7744 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7745 mPersistentStartingProcesses.add(app);
7746 startProcessLocked(app, "added application", app.processName);
7747 }
7748
7749 return app;
7750 }
7751
7752 public void unhandledBack() {
7753 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7754 "unhandledBack()");
7755
7756 synchronized(this) {
7757 int count = mHistory.size();
7758 if (Config.LOGD) Log.d(
7759 TAG, "Performing unhandledBack(): stack size = " + count);
7760 if (count > 1) {
7761 final long origId = Binder.clearCallingIdentity();
7762 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7763 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7764 Binder.restoreCallingIdentity(origId);
7765 }
7766 }
7767 }
7768
7769 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7770 String name = uri.getAuthority();
7771 ContentProviderHolder cph = getContentProviderExternal(name);
7772 ParcelFileDescriptor pfd = null;
7773 if (cph != null) {
7774 // We record the binder invoker's uid in thread-local storage before
7775 // going to the content provider to open the file. Later, in the code
7776 // that handles all permissions checks, we look for this uid and use
7777 // that rather than the Activity Manager's own uid. The effect is that
7778 // we do the check against the caller's permissions even though it looks
7779 // to the content provider like the Activity Manager itself is making
7780 // the request.
7781 sCallerIdentity.set(new Identity(
7782 Binder.getCallingPid(), Binder.getCallingUid()));
7783 try {
7784 pfd = cph.provider.openFile(uri, "r");
7785 } catch (FileNotFoundException e) {
7786 // do nothing; pfd will be returned null
7787 } finally {
7788 // Ensure that whatever happens, we clean up the identity state
7789 sCallerIdentity.remove();
7790 }
7791
7792 // We've got the fd now, so we're done with the provider.
7793 removeContentProviderExternal(name);
7794 } else {
7795 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7796 }
7797 return pfd;
7798 }
7799
7800 public void goingToSleep() {
7801 synchronized(this) {
7802 mSleeping = true;
7803 mWindowManager.setEventDispatching(false);
7804
7805 if (mResumedActivity != null) {
7806 pauseIfSleepingLocked();
7807 } else {
7808 Log.w(TAG, "goingToSleep with no resumed activity!");
7809 }
7810 }
7811 }
7812
Dianne Hackborn55280a92009-05-07 15:53:46 -07007813 public boolean shutdown(int timeout) {
7814 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7815 != PackageManager.PERMISSION_GRANTED) {
7816 throw new SecurityException("Requires permission "
7817 + android.Manifest.permission.SHUTDOWN);
7818 }
7819
7820 boolean timedout = false;
7821
7822 synchronized(this) {
7823 mShuttingDown = true;
7824 mWindowManager.setEventDispatching(false);
7825
7826 if (mResumedActivity != null) {
7827 pauseIfSleepingLocked();
7828 final long endTime = System.currentTimeMillis() + timeout;
7829 while (mResumedActivity != null || mPausingActivity != null) {
7830 long delay = endTime - System.currentTimeMillis();
7831 if (delay <= 0) {
7832 Log.w(TAG, "Activity manager shutdown timed out");
7833 timedout = true;
7834 break;
7835 }
7836 try {
7837 this.wait();
7838 } catch (InterruptedException e) {
7839 }
7840 }
7841 }
7842 }
7843
7844 mUsageStatsService.shutdown();
7845 mBatteryStatsService.shutdown();
7846
7847 return timedout;
7848 }
7849
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007850 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007851 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007852 if (!mGoingToSleep.isHeld()) {
7853 mGoingToSleep.acquire();
7854 if (mLaunchingActivity.isHeld()) {
7855 mLaunchingActivity.release();
7856 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7857 }
7858 }
7859
7860 // If we are not currently pausing an activity, get the current
7861 // one to pause. If we are pausing one, we will just let that stuff
7862 // run and release the wake lock when all done.
7863 if (mPausingActivity == null) {
7864 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7865 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7866 startPausingLocked(false, true);
7867 }
7868 }
7869 }
7870
7871 public void wakingUp() {
7872 synchronized(this) {
7873 if (mGoingToSleep.isHeld()) {
7874 mGoingToSleep.release();
7875 }
7876 mWindowManager.setEventDispatching(true);
7877 mSleeping = false;
7878 resumeTopActivityLocked(null);
7879 }
7880 }
7881
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007882 public void stopAppSwitches() {
7883 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7884 != PackageManager.PERMISSION_GRANTED) {
7885 throw new SecurityException("Requires permission "
7886 + android.Manifest.permission.STOP_APP_SWITCHES);
7887 }
7888
7889 synchronized(this) {
7890 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7891 + APP_SWITCH_DELAY_TIME;
7892 mDidAppSwitch = false;
7893 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7894 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7895 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7896 }
7897 }
7898
7899 public void resumeAppSwitches() {
7900 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7901 != PackageManager.PERMISSION_GRANTED) {
7902 throw new SecurityException("Requires permission "
7903 + android.Manifest.permission.STOP_APP_SWITCHES);
7904 }
7905
7906 synchronized(this) {
7907 // Note that we don't execute any pending app switches... we will
7908 // let those wait until either the timeout, or the next start
7909 // activity request.
7910 mAppSwitchesAllowedTime = 0;
7911 }
7912 }
7913
7914 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7915 String name) {
7916 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7917 return true;
7918 }
7919
7920 final int perm = checkComponentPermission(
7921 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7922 callingUid, -1);
7923 if (perm == PackageManager.PERMISSION_GRANTED) {
7924 return true;
7925 }
7926
7927 Log.w(TAG, name + " request from " + callingUid + " stopped");
7928 return false;
7929 }
7930
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007931 public void setDebugApp(String packageName, boolean waitForDebugger,
7932 boolean persistent) {
7933 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7934 "setDebugApp()");
7935
7936 // Note that this is not really thread safe if there are multiple
7937 // callers into it at the same time, but that's not a situation we
7938 // care about.
7939 if (persistent) {
7940 final ContentResolver resolver = mContext.getContentResolver();
7941 Settings.System.putString(
7942 resolver, Settings.System.DEBUG_APP,
7943 packageName);
7944 Settings.System.putInt(
7945 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7946 waitForDebugger ? 1 : 0);
7947 }
7948
7949 synchronized (this) {
7950 if (!persistent) {
7951 mOrigDebugApp = mDebugApp;
7952 mOrigWaitForDebugger = mWaitForDebugger;
7953 }
7954 mDebugApp = packageName;
7955 mWaitForDebugger = waitForDebugger;
7956 mDebugTransient = !persistent;
7957 if (packageName != null) {
7958 final long origId = Binder.clearCallingIdentity();
7959 uninstallPackageLocked(packageName, -1, false);
7960 Binder.restoreCallingIdentity(origId);
7961 }
7962 }
7963 }
7964
7965 public void setAlwaysFinish(boolean enabled) {
7966 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7967 "setAlwaysFinish()");
7968
7969 Settings.System.putInt(
7970 mContext.getContentResolver(),
7971 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7972
7973 synchronized (this) {
7974 mAlwaysFinishActivities = enabled;
7975 }
7976 }
7977
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007978 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007979 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007980 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007981 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007982 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007983 }
7984 }
7985
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007986 public void registerActivityWatcher(IActivityWatcher watcher) {
7987 mWatchers.register(watcher);
7988 }
7989
7990 public void unregisterActivityWatcher(IActivityWatcher watcher) {
7991 mWatchers.unregister(watcher);
7992 }
7993
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007994 public final void enterSafeMode() {
7995 synchronized(this) {
7996 // It only makes sense to do this before the system is ready
7997 // and started launching other packages.
7998 if (!mSystemReady) {
7999 try {
8000 ActivityThread.getPackageManager().enterSafeMode();
8001 } catch (RemoteException e) {
8002 }
8003
8004 View v = LayoutInflater.from(mContext).inflate(
8005 com.android.internal.R.layout.safe_mode, null);
8006 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8007 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8008 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8009 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8010 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8011 lp.format = v.getBackground().getOpacity();
8012 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8013 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8014 ((WindowManager)mContext.getSystemService(
8015 Context.WINDOW_SERVICE)).addView(v, lp);
8016 }
8017 }
8018 }
8019
8020 public void noteWakeupAlarm(IIntentSender sender) {
8021 if (!(sender instanceof PendingIntentRecord)) {
8022 return;
8023 }
8024 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8025 synchronized (stats) {
8026 if (mBatteryStatsService.isOnBattery()) {
8027 mBatteryStatsService.enforceCallingPermission();
8028 PendingIntentRecord rec = (PendingIntentRecord)sender;
8029 int MY_UID = Binder.getCallingUid();
8030 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8031 BatteryStatsImpl.Uid.Pkg pkg =
8032 stats.getPackageStatsLocked(uid, rec.key.packageName);
8033 pkg.incWakeupsLocked();
8034 }
8035 }
8036 }
8037
8038 public boolean killPidsForMemory(int[] pids) {
8039 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8040 throw new SecurityException("killPidsForMemory only available to the system");
8041 }
8042
8043 // XXX Note: don't acquire main activity lock here, because the window
8044 // manager calls in with its locks held.
8045
8046 boolean killed = false;
8047 synchronized (mPidsSelfLocked) {
8048 int[] types = new int[pids.length];
8049 int worstType = 0;
8050 for (int i=0; i<pids.length; i++) {
8051 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8052 if (proc != null) {
8053 int type = proc.setAdj;
8054 types[i] = type;
8055 if (type > worstType) {
8056 worstType = type;
8057 }
8058 }
8059 }
8060
8061 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8062 // then constrain it so we will kill all hidden procs.
8063 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8064 worstType = HIDDEN_APP_MIN_ADJ;
8065 }
8066 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8067 for (int i=0; i<pids.length; i++) {
8068 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8069 if (proc == null) {
8070 continue;
8071 }
8072 int adj = proc.setAdj;
8073 if (adj >= worstType) {
8074 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8075 + adj + ")");
8076 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
8077 proc.processName, adj);
8078 killed = true;
8079 Process.killProcess(pids[i]);
8080 }
8081 }
8082 }
8083 return killed;
8084 }
8085
8086 public void reportPss(IApplicationThread caller, int pss) {
8087 Watchdog.PssRequestor req;
8088 String name;
8089 ProcessRecord callerApp;
8090 synchronized (this) {
8091 if (caller == null) {
8092 return;
8093 }
8094 callerApp = getRecordForAppLocked(caller);
8095 if (callerApp == null) {
8096 return;
8097 }
8098 callerApp.lastPss = pss;
8099 req = callerApp;
8100 name = callerApp.processName;
8101 }
8102 Watchdog.getInstance().reportPss(req, name, pss);
8103 if (!callerApp.persistent) {
8104 removeRequestedPss(callerApp);
8105 }
8106 }
8107
8108 public void requestPss(Runnable completeCallback) {
8109 ArrayList<ProcessRecord> procs;
8110 synchronized (this) {
8111 mRequestPssCallback = completeCallback;
8112 mRequestPssList.clear();
8113 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8114 ProcessRecord proc = mLRUProcesses.get(i);
8115 if (!proc.persistent) {
8116 mRequestPssList.add(proc);
8117 }
8118 }
8119 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8120 }
8121
8122 int oldPri = Process.getThreadPriority(Process.myTid());
8123 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8124 for (int i=procs.size()-1; i>=0; i--) {
8125 ProcessRecord proc = procs.get(i);
8126 proc.lastPss = 0;
8127 proc.requestPss();
8128 }
8129 Process.setThreadPriority(oldPri);
8130 }
8131
8132 void removeRequestedPss(ProcessRecord proc) {
8133 Runnable callback = null;
8134 synchronized (this) {
8135 if (mRequestPssList.remove(proc)) {
8136 if (mRequestPssList.size() == 0) {
8137 callback = mRequestPssCallback;
8138 mRequestPssCallback = null;
8139 }
8140 }
8141 }
8142
8143 if (callback != null) {
8144 callback.run();
8145 }
8146 }
8147
8148 public void collectPss(Watchdog.PssStats stats) {
8149 stats.mEmptyPss = 0;
8150 stats.mEmptyCount = 0;
8151 stats.mBackgroundPss = 0;
8152 stats.mBackgroundCount = 0;
8153 stats.mServicePss = 0;
8154 stats.mServiceCount = 0;
8155 stats.mVisiblePss = 0;
8156 stats.mVisibleCount = 0;
8157 stats.mForegroundPss = 0;
8158 stats.mForegroundCount = 0;
8159 stats.mNoPssCount = 0;
8160 synchronized (this) {
8161 int i;
8162 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8163 ? mProcDeaths.length : stats.mProcDeaths.length;
8164 int aggr = 0;
8165 for (i=0; i<NPD; i++) {
8166 aggr += mProcDeaths[i];
8167 stats.mProcDeaths[i] = aggr;
8168 }
8169 while (i<stats.mProcDeaths.length) {
8170 stats.mProcDeaths[i] = 0;
8171 i++;
8172 }
8173
8174 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8175 ProcessRecord proc = mLRUProcesses.get(i);
8176 if (proc.persistent) {
8177 continue;
8178 }
8179 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8180 if (proc.lastPss == 0) {
8181 stats.mNoPssCount++;
8182 continue;
8183 }
8184 if (proc.setAdj == EMPTY_APP_ADJ) {
8185 stats.mEmptyPss += proc.lastPss;
8186 stats.mEmptyCount++;
8187 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8188 stats.mEmptyPss += proc.lastPss;
8189 stats.mEmptyCount++;
8190 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8191 stats.mBackgroundPss += proc.lastPss;
8192 stats.mBackgroundCount++;
8193 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8194 stats.mVisiblePss += proc.lastPss;
8195 stats.mVisibleCount++;
8196 } else {
8197 stats.mForegroundPss += proc.lastPss;
8198 stats.mForegroundCount++;
8199 }
8200 }
8201 }
8202 }
8203
8204 public final void startRunning(String pkg, String cls, String action,
8205 String data) {
8206 synchronized(this) {
8207 if (mStartRunning) {
8208 return;
8209 }
8210 mStartRunning = true;
8211 mTopComponent = pkg != null && cls != null
8212 ? new ComponentName(pkg, cls) : null;
8213 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8214 mTopData = data;
8215 if (!mSystemReady) {
8216 return;
8217 }
8218 }
8219
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008220 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008221 }
8222
8223 private void retrieveSettings() {
8224 final ContentResolver resolver = mContext.getContentResolver();
8225 String debugApp = Settings.System.getString(
8226 resolver, Settings.System.DEBUG_APP);
8227 boolean waitForDebugger = Settings.System.getInt(
8228 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8229 boolean alwaysFinishActivities = Settings.System.getInt(
8230 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8231
8232 Configuration configuration = new Configuration();
8233 Settings.System.getConfiguration(resolver, configuration);
8234
8235 synchronized (this) {
8236 mDebugApp = mOrigDebugApp = debugApp;
8237 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8238 mAlwaysFinishActivities = alwaysFinishActivities;
8239 // This happens before any activities are started, so we can
8240 // change mConfiguration in-place.
8241 mConfiguration.updateFrom(configuration);
8242 }
8243 }
8244
8245 public boolean testIsSystemReady() {
8246 // no need to synchronize(this) just to read & return the value
8247 return mSystemReady;
8248 }
8249
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008250 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008251 // In the simulator, startRunning will never have been called, which
8252 // normally sets a few crucial variables. Do it here instead.
8253 if (!Process.supportsProcesses()) {
8254 mStartRunning = true;
8255 mTopAction = Intent.ACTION_MAIN;
8256 }
8257
8258 synchronized(this) {
8259 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008260 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008261 return;
8262 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008263
8264 // Check to see if there are any update receivers to run.
8265 if (!mDidUpdate) {
8266 if (mWaitingUpdate) {
8267 return;
8268 }
8269 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8270 List<ResolveInfo> ris = null;
8271 try {
8272 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8273 intent, null, 0);
8274 } catch (RemoteException e) {
8275 }
8276 if (ris != null) {
8277 for (int i=ris.size()-1; i>=0; i--) {
8278 if ((ris.get(i).activityInfo.applicationInfo.flags
8279 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8280 ris.remove(i);
8281 }
8282 }
8283 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8284 for (int i=0; i<ris.size(); i++) {
8285 ActivityInfo ai = ris.get(i).activityInfo;
8286 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8287 IIntentReceiver finisher = null;
8288 if (i == 0) {
8289 finisher = new IIntentReceiver.Stub() {
8290 public void performReceive(Intent intent, int resultCode,
8291 String data, Bundle extras, boolean ordered)
8292 throws RemoteException {
8293 synchronized (ActivityManagerService.this) {
8294 mDidUpdate = true;
8295 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008296 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008297 }
8298 };
8299 }
8300 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8301 broadcastIntentLocked(null, null, intent, null, finisher,
8302 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8303 if (i == 0) {
8304 mWaitingUpdate = true;
8305 }
8306 }
8307 }
8308 if (mWaitingUpdate) {
8309 return;
8310 }
8311 mDidUpdate = true;
8312 }
8313
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008314 mSystemReady = true;
8315 if (!mStartRunning) {
8316 return;
8317 }
8318 }
8319
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008320 ArrayList<ProcessRecord> procsToKill = null;
8321 synchronized(mPidsSelfLocked) {
8322 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8323 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8324 if (!isAllowedWhileBooting(proc.info)){
8325 if (procsToKill == null) {
8326 procsToKill = new ArrayList<ProcessRecord>();
8327 }
8328 procsToKill.add(proc);
8329 }
8330 }
8331 }
8332
8333 if (procsToKill != null) {
8334 synchronized(this) {
8335 for (int i=procsToKill.size()-1; i>=0; i--) {
8336 ProcessRecord proc = procsToKill.get(i);
8337 Log.i(TAG, "Removing system update proc: " + proc);
8338 removeProcessLocked(proc, true);
8339 }
8340 }
8341 }
8342
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008343 Log.i(TAG, "System now ready");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008344 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8345 SystemClock.uptimeMillis());
8346
8347 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008348 // Make sure we have no pre-ready processes sitting around.
8349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008350 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8351 ResolveInfo ri = mContext.getPackageManager()
8352 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008353 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008354 CharSequence errorMsg = null;
8355 if (ri != null) {
8356 ActivityInfo ai = ri.activityInfo;
8357 ApplicationInfo app = ai.applicationInfo;
8358 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8359 mTopAction = Intent.ACTION_FACTORY_TEST;
8360 mTopData = null;
8361 mTopComponent = new ComponentName(app.packageName,
8362 ai.name);
8363 } else {
8364 errorMsg = mContext.getResources().getText(
8365 com.android.internal.R.string.factorytest_not_system);
8366 }
8367 } else {
8368 errorMsg = mContext.getResources().getText(
8369 com.android.internal.R.string.factorytest_no_action);
8370 }
8371 if (errorMsg != null) {
8372 mTopAction = null;
8373 mTopData = null;
8374 mTopComponent = null;
8375 Message msg = Message.obtain();
8376 msg.what = SHOW_FACTORY_ERROR_MSG;
8377 msg.getData().putCharSequence("msg", errorMsg);
8378 mHandler.sendMessage(msg);
8379 }
8380 }
8381 }
8382
8383 retrieveSettings();
8384
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008385 if (goingCallback != null) goingCallback.run();
8386
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008387 synchronized (this) {
8388 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8389 try {
8390 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008391 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008392 if (apps != null) {
8393 int N = apps.size();
8394 int i;
8395 for (i=0; i<N; i++) {
8396 ApplicationInfo info
8397 = (ApplicationInfo)apps.get(i);
8398 if (info != null &&
8399 !info.packageName.equals("android")) {
8400 addAppLocked(info);
8401 }
8402 }
8403 }
8404 } catch (RemoteException ex) {
8405 // pm is in same process, this will never happen.
8406 }
8407 }
8408
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008409 // Start up initial activity.
8410 mBooting = true;
8411
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008412 try {
8413 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8414 Message msg = Message.obtain();
8415 msg.what = SHOW_UID_ERROR_MSG;
8416 mHandler.sendMessage(msg);
8417 }
8418 } catch (RemoteException e) {
8419 }
8420
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008421 resumeTopActivityLocked(null);
8422 }
8423 }
8424
8425 boolean makeAppCrashingLocked(ProcessRecord app,
8426 String tag, String shortMsg, String longMsg, byte[] crashData) {
8427 app.crashing = true;
8428 app.crashingReport = generateProcessError(app,
8429 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8430 startAppProblemLocked(app);
8431 app.stopFreezingAllLocked();
8432 return handleAppCrashLocked(app);
8433 }
8434
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008435 private ComponentName getErrorReportReceiver(ProcessRecord app) {
8436 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008437
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008438 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008439 // look for receiver in the installer package
8440 String candidate = pm.getInstallerPackageName(app.info.packageName);
8441 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8442 if (result != null) {
8443 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008444 }
8445
Jacek Surazski82a73df2009-06-17 14:33:18 +02008446 // if the error app is on the system image, look for system apps
8447 // error receiver
8448 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8449 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8450 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8451 if (result != null) {
8452 return result;
8453 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008454 }
8455
Jacek Surazski82a73df2009-06-17 14:33:18 +02008456 // if there is a default receiver, try that
8457 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8458 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008459 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008460 // should not happen
8461 Log.e(TAG, "error talking to PackageManager", e);
8462 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008463 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008464 }
8465
8466 /**
8467 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8468 *
8469 * @param pm PackageManager isntance
8470 * @param errorPackage package which caused the error
8471 * @param receiverPackage candidate package to receive the error
8472 * @return activity component within receiverPackage which handles
8473 * ACTION_APP_ERROR, or null if not found
8474 */
8475 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8476 String receiverPackage) throws RemoteException {
8477 if (receiverPackage == null || receiverPackage.length() == 0) {
8478 return null;
8479 }
8480
8481 // break the loop if it's the error report receiver package that crashed
8482 if (receiverPackage.equals(errorPackage)) {
8483 return null;
8484 }
8485
8486 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8487 intent.setPackage(receiverPackage);
8488 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8489 if (info == null || info.activityInfo == null) {
8490 return null;
8491 }
8492 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008493 }
8494
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008495 void makeAppNotRespondingLocked(ProcessRecord app,
8496 String tag, String shortMsg, String longMsg, byte[] crashData) {
8497 app.notResponding = true;
8498 app.notRespondingReport = generateProcessError(app,
8499 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8500 crashData);
8501 startAppProblemLocked(app);
8502 app.stopFreezingAllLocked();
8503 }
8504
8505 /**
8506 * Generate a process error record, suitable for attachment to a ProcessRecord.
8507 *
8508 * @param app The ProcessRecord in which the error occurred.
8509 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8510 * ActivityManager.AppErrorStateInfo
8511 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8512 * @param shortMsg Short message describing the crash.
8513 * @param longMsg Long message describing the crash.
8514 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8515 *
8516 * @return Returns a fully-formed AppErrorStateInfo record.
8517 */
8518 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8519 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8520 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8521
8522 report.condition = condition;
8523 report.processName = app.processName;
8524 report.pid = app.pid;
8525 report.uid = app.info.uid;
8526 report.tag = tag;
8527 report.shortMsg = shortMsg;
8528 report.longMsg = longMsg;
8529 report.crashData = crashData;
8530
8531 return report;
8532 }
8533
8534 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8535 boolean crashed) {
8536 synchronized (this) {
8537 app.crashing = false;
8538 app.crashingReport = null;
8539 app.notResponding = false;
8540 app.notRespondingReport = null;
8541 if (app.anrDialog == fromDialog) {
8542 app.anrDialog = null;
8543 }
8544 if (app.waitDialog == fromDialog) {
8545 app.waitDialog = null;
8546 }
8547 if (app.pid > 0 && app.pid != MY_PID) {
8548 if (crashed) {
8549 handleAppCrashLocked(app);
8550 }
8551 Log.i(ActivityManagerService.TAG, "Killing process "
8552 + app.processName
8553 + " (pid=" + app.pid + ") at user's request");
8554 Process.killProcess(app.pid);
8555 }
8556
8557 }
8558 }
8559
8560 boolean handleAppCrashLocked(ProcessRecord app) {
8561 long now = SystemClock.uptimeMillis();
8562
8563 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8564 app.info.uid);
8565 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8566 // This process loses!
8567 Log.w(TAG, "Process " + app.info.processName
8568 + " has crashed too many times: killing!");
8569 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8570 app.info.processName, app.info.uid);
8571 killServicesLocked(app, false);
8572 for (int i=mHistory.size()-1; i>=0; i--) {
8573 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8574 if (r.app == app) {
8575 if (Config.LOGD) Log.d(
8576 TAG, " Force finishing activity "
8577 + r.intent.getComponent().flattenToShortString());
8578 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8579 }
8580 }
8581 if (!app.persistent) {
8582 // We don't want to start this process again until the user
8583 // explicitly does so... but for persistent process, we really
8584 // need to keep it running. If a persistent process is actually
8585 // repeatedly crashing, then badness for everyone.
8586 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8587 app.info.processName);
8588 mBadProcesses.put(app.info.processName, app.info.uid, now);
8589 app.bad = true;
8590 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8591 app.removed = true;
8592 removeProcessLocked(app, false);
8593 return false;
8594 }
8595 }
8596
8597 // Bump up the crash count of any services currently running in the proc.
8598 if (app.services.size() != 0) {
8599 // Any services running in the application need to be placed
8600 // back in the pending list.
8601 Iterator it = app.services.iterator();
8602 while (it.hasNext()) {
8603 ServiceRecord sr = (ServiceRecord)it.next();
8604 sr.crashCount++;
8605 }
8606 }
8607
8608 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8609 return true;
8610 }
8611
8612 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008613 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008614 skipCurrentReceiverLocked(app);
8615 }
8616
8617 void skipCurrentReceiverLocked(ProcessRecord app) {
8618 boolean reschedule = false;
8619 BroadcastRecord r = app.curReceiver;
8620 if (r != null) {
8621 // The current broadcast is waiting for this app's receiver
8622 // to be finished. Looks like that's not going to happen, so
8623 // let the broadcast continue.
8624 logBroadcastReceiverDiscard(r);
8625 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8626 r.resultExtras, r.resultAbort, true);
8627 reschedule = true;
8628 }
8629 r = mPendingBroadcast;
8630 if (r != null && r.curApp == app) {
8631 if (DEBUG_BROADCAST) Log.v(TAG,
8632 "skip & discard pending app " + r);
8633 logBroadcastReceiverDiscard(r);
8634 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8635 r.resultExtras, r.resultAbort, true);
8636 reschedule = true;
8637 }
8638 if (reschedule) {
8639 scheduleBroadcastsLocked();
8640 }
8641 }
8642
8643 public int handleApplicationError(IBinder app, int flags,
8644 String tag, String shortMsg, String longMsg, byte[] crashData) {
8645 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008646 ProcessRecord r = null;
8647 synchronized (this) {
8648 if (app != null) {
8649 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8650 final int NA = apps.size();
8651 for (int ia=0; ia<NA; ia++) {
8652 ProcessRecord p = apps.valueAt(ia);
8653 if (p.thread != null && p.thread.asBinder() == app) {
8654 r = p;
8655 break;
8656 }
8657 }
8658 }
8659 }
8660
8661 if (r != null) {
8662 // The application has crashed. Send the SIGQUIT to the process so
8663 // that it can dump its state.
8664 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8665 //Log.i(TAG, "Current system threads:");
8666 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8667 }
8668
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008669 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008670 try {
8671 String name = r != null ? r.processName : null;
8672 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008673 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008674 shortMsg, longMsg, crashData)) {
8675 Log.w(TAG, "Force-killing crashed app " + name
8676 + " at watcher's request");
8677 Process.killProcess(pid);
8678 return 0;
8679 }
8680 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008681 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008682 }
8683 }
8684
8685 final long origId = Binder.clearCallingIdentity();
8686
8687 // If this process is running instrumentation, finish it.
8688 if (r != null && r.instrumentationClass != null) {
8689 Log.w(TAG, "Error in app " + r.processName
8690 + " running instrumentation " + r.instrumentationClass + ":");
8691 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8692 if (longMsg != null) Log.w(TAG, " " + longMsg);
8693 Bundle info = new Bundle();
8694 info.putString("shortMsg", shortMsg);
8695 info.putString("longMsg", longMsg);
8696 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8697 Binder.restoreCallingIdentity(origId);
8698 return 0;
8699 }
8700
8701 if (r != null) {
8702 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8703 return 0;
8704 }
8705 } else {
8706 Log.w(TAG, "Some application object " + app + " tag " + tag
8707 + " has crashed, but I don't know who it is.");
8708 Log.w(TAG, "ShortMsg:" + shortMsg);
8709 Log.w(TAG, "LongMsg:" + longMsg);
8710 Binder.restoreCallingIdentity(origId);
8711 return 0;
8712 }
8713
8714 Message msg = Message.obtain();
8715 msg.what = SHOW_ERROR_MSG;
8716 HashMap data = new HashMap();
8717 data.put("result", result);
8718 data.put("app", r);
8719 data.put("flags", flags);
8720 data.put("shortMsg", shortMsg);
8721 data.put("longMsg", longMsg);
8722 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8723 // For system processes, submit crash data to the server.
8724 data.put("crashData", crashData);
8725 }
8726 msg.obj = data;
8727 mHandler.sendMessage(msg);
8728
8729 Binder.restoreCallingIdentity(origId);
8730 }
8731
8732 int res = result.get();
8733
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008734 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008735 synchronized (this) {
8736 if (r != null) {
8737 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8738 SystemClock.uptimeMillis());
8739 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008740 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8741 appErrorIntent = createAppErrorIntentLocked(r);
8742 res = AppErrorDialog.FORCE_QUIT;
8743 }
8744 }
8745
8746 if (appErrorIntent != null) {
8747 try {
8748 mContext.startActivity(appErrorIntent);
8749 } catch (ActivityNotFoundException e) {
8750 Log.w(TAG, "bug report receiver dissappeared", e);
8751 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008752 }
8753
8754 return res;
8755 }
8756
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008757 Intent createAppErrorIntentLocked(ProcessRecord r) {
8758 ApplicationErrorReport report = createAppErrorReportLocked(r);
8759 if (report == null) {
8760 return null;
8761 }
8762 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8763 result.setComponent(r.errorReportReceiver);
8764 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8765 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8766 return result;
8767 }
8768
8769 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8770 if (r.errorReportReceiver == null) {
8771 return null;
8772 }
8773
8774 if (!r.crashing && !r.notResponding) {
8775 return null;
8776 }
8777
8778 try {
8779 ApplicationErrorReport report = new ApplicationErrorReport();
8780 report.packageName = r.info.packageName;
8781 report.installerPackageName = r.errorReportReceiver.getPackageName();
8782 report.processName = r.processName;
8783
8784 if (r.crashing) {
8785 report.type = ApplicationErrorReport.TYPE_CRASH;
8786 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8787
8788 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8789 r.crashingReport.crashData);
8790 DataInputStream dataStream = new DataInputStream(byteStream);
8791 CrashData crashData = new CrashData(dataStream);
8792 ThrowableData throwData = crashData.getThrowableData();
8793
8794 report.time = crashData.getTime();
8795 report.crashInfo.stackTrace = throwData.toString();
8796
Jacek Surazskif829a782009-06-11 22:47:02 +02008797 // Extract the source of the exception, useful for report
8798 // clustering. Also extract the "deepest" non-null exception
8799 // message.
8800 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008801 while (throwData.getCause() != null) {
8802 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008803 String msg = throwData.getMessage();
8804 if (msg != null && msg.length() > 0) {
8805 exceptionMessage = msg;
8806 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008807 }
8808 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008809 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008810 report.crashInfo.exceptionClassName = throwData.getType();
8811 report.crashInfo.throwFileName = trace.getFileName();
8812 report.crashInfo.throwClassName = trace.getClassName();
8813 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008814 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008815 } else if (r.notResponding) {
8816 report.type = ApplicationErrorReport.TYPE_ANR;
8817 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8818
8819 report.anrInfo.activity = r.notRespondingReport.tag;
8820 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8821 report.anrInfo.info = r.notRespondingReport.longMsg;
8822 }
8823
8824 return report;
8825 } catch (IOException e) {
8826 // we don't send it
8827 }
8828
8829 return null;
8830 }
8831
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008832 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8833 // assume our apps are happy - lazy create the list
8834 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8835
8836 synchronized (this) {
8837
8838 // iterate across all processes
8839 final int N = mLRUProcesses.size();
8840 for (int i = 0; i < N; i++) {
8841 ProcessRecord app = mLRUProcesses.get(i);
8842 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8843 // This one's in trouble, so we'll generate a report for it
8844 // crashes are higher priority (in case there's a crash *and* an anr)
8845 ActivityManager.ProcessErrorStateInfo report = null;
8846 if (app.crashing) {
8847 report = app.crashingReport;
8848 } else if (app.notResponding) {
8849 report = app.notRespondingReport;
8850 }
8851
8852 if (report != null) {
8853 if (errList == null) {
8854 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8855 }
8856 errList.add(report);
8857 } else {
8858 Log.w(TAG, "Missing app error report, app = " + app.processName +
8859 " crashing = " + app.crashing +
8860 " notResponding = " + app.notResponding);
8861 }
8862 }
8863 }
8864 }
8865
8866 return errList;
8867 }
8868
8869 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8870 // Lazy instantiation of list
8871 List<ActivityManager.RunningAppProcessInfo> runList = null;
8872 synchronized (this) {
8873 // Iterate across all processes
8874 final int N = mLRUProcesses.size();
8875 for (int i = 0; i < N; i++) {
8876 ProcessRecord app = mLRUProcesses.get(i);
8877 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8878 // Generate process state info for running application
8879 ActivityManager.RunningAppProcessInfo currApp =
8880 new ActivityManager.RunningAppProcessInfo(app.processName,
8881 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07008882 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008883 int adj = app.curAdj;
8884 if (adj >= CONTENT_PROVIDER_ADJ) {
8885 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8886 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8887 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008888 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8889 } else if (adj >= HOME_APP_ADJ) {
8890 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8891 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008892 } else if (adj >= SECONDARY_SERVER_ADJ) {
8893 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8894 } else if (adj >= VISIBLE_APP_ADJ) {
8895 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8896 } else {
8897 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8898 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07008899 currApp.importanceReasonCode = app.adjTypeCode;
8900 if (app.adjSource instanceof ProcessRecord) {
8901 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
8902 } else if (app.adjSource instanceof HistoryRecord) {
8903 HistoryRecord r = (HistoryRecord)app.adjSource;
8904 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
8905 }
8906 if (app.adjTarget instanceof ComponentName) {
8907 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
8908 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008909 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8910 // + " lru=" + currApp.lru);
8911 if (runList == null) {
8912 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8913 }
8914 runList.add(currApp);
8915 }
8916 }
8917 }
8918 return runList;
8919 }
8920
8921 @Override
8922 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8923 synchronized (this) {
8924 if (checkCallingPermission(android.Manifest.permission.DUMP)
8925 != PackageManager.PERMISSION_GRANTED) {
8926 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8927 + Binder.getCallingPid()
8928 + ", uid=" + Binder.getCallingUid()
8929 + " without permission "
8930 + android.Manifest.permission.DUMP);
8931 return;
8932 }
8933 if (args.length != 0 && "service".equals(args[0])) {
8934 dumpService(fd, pw, args);
8935 return;
8936 }
8937 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008938 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008939 pw.println(" ");
8940 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008941 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008942 if (mWaitingVisibleActivities.size() > 0) {
8943 pw.println(" ");
8944 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008945 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008946 }
8947 if (mStoppingActivities.size() > 0) {
8948 pw.println(" ");
8949 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008950 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008951 }
8952 if (mFinishingActivities.size() > 0) {
8953 pw.println(" ");
8954 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008955 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008956 }
8957
8958 pw.println(" ");
8959 pw.println(" mPausingActivity: " + mPausingActivity);
8960 pw.println(" mResumedActivity: " + mResumedActivity);
8961 pw.println(" mFocusedActivity: " + mFocusedActivity);
8962 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8963
8964 if (mRecentTasks.size() > 0) {
8965 pw.println(" ");
8966 pw.println("Recent tasks in Current Activity Manager State:");
8967
8968 final int N = mRecentTasks.size();
8969 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008970 TaskRecord tr = mRecentTasks.get(i);
8971 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8972 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008973 mRecentTasks.get(i).dump(pw, " ");
8974 }
8975 }
8976
8977 pw.println(" ");
8978 pw.println(" mCurTask: " + mCurTask);
8979
8980 pw.println(" ");
8981 pw.println("Processes in Current Activity Manager State:");
8982
8983 boolean needSep = false;
8984 int numPers = 0;
8985
8986 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8987 final int NA = procs.size();
8988 for (int ia=0; ia<NA; ia++) {
8989 if (!needSep) {
8990 pw.println(" All known processes:");
8991 needSep = true;
8992 }
8993 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008994 pw.print(r.persistent ? " *PERS*" : " *APP*");
8995 pw.print(" UID "); pw.print(procs.keyAt(ia));
8996 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008997 r.dump(pw, " ");
8998 if (r.persistent) {
8999 numPers++;
9000 }
9001 }
9002 }
9003
9004 if (mLRUProcesses.size() > 0) {
9005 if (needSep) pw.println(" ");
9006 needSep = true;
9007 pw.println(" Running processes (most recent first):");
9008 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009009 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009010 needSep = true;
9011 }
9012
9013 synchronized (mPidsSelfLocked) {
9014 if (mPidsSelfLocked.size() > 0) {
9015 if (needSep) pw.println(" ");
9016 needSep = true;
9017 pw.println(" PID mappings:");
9018 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009019 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9020 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009021 }
9022 }
9023 }
9024
9025 if (mForegroundProcesses.size() > 0) {
9026 if (needSep) pw.println(" ");
9027 needSep = true;
9028 pw.println(" Foreground Processes:");
9029 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009030 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9031 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009032 }
9033 }
9034
9035 if (mPersistentStartingProcesses.size() > 0) {
9036 if (needSep) pw.println(" ");
9037 needSep = true;
9038 pw.println(" Persisent processes that are starting:");
9039 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009040 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009041 }
9042
9043 if (mStartingProcesses.size() > 0) {
9044 if (needSep) pw.println(" ");
9045 needSep = true;
9046 pw.println(" Processes that are starting:");
9047 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009048 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009049 }
9050
9051 if (mRemovedProcesses.size() > 0) {
9052 if (needSep) pw.println(" ");
9053 needSep = true;
9054 pw.println(" Processes that are being removed:");
9055 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009056 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009057 }
9058
9059 if (mProcessesOnHold.size() > 0) {
9060 if (needSep) pw.println(" ");
9061 needSep = true;
9062 pw.println(" Processes that are on old until the system is ready:");
9063 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009064 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009065 }
9066
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009067 if (mProcessesToGc.size() > 0) {
9068 if (needSep) pw.println(" ");
9069 needSep = true;
9070 pw.println(" Processes that are waiting to GC:");
9071 long now = SystemClock.uptimeMillis();
9072 for (int i=0; i<mProcessesToGc.size(); i++) {
9073 ProcessRecord proc = mProcessesToGc.get(i);
9074 pw.print(" Process "); pw.println(proc);
9075 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9076 pw.print(", last gced=");
9077 pw.print(now-proc.lastRequestedGc);
9078 pw.print(" ms ago, last lowMwm=");
9079 pw.print(now-proc.lastLowMemory);
9080 pw.println(" ms ago");
9081
9082 }
9083 }
9084
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009085 if (mProcessCrashTimes.getMap().size() > 0) {
9086 if (needSep) pw.println(" ");
9087 needSep = true;
9088 pw.println(" Time since processes crashed:");
9089 long now = SystemClock.uptimeMillis();
9090 for (Map.Entry<String, SparseArray<Long>> procs
9091 : mProcessCrashTimes.getMap().entrySet()) {
9092 SparseArray<Long> uids = procs.getValue();
9093 final int N = uids.size();
9094 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009095 pw.print(" Process "); pw.print(procs.getKey());
9096 pw.print(" uid "); pw.print(uids.keyAt(i));
9097 pw.print(": last crashed ");
9098 pw.print((now-uids.valueAt(i)));
9099 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009100 }
9101 }
9102 }
9103
9104 if (mBadProcesses.getMap().size() > 0) {
9105 if (needSep) pw.println(" ");
9106 needSep = true;
9107 pw.println(" Bad processes:");
9108 for (Map.Entry<String, SparseArray<Long>> procs
9109 : mBadProcesses.getMap().entrySet()) {
9110 SparseArray<Long> uids = procs.getValue();
9111 final int N = uids.size();
9112 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009113 pw.print(" Bad process "); pw.print(procs.getKey());
9114 pw.print(" uid "); pw.print(uids.keyAt(i));
9115 pw.print(": crashed at time ");
9116 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009117 }
9118 }
9119 }
9120
9121 pw.println(" ");
9122 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009123 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009124 pw.println(" mConfiguration: " + mConfiguration);
9125 pw.println(" mStartRunning=" + mStartRunning
9126 + " mSystemReady=" + mSystemReady
9127 + " mBooting=" + mBooting
9128 + " mBooted=" + mBooted
9129 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009130 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009131 pw.println(" mGoingToSleep=" + mGoingToSleep);
9132 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9133 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9134 + " mDebugTransient=" + mDebugTransient
9135 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9136 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009137 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009138 }
9139 }
9140
9141 /**
9142 * There are three ways to call this:
9143 * - no service specified: dump all the services
9144 * - a flattened component name that matched an existing service was specified as the
9145 * first arg: dump that one service
9146 * - the first arg isn't the flattened component name of an existing service:
9147 * dump all services whose component contains the first arg as a substring
9148 */
9149 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9150 String[] newArgs;
9151 String componentNameString;
9152 ServiceRecord r;
9153 if (args.length == 1) {
9154 componentNameString = null;
9155 newArgs = EMPTY_STRING_ARRAY;
9156 r = null;
9157 } else {
9158 componentNameString = args[1];
9159 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9160 r = componentName != null ? mServices.get(componentName) : null;
9161 newArgs = new String[args.length - 2];
9162 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9163 }
9164
9165 if (r != null) {
9166 dumpService(fd, pw, r, newArgs);
9167 } else {
9168 for (ServiceRecord r1 : mServices.values()) {
9169 if (componentNameString == null
9170 || r1.name.flattenToString().contains(componentNameString)) {
9171 dumpService(fd, pw, r1, newArgs);
9172 }
9173 }
9174 }
9175 }
9176
9177 /**
9178 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9179 * there is a thread associated with the service.
9180 */
9181 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9182 pw.println(" Service " + r.name.flattenToString());
9183 if (r.app != null && r.app.thread != null) {
9184 try {
9185 // flush anything that is already in the PrintWriter since the thread is going
9186 // to write to the file descriptor directly
9187 pw.flush();
9188 r.app.thread.dumpService(fd, r, args);
9189 pw.print("\n");
9190 } catch (RemoteException e) {
9191 pw.println("got a RemoteException while dumping the service");
9192 }
9193 }
9194 }
9195
9196 void dumpBroadcasts(PrintWriter pw) {
9197 synchronized (this) {
9198 if (checkCallingPermission(android.Manifest.permission.DUMP)
9199 != PackageManager.PERMISSION_GRANTED) {
9200 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9201 + Binder.getCallingPid()
9202 + ", uid=" + Binder.getCallingUid()
9203 + " without permission "
9204 + android.Manifest.permission.DUMP);
9205 return;
9206 }
9207 pw.println("Broadcasts in Current Activity Manager State:");
9208
9209 if (mRegisteredReceivers.size() > 0) {
9210 pw.println(" ");
9211 pw.println(" Registered Receivers:");
9212 Iterator it = mRegisteredReceivers.values().iterator();
9213 while (it.hasNext()) {
9214 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009215 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009216 r.dump(pw, " ");
9217 }
9218 }
9219
9220 pw.println(" ");
9221 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009222 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009223
9224 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9225 || mPendingBroadcast != null) {
9226 if (mParallelBroadcasts.size() > 0) {
9227 pw.println(" ");
9228 pw.println(" Active broadcasts:");
9229 }
9230 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9231 pw.println(" Broadcast #" + i + ":");
9232 mParallelBroadcasts.get(i).dump(pw, " ");
9233 }
9234 if (mOrderedBroadcasts.size() > 0) {
9235 pw.println(" ");
9236 pw.println(" Active serialized broadcasts:");
9237 }
9238 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9239 pw.println(" Serialized Broadcast #" + i + ":");
9240 mOrderedBroadcasts.get(i).dump(pw, " ");
9241 }
9242 pw.println(" ");
9243 pw.println(" Pending broadcast:");
9244 if (mPendingBroadcast != null) {
9245 mPendingBroadcast.dump(pw, " ");
9246 } else {
9247 pw.println(" (null)");
9248 }
9249 }
9250
9251 pw.println(" ");
9252 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9253 if (mStickyBroadcasts != null) {
9254 pw.println(" ");
9255 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009256 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009257 for (Map.Entry<String, ArrayList<Intent>> ent
9258 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009259 pw.print(" * Sticky action "); pw.print(ent.getKey());
9260 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009261 ArrayList<Intent> intents = ent.getValue();
9262 final int N = intents.size();
9263 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009264 sb.setLength(0);
9265 sb.append(" Intent: ");
9266 intents.get(i).toShortString(sb, true, false);
9267 pw.println(sb.toString());
9268 Bundle bundle = intents.get(i).getExtras();
9269 if (bundle != null) {
9270 pw.print(" ");
9271 pw.println(bundle.toString());
9272 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009273 }
9274 }
9275 }
9276
9277 pw.println(" ");
9278 pw.println(" mHandler:");
9279 mHandler.dump(new PrintWriterPrinter(pw), " ");
9280 }
9281 }
9282
9283 void dumpServices(PrintWriter pw) {
9284 synchronized (this) {
9285 if (checkCallingPermission(android.Manifest.permission.DUMP)
9286 != PackageManager.PERMISSION_GRANTED) {
9287 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9288 + Binder.getCallingPid()
9289 + ", uid=" + Binder.getCallingUid()
9290 + " without permission "
9291 + android.Manifest.permission.DUMP);
9292 return;
9293 }
9294 pw.println("Services in Current Activity Manager State:");
9295
9296 boolean needSep = false;
9297
9298 if (mServices.size() > 0) {
9299 pw.println(" Active services:");
9300 Iterator<ServiceRecord> it = mServices.values().iterator();
9301 while (it.hasNext()) {
9302 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009303 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009304 r.dump(pw, " ");
9305 }
9306 needSep = true;
9307 }
9308
9309 if (mPendingServices.size() > 0) {
9310 if (needSep) pw.println(" ");
9311 pw.println(" Pending services:");
9312 for (int i=0; i<mPendingServices.size(); i++) {
9313 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009314 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009315 r.dump(pw, " ");
9316 }
9317 needSep = true;
9318 }
9319
9320 if (mRestartingServices.size() > 0) {
9321 if (needSep) pw.println(" ");
9322 pw.println(" Restarting services:");
9323 for (int i=0; i<mRestartingServices.size(); i++) {
9324 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009325 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009326 r.dump(pw, " ");
9327 }
9328 needSep = true;
9329 }
9330
9331 if (mStoppingServices.size() > 0) {
9332 if (needSep) pw.println(" ");
9333 pw.println(" Stopping services:");
9334 for (int i=0; i<mStoppingServices.size(); i++) {
9335 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009336 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009337 r.dump(pw, " ");
9338 }
9339 needSep = true;
9340 }
9341
9342 if (mServiceConnections.size() > 0) {
9343 if (needSep) pw.println(" ");
9344 pw.println(" Connection bindings to services:");
9345 Iterator<ConnectionRecord> it
9346 = mServiceConnections.values().iterator();
9347 while (it.hasNext()) {
9348 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009349 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009350 r.dump(pw, " ");
9351 }
9352 }
9353 }
9354 }
9355
9356 void dumpProviders(PrintWriter pw) {
9357 synchronized (this) {
9358 if (checkCallingPermission(android.Manifest.permission.DUMP)
9359 != PackageManager.PERMISSION_GRANTED) {
9360 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9361 + Binder.getCallingPid()
9362 + ", uid=" + Binder.getCallingUid()
9363 + " without permission "
9364 + android.Manifest.permission.DUMP);
9365 return;
9366 }
9367
9368 pw.println("Content Providers in Current Activity Manager State:");
9369
9370 boolean needSep = false;
9371
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009372 if (mProvidersByClass.size() > 0) {
9373 if (needSep) pw.println(" ");
9374 pw.println(" Published content providers (by class):");
9375 Iterator it = mProvidersByClass.entrySet().iterator();
9376 while (it.hasNext()) {
9377 Map.Entry e = (Map.Entry)it.next();
9378 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009379 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009380 r.dump(pw, " ");
9381 }
9382 needSep = true;
9383 }
9384
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009385 if (mProvidersByName.size() > 0) {
9386 pw.println(" ");
9387 pw.println(" Authority to provider mappings:");
9388 Iterator it = mProvidersByName.entrySet().iterator();
9389 while (it.hasNext()) {
9390 Map.Entry e = (Map.Entry)it.next();
9391 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9392 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9393 pw.println(r);
9394 }
9395 needSep = true;
9396 }
9397
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009398 if (mLaunchingProviders.size() > 0) {
9399 if (needSep) pw.println(" ");
9400 pw.println(" Launching content providers:");
9401 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009402 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9403 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009404 }
9405 needSep = true;
9406 }
9407
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009408 if (mGrantedUriPermissions.size() > 0) {
9409 pw.println();
9410 pw.println("Granted Uri Permissions:");
9411 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9412 int uid = mGrantedUriPermissions.keyAt(i);
9413 HashMap<Uri, UriPermission> perms
9414 = mGrantedUriPermissions.valueAt(i);
9415 pw.print(" * UID "); pw.print(uid);
9416 pw.println(" holds:");
9417 for (UriPermission perm : perms.values()) {
9418 pw.print(" "); pw.println(perm);
9419 perm.dump(pw, " ");
9420 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009421 }
9422 }
9423 }
9424 }
9425
9426 void dumpSenders(PrintWriter pw) {
9427 synchronized (this) {
9428 if (checkCallingPermission(android.Manifest.permission.DUMP)
9429 != PackageManager.PERMISSION_GRANTED) {
9430 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9431 + Binder.getCallingPid()
9432 + ", uid=" + Binder.getCallingUid()
9433 + " without permission "
9434 + android.Manifest.permission.DUMP);
9435 return;
9436 }
9437
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009438 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009439
9440 if (this.mIntentSenderRecords.size() > 0) {
9441 Iterator<WeakReference<PendingIntentRecord>> it
9442 = mIntentSenderRecords.values().iterator();
9443 while (it.hasNext()) {
9444 WeakReference<PendingIntentRecord> ref = it.next();
9445 PendingIntentRecord rec = ref != null ? ref.get(): null;
9446 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009447 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009448 rec.dump(pw, " ");
9449 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009450 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009451 }
9452 }
9453 }
9454 }
9455 }
9456
9457 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009458 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009459 TaskRecord lastTask = null;
9460 for (int i=list.size()-1; i>=0; i--) {
9461 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009462 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009463 if (lastTask != r.task) {
9464 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009465 pw.print(prefix);
9466 pw.print(full ? "* " : " ");
9467 pw.println(lastTask);
9468 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009469 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009470 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009471 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009472 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9473 pw.print(" #"); pw.print(i); pw.print(": ");
9474 pw.println(r);
9475 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009476 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009477 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009478 }
9479 }
9480
9481 private static final int dumpProcessList(PrintWriter pw, List list,
9482 String prefix, String normalLabel, String persistentLabel,
9483 boolean inclOomAdj) {
9484 int numPers = 0;
9485 for (int i=list.size()-1; i>=0; i--) {
9486 ProcessRecord r = (ProcessRecord)list.get(i);
9487 if (false) {
9488 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9489 + " #" + i + ":");
9490 r.dump(pw, prefix + " ");
9491 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009492 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009493 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009494 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9495 if (r.adjSource != null || r.adjTarget != null) {
9496 pw.println(prefix + " " + r.adjTarget
9497 + " used by " + r.adjSource);
9498 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009499 } else {
9500 pw.println(String.format("%s%s #%2d: %s",
9501 prefix, (r.persistent ? persistentLabel : normalLabel),
9502 i, r.toString()));
9503 }
9504 if (r.persistent) {
9505 numPers++;
9506 }
9507 }
9508 return numPers;
9509 }
9510
9511 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9512 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009513 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009514 long uptime = SystemClock.uptimeMillis();
9515 long realtime = SystemClock.elapsedRealtime();
9516
9517 if (isCheckinRequest) {
9518 // short checkin version
9519 pw.println(uptime + "," + realtime);
9520 pw.flush();
9521 } else {
9522 pw.println("Applications Memory Usage (kB):");
9523 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9524 }
9525 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9526 ProcessRecord r = (ProcessRecord)list.get(i);
9527 if (r.thread != null) {
9528 if (!isCheckinRequest) {
9529 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9530 pw.flush();
9531 }
9532 try {
9533 r.thread.asBinder().dump(fd, args);
9534 } catch (RemoteException e) {
9535 if (!isCheckinRequest) {
9536 pw.println("Got RemoteException!");
9537 pw.flush();
9538 }
9539 }
9540 }
9541 }
9542 }
9543
9544 /**
9545 * Searches array of arguments for the specified string
9546 * @param args array of argument strings
9547 * @param value value to search for
9548 * @return true if the value is contained in the array
9549 */
9550 private static boolean scanArgs(String[] args, String value) {
9551 if (args != null) {
9552 for (String arg : args) {
9553 if (value.equals(arg)) {
9554 return true;
9555 }
9556 }
9557 }
9558 return false;
9559 }
9560
Dianne Hackborn75b03852009-06-12 15:43:26 -07009561 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009562 int count = mHistory.size();
9563
9564 // convert the token to an entry in the history.
9565 HistoryRecord r = null;
9566 int index = -1;
9567 for (int i=count-1; i>=0; i--) {
9568 Object o = mHistory.get(i);
9569 if (o == token) {
9570 r = (HistoryRecord)o;
9571 index = i;
9572 break;
9573 }
9574 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009575
9576 return index;
9577 }
9578
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009579 private final void killServicesLocked(ProcessRecord app,
9580 boolean allowRestart) {
9581 // Report disconnected services.
9582 if (false) {
9583 // XXX we are letting the client link to the service for
9584 // death notifications.
9585 if (app.services.size() > 0) {
9586 Iterator it = app.services.iterator();
9587 while (it.hasNext()) {
9588 ServiceRecord r = (ServiceRecord)it.next();
9589 if (r.connections.size() > 0) {
9590 Iterator<ConnectionRecord> jt
9591 = r.connections.values().iterator();
9592 while (jt.hasNext()) {
9593 ConnectionRecord c = jt.next();
9594 if (c.binding.client != app) {
9595 try {
9596 //c.conn.connected(r.className, null);
9597 } catch (Exception e) {
9598 // todo: this should be asynchronous!
9599 Log.w(TAG, "Exception thrown disconnected servce "
9600 + r.shortName
9601 + " from app " + app.processName, e);
9602 }
9603 }
9604 }
9605 }
9606 }
9607 }
9608 }
9609
9610 // Clean up any connections this application has to other services.
9611 if (app.connections.size() > 0) {
9612 Iterator<ConnectionRecord> it = app.connections.iterator();
9613 while (it.hasNext()) {
9614 ConnectionRecord r = it.next();
9615 removeConnectionLocked(r, app, null);
9616 }
9617 }
9618 app.connections.clear();
9619
9620 if (app.services.size() != 0) {
9621 // Any services running in the application need to be placed
9622 // back in the pending list.
9623 Iterator it = app.services.iterator();
9624 while (it.hasNext()) {
9625 ServiceRecord sr = (ServiceRecord)it.next();
9626 synchronized (sr.stats.getBatteryStats()) {
9627 sr.stats.stopLaunchedLocked();
9628 }
9629 sr.app = null;
9630 sr.executeNesting = 0;
9631 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009632
9633 boolean hasClients = sr.bindings.size() > 0;
9634 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009635 Iterator<IntentBindRecord> bindings
9636 = sr.bindings.values().iterator();
9637 while (bindings.hasNext()) {
9638 IntentBindRecord b = bindings.next();
9639 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9640 + ": shouldUnbind=" + b.hasBound);
9641 b.binder = null;
9642 b.requested = b.received = b.hasBound = false;
9643 }
9644 }
9645
9646 if (sr.crashCount >= 2) {
9647 Log.w(TAG, "Service crashed " + sr.crashCount
9648 + " times, stopping: " + sr);
9649 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9650 sr.crashCount, sr.shortName, app.pid);
9651 bringDownServiceLocked(sr, true);
9652 } else if (!allowRestart) {
9653 bringDownServiceLocked(sr, true);
9654 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009655 boolean canceled = scheduleServiceRestartLocked(sr, true);
9656
9657 // Should the service remain running? Note that in the
9658 // extreme case of so many attempts to deliver a command
9659 // that it failed, that we also will stop it here.
9660 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9661 if (sr.pendingStarts.size() == 0) {
9662 sr.startRequested = false;
9663 if (!hasClients) {
9664 // Whoops, no reason to restart!
9665 bringDownServiceLocked(sr, true);
9666 }
9667 }
9668 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009669 }
9670 }
9671
9672 if (!allowRestart) {
9673 app.services.clear();
9674 }
9675 }
9676
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009677 // Make sure we have no more records on the stopping list.
9678 int i = mStoppingServices.size();
9679 while (i > 0) {
9680 i--;
9681 ServiceRecord sr = mStoppingServices.get(i);
9682 if (sr.app == app) {
9683 mStoppingServices.remove(i);
9684 }
9685 }
9686
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009687 app.executingServices.clear();
9688 }
9689
9690 private final void removeDyingProviderLocked(ProcessRecord proc,
9691 ContentProviderRecord cpr) {
9692 synchronized (cpr) {
9693 cpr.launchingApp = null;
9694 cpr.notifyAll();
9695 }
9696
9697 mProvidersByClass.remove(cpr.info.name);
9698 String names[] = cpr.info.authority.split(";");
9699 for (int j = 0; j < names.length; j++) {
9700 mProvidersByName.remove(names[j]);
9701 }
9702
9703 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9704 while (cit.hasNext()) {
9705 ProcessRecord capp = cit.next();
9706 if (!capp.persistent && capp.thread != null
9707 && capp.pid != 0
9708 && capp.pid != MY_PID) {
9709 Log.i(TAG, "Killing app " + capp.processName
9710 + " (pid " + capp.pid
9711 + ") because provider " + cpr.info.name
9712 + " is in dying process " + proc.processName);
9713 Process.killProcess(capp.pid);
9714 }
9715 }
9716
9717 mLaunchingProviders.remove(cpr);
9718 }
9719
9720 /**
9721 * Main code for cleaning up a process when it has gone away. This is
9722 * called both as a result of the process dying, or directly when stopping
9723 * a process when running in single process mode.
9724 */
9725 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9726 boolean restarting, int index) {
9727 if (index >= 0) {
9728 mLRUProcesses.remove(index);
9729 }
9730
9731 // Dismiss any open dialogs.
9732 if (app.crashDialog != null) {
9733 app.crashDialog.dismiss();
9734 app.crashDialog = null;
9735 }
9736 if (app.anrDialog != null) {
9737 app.anrDialog.dismiss();
9738 app.anrDialog = null;
9739 }
9740 if (app.waitDialog != null) {
9741 app.waitDialog.dismiss();
9742 app.waitDialog = null;
9743 }
9744
9745 app.crashing = false;
9746 app.notResponding = false;
9747
9748 app.resetPackageList();
9749 app.thread = null;
9750 app.forcingToForeground = null;
9751 app.foregroundServices = false;
9752
9753 killServicesLocked(app, true);
9754
9755 boolean restart = false;
9756
9757 int NL = mLaunchingProviders.size();
9758
9759 // Remove published content providers.
9760 if (!app.pubProviders.isEmpty()) {
9761 Iterator it = app.pubProviders.values().iterator();
9762 while (it.hasNext()) {
9763 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9764 cpr.provider = null;
9765 cpr.app = null;
9766
9767 // See if someone is waiting for this provider... in which
9768 // case we don't remove it, but just let it restart.
9769 int i = 0;
9770 if (!app.bad) {
9771 for (; i<NL; i++) {
9772 if (mLaunchingProviders.get(i) == cpr) {
9773 restart = true;
9774 break;
9775 }
9776 }
9777 } else {
9778 i = NL;
9779 }
9780
9781 if (i >= NL) {
9782 removeDyingProviderLocked(app, cpr);
9783 NL = mLaunchingProviders.size();
9784 }
9785 }
9786 app.pubProviders.clear();
9787 }
9788
9789 // Look through the content providers we are waiting to have launched,
9790 // and if any run in this process then either schedule a restart of
9791 // the process or kill the client waiting for it if this process has
9792 // gone bad.
9793 for (int i=0; i<NL; i++) {
9794 ContentProviderRecord cpr = (ContentProviderRecord)
9795 mLaunchingProviders.get(i);
9796 if (cpr.launchingApp == app) {
9797 if (!app.bad) {
9798 restart = true;
9799 } else {
9800 removeDyingProviderLocked(app, cpr);
9801 NL = mLaunchingProviders.size();
9802 }
9803 }
9804 }
9805
9806 // Unregister from connected content providers.
9807 if (!app.conProviders.isEmpty()) {
9808 Iterator it = app.conProviders.iterator();
9809 while (it.hasNext()) {
9810 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9811 cpr.clients.remove(app);
9812 }
9813 app.conProviders.clear();
9814 }
9815
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009816 // At this point there may be remaining entries in mLaunchingProviders
9817 // where we were the only one waiting, so they are no longer of use.
9818 // Look for these and clean up if found.
9819 // XXX Commented out for now. Trying to figure out a way to reproduce
9820 // the actual situation to identify what is actually going on.
9821 if (false) {
9822 for (int i=0; i<NL; i++) {
9823 ContentProviderRecord cpr = (ContentProviderRecord)
9824 mLaunchingProviders.get(i);
9825 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9826 synchronized (cpr) {
9827 cpr.launchingApp = null;
9828 cpr.notifyAll();
9829 }
9830 }
9831 }
9832 }
9833
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009834 skipCurrentReceiverLocked(app);
9835
9836 // Unregister any receivers.
9837 if (app.receivers.size() > 0) {
9838 Iterator<ReceiverList> it = app.receivers.iterator();
9839 while (it.hasNext()) {
9840 removeReceiverLocked(it.next());
9841 }
9842 app.receivers.clear();
9843 }
9844
Christopher Tate181fafa2009-05-14 11:12:14 -07009845 // If the app is undergoing backup, tell the backup manager about it
9846 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9847 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9848 try {
9849 IBackupManager bm = IBackupManager.Stub.asInterface(
9850 ServiceManager.getService(Context.BACKUP_SERVICE));
9851 bm.agentDisconnected(app.info.packageName);
9852 } catch (RemoteException e) {
9853 // can't happen; backup manager is local
9854 }
9855 }
9856
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009857 // If the caller is restarting this app, then leave it in its
9858 // current lists and let the caller take care of it.
9859 if (restarting) {
9860 return;
9861 }
9862
9863 if (!app.persistent) {
9864 if (DEBUG_PROCESSES) Log.v(TAG,
9865 "Removing non-persistent process during cleanup: " + app);
9866 mProcessNames.remove(app.processName, app.info.uid);
9867 } else if (!app.removed) {
9868 // This app is persistent, so we need to keep its record around.
9869 // If it is not already on the pending app list, add it there
9870 // and start a new process for it.
9871 app.thread = null;
9872 app.forcingToForeground = null;
9873 app.foregroundServices = false;
9874 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9875 mPersistentStartingProcesses.add(app);
9876 restart = true;
9877 }
9878 }
9879 mProcessesOnHold.remove(app);
9880
The Android Open Source Project4df24232009-03-05 14:34:35 -08009881 if (app == mHomeProcess) {
9882 mHomeProcess = null;
9883 }
9884
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009885 if (restart) {
9886 // We have components that still need to be running in the
9887 // process, so re-launch it.
9888 mProcessNames.put(app.processName, app.info.uid, app);
9889 startProcessLocked(app, "restart", app.processName);
9890 } else if (app.pid > 0 && app.pid != MY_PID) {
9891 // Goodbye!
9892 synchronized (mPidsSelfLocked) {
9893 mPidsSelfLocked.remove(app.pid);
9894 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9895 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009896 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009897 }
9898 }
9899
9900 // =========================================================
9901 // SERVICES
9902 // =========================================================
9903
9904 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9905 ActivityManager.RunningServiceInfo info =
9906 new ActivityManager.RunningServiceInfo();
9907 info.service = r.name;
9908 if (r.app != null) {
9909 info.pid = r.app.pid;
9910 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -07009911 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009912 info.process = r.processName;
9913 info.foreground = r.isForeground;
9914 info.activeSince = r.createTime;
9915 info.started = r.startRequested;
9916 info.clientCount = r.connections.size();
9917 info.crashCount = r.crashCount;
9918 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07009919 if (r.isForeground) {
9920 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
9921 }
9922 if (r.startRequested) {
9923 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
9924 }
9925 if (r.app != null && r.app.pid == Process.myPid()) {
9926 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
9927 }
9928 if (r.app != null && r.app.persistent) {
9929 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
9930 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009931 for (ConnectionRecord conn : r.connections.values()) {
9932 if (conn.clientLabel != 0) {
9933 info.clientPackage = conn.binding.client.info.packageName;
9934 info.clientLabel = conn.clientLabel;
9935 break;
9936 }
9937 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009938 return info;
9939 }
9940
9941 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9942 int flags) {
9943 synchronized (this) {
9944 ArrayList<ActivityManager.RunningServiceInfo> res
9945 = new ArrayList<ActivityManager.RunningServiceInfo>();
9946
9947 if (mServices.size() > 0) {
9948 Iterator<ServiceRecord> it = mServices.values().iterator();
9949 while (it.hasNext() && res.size() < maxNum) {
9950 res.add(makeRunningServiceInfoLocked(it.next()));
9951 }
9952 }
9953
9954 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9955 ServiceRecord r = mRestartingServices.get(i);
9956 ActivityManager.RunningServiceInfo info =
9957 makeRunningServiceInfoLocked(r);
9958 info.restarting = r.nextRestartTime;
9959 res.add(info);
9960 }
9961
9962 return res;
9963 }
9964 }
9965
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009966 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
9967 synchronized (this) {
9968 ServiceRecord r = mServices.get(name);
9969 if (r != null) {
9970 for (ConnectionRecord conn : r.connections.values()) {
9971 if (conn.clientIntent != null) {
9972 return conn.clientIntent;
9973 }
9974 }
9975 }
9976 }
9977 return null;
9978 }
9979
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009980 private final ServiceRecord findServiceLocked(ComponentName name,
9981 IBinder token) {
9982 ServiceRecord r = mServices.get(name);
9983 return r == token ? r : null;
9984 }
9985
9986 private final class ServiceLookupResult {
9987 final ServiceRecord record;
9988 final String permission;
9989
9990 ServiceLookupResult(ServiceRecord _record, String _permission) {
9991 record = _record;
9992 permission = _permission;
9993 }
9994 };
9995
9996 private ServiceLookupResult findServiceLocked(Intent service,
9997 String resolvedType) {
9998 ServiceRecord r = null;
9999 if (service.getComponent() != null) {
10000 r = mServices.get(service.getComponent());
10001 }
10002 if (r == null) {
10003 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10004 r = mServicesByIntent.get(filter);
10005 }
10006
10007 if (r == null) {
10008 try {
10009 ResolveInfo rInfo =
10010 ActivityThread.getPackageManager().resolveService(
10011 service, resolvedType, 0);
10012 ServiceInfo sInfo =
10013 rInfo != null ? rInfo.serviceInfo : null;
10014 if (sInfo == null) {
10015 return null;
10016 }
10017
10018 ComponentName name = new ComponentName(
10019 sInfo.applicationInfo.packageName, sInfo.name);
10020 r = mServices.get(name);
10021 } catch (RemoteException ex) {
10022 // pm is in same process, this will never happen.
10023 }
10024 }
10025 if (r != null) {
10026 int callingPid = Binder.getCallingPid();
10027 int callingUid = Binder.getCallingUid();
10028 if (checkComponentPermission(r.permission,
10029 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10030 != PackageManager.PERMISSION_GRANTED) {
10031 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10032 + " from pid=" + callingPid
10033 + ", uid=" + callingUid
10034 + " requires " + r.permission);
10035 return new ServiceLookupResult(null, r.permission);
10036 }
10037 return new ServiceLookupResult(r, null);
10038 }
10039 return null;
10040 }
10041
10042 private class ServiceRestarter implements Runnable {
10043 private ServiceRecord mService;
10044
10045 void setService(ServiceRecord service) {
10046 mService = service;
10047 }
10048
10049 public void run() {
10050 synchronized(ActivityManagerService.this) {
10051 performServiceRestartLocked(mService);
10052 }
10053 }
10054 }
10055
10056 private ServiceLookupResult retrieveServiceLocked(Intent service,
10057 String resolvedType, int callingPid, int callingUid) {
10058 ServiceRecord r = null;
10059 if (service.getComponent() != null) {
10060 r = mServices.get(service.getComponent());
10061 }
10062 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10063 r = mServicesByIntent.get(filter);
10064 if (r == null) {
10065 try {
10066 ResolveInfo rInfo =
10067 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010068 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010069 ServiceInfo sInfo =
10070 rInfo != null ? rInfo.serviceInfo : null;
10071 if (sInfo == null) {
10072 Log.w(TAG, "Unable to start service " + service +
10073 ": not found");
10074 return null;
10075 }
10076
10077 ComponentName name = new ComponentName(
10078 sInfo.applicationInfo.packageName, sInfo.name);
10079 r = mServices.get(name);
10080 if (r == null) {
10081 filter = new Intent.FilterComparison(service.cloneFilter());
10082 ServiceRestarter res = new ServiceRestarter();
10083 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10084 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10085 synchronized (stats) {
10086 ss = stats.getServiceStatsLocked(
10087 sInfo.applicationInfo.uid, sInfo.packageName,
10088 sInfo.name);
10089 }
10090 r = new ServiceRecord(ss, name, filter, sInfo, res);
10091 res.setService(r);
10092 mServices.put(name, r);
10093 mServicesByIntent.put(filter, r);
10094
10095 // Make sure this component isn't in the pending list.
10096 int N = mPendingServices.size();
10097 for (int i=0; i<N; i++) {
10098 ServiceRecord pr = mPendingServices.get(i);
10099 if (pr.name.equals(name)) {
10100 mPendingServices.remove(i);
10101 i--;
10102 N--;
10103 }
10104 }
10105 }
10106 } catch (RemoteException ex) {
10107 // pm is in same process, this will never happen.
10108 }
10109 }
10110 if (r != null) {
10111 if (checkComponentPermission(r.permission,
10112 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10113 != PackageManager.PERMISSION_GRANTED) {
10114 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10115 + " from pid=" + Binder.getCallingPid()
10116 + ", uid=" + Binder.getCallingUid()
10117 + " requires " + r.permission);
10118 return new ServiceLookupResult(null, r.permission);
10119 }
10120 return new ServiceLookupResult(r, null);
10121 }
10122 return null;
10123 }
10124
10125 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10126 long now = SystemClock.uptimeMillis();
10127 if (r.executeNesting == 0 && r.app != null) {
10128 if (r.app.executingServices.size() == 0) {
10129 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10130 msg.obj = r.app;
10131 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10132 }
10133 r.app.executingServices.add(r);
10134 }
10135 r.executeNesting++;
10136 r.executingStart = now;
10137 }
10138
10139 private final void sendServiceArgsLocked(ServiceRecord r,
10140 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010141 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010142 if (N == 0) {
10143 return;
10144 }
10145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010146 int i = 0;
10147 while (i < N) {
10148 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010149 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010150 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010151 + r.name + " " + r.intent + " args=" + si.intent);
10152 if (si.intent == null && N > 0) {
10153 // If somehow we got a dummy start at the front, then
10154 // just drop it here.
10155 i++;
10156 continue;
10157 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010158 bumpServiceExecutingLocked(r);
10159 if (!oomAdjusted) {
10160 oomAdjusted = true;
10161 updateOomAdjLocked(r.app);
10162 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010163 int flags = 0;
10164 if (si.deliveryCount > 0) {
10165 flags |= Service.START_FLAG_RETRY;
10166 }
10167 if (si.doneExecutingCount > 0) {
10168 flags |= Service.START_FLAG_REDELIVERY;
10169 }
10170 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10171 si.deliveredTime = SystemClock.uptimeMillis();
10172 r.deliveredStarts.add(si);
10173 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010174 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010175 } catch (RemoteException e) {
10176 // Remote process gone... we'll let the normal cleanup take
10177 // care of this.
10178 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010179 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010180 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010181 break;
10182 }
10183 }
10184 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010185 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010186 } else {
10187 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010188 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010189 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010190 }
10191 }
10192 }
10193
10194 private final boolean requestServiceBindingLocked(ServiceRecord r,
10195 IntentBindRecord i, boolean rebind) {
10196 if (r.app == null || r.app.thread == null) {
10197 // If service is not currently running, can't yet bind.
10198 return false;
10199 }
10200 if ((!i.requested || rebind) && i.apps.size() > 0) {
10201 try {
10202 bumpServiceExecutingLocked(r);
10203 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10204 + ": shouldUnbind=" + i.hasBound);
10205 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10206 if (!rebind) {
10207 i.requested = true;
10208 }
10209 i.hasBound = true;
10210 i.doRebind = false;
10211 } catch (RemoteException e) {
10212 return false;
10213 }
10214 }
10215 return true;
10216 }
10217
10218 private final void requestServiceBindingsLocked(ServiceRecord r) {
10219 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10220 while (bindings.hasNext()) {
10221 IntentBindRecord i = bindings.next();
10222 if (!requestServiceBindingLocked(r, i, false)) {
10223 break;
10224 }
10225 }
10226 }
10227
10228 private final void realStartServiceLocked(ServiceRecord r,
10229 ProcessRecord app) throws RemoteException {
10230 if (app.thread == null) {
10231 throw new RemoteException();
10232 }
10233
10234 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010235 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010236
10237 app.services.add(r);
10238 bumpServiceExecutingLocked(r);
10239 updateLRUListLocked(app, true);
10240
10241 boolean created = false;
10242 try {
10243 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10244 + r.name + " " + r.intent);
10245 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
10246 System.identityHashCode(r), r.shortName,
10247 r.intent.getIntent().toString(), r.app.pid);
10248 synchronized (r.stats.getBatteryStats()) {
10249 r.stats.startLaunchedLocked();
10250 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010251 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010252 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010253 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010254 created = true;
10255 } finally {
10256 if (!created) {
10257 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010258 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010259 }
10260 }
10261
10262 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010263
10264 // If the service is in the started state, and there are no
10265 // pending arguments, then fake up one so its onStartCommand() will
10266 // be called.
10267 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10268 r.lastStartId++;
10269 if (r.lastStartId < 1) {
10270 r.lastStartId = 1;
10271 }
10272 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10273 }
10274
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010275 sendServiceArgsLocked(r, true);
10276 }
10277
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010278 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10279 boolean allowCancel) {
10280 boolean canceled = false;
10281
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010282 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010283 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010284 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010285
10286 // Any delivered but not yet finished starts should be put back
10287 // on the pending list.
10288 final int N = r.deliveredStarts.size();
10289 if (N > 0) {
10290 for (int i=N-1; i>=0; i--) {
10291 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10292 if (si.intent == null) {
10293 // We'll generate this again if needed.
10294 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10295 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10296 r.pendingStarts.add(0, si);
10297 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10298 dur *= 2;
10299 if (minDuration < dur) minDuration = dur;
10300 if (resetTime < dur) resetTime = dur;
10301 } else {
10302 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10303 + r.name);
10304 canceled = true;
10305 }
10306 }
10307 r.deliveredStarts.clear();
10308 }
10309
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010310 r.totalRestartCount++;
10311 if (r.restartDelay == 0) {
10312 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010313 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010314 } else {
10315 // If it has been a "reasonably long time" since the service
10316 // was started, then reset our restart duration back to
10317 // the beginning, so we don't infinitely increase the duration
10318 // on a service that just occasionally gets killed (which is
10319 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010320 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010321 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010322 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010323 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010324 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010325 if (r.restartDelay < minDuration) {
10326 r.restartDelay = minDuration;
10327 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010328 }
10329 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010330
10331 r.nextRestartTime = now + r.restartDelay;
10332
10333 // Make sure that we don't end up restarting a bunch of services
10334 // all at the same time.
10335 boolean repeat;
10336 do {
10337 repeat = false;
10338 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10339 ServiceRecord r2 = mRestartingServices.get(i);
10340 if (r2 != r && r.nextRestartTime
10341 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10342 && r.nextRestartTime
10343 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10344 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10345 r.restartDelay = r.nextRestartTime - now;
10346 repeat = true;
10347 break;
10348 }
10349 }
10350 } while (repeat);
10351
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010352 if (!mRestartingServices.contains(r)) {
10353 mRestartingServices.add(r);
10354 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010355
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010356 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010357
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010358 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010359 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010360 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10361 Log.w(TAG, "Scheduling restart of crashed service "
10362 + r.shortName + " in " + r.restartDelay + "ms");
10363 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10364 r.shortName, r.restartDelay);
10365
10366 Message msg = Message.obtain();
10367 msg.what = SERVICE_ERROR_MSG;
10368 msg.obj = r;
10369 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010370
10371 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010372 }
10373
10374 final void performServiceRestartLocked(ServiceRecord r) {
10375 if (!mRestartingServices.contains(r)) {
10376 return;
10377 }
10378 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10379 }
10380
10381 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10382 if (r.restartDelay == 0) {
10383 return false;
10384 }
10385 r.resetRestartCounter();
10386 mRestartingServices.remove(r);
10387 mHandler.removeCallbacks(r.restarter);
10388 return true;
10389 }
10390
10391 private final boolean bringUpServiceLocked(ServiceRecord r,
10392 int intentFlags, boolean whileRestarting) {
10393 //Log.i(TAG, "Bring up service:");
10394 //r.dump(" ");
10395
10396 if (r.app != null) {
10397 sendServiceArgsLocked(r, false);
10398 return true;
10399 }
10400
10401 if (!whileRestarting && r.restartDelay > 0) {
10402 // If waiting for a restart, then do nothing.
10403 return true;
10404 }
10405
10406 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10407 + " " + r.intent);
10408
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010409 // We are now bringing the service up, so no longer in the
10410 // restarting state.
10411 mRestartingServices.remove(r);
10412
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010413 final String appName = r.processName;
10414 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10415 if (app != null && app.thread != null) {
10416 try {
10417 realStartServiceLocked(r, app);
10418 return true;
10419 } catch (RemoteException e) {
10420 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10421 }
10422
10423 // If a dead object exception was thrown -- fall through to
10424 // restart the application.
10425 }
10426
10427 if (!mPendingServices.contains(r)) {
10428 // Not running -- get it started, and enqueue this service record
10429 // to be executed when the app comes up.
10430 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070010431 "service", r.name, false) == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010432 Log.w(TAG, "Unable to launch app "
10433 + r.appInfo.packageName + "/"
10434 + r.appInfo.uid + " for service "
10435 + r.intent.getIntent() + ": process is bad");
10436 bringDownServiceLocked(r, true);
10437 return false;
10438 }
10439 mPendingServices.add(r);
10440 }
10441 return true;
10442 }
10443
10444 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10445 //Log.i(TAG, "Bring down service:");
10446 //r.dump(" ");
10447
10448 // Does it still need to run?
10449 if (!force && r.startRequested) {
10450 return;
10451 }
10452 if (r.connections.size() > 0) {
10453 if (!force) {
10454 // XXX should probably keep a count of the number of auto-create
10455 // connections directly in the service.
10456 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10457 while (it.hasNext()) {
10458 ConnectionRecord cr = it.next();
10459 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10460 return;
10461 }
10462 }
10463 }
10464
10465 // Report to all of the connections that the service is no longer
10466 // available.
10467 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10468 while (it.hasNext()) {
10469 ConnectionRecord c = it.next();
10470 try {
10471 // todo: shouldn't be a synchronous call!
10472 c.conn.connected(r.name, null);
10473 } catch (Exception e) {
10474 Log.w(TAG, "Failure disconnecting service " + r.name +
10475 " to connection " + c.conn.asBinder() +
10476 " (in " + c.binding.client.processName + ")", e);
10477 }
10478 }
10479 }
10480
10481 // Tell the service that it has been unbound.
10482 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10483 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10484 while (it.hasNext()) {
10485 IntentBindRecord ibr = it.next();
10486 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10487 + ": hasBound=" + ibr.hasBound);
10488 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10489 try {
10490 bumpServiceExecutingLocked(r);
10491 updateOomAdjLocked(r.app);
10492 ibr.hasBound = false;
10493 r.app.thread.scheduleUnbindService(r,
10494 ibr.intent.getIntent());
10495 } catch (Exception e) {
10496 Log.w(TAG, "Exception when unbinding service "
10497 + r.shortName, e);
10498 serviceDoneExecutingLocked(r, true);
10499 }
10500 }
10501 }
10502 }
10503
10504 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10505 + " " + r.intent);
10506 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10507 System.identityHashCode(r), r.shortName,
10508 (r.app != null) ? r.app.pid : -1);
10509
10510 mServices.remove(r.name);
10511 mServicesByIntent.remove(r.intent);
10512 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10513 r.totalRestartCount = 0;
10514 unscheduleServiceRestartLocked(r);
10515
10516 // Also make sure it is not on the pending list.
10517 int N = mPendingServices.size();
10518 for (int i=0; i<N; i++) {
10519 if (mPendingServices.get(i) == r) {
10520 mPendingServices.remove(i);
10521 if (DEBUG_SERVICE) Log.v(
10522 TAG, "Removed pending service: " + r.shortName);
10523 i--;
10524 N--;
10525 }
10526 }
10527
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010528 r.cancelNotification();
10529 r.isForeground = false;
10530 r.foregroundId = 0;
10531 r.foregroundNoti = null;
10532
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010533 // Clear start entries.
10534 r.deliveredStarts.clear();
10535 r.pendingStarts.clear();
10536
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010537 if (r.app != null) {
10538 synchronized (r.stats.getBatteryStats()) {
10539 r.stats.stopLaunchedLocked();
10540 }
10541 r.app.services.remove(r);
10542 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010543 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010544 if (DEBUG_SERVICE) Log.v(TAG,
10545 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010546 bumpServiceExecutingLocked(r);
10547 mStoppingServices.add(r);
10548 updateOomAdjLocked(r.app);
10549 r.app.thread.scheduleStopService(r);
10550 } catch (Exception e) {
10551 Log.w(TAG, "Exception when stopping service "
10552 + r.shortName, e);
10553 serviceDoneExecutingLocked(r, true);
10554 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010555 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010556 } else {
10557 if (DEBUG_SERVICE) Log.v(
10558 TAG, "Removed service that has no process: " + r.shortName);
10559 }
10560 } else {
10561 if (DEBUG_SERVICE) Log.v(
10562 TAG, "Removed service that is not running: " + r.shortName);
10563 }
10564 }
10565
10566 ComponentName startServiceLocked(IApplicationThread caller,
10567 Intent service, String resolvedType,
10568 int callingPid, int callingUid) {
10569 synchronized(this) {
10570 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10571 + " type=" + resolvedType + " args=" + service.getExtras());
10572
10573 if (caller != null) {
10574 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10575 if (callerApp == null) {
10576 throw new SecurityException(
10577 "Unable to find app for caller " + caller
10578 + " (pid=" + Binder.getCallingPid()
10579 + ") when starting service " + service);
10580 }
10581 }
10582
10583 ServiceLookupResult res =
10584 retrieveServiceLocked(service, resolvedType,
10585 callingPid, callingUid);
10586 if (res == null) {
10587 return null;
10588 }
10589 if (res.record == null) {
10590 return new ComponentName("!", res.permission != null
10591 ? res.permission : "private to package");
10592 }
10593 ServiceRecord r = res.record;
10594 if (unscheduleServiceRestartLocked(r)) {
10595 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10596 + r.shortName);
10597 }
10598 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010599 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010600 r.lastStartId++;
10601 if (r.lastStartId < 1) {
10602 r.lastStartId = 1;
10603 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010604 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010605 r.lastActivity = SystemClock.uptimeMillis();
10606 synchronized (r.stats.getBatteryStats()) {
10607 r.stats.startRunningLocked();
10608 }
10609 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10610 return new ComponentName("!", "Service process is bad");
10611 }
10612 return r.name;
10613 }
10614 }
10615
10616 public ComponentName startService(IApplicationThread caller, Intent service,
10617 String resolvedType) {
10618 // Refuse possible leaked file descriptors
10619 if (service != null && service.hasFileDescriptors() == true) {
10620 throw new IllegalArgumentException("File descriptors passed in Intent");
10621 }
10622
10623 synchronized(this) {
10624 final int callingPid = Binder.getCallingPid();
10625 final int callingUid = Binder.getCallingUid();
10626 final long origId = Binder.clearCallingIdentity();
10627 ComponentName res = startServiceLocked(caller, service,
10628 resolvedType, callingPid, callingUid);
10629 Binder.restoreCallingIdentity(origId);
10630 return res;
10631 }
10632 }
10633
10634 ComponentName startServiceInPackage(int uid,
10635 Intent service, String resolvedType) {
10636 synchronized(this) {
10637 final long origId = Binder.clearCallingIdentity();
10638 ComponentName res = startServiceLocked(null, service,
10639 resolvedType, -1, uid);
10640 Binder.restoreCallingIdentity(origId);
10641 return res;
10642 }
10643 }
10644
10645 public int stopService(IApplicationThread caller, Intent service,
10646 String resolvedType) {
10647 // Refuse possible leaked file descriptors
10648 if (service != null && service.hasFileDescriptors() == true) {
10649 throw new IllegalArgumentException("File descriptors passed in Intent");
10650 }
10651
10652 synchronized(this) {
10653 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10654 + " type=" + resolvedType);
10655
10656 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10657 if (caller != null && callerApp == null) {
10658 throw new SecurityException(
10659 "Unable to find app for caller " + caller
10660 + " (pid=" + Binder.getCallingPid()
10661 + ") when stopping service " + service);
10662 }
10663
10664 // If this service is active, make sure it is stopped.
10665 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10666 if (r != null) {
10667 if (r.record != null) {
10668 synchronized (r.record.stats.getBatteryStats()) {
10669 r.record.stats.stopRunningLocked();
10670 }
10671 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010672 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010673 final long origId = Binder.clearCallingIdentity();
10674 bringDownServiceLocked(r.record, false);
10675 Binder.restoreCallingIdentity(origId);
10676 return 1;
10677 }
10678 return -1;
10679 }
10680 }
10681
10682 return 0;
10683 }
10684
10685 public IBinder peekService(Intent service, String resolvedType) {
10686 // Refuse possible leaked file descriptors
10687 if (service != null && service.hasFileDescriptors() == true) {
10688 throw new IllegalArgumentException("File descriptors passed in Intent");
10689 }
10690
10691 IBinder ret = null;
10692
10693 synchronized(this) {
10694 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10695
10696 if (r != null) {
10697 // r.record is null if findServiceLocked() failed the caller permission check
10698 if (r.record == null) {
10699 throw new SecurityException(
10700 "Permission Denial: Accessing service " + r.record.name
10701 + " from pid=" + Binder.getCallingPid()
10702 + ", uid=" + Binder.getCallingUid()
10703 + " requires " + r.permission);
10704 }
10705 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10706 if (ib != null) {
10707 ret = ib.binder;
10708 }
10709 }
10710 }
10711
10712 return ret;
10713 }
10714
10715 public boolean stopServiceToken(ComponentName className, IBinder token,
10716 int startId) {
10717 synchronized(this) {
10718 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10719 + " " + token + " startId=" + startId);
10720 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010721 if (r != null) {
10722 if (startId >= 0) {
10723 // Asked to only stop if done with all work. Note that
10724 // to avoid leaks, we will take this as dropping all
10725 // start items up to and including this one.
10726 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10727 if (si != null) {
10728 while (r.deliveredStarts.size() > 0) {
10729 if (r.deliveredStarts.remove(0) == si) {
10730 break;
10731 }
10732 }
10733 }
10734
10735 if (r.lastStartId != startId) {
10736 return false;
10737 }
10738
10739 if (r.deliveredStarts.size() > 0) {
10740 Log.w(TAG, "stopServiceToken startId " + startId
10741 + " is last, but have " + r.deliveredStarts.size()
10742 + " remaining args");
10743 }
10744 }
10745
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010746 synchronized (r.stats.getBatteryStats()) {
10747 r.stats.stopRunningLocked();
10748 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010749 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010750 }
10751 final long origId = Binder.clearCallingIdentity();
10752 bringDownServiceLocked(r, false);
10753 Binder.restoreCallingIdentity(origId);
10754 return true;
10755 }
10756 }
10757 return false;
10758 }
10759
10760 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010761 int id, Notification notification, boolean removeNotification) {
10762 final long origId = Binder.clearCallingIdentity();
10763 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010764 synchronized(this) {
10765 ServiceRecord r = findServiceLocked(className, token);
10766 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010767 if (id != 0) {
10768 if (notification == null) {
10769 throw new IllegalArgumentException("null notification");
10770 }
10771 if (r.foregroundId != id) {
10772 r.cancelNotification();
10773 r.foregroundId = id;
10774 }
10775 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10776 r.foregroundNoti = notification;
10777 r.isForeground = true;
10778 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010779 if (r.app != null) {
10780 updateServiceForegroundLocked(r.app, true);
10781 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010782 } else {
10783 if (r.isForeground) {
10784 r.isForeground = false;
10785 if (r.app != null) {
10786 updateServiceForegroundLocked(r.app, true);
10787 }
10788 }
10789 if (removeNotification) {
10790 r.cancelNotification();
10791 r.foregroundId = 0;
10792 r.foregroundNoti = null;
10793 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010794 }
10795 }
10796 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010797 } finally {
10798 Binder.restoreCallingIdentity(origId);
10799 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010800 }
10801
10802 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10803 boolean anyForeground = false;
10804 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10805 if (sr.isForeground) {
10806 anyForeground = true;
10807 break;
10808 }
10809 }
10810 if (anyForeground != proc.foregroundServices) {
10811 proc.foregroundServices = anyForeground;
10812 if (oomAdj) {
10813 updateOomAdjLocked();
10814 }
10815 }
10816 }
10817
10818 public int bindService(IApplicationThread caller, IBinder token,
10819 Intent service, String resolvedType,
10820 IServiceConnection connection, int flags) {
10821 // Refuse possible leaked file descriptors
10822 if (service != null && service.hasFileDescriptors() == true) {
10823 throw new IllegalArgumentException("File descriptors passed in Intent");
10824 }
10825
10826 synchronized(this) {
10827 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10828 + " type=" + resolvedType + " conn=" + connection.asBinder()
10829 + " flags=0x" + Integer.toHexString(flags));
10830 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10831 if (callerApp == null) {
10832 throw new SecurityException(
10833 "Unable to find app for caller " + caller
10834 + " (pid=" + Binder.getCallingPid()
10835 + ") when binding service " + service);
10836 }
10837
10838 HistoryRecord activity = null;
10839 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010840 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010841 if (aindex < 0) {
10842 Log.w(TAG, "Binding with unknown activity: " + token);
10843 return 0;
10844 }
10845 activity = (HistoryRecord)mHistory.get(aindex);
10846 }
10847
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010848 int clientLabel = 0;
10849 PendingIntent clientIntent = null;
10850
10851 if (callerApp.info.uid == Process.SYSTEM_UID) {
10852 // Hacky kind of thing -- allow system stuff to tell us
10853 // what they are, so we can report this elsewhere for
10854 // others to know why certain services are running.
10855 try {
10856 clientIntent = (PendingIntent)service.getParcelableExtra(
10857 Intent.EXTRA_CLIENT_INTENT);
10858 } catch (RuntimeException e) {
10859 }
10860 if (clientIntent != null) {
10861 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
10862 if (clientLabel != 0) {
10863 // There are no useful extras in the intent, trash them.
10864 // System code calling with this stuff just needs to know
10865 // this will happen.
10866 service = service.cloneFilter();
10867 }
10868 }
10869 }
10870
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010871 ServiceLookupResult res =
10872 retrieveServiceLocked(service, resolvedType,
10873 Binder.getCallingPid(), Binder.getCallingUid());
10874 if (res == null) {
10875 return 0;
10876 }
10877 if (res.record == null) {
10878 return -1;
10879 }
10880 ServiceRecord s = res.record;
10881
10882 final long origId = Binder.clearCallingIdentity();
10883
10884 if (unscheduleServiceRestartLocked(s)) {
10885 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10886 + s.shortName);
10887 }
10888
10889 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10890 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010891 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010892
10893 IBinder binder = connection.asBinder();
10894 s.connections.put(binder, c);
10895 b.connections.add(c);
10896 if (activity != null) {
10897 if (activity.connections == null) {
10898 activity.connections = new HashSet<ConnectionRecord>();
10899 }
10900 activity.connections.add(c);
10901 }
10902 b.client.connections.add(c);
10903 mServiceConnections.put(binder, c);
10904
10905 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10906 s.lastActivity = SystemClock.uptimeMillis();
10907 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10908 return 0;
10909 }
10910 }
10911
10912 if (s.app != null) {
10913 // This could have made the service more important.
10914 updateOomAdjLocked(s.app);
10915 }
10916
10917 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10918 + ": received=" + b.intent.received
10919 + " apps=" + b.intent.apps.size()
10920 + " doRebind=" + b.intent.doRebind);
10921
10922 if (s.app != null && b.intent.received) {
10923 // Service is already running, so we can immediately
10924 // publish the connection.
10925 try {
10926 c.conn.connected(s.name, b.intent.binder);
10927 } catch (Exception e) {
10928 Log.w(TAG, "Failure sending service " + s.shortName
10929 + " to connection " + c.conn.asBinder()
10930 + " (in " + c.binding.client.processName + ")", e);
10931 }
10932
10933 // If this is the first app connected back to this binding,
10934 // and the service had previously asked to be told when
10935 // rebound, then do so.
10936 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10937 requestServiceBindingLocked(s, b.intent, true);
10938 }
10939 } else if (!b.intent.requested) {
10940 requestServiceBindingLocked(s, b.intent, false);
10941 }
10942
10943 Binder.restoreCallingIdentity(origId);
10944 }
10945
10946 return 1;
10947 }
10948
10949 private void removeConnectionLocked(
10950 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10951 IBinder binder = c.conn.asBinder();
10952 AppBindRecord b = c.binding;
10953 ServiceRecord s = b.service;
10954 s.connections.remove(binder);
10955 b.connections.remove(c);
10956 if (c.activity != null && c.activity != skipAct) {
10957 if (c.activity.connections != null) {
10958 c.activity.connections.remove(c);
10959 }
10960 }
10961 if (b.client != skipApp) {
10962 b.client.connections.remove(c);
10963 }
10964 mServiceConnections.remove(binder);
10965
10966 if (b.connections.size() == 0) {
10967 b.intent.apps.remove(b.client);
10968 }
10969
10970 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10971 + ": shouldUnbind=" + b.intent.hasBound);
10972 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10973 && b.intent.hasBound) {
10974 try {
10975 bumpServiceExecutingLocked(s);
10976 updateOomAdjLocked(s.app);
10977 b.intent.hasBound = false;
10978 // Assume the client doesn't want to know about a rebind;
10979 // we will deal with that later if it asks for one.
10980 b.intent.doRebind = false;
10981 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10982 } catch (Exception e) {
10983 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10984 serviceDoneExecutingLocked(s, true);
10985 }
10986 }
10987
10988 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10989 bringDownServiceLocked(s, false);
10990 }
10991 }
10992
10993 public boolean unbindService(IServiceConnection connection) {
10994 synchronized (this) {
10995 IBinder binder = connection.asBinder();
10996 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10997 ConnectionRecord r = mServiceConnections.get(binder);
10998 if (r == null) {
10999 Log.w(TAG, "Unbind failed: could not find connection for "
11000 + connection.asBinder());
11001 return false;
11002 }
11003
11004 final long origId = Binder.clearCallingIdentity();
11005
11006 removeConnectionLocked(r, null, null);
11007
11008 if (r.binding.service.app != null) {
11009 // This could have made the service less important.
11010 updateOomAdjLocked(r.binding.service.app);
11011 }
11012
11013 Binder.restoreCallingIdentity(origId);
11014 }
11015
11016 return true;
11017 }
11018
11019 public void publishService(IBinder token, Intent intent, IBinder service) {
11020 // Refuse possible leaked file descriptors
11021 if (intent != null && intent.hasFileDescriptors() == true) {
11022 throw new IllegalArgumentException("File descriptors passed in Intent");
11023 }
11024
11025 synchronized(this) {
11026 if (!(token instanceof ServiceRecord)) {
11027 throw new IllegalArgumentException("Invalid service token");
11028 }
11029 ServiceRecord r = (ServiceRecord)token;
11030
11031 final long origId = Binder.clearCallingIdentity();
11032
11033 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11034 + " " + intent + ": " + service);
11035 if (r != null) {
11036 Intent.FilterComparison filter
11037 = new Intent.FilterComparison(intent);
11038 IntentBindRecord b = r.bindings.get(filter);
11039 if (b != null && !b.received) {
11040 b.binder = service;
11041 b.requested = true;
11042 b.received = true;
11043 if (r.connections.size() > 0) {
11044 Iterator<ConnectionRecord> it
11045 = r.connections.values().iterator();
11046 while (it.hasNext()) {
11047 ConnectionRecord c = it.next();
11048 if (!filter.equals(c.binding.intent.intent)) {
11049 if (DEBUG_SERVICE) Log.v(
11050 TAG, "Not publishing to: " + c);
11051 if (DEBUG_SERVICE) Log.v(
11052 TAG, "Bound intent: " + c.binding.intent.intent);
11053 if (DEBUG_SERVICE) Log.v(
11054 TAG, "Published intent: " + intent);
11055 continue;
11056 }
11057 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11058 try {
11059 c.conn.connected(r.name, service);
11060 } catch (Exception e) {
11061 Log.w(TAG, "Failure sending service " + r.name +
11062 " to connection " + c.conn.asBinder() +
11063 " (in " + c.binding.client.processName + ")", e);
11064 }
11065 }
11066 }
11067 }
11068
11069 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11070
11071 Binder.restoreCallingIdentity(origId);
11072 }
11073 }
11074 }
11075
11076 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11077 // Refuse possible leaked file descriptors
11078 if (intent != null && intent.hasFileDescriptors() == true) {
11079 throw new IllegalArgumentException("File descriptors passed in Intent");
11080 }
11081
11082 synchronized(this) {
11083 if (!(token instanceof ServiceRecord)) {
11084 throw new IllegalArgumentException("Invalid service token");
11085 }
11086 ServiceRecord r = (ServiceRecord)token;
11087
11088 final long origId = Binder.clearCallingIdentity();
11089
11090 if (r != null) {
11091 Intent.FilterComparison filter
11092 = new Intent.FilterComparison(intent);
11093 IntentBindRecord b = r.bindings.get(filter);
11094 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11095 + " at " + b + ": apps="
11096 + (b != null ? b.apps.size() : 0));
11097 if (b != null) {
11098 if (b.apps.size() > 0) {
11099 // Applications have already bound since the last
11100 // unbind, so just rebind right here.
11101 requestServiceBindingLocked(r, b, true);
11102 } else {
11103 // Note to tell the service the next time there is
11104 // a new client.
11105 b.doRebind = true;
11106 }
11107 }
11108
11109 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11110
11111 Binder.restoreCallingIdentity(origId);
11112 }
11113 }
11114 }
11115
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011116 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011117 synchronized(this) {
11118 if (!(token instanceof ServiceRecord)) {
11119 throw new IllegalArgumentException("Invalid service token");
11120 }
11121 ServiceRecord r = (ServiceRecord)token;
11122 boolean inStopping = mStoppingServices.contains(token);
11123 if (r != null) {
11124 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11125 + ": nesting=" + r.executeNesting
11126 + ", inStopping=" + inStopping);
11127 if (r != token) {
11128 Log.w(TAG, "Done executing service " + r.name
11129 + " with incorrect token: given " + token
11130 + ", expected " + r);
11131 return;
11132 }
11133
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011134 if (type == 1) {
11135 // This is a call from a service start... take care of
11136 // book-keeping.
11137 r.callStart = true;
11138 switch (res) {
11139 case Service.START_STICKY_COMPATIBILITY:
11140 case Service.START_STICKY: {
11141 // We are done with the associated start arguments.
11142 r.findDeliveredStart(startId, true);
11143 // Don't stop if killed.
11144 r.stopIfKilled = false;
11145 break;
11146 }
11147 case Service.START_NOT_STICKY: {
11148 // We are done with the associated start arguments.
11149 r.findDeliveredStart(startId, true);
11150 if (r.lastStartId == startId) {
11151 // There is no more work, and this service
11152 // doesn't want to hang around if killed.
11153 r.stopIfKilled = true;
11154 }
11155 break;
11156 }
11157 case Service.START_REDELIVER_INTENT: {
11158 // We'll keep this item until they explicitly
11159 // call stop for it, but keep track of the fact
11160 // that it was delivered.
11161 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11162 if (si != null) {
11163 si.deliveryCount = 0;
11164 si.doneExecutingCount++;
11165 // Don't stop if killed.
11166 r.stopIfKilled = true;
11167 }
11168 break;
11169 }
11170 default:
11171 throw new IllegalArgumentException(
11172 "Unknown service start result: " + res);
11173 }
11174 if (res == Service.START_STICKY_COMPATIBILITY) {
11175 r.callStart = false;
11176 }
11177 }
11178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011179 final long origId = Binder.clearCallingIdentity();
11180 serviceDoneExecutingLocked(r, inStopping);
11181 Binder.restoreCallingIdentity(origId);
11182 } else {
11183 Log.w(TAG, "Done executing unknown service " + r.name
11184 + " with token " + token);
11185 }
11186 }
11187 }
11188
11189 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11190 r.executeNesting--;
11191 if (r.executeNesting <= 0 && r.app != null) {
11192 r.app.executingServices.remove(r);
11193 if (r.app.executingServices.size() == 0) {
11194 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11195 }
11196 if (inStopping) {
11197 mStoppingServices.remove(r);
11198 }
11199 updateOomAdjLocked(r.app);
11200 }
11201 }
11202
11203 void serviceTimeout(ProcessRecord proc) {
11204 synchronized(this) {
11205 if (proc.executingServices.size() == 0 || proc.thread == null) {
11206 return;
11207 }
11208 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11209 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11210 ServiceRecord timeout = null;
11211 long nextTime = 0;
11212 while (it.hasNext()) {
11213 ServiceRecord sr = it.next();
11214 if (sr.executingStart < maxTime) {
11215 timeout = sr;
11216 break;
11217 }
11218 if (sr.executingStart > nextTime) {
11219 nextTime = sr.executingStart;
11220 }
11221 }
11222 if (timeout != null && mLRUProcesses.contains(proc)) {
11223 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011224 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011225 + timeout.name);
11226 } else {
11227 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11228 msg.obj = proc;
11229 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11230 }
11231 }
11232 }
11233
11234 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011235 // BACKUP AND RESTORE
11236 // =========================================================
11237
11238 // Cause the target app to be launched if necessary and its backup agent
11239 // instantiated. The backup agent will invoke backupAgentCreated() on the
11240 // activity manager to announce its creation.
11241 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11242 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11243 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11244
11245 synchronized(this) {
11246 // !!! TODO: currently no check here that we're already bound
11247 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11248 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11249 synchronized (stats) {
11250 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11251 }
11252
11253 BackupRecord r = new BackupRecord(ss, app, backupMode);
11254 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11255 // startProcessLocked() returns existing proc's record if it's already running
11256 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011257 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011258 if (proc == null) {
11259 Log.e(TAG, "Unable to start backup agent process " + r);
11260 return false;
11261 }
11262
11263 r.app = proc;
11264 mBackupTarget = r;
11265 mBackupAppName = app.packageName;
11266
Christopher Tate6fa95972009-06-05 18:43:55 -070011267 // Try not to kill the process during backup
11268 updateOomAdjLocked(proc);
11269
Christopher Tate181fafa2009-05-14 11:12:14 -070011270 // If the process is already attached, schedule the creation of the backup agent now.
11271 // If it is not yet live, this will be done when it attaches to the framework.
11272 if (proc.thread != null) {
11273 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11274 try {
11275 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11276 } catch (RemoteException e) {
11277 // !!! TODO: notify the backup manager that we crashed, or rely on
11278 // death notices, or...?
11279 }
11280 } else {
11281 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11282 }
11283 // Invariants: at this point, the target app process exists and the application
11284 // is either already running or in the process of coming up. mBackupTarget and
11285 // mBackupAppName describe the app, so that when it binds back to the AM we
11286 // know that it's scheduled for a backup-agent operation.
11287 }
11288
11289 return true;
11290 }
11291
11292 // A backup agent has just come up
11293 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11294 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11295 + " = " + agent);
11296
11297 synchronized(this) {
11298 if (!agentPackageName.equals(mBackupAppName)) {
11299 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11300 return;
11301 }
11302
Christopher Tate043dadc2009-06-02 16:11:00 -070011303 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011304 try {
11305 IBackupManager bm = IBackupManager.Stub.asInterface(
11306 ServiceManager.getService(Context.BACKUP_SERVICE));
11307 bm.agentConnected(agentPackageName, agent);
11308 } catch (RemoteException e) {
11309 // can't happen; the backup manager service is local
11310 } catch (Exception e) {
11311 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11312 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011313 } finally {
11314 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011315 }
11316 }
11317 }
11318
11319 // done with this agent
11320 public void unbindBackupAgent(ApplicationInfo appInfo) {
11321 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011322 if (appInfo == null) {
11323 Log.w(TAG, "unbind backup agent for null app");
11324 return;
11325 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011326
11327 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011328 if (mBackupAppName == null) {
11329 Log.w(TAG, "Unbinding backup agent with no active backup");
11330 return;
11331 }
11332
Christopher Tate181fafa2009-05-14 11:12:14 -070011333 if (!mBackupAppName.equals(appInfo.packageName)) {
11334 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11335 return;
11336 }
11337
Christopher Tate6fa95972009-06-05 18:43:55 -070011338 ProcessRecord proc = mBackupTarget.app;
11339 mBackupTarget = null;
11340 mBackupAppName = null;
11341
11342 // Not backing this app up any more; reset its OOM adjustment
11343 updateOomAdjLocked(proc);
11344
Christopher Tatec7b31e32009-06-10 15:49:30 -070011345 // If the app crashed during backup, 'thread' will be null here
11346 if (proc.thread != null) {
11347 try {
11348 proc.thread.scheduleDestroyBackupAgent(appInfo);
11349 } catch (Exception e) {
11350 Log.e(TAG, "Exception when unbinding backup agent:");
11351 e.printStackTrace();
11352 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011353 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011354 }
11355 }
11356 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011357 // BROADCASTS
11358 // =========================================================
11359
11360 private final List getStickies(String action, IntentFilter filter,
11361 List cur) {
11362 final ContentResolver resolver = mContext.getContentResolver();
11363 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11364 if (list == null) {
11365 return cur;
11366 }
11367 int N = list.size();
11368 for (int i=0; i<N; i++) {
11369 Intent intent = list.get(i);
11370 if (filter.match(resolver, intent, true, TAG) >= 0) {
11371 if (cur == null) {
11372 cur = new ArrayList<Intent>();
11373 }
11374 cur.add(intent);
11375 }
11376 }
11377 return cur;
11378 }
11379
11380 private final void scheduleBroadcastsLocked() {
11381 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11382 + mBroadcastsScheduled);
11383
11384 if (mBroadcastsScheduled) {
11385 return;
11386 }
11387 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11388 mBroadcastsScheduled = true;
11389 }
11390
11391 public Intent registerReceiver(IApplicationThread caller,
11392 IIntentReceiver receiver, IntentFilter filter, String permission) {
11393 synchronized(this) {
11394 ProcessRecord callerApp = null;
11395 if (caller != null) {
11396 callerApp = getRecordForAppLocked(caller);
11397 if (callerApp == null) {
11398 throw new SecurityException(
11399 "Unable to find app for caller " + caller
11400 + " (pid=" + Binder.getCallingPid()
11401 + ") when registering receiver " + receiver);
11402 }
11403 }
11404
11405 List allSticky = null;
11406
11407 // Look for any matching sticky broadcasts...
11408 Iterator actions = filter.actionsIterator();
11409 if (actions != null) {
11410 while (actions.hasNext()) {
11411 String action = (String)actions.next();
11412 allSticky = getStickies(action, filter, allSticky);
11413 }
11414 } else {
11415 allSticky = getStickies(null, filter, allSticky);
11416 }
11417
11418 // The first sticky in the list is returned directly back to
11419 // the client.
11420 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11421
11422 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11423 + ": " + sticky);
11424
11425 if (receiver == null) {
11426 return sticky;
11427 }
11428
11429 ReceiverList rl
11430 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11431 if (rl == null) {
11432 rl = new ReceiverList(this, callerApp,
11433 Binder.getCallingPid(),
11434 Binder.getCallingUid(), receiver);
11435 if (rl.app != null) {
11436 rl.app.receivers.add(rl);
11437 } else {
11438 try {
11439 receiver.asBinder().linkToDeath(rl, 0);
11440 } catch (RemoteException e) {
11441 return sticky;
11442 }
11443 rl.linkedToDeath = true;
11444 }
11445 mRegisteredReceivers.put(receiver.asBinder(), rl);
11446 }
11447 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11448 rl.add(bf);
11449 if (!bf.debugCheck()) {
11450 Log.w(TAG, "==> For Dynamic broadast");
11451 }
11452 mReceiverResolver.addFilter(bf);
11453
11454 // Enqueue broadcasts for all existing stickies that match
11455 // this filter.
11456 if (allSticky != null) {
11457 ArrayList receivers = new ArrayList();
11458 receivers.add(bf);
11459
11460 int N = allSticky.size();
11461 for (int i=0; i<N; i++) {
11462 Intent intent = (Intent)allSticky.get(i);
11463 BroadcastRecord r = new BroadcastRecord(intent, null,
11464 null, -1, -1, null, receivers, null, 0, null, null,
11465 false);
11466 if (mParallelBroadcasts.size() == 0) {
11467 scheduleBroadcastsLocked();
11468 }
11469 mParallelBroadcasts.add(r);
11470 }
11471 }
11472
11473 return sticky;
11474 }
11475 }
11476
11477 public void unregisterReceiver(IIntentReceiver receiver) {
11478 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11479
11480 boolean doNext = false;
11481
11482 synchronized(this) {
11483 ReceiverList rl
11484 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11485 if (rl != null) {
11486 if (rl.curBroadcast != null) {
11487 BroadcastRecord r = rl.curBroadcast;
11488 doNext = finishReceiverLocked(
11489 receiver.asBinder(), r.resultCode, r.resultData,
11490 r.resultExtras, r.resultAbort, true);
11491 }
11492
11493 if (rl.app != null) {
11494 rl.app.receivers.remove(rl);
11495 }
11496 removeReceiverLocked(rl);
11497 if (rl.linkedToDeath) {
11498 rl.linkedToDeath = false;
11499 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11500 }
11501 }
11502 }
11503
11504 if (!doNext) {
11505 return;
11506 }
11507
11508 final long origId = Binder.clearCallingIdentity();
11509 processNextBroadcast(false);
11510 trimApplications();
11511 Binder.restoreCallingIdentity(origId);
11512 }
11513
11514 void removeReceiverLocked(ReceiverList rl) {
11515 mRegisteredReceivers.remove(rl.receiver.asBinder());
11516 int N = rl.size();
11517 for (int i=0; i<N; i++) {
11518 mReceiverResolver.removeFilter(rl.get(i));
11519 }
11520 }
11521
11522 private final int broadcastIntentLocked(ProcessRecord callerApp,
11523 String callerPackage, Intent intent, String resolvedType,
11524 IIntentReceiver resultTo, int resultCode, String resultData,
11525 Bundle map, String requiredPermission,
11526 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11527 intent = new Intent(intent);
11528
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011529 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011530 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11531 + " ordered=" + ordered);
11532 if ((resultTo != null) && !ordered) {
11533 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11534 }
11535
11536 // Handle special intents: if this broadcast is from the package
11537 // manager about a package being removed, we need to remove all of
11538 // its activities from the history stack.
11539 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11540 intent.getAction());
11541 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11542 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11543 || uidRemoved) {
11544 if (checkComponentPermission(
11545 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11546 callingPid, callingUid, -1)
11547 == PackageManager.PERMISSION_GRANTED) {
11548 if (uidRemoved) {
11549 final Bundle intentExtras = intent.getExtras();
11550 final int uid = intentExtras != null
11551 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11552 if (uid >= 0) {
11553 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11554 synchronized (bs) {
11555 bs.removeUidStatsLocked(uid);
11556 }
11557 }
11558 } else {
11559 Uri data = intent.getData();
11560 String ssp;
11561 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11562 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11563 uninstallPackageLocked(ssp,
11564 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011565 AttributeCache ac = AttributeCache.instance();
11566 if (ac != null) {
11567 ac.removePackage(ssp);
11568 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011569 }
11570 }
11571 }
11572 } else {
11573 String msg = "Permission Denial: " + intent.getAction()
11574 + " broadcast from " + callerPackage + " (pid=" + callingPid
11575 + ", uid=" + callingUid + ")"
11576 + " requires "
11577 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11578 Log.w(TAG, msg);
11579 throw new SecurityException(msg);
11580 }
11581 }
11582
11583 /*
11584 * If this is the time zone changed action, queue up a message that will reset the timezone
11585 * of all currently running processes. This message will get queued up before the broadcast
11586 * happens.
11587 */
11588 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11589 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11590 }
11591
Dianne Hackborn854060af2009-07-09 18:14:31 -070011592 /*
11593 * Prevent non-system code (defined here to be non-persistent
11594 * processes) from sending protected broadcasts.
11595 */
11596 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11597 || callingUid == Process.SHELL_UID || callingUid == 0) {
11598 // Always okay.
11599 } else if (callerApp == null || !callerApp.persistent) {
11600 try {
11601 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11602 intent.getAction())) {
11603 String msg = "Permission Denial: not allowed to send broadcast "
11604 + intent.getAction() + " from pid="
11605 + callingPid + ", uid=" + callingUid;
11606 Log.w(TAG, msg);
11607 throw new SecurityException(msg);
11608 }
11609 } catch (RemoteException e) {
11610 Log.w(TAG, "Remote exception", e);
11611 return BROADCAST_SUCCESS;
11612 }
11613 }
11614
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011615 // Add to the sticky list if requested.
11616 if (sticky) {
11617 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11618 callingPid, callingUid)
11619 != PackageManager.PERMISSION_GRANTED) {
11620 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11621 + callingPid + ", uid=" + callingUid
11622 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11623 Log.w(TAG, msg);
11624 throw new SecurityException(msg);
11625 }
11626 if (requiredPermission != null) {
11627 Log.w(TAG, "Can't broadcast sticky intent " + intent
11628 + " and enforce permission " + requiredPermission);
11629 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11630 }
11631 if (intent.getComponent() != null) {
11632 throw new SecurityException(
11633 "Sticky broadcasts can't target a specific component");
11634 }
11635 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11636 if (list == null) {
11637 list = new ArrayList<Intent>();
11638 mStickyBroadcasts.put(intent.getAction(), list);
11639 }
11640 int N = list.size();
11641 int i;
11642 for (i=0; i<N; i++) {
11643 if (intent.filterEquals(list.get(i))) {
11644 // This sticky already exists, replace it.
11645 list.set(i, new Intent(intent));
11646 break;
11647 }
11648 }
11649 if (i >= N) {
11650 list.add(new Intent(intent));
11651 }
11652 }
11653
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011654 // Figure out who all will receive this broadcast.
11655 List receivers = null;
11656 List<BroadcastFilter> registeredReceivers = null;
11657 try {
11658 if (intent.getComponent() != null) {
11659 // Broadcast is going to one specific receiver class...
11660 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011661 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011662 if (ai != null) {
11663 receivers = new ArrayList();
11664 ResolveInfo ri = new ResolveInfo();
11665 ri.activityInfo = ai;
11666 receivers.add(ri);
11667 }
11668 } else {
11669 // Need to resolve the intent to interested receivers...
11670 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11671 == 0) {
11672 receivers =
11673 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011674 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011675 }
Mihai Preda074edef2009-05-18 17:13:31 +020011676 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011677 }
11678 } catch (RemoteException ex) {
11679 // pm is in same process, this will never happen.
11680 }
11681
11682 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11683 if (!ordered && NR > 0) {
11684 // If we are not serializing this broadcast, then send the
11685 // registered receivers separately so they don't wait for the
11686 // components to be launched.
11687 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11688 callerPackage, callingPid, callingUid, requiredPermission,
11689 registeredReceivers, resultTo, resultCode, resultData, map,
11690 ordered);
11691 if (DEBUG_BROADCAST) Log.v(
11692 TAG, "Enqueueing parallel broadcast " + r
11693 + ": prev had " + mParallelBroadcasts.size());
11694 mParallelBroadcasts.add(r);
11695 scheduleBroadcastsLocked();
11696 registeredReceivers = null;
11697 NR = 0;
11698 }
11699
11700 // Merge into one list.
11701 int ir = 0;
11702 if (receivers != null) {
11703 // A special case for PACKAGE_ADDED: do not allow the package
11704 // being added to see this broadcast. This prevents them from
11705 // using this as a back door to get run as soon as they are
11706 // installed. Maybe in the future we want to have a special install
11707 // broadcast or such for apps, but we'd like to deliberately make
11708 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011709 boolean skip = false;
11710 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011711 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011712 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11713 skip = true;
11714 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11715 skip = true;
11716 }
11717 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011718 ? intent.getData().getSchemeSpecificPart()
11719 : null;
11720 if (skipPackage != null && receivers != null) {
11721 int NT = receivers.size();
11722 for (int it=0; it<NT; it++) {
11723 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11724 if (curt.activityInfo.packageName.equals(skipPackage)) {
11725 receivers.remove(it);
11726 it--;
11727 NT--;
11728 }
11729 }
11730 }
11731
11732 int NT = receivers != null ? receivers.size() : 0;
11733 int it = 0;
11734 ResolveInfo curt = null;
11735 BroadcastFilter curr = null;
11736 while (it < NT && ir < NR) {
11737 if (curt == null) {
11738 curt = (ResolveInfo)receivers.get(it);
11739 }
11740 if (curr == null) {
11741 curr = registeredReceivers.get(ir);
11742 }
11743 if (curr.getPriority() >= curt.priority) {
11744 // Insert this broadcast record into the final list.
11745 receivers.add(it, curr);
11746 ir++;
11747 curr = null;
11748 it++;
11749 NT++;
11750 } else {
11751 // Skip to the next ResolveInfo in the final list.
11752 it++;
11753 curt = null;
11754 }
11755 }
11756 }
11757 while (ir < NR) {
11758 if (receivers == null) {
11759 receivers = new ArrayList();
11760 }
11761 receivers.add(registeredReceivers.get(ir));
11762 ir++;
11763 }
11764
11765 if ((receivers != null && receivers.size() > 0)
11766 || resultTo != null) {
11767 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11768 callerPackage, callingPid, callingUid, requiredPermission,
11769 receivers, resultTo, resultCode, resultData, map, ordered);
11770 if (DEBUG_BROADCAST) Log.v(
11771 TAG, "Enqueueing ordered broadcast " + r
11772 + ": prev had " + mOrderedBroadcasts.size());
11773 if (DEBUG_BROADCAST) {
11774 int seq = r.intent.getIntExtra("seq", -1);
11775 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11776 }
11777 mOrderedBroadcasts.add(r);
11778 scheduleBroadcastsLocked();
11779 }
11780
11781 return BROADCAST_SUCCESS;
11782 }
11783
11784 public final int broadcastIntent(IApplicationThread caller,
11785 Intent intent, String resolvedType, IIntentReceiver resultTo,
11786 int resultCode, String resultData, Bundle map,
11787 String requiredPermission, boolean serialized, boolean sticky) {
11788 // Refuse possible leaked file descriptors
11789 if (intent != null && intent.hasFileDescriptors() == true) {
11790 throw new IllegalArgumentException("File descriptors passed in Intent");
11791 }
11792
11793 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011794 int flags = intent.getFlags();
11795
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011796 if (!mSystemReady) {
11797 // if the caller really truly claims to know what they're doing, go
11798 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011799 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11800 intent = new Intent(intent);
11801 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11802 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11803 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11804 + " before boot completion");
11805 throw new IllegalStateException("Cannot broadcast before boot completed");
11806 }
11807 }
11808
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011809 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
11810 throw new IllegalArgumentException(
11811 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
11812 }
11813
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011814 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11815 final int callingPid = Binder.getCallingPid();
11816 final int callingUid = Binder.getCallingUid();
11817 final long origId = Binder.clearCallingIdentity();
11818 int res = broadcastIntentLocked(callerApp,
11819 callerApp != null ? callerApp.info.packageName : null,
11820 intent, resolvedType, resultTo,
11821 resultCode, resultData, map, requiredPermission, serialized,
11822 sticky, callingPid, callingUid);
11823 Binder.restoreCallingIdentity(origId);
11824 return res;
11825 }
11826 }
11827
11828 int broadcastIntentInPackage(String packageName, int uid,
11829 Intent intent, String resolvedType, IIntentReceiver resultTo,
11830 int resultCode, String resultData, Bundle map,
11831 String requiredPermission, boolean serialized, boolean sticky) {
11832 synchronized(this) {
11833 final long origId = Binder.clearCallingIdentity();
11834 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11835 resultTo, resultCode, resultData, map, requiredPermission,
11836 serialized, sticky, -1, uid);
11837 Binder.restoreCallingIdentity(origId);
11838 return res;
11839 }
11840 }
11841
11842 public final void unbroadcastIntent(IApplicationThread caller,
11843 Intent intent) {
11844 // Refuse possible leaked file descriptors
11845 if (intent != null && intent.hasFileDescriptors() == true) {
11846 throw new IllegalArgumentException("File descriptors passed in Intent");
11847 }
11848
11849 synchronized(this) {
11850 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11851 != PackageManager.PERMISSION_GRANTED) {
11852 String msg = "Permission Denial: unbroadcastIntent() from pid="
11853 + Binder.getCallingPid()
11854 + ", uid=" + Binder.getCallingUid()
11855 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11856 Log.w(TAG, msg);
11857 throw new SecurityException(msg);
11858 }
11859 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11860 if (list != null) {
11861 int N = list.size();
11862 int i;
11863 for (i=0; i<N; i++) {
11864 if (intent.filterEquals(list.get(i))) {
11865 list.remove(i);
11866 break;
11867 }
11868 }
11869 }
11870 }
11871 }
11872
11873 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11874 String resultData, Bundle resultExtras, boolean resultAbort,
11875 boolean explicit) {
11876 if (mOrderedBroadcasts.size() == 0) {
11877 if (explicit) {
11878 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11879 }
11880 return false;
11881 }
11882 BroadcastRecord r = mOrderedBroadcasts.get(0);
11883 if (r.receiver == null) {
11884 if (explicit) {
11885 Log.w(TAG, "finishReceiver called but none active");
11886 }
11887 return false;
11888 }
11889 if (r.receiver != receiver) {
11890 Log.w(TAG, "finishReceiver called but active receiver is different");
11891 return false;
11892 }
11893 int state = r.state;
11894 r.state = r.IDLE;
11895 if (state == r.IDLE) {
11896 if (explicit) {
11897 Log.w(TAG, "finishReceiver called but state is IDLE");
11898 }
11899 }
11900 r.receiver = null;
11901 r.intent.setComponent(null);
11902 if (r.curApp != null) {
11903 r.curApp.curReceiver = null;
11904 }
11905 if (r.curFilter != null) {
11906 r.curFilter.receiverList.curBroadcast = null;
11907 }
11908 r.curFilter = null;
11909 r.curApp = null;
11910 r.curComponent = null;
11911 r.curReceiver = null;
11912 mPendingBroadcast = null;
11913
11914 r.resultCode = resultCode;
11915 r.resultData = resultData;
11916 r.resultExtras = resultExtras;
11917 r.resultAbort = resultAbort;
11918
11919 // We will process the next receiver right now if this is finishing
11920 // an app receiver (which is always asynchronous) or after we have
11921 // come back from calling a receiver.
11922 return state == BroadcastRecord.APP_RECEIVE
11923 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11924 }
11925
11926 public void finishReceiver(IBinder who, int resultCode, String resultData,
11927 Bundle resultExtras, boolean resultAbort) {
11928 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11929
11930 // Refuse possible leaked file descriptors
11931 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11932 throw new IllegalArgumentException("File descriptors passed in Bundle");
11933 }
11934
11935 boolean doNext;
11936
11937 final long origId = Binder.clearCallingIdentity();
11938
11939 synchronized(this) {
11940 doNext = finishReceiverLocked(
11941 who, resultCode, resultData, resultExtras, resultAbort, true);
11942 }
11943
11944 if (doNext) {
11945 processNextBroadcast(false);
11946 }
11947 trimApplications();
11948
11949 Binder.restoreCallingIdentity(origId);
11950 }
11951
11952 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11953 if (r.nextReceiver > 0) {
11954 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11955 if (curReceiver instanceof BroadcastFilter) {
11956 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11957 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11958 System.identityHashCode(r),
11959 r.intent.getAction(),
11960 r.nextReceiver - 1,
11961 System.identityHashCode(bf));
11962 } else {
11963 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11964 System.identityHashCode(r),
11965 r.intent.getAction(),
11966 r.nextReceiver - 1,
11967 ((ResolveInfo)curReceiver).toString());
11968 }
11969 } else {
11970 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11971 + r);
11972 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11973 System.identityHashCode(r),
11974 r.intent.getAction(),
11975 r.nextReceiver,
11976 "NONE");
11977 }
11978 }
11979
11980 private final void broadcastTimeout() {
11981 synchronized (this) {
11982 if (mOrderedBroadcasts.size() == 0) {
11983 return;
11984 }
11985 long now = SystemClock.uptimeMillis();
11986 BroadcastRecord r = mOrderedBroadcasts.get(0);
11987 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11988 if (DEBUG_BROADCAST) Log.v(TAG,
11989 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11990 + (r.startTime + BROADCAST_TIMEOUT));
11991 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11992 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11993 return;
11994 }
11995
11996 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11997 r.startTime = now;
11998 r.anrCount++;
11999
12000 // Current receiver has passed its expiration date.
12001 if (r.nextReceiver <= 0) {
12002 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12003 return;
12004 }
12005
12006 ProcessRecord app = null;
12007
12008 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12009 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12010 logBroadcastReceiverDiscard(r);
12011 if (curReceiver instanceof BroadcastFilter) {
12012 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12013 if (bf.receiverList.pid != 0
12014 && bf.receiverList.pid != MY_PID) {
12015 synchronized (this.mPidsSelfLocked) {
12016 app = this.mPidsSelfLocked.get(
12017 bf.receiverList.pid);
12018 }
12019 }
12020 } else {
12021 app = r.curApp;
12022 }
12023
12024 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070012025 appNotRespondingLocked(app, null, null,
12026 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012027 }
12028
12029 if (mPendingBroadcast == r) {
12030 mPendingBroadcast = null;
12031 }
12032
12033 // Move on to the next receiver.
12034 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12035 r.resultExtras, r.resultAbort, true);
12036 scheduleBroadcastsLocked();
12037 }
12038 }
12039
12040 private final void processCurBroadcastLocked(BroadcastRecord r,
12041 ProcessRecord app) throws RemoteException {
12042 if (app.thread == null) {
12043 throw new RemoteException();
12044 }
12045 r.receiver = app.thread.asBinder();
12046 r.curApp = app;
12047 app.curReceiver = r;
12048 updateLRUListLocked(app, true);
12049
12050 // Tell the application to launch this receiver.
12051 r.intent.setComponent(r.curComponent);
12052
12053 boolean started = false;
12054 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012055 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012056 "Delivering to component " + r.curComponent
12057 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012058 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012059 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12060 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12061 started = true;
12062 } finally {
12063 if (!started) {
12064 r.receiver = null;
12065 r.curApp = null;
12066 app.curReceiver = null;
12067 }
12068 }
12069
12070 }
12071
12072 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
12073 Intent intent, int resultCode, String data,
12074 Bundle extras, boolean ordered) throws RemoteException {
12075 if (app != null && app.thread != null) {
12076 // If we have an app thread, do the call through that so it is
12077 // correctly ordered with other one-way calls.
12078 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
12079 data, extras, ordered);
12080 } else {
12081 receiver.performReceive(intent, resultCode, data, extras, ordered);
12082 }
12083 }
12084
12085 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12086 BroadcastFilter filter, boolean ordered) {
12087 boolean skip = false;
12088 if (filter.requiredPermission != null) {
12089 int perm = checkComponentPermission(filter.requiredPermission,
12090 r.callingPid, r.callingUid, -1);
12091 if (perm != PackageManager.PERMISSION_GRANTED) {
12092 Log.w(TAG, "Permission Denial: broadcasting "
12093 + r.intent.toString()
12094 + " from " + r.callerPackage + " (pid="
12095 + r.callingPid + ", uid=" + r.callingUid + ")"
12096 + " requires " + filter.requiredPermission
12097 + " due to registered receiver " + filter);
12098 skip = true;
12099 }
12100 }
12101 if (r.requiredPermission != null) {
12102 int perm = checkComponentPermission(r.requiredPermission,
12103 filter.receiverList.pid, filter.receiverList.uid, -1);
12104 if (perm != PackageManager.PERMISSION_GRANTED) {
12105 Log.w(TAG, "Permission Denial: receiving "
12106 + r.intent.toString()
12107 + " to " + filter.receiverList.app
12108 + " (pid=" + filter.receiverList.pid
12109 + ", uid=" + filter.receiverList.uid + ")"
12110 + " requires " + r.requiredPermission
12111 + " due to sender " + r.callerPackage
12112 + " (uid " + r.callingUid + ")");
12113 skip = true;
12114 }
12115 }
12116
12117 if (!skip) {
12118 // If this is not being sent as an ordered broadcast, then we
12119 // don't want to touch the fields that keep track of the current
12120 // state of ordered broadcasts.
12121 if (ordered) {
12122 r.receiver = filter.receiverList.receiver.asBinder();
12123 r.curFilter = filter;
12124 filter.receiverList.curBroadcast = r;
12125 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012126 if (filter.receiverList.app != null) {
12127 // Bump hosting application to no longer be in background
12128 // scheduling class. Note that we can't do that if there
12129 // isn't an app... but we can only be in that case for
12130 // things that directly call the IActivityManager API, which
12131 // are already core system stuff so don't matter for this.
12132 r.curApp = filter.receiverList.app;
12133 filter.receiverList.app.curReceiver = r;
12134 updateOomAdjLocked();
12135 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012136 }
12137 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012138 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012139 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012140 Log.i(TAG, "Delivering to " + filter.receiverList.app
12141 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012142 }
12143 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12144 new Intent(r.intent), r.resultCode,
12145 r.resultData, r.resultExtras, r.ordered);
12146 if (ordered) {
12147 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12148 }
12149 } catch (RemoteException e) {
12150 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12151 if (ordered) {
12152 r.receiver = null;
12153 r.curFilter = null;
12154 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012155 if (filter.receiverList.app != null) {
12156 filter.receiverList.app.curReceiver = null;
12157 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012158 }
12159 }
12160 }
12161 }
12162
12163 private final void processNextBroadcast(boolean fromMsg) {
12164 synchronized(this) {
12165 BroadcastRecord r;
12166
12167 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12168 + mParallelBroadcasts.size() + " broadcasts, "
12169 + mOrderedBroadcasts.size() + " serialized broadcasts");
12170
12171 updateCpuStats();
12172
12173 if (fromMsg) {
12174 mBroadcastsScheduled = false;
12175 }
12176
12177 // First, deliver any non-serialized broadcasts right away.
12178 while (mParallelBroadcasts.size() > 0) {
12179 r = mParallelBroadcasts.remove(0);
12180 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012181 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12182 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012183 for (int i=0; i<N; i++) {
12184 Object target = r.receivers.get(i);
12185 if (DEBUG_BROADCAST) Log.v(TAG,
12186 "Delivering non-serialized to registered "
12187 + target + ": " + r);
12188 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12189 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012190 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12191 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012192 }
12193
12194 // Now take care of the next serialized one...
12195
12196 // If we are waiting for a process to come up to handle the next
12197 // broadcast, then do nothing at this point. Just in case, we
12198 // check that the process we're waiting for still exists.
12199 if (mPendingBroadcast != null) {
12200 Log.i(TAG, "processNextBroadcast: waiting for "
12201 + mPendingBroadcast.curApp);
12202
12203 boolean isDead;
12204 synchronized (mPidsSelfLocked) {
12205 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12206 }
12207 if (!isDead) {
12208 // It's still alive, so keep waiting
12209 return;
12210 } else {
12211 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12212 + " died before responding to broadcast");
12213 mPendingBroadcast = null;
12214 }
12215 }
12216
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012217 boolean looped = false;
12218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012219 do {
12220 if (mOrderedBroadcasts.size() == 0) {
12221 // No more broadcasts pending, so all done!
12222 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012223 if (looped) {
12224 // If we had finished the last ordered broadcast, then
12225 // make sure all processes have correct oom and sched
12226 // adjustments.
12227 updateOomAdjLocked();
12228 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012229 return;
12230 }
12231 r = mOrderedBroadcasts.get(0);
12232 boolean forceReceive = false;
12233
12234 // Ensure that even if something goes awry with the timeout
12235 // detection, we catch "hung" broadcasts here, discard them,
12236 // and continue to make progress.
12237 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12238 long now = SystemClock.uptimeMillis();
12239 if (r.dispatchTime > 0) {
12240 if ((numReceivers > 0) &&
12241 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12242 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12243 + " now=" + now
12244 + " dispatchTime=" + r.dispatchTime
12245 + " startTime=" + r.startTime
12246 + " intent=" + r.intent
12247 + " numReceivers=" + numReceivers
12248 + " nextReceiver=" + r.nextReceiver
12249 + " state=" + r.state);
12250 broadcastTimeout(); // forcibly finish this broadcast
12251 forceReceive = true;
12252 r.state = BroadcastRecord.IDLE;
12253 }
12254 }
12255
12256 if (r.state != BroadcastRecord.IDLE) {
12257 if (DEBUG_BROADCAST) Log.d(TAG,
12258 "processNextBroadcast() called when not idle (state="
12259 + r.state + ")");
12260 return;
12261 }
12262
12263 if (r.receivers == null || r.nextReceiver >= numReceivers
12264 || r.resultAbort || forceReceive) {
12265 // No more receivers for this broadcast! Send the final
12266 // result if requested...
12267 if (r.resultTo != null) {
12268 try {
12269 if (DEBUG_BROADCAST) {
12270 int seq = r.intent.getIntExtra("seq", -1);
12271 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12272 + " seq=" + seq + " app=" + r.callerApp);
12273 }
12274 performReceive(r.callerApp, r.resultTo,
12275 new Intent(r.intent), r.resultCode,
12276 r.resultData, r.resultExtras, false);
12277 } catch (RemoteException e) {
12278 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12279 }
12280 }
12281
12282 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12283 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12284
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012285 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12286 + r);
12287
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012288 // ... and on to the next...
12289 mOrderedBroadcasts.remove(0);
12290 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012291 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012292 continue;
12293 }
12294 } while (r == null);
12295
12296 // Get the next receiver...
12297 int recIdx = r.nextReceiver++;
12298
12299 // Keep track of when this receiver started, and make sure there
12300 // is a timeout message pending to kill it if need be.
12301 r.startTime = SystemClock.uptimeMillis();
12302 if (recIdx == 0) {
12303 r.dispatchTime = r.startTime;
12304
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012305 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12306 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012307 if (DEBUG_BROADCAST) Log.v(TAG,
12308 "Submitting BROADCAST_TIMEOUT_MSG for "
12309 + (r.startTime + BROADCAST_TIMEOUT));
12310 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12311 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12312 }
12313
12314 Object nextReceiver = r.receivers.get(recIdx);
12315 if (nextReceiver instanceof BroadcastFilter) {
12316 // Simple case: this is a registered receiver who gets
12317 // a direct call.
12318 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12319 if (DEBUG_BROADCAST) Log.v(TAG,
12320 "Delivering serialized to registered "
12321 + filter + ": " + r);
12322 deliverToRegisteredReceiver(r, filter, r.ordered);
12323 if (r.receiver == null || !r.ordered) {
12324 // The receiver has already finished, so schedule to
12325 // process the next one.
12326 r.state = BroadcastRecord.IDLE;
12327 scheduleBroadcastsLocked();
12328 }
12329 return;
12330 }
12331
12332 // Hard case: need to instantiate the receiver, possibly
12333 // starting its application process to host it.
12334
12335 ResolveInfo info =
12336 (ResolveInfo)nextReceiver;
12337
12338 boolean skip = false;
12339 int perm = checkComponentPermission(info.activityInfo.permission,
12340 r.callingPid, r.callingUid,
12341 info.activityInfo.exported
12342 ? -1 : info.activityInfo.applicationInfo.uid);
12343 if (perm != PackageManager.PERMISSION_GRANTED) {
12344 Log.w(TAG, "Permission Denial: broadcasting "
12345 + r.intent.toString()
12346 + " from " + r.callerPackage + " (pid=" + r.callingPid
12347 + ", uid=" + r.callingUid + ")"
12348 + " requires " + info.activityInfo.permission
12349 + " due to receiver " + info.activityInfo.packageName
12350 + "/" + info.activityInfo.name);
12351 skip = true;
12352 }
12353 if (r.callingUid != Process.SYSTEM_UID &&
12354 r.requiredPermission != null) {
12355 try {
12356 perm = ActivityThread.getPackageManager().
12357 checkPermission(r.requiredPermission,
12358 info.activityInfo.applicationInfo.packageName);
12359 } catch (RemoteException e) {
12360 perm = PackageManager.PERMISSION_DENIED;
12361 }
12362 if (perm != PackageManager.PERMISSION_GRANTED) {
12363 Log.w(TAG, "Permission Denial: receiving "
12364 + r.intent + " to "
12365 + info.activityInfo.applicationInfo.packageName
12366 + " requires " + r.requiredPermission
12367 + " due to sender " + r.callerPackage
12368 + " (uid " + r.callingUid + ")");
12369 skip = true;
12370 }
12371 }
12372 if (r.curApp != null && r.curApp.crashing) {
12373 // If the target process is crashing, just skip it.
12374 skip = true;
12375 }
12376
12377 if (skip) {
12378 r.receiver = null;
12379 r.curFilter = null;
12380 r.state = BroadcastRecord.IDLE;
12381 scheduleBroadcastsLocked();
12382 return;
12383 }
12384
12385 r.state = BroadcastRecord.APP_RECEIVE;
12386 String targetProcess = info.activityInfo.processName;
12387 r.curComponent = new ComponentName(
12388 info.activityInfo.applicationInfo.packageName,
12389 info.activityInfo.name);
12390 r.curReceiver = info.activityInfo;
12391
12392 // Is this receiver's application already running?
12393 ProcessRecord app = getProcessRecordLocked(targetProcess,
12394 info.activityInfo.applicationInfo.uid);
12395 if (app != null && app.thread != null) {
12396 try {
12397 processCurBroadcastLocked(r, app);
12398 return;
12399 } catch (RemoteException e) {
12400 Log.w(TAG, "Exception when sending broadcast to "
12401 + r.curComponent, e);
12402 }
12403
12404 // If a dead object exception was thrown -- fall through to
12405 // restart the application.
12406 }
12407
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012408 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012409 if ((r.curApp=startProcessLocked(targetProcess,
12410 info.activityInfo.applicationInfo, true,
12411 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012412 "broadcast", r.curComponent,
12413 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12414 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012415 // Ah, this recipient is unavailable. Finish it if necessary,
12416 // and mark the broadcast record as ready for the next.
12417 Log.w(TAG, "Unable to launch app "
12418 + info.activityInfo.applicationInfo.packageName + "/"
12419 + info.activityInfo.applicationInfo.uid + " for broadcast "
12420 + r.intent + ": process is bad");
12421 logBroadcastReceiverDiscard(r);
12422 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12423 r.resultExtras, r.resultAbort, true);
12424 scheduleBroadcastsLocked();
12425 r.state = BroadcastRecord.IDLE;
12426 return;
12427 }
12428
12429 mPendingBroadcast = r;
12430 }
12431 }
12432
12433 // =========================================================
12434 // INSTRUMENTATION
12435 // =========================================================
12436
12437 public boolean startInstrumentation(ComponentName className,
12438 String profileFile, int flags, Bundle arguments,
12439 IInstrumentationWatcher watcher) {
12440 // Refuse possible leaked file descriptors
12441 if (arguments != null && arguments.hasFileDescriptors()) {
12442 throw new IllegalArgumentException("File descriptors passed in Bundle");
12443 }
12444
12445 synchronized(this) {
12446 InstrumentationInfo ii = null;
12447 ApplicationInfo ai = null;
12448 try {
12449 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012450 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012451 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012452 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012453 } catch (PackageManager.NameNotFoundException e) {
12454 }
12455 if (ii == null) {
12456 reportStartInstrumentationFailure(watcher, className,
12457 "Unable to find instrumentation info for: " + className);
12458 return false;
12459 }
12460 if (ai == null) {
12461 reportStartInstrumentationFailure(watcher, className,
12462 "Unable to find instrumentation target package: " + ii.targetPackage);
12463 return false;
12464 }
12465
12466 int match = mContext.getPackageManager().checkSignatures(
12467 ii.targetPackage, ii.packageName);
12468 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12469 String msg = "Permission Denial: starting instrumentation "
12470 + className + " from pid="
12471 + Binder.getCallingPid()
12472 + ", uid=" + Binder.getCallingPid()
12473 + " not allowed because package " + ii.packageName
12474 + " does not have a signature matching the target "
12475 + ii.targetPackage;
12476 reportStartInstrumentationFailure(watcher, className, msg);
12477 throw new SecurityException(msg);
12478 }
12479
12480 final long origId = Binder.clearCallingIdentity();
12481 uninstallPackageLocked(ii.targetPackage, -1, true);
12482 ProcessRecord app = addAppLocked(ai);
12483 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012484 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012485 app.instrumentationProfileFile = profileFile;
12486 app.instrumentationArguments = arguments;
12487 app.instrumentationWatcher = watcher;
12488 app.instrumentationResultClass = className;
12489 Binder.restoreCallingIdentity(origId);
12490 }
12491
12492 return true;
12493 }
12494
12495 /**
12496 * Report errors that occur while attempting to start Instrumentation. Always writes the
12497 * error to the logs, but if somebody is watching, send the report there too. This enables
12498 * the "am" command to report errors with more information.
12499 *
12500 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12501 * @param cn The component name of the instrumentation.
12502 * @param report The error report.
12503 */
12504 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12505 ComponentName cn, String report) {
12506 Log.w(TAG, report);
12507 try {
12508 if (watcher != null) {
12509 Bundle results = new Bundle();
12510 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12511 results.putString("Error", report);
12512 watcher.instrumentationStatus(cn, -1, results);
12513 }
12514 } catch (RemoteException e) {
12515 Log.w(TAG, e);
12516 }
12517 }
12518
12519 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12520 if (app.instrumentationWatcher != null) {
12521 try {
12522 // NOTE: IInstrumentationWatcher *must* be oneway here
12523 app.instrumentationWatcher.instrumentationFinished(
12524 app.instrumentationClass,
12525 resultCode,
12526 results);
12527 } catch (RemoteException e) {
12528 }
12529 }
12530 app.instrumentationWatcher = null;
12531 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012532 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012533 app.instrumentationProfileFile = null;
12534 app.instrumentationArguments = null;
12535
12536 uninstallPackageLocked(app.processName, -1, false);
12537 }
12538
12539 public void finishInstrumentation(IApplicationThread target,
12540 int resultCode, Bundle results) {
12541 // Refuse possible leaked file descriptors
12542 if (results != null && results.hasFileDescriptors()) {
12543 throw new IllegalArgumentException("File descriptors passed in Intent");
12544 }
12545
12546 synchronized(this) {
12547 ProcessRecord app = getRecordForAppLocked(target);
12548 if (app == null) {
12549 Log.w(TAG, "finishInstrumentation: no app for " + target);
12550 return;
12551 }
12552 final long origId = Binder.clearCallingIdentity();
12553 finishInstrumentationLocked(app, resultCode, results);
12554 Binder.restoreCallingIdentity(origId);
12555 }
12556 }
12557
12558 // =========================================================
12559 // CONFIGURATION
12560 // =========================================================
12561
12562 public ConfigurationInfo getDeviceConfigurationInfo() {
12563 ConfigurationInfo config = new ConfigurationInfo();
12564 synchronized (this) {
12565 config.reqTouchScreen = mConfiguration.touchscreen;
12566 config.reqKeyboardType = mConfiguration.keyboard;
12567 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012568 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12569 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012570 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12571 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012572 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12573 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012574 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12575 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012576 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012577 }
12578 return config;
12579 }
12580
12581 public Configuration getConfiguration() {
12582 Configuration ci;
12583 synchronized(this) {
12584 ci = new Configuration(mConfiguration);
12585 }
12586 return ci;
12587 }
12588
12589 public void updateConfiguration(Configuration values) {
12590 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12591 "updateConfiguration()");
12592
12593 synchronized(this) {
12594 if (values == null && mWindowManager != null) {
12595 // sentinel: fetch the current configuration from the window manager
12596 values = mWindowManager.computeNewConfiguration();
12597 }
12598
12599 final long origId = Binder.clearCallingIdentity();
12600 updateConfigurationLocked(values, null);
12601 Binder.restoreCallingIdentity(origId);
12602 }
12603 }
12604
12605 /**
12606 * Do either or both things: (1) change the current configuration, and (2)
12607 * make sure the given activity is running with the (now) current
12608 * configuration. Returns true if the activity has been left running, or
12609 * false if <var>starting</var> is being destroyed to match the new
12610 * configuration.
12611 */
12612 public boolean updateConfigurationLocked(Configuration values,
12613 HistoryRecord starting) {
12614 int changes = 0;
12615
12616 boolean kept = true;
12617
12618 if (values != null) {
12619 Configuration newConfig = new Configuration(mConfiguration);
12620 changes = newConfig.updateFrom(values);
12621 if (changes != 0) {
12622 if (DEBUG_SWITCH) {
12623 Log.i(TAG, "Updating configuration to: " + values);
12624 }
12625
12626 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12627
12628 if (values.locale != null) {
12629 saveLocaleLocked(values.locale,
12630 !values.locale.equals(mConfiguration.locale),
12631 values.userSetLocale);
12632 }
12633
12634 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012635 Log.i(TAG, "Config changed: " + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012636
12637 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12638 msg.obj = new Configuration(mConfiguration);
12639 mHandler.sendMessage(msg);
12640
12641 final int N = mLRUProcesses.size();
12642 for (int i=0; i<N; i++) {
12643 ProcessRecord app = mLRUProcesses.get(i);
12644 try {
12645 if (app.thread != null) {
12646 app.thread.scheduleConfigurationChanged(mConfiguration);
12647 }
12648 } catch (Exception e) {
12649 }
12650 }
12651 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12652 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12653 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012654
12655 AttributeCache ac = AttributeCache.instance();
12656 if (ac != null) {
12657 ac.updateConfiguration(mConfiguration);
12658 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012659 }
12660 }
12661
12662 if (changes != 0 && starting == null) {
12663 // If the configuration changed, and the caller is not already
12664 // in the process of starting an activity, then find the top
12665 // activity to check if its configuration needs to change.
12666 starting = topRunningActivityLocked(null);
12667 }
12668
12669 if (starting != null) {
12670 kept = ensureActivityConfigurationLocked(starting, changes);
12671 if (kept) {
12672 // If this didn't result in the starting activity being
12673 // destroyed, then we need to make sure at this point that all
12674 // other activities are made visible.
12675 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12676 + ", ensuring others are correct.");
12677 ensureActivitiesVisibleLocked(starting, changes);
12678 }
12679 }
12680
12681 return kept;
12682 }
12683
12684 private final boolean relaunchActivityLocked(HistoryRecord r,
12685 int changes, boolean andResume) {
12686 List<ResultInfo> results = null;
12687 List<Intent> newIntents = null;
12688 if (andResume) {
12689 results = r.results;
12690 newIntents = r.newIntents;
12691 }
12692 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12693 + " with results=" + results + " newIntents=" + newIntents
12694 + " andResume=" + andResume);
12695 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12696 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12697 r.task.taskId, r.shortComponentName);
12698
12699 r.startFreezingScreenLocked(r.app, 0);
12700
12701 try {
12702 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12703 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12704 changes, !andResume);
12705 // Note: don't need to call pauseIfSleepingLocked() here, because
12706 // the caller will only pass in 'andResume' if this activity is
12707 // currently resumed, which implies we aren't sleeping.
12708 } catch (RemoteException e) {
12709 return false;
12710 }
12711
12712 if (andResume) {
12713 r.results = null;
12714 r.newIntents = null;
12715 }
12716
12717 return true;
12718 }
12719
12720 /**
12721 * Make sure the given activity matches the current configuration. Returns
12722 * false if the activity had to be destroyed. Returns true if the
12723 * configuration is the same, or the activity will remain running as-is
12724 * for whatever reason. Ensures the HistoryRecord is updated with the
12725 * correct configuration and all other bookkeeping is handled.
12726 */
12727 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12728 int globalChanges) {
12729 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12730
12731 // Short circuit: if the two configurations are the exact same
12732 // object (the common case), then there is nothing to do.
12733 Configuration newConfig = mConfiguration;
12734 if (r.configuration == newConfig) {
12735 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12736 return true;
12737 }
12738
12739 // We don't worry about activities that are finishing.
12740 if (r.finishing) {
12741 if (DEBUG_SWITCH) Log.i(TAG,
12742 "Configuration doesn't matter in finishing " + r);
12743 r.stopFreezingScreenLocked(false);
12744 return true;
12745 }
12746
12747 // Okay we now are going to make this activity have the new config.
12748 // But then we need to figure out how it needs to deal with that.
12749 Configuration oldConfig = r.configuration;
12750 r.configuration = newConfig;
12751
12752 // If the activity isn't currently running, just leave the new
12753 // configuration and it will pick that up next time it starts.
12754 if (r.app == null || r.app.thread == null) {
12755 if (DEBUG_SWITCH) Log.i(TAG,
12756 "Configuration doesn't matter not running " + r);
12757 r.stopFreezingScreenLocked(false);
12758 return true;
12759 }
12760
12761 // If the activity isn't persistent, there is a chance we will
12762 // need to restart it.
12763 if (!r.persistent) {
12764
12765 // Figure out what has changed between the two configurations.
12766 int changes = oldConfig.diff(newConfig);
12767 if (DEBUG_SWITCH) {
12768 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12769 + Integer.toHexString(changes) + ", handles=0x"
12770 + Integer.toHexString(r.info.configChanges));
12771 }
12772 if ((changes&(~r.info.configChanges)) != 0) {
12773 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12774 r.configChangeFlags |= changes;
12775 r.startFreezingScreenLocked(r.app, globalChanges);
12776 if (r.app == null || r.app.thread == null) {
12777 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12778 destroyActivityLocked(r, true);
12779 } else if (r.state == ActivityState.PAUSING) {
12780 // A little annoying: we are waiting for this activity to
12781 // finish pausing. Let's not do anything now, but just
12782 // flag that it needs to be restarted when done pausing.
12783 r.configDestroy = true;
12784 return true;
12785 } else if (r.state == ActivityState.RESUMED) {
12786 // Try to optimize this case: the configuration is changing
12787 // and we need to restart the top, resumed activity.
12788 // Instead of doing the normal handshaking, just say
12789 // "restart!".
12790 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12791 relaunchActivityLocked(r, r.configChangeFlags, true);
12792 r.configChangeFlags = 0;
12793 } else {
12794 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12795 relaunchActivityLocked(r, r.configChangeFlags, false);
12796 r.configChangeFlags = 0;
12797 }
12798
12799 // All done... tell the caller we weren't able to keep this
12800 // activity around.
12801 return false;
12802 }
12803 }
12804
12805 // Default case: the activity can handle this new configuration, so
12806 // hand it over. Note that we don't need to give it the new
12807 // configuration, since we always send configuration changes to all
12808 // process when they happen so it can just use whatever configuration
12809 // it last got.
12810 if (r.app != null && r.app.thread != null) {
12811 try {
12812 r.app.thread.scheduleActivityConfigurationChanged(r);
12813 } catch (RemoteException e) {
12814 // If process died, whatever.
12815 }
12816 }
12817 r.stopFreezingScreenLocked(false);
12818
12819 return true;
12820 }
12821
12822 /**
12823 * Save the locale. You must be inside a synchronized (this) block.
12824 */
12825 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12826 if(isDiff) {
12827 SystemProperties.set("user.language", l.getLanguage());
12828 SystemProperties.set("user.region", l.getCountry());
12829 }
12830
12831 if(isPersist) {
12832 SystemProperties.set("persist.sys.language", l.getLanguage());
12833 SystemProperties.set("persist.sys.country", l.getCountry());
12834 SystemProperties.set("persist.sys.localevar", l.getVariant());
12835 }
12836 }
12837
12838 // =========================================================
12839 // LIFETIME MANAGEMENT
12840 // =========================================================
12841
12842 private final int computeOomAdjLocked(
12843 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12844 if (mAdjSeq == app.adjSeq) {
12845 // This adjustment has already been computed.
12846 return app.curAdj;
12847 }
12848
12849 if (app.thread == null) {
12850 app.adjSeq = mAdjSeq;
12851 return (app.curAdj=EMPTY_APP_ADJ);
12852 }
12853
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012854 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
12855 // The max adjustment doesn't allow this app to be anything
12856 // below foreground, so it is not worth doing work for it.
12857 app.adjType = "fixed";
12858 app.adjSeq = mAdjSeq;
12859 app.curRawAdj = app.maxAdj;
12860 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
12861 return (app.curAdj=app.maxAdj);
12862 }
12863
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070012864 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012865 app.adjSource = null;
12866 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012867
The Android Open Source Project4df24232009-03-05 14:34:35 -080012868 // Determine the importance of the process, starting with most
12869 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012870 int adj;
12871 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012872 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012873 // The last app on the list is the foreground app.
12874 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012875 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012876 } else if (app.instrumentationClass != null) {
12877 // Don't want to kill running instrumentation.
12878 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012879 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012880 } else if (app.persistentActivities > 0) {
12881 // Special persistent activities... shouldn't be used these days.
12882 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012883 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012884 } else if (app.curReceiver != null ||
12885 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12886 // An app that is currently receiving a broadcast also
12887 // counts as being in the foreground.
12888 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012889 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012890 } else if (app.executingServices.size() > 0) {
12891 // An app that is currently executing a service callback also
12892 // counts as being in the foreground.
12893 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012894 app.adjType = "exec-service";
12895 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012896 // The user is aware of this app, so make it visible.
12897 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012898 app.adjType = "foreground-service";
12899 } else if (app.forcingToForeground != null) {
12900 // The user is aware of this app, so make it visible.
12901 adj = VISIBLE_APP_ADJ;
12902 app.adjType = "force-foreground";
12903 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012904 } else if (app == mHomeProcess) {
12905 // This process is hosting what we currently consider to be the
12906 // home app, so we don't want to let it go into the background.
12907 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012908 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012909 } else if ((N=app.activities.size()) != 0) {
12910 // This app is in the background with paused activities.
12911 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012912 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012913 for (int j=0; j<N; j++) {
12914 if (((HistoryRecord)app.activities.get(j)).visible) {
12915 // This app has a visible activity!
12916 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012917 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012918 break;
12919 }
12920 }
12921 } else {
12922 // A very not-needed process.
12923 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012924 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012925 }
12926
The Android Open Source Project4df24232009-03-05 14:34:35 -080012927 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012928 // there are applications dependent on our services or providers, but
12929 // this gives us a baseline and makes sure we don't get into an
12930 // infinite recursion.
12931 app.adjSeq = mAdjSeq;
12932 app.curRawAdj = adj;
12933 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12934
Christopher Tate6fa95972009-06-05 18:43:55 -070012935 if (mBackupTarget != null && app == mBackupTarget.app) {
12936 // If possible we want to avoid killing apps while they're being backed up
12937 if (adj > BACKUP_APP_ADJ) {
12938 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12939 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012940 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070012941 }
12942 }
12943
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012944 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012945 final long now = SystemClock.uptimeMillis();
12946 // This process is more important if the top activity is
12947 // bound to the service.
12948 Iterator jt = app.services.iterator();
12949 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12950 ServiceRecord s = (ServiceRecord)jt.next();
12951 if (s.startRequested) {
12952 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12953 // This service has seen some activity within
12954 // recent memory, so we will keep its process ahead
12955 // of the background processes.
12956 if (adj > SECONDARY_SERVER_ADJ) {
12957 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012958 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012959 }
12960 }
12961 }
12962 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12963 Iterator<ConnectionRecord> kt
12964 = s.connections.values().iterator();
12965 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12966 // XXX should compute this based on the max of
12967 // all connected clients.
12968 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012969 if (cr.binding.client == app) {
12970 // Binding to ourself is not interesting.
12971 continue;
12972 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012973 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12974 ProcessRecord client = cr.binding.client;
12975 int myHiddenAdj = hiddenAdj;
12976 if (myHiddenAdj > client.hiddenAdj) {
12977 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12978 myHiddenAdj = client.hiddenAdj;
12979 } else {
12980 myHiddenAdj = VISIBLE_APP_ADJ;
12981 }
12982 }
12983 int clientAdj = computeOomAdjLocked(
12984 client, myHiddenAdj, TOP_APP);
12985 if (adj > clientAdj) {
12986 adj = clientAdj > VISIBLE_APP_ADJ
12987 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012988 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070012989 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
12990 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012991 app.adjSource = cr.binding.client;
12992 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012993 }
12994 }
12995 HistoryRecord a = cr.activity;
12996 //if (a != null) {
12997 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12998 //}
12999 if (a != null && adj > FOREGROUND_APP_ADJ &&
13000 (a.state == ActivityState.RESUMED
13001 || a.state == ActivityState.PAUSING)) {
13002 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013003 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013004 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13005 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013006 app.adjSource = a;
13007 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013008 }
13009 }
13010 }
13011 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013012
13013 // Finally, f this process has active services running in it, we
13014 // would like to avoid killing it unless it would prevent the current
13015 // application from running. By default we put the process in
13016 // with the rest of the background processes; as we scan through
13017 // its services we may bump it up from there.
13018 if (adj > hiddenAdj) {
13019 adj = hiddenAdj;
13020 app.adjType = "bg-services";
13021 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013022 }
13023
13024 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013025 Iterator jt = app.pubProviders.values().iterator();
13026 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13027 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13028 if (cpr.clients.size() != 0) {
13029 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13030 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13031 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013032 if (client == app) {
13033 // Being our own client is not interesting.
13034 continue;
13035 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013036 int myHiddenAdj = hiddenAdj;
13037 if (myHiddenAdj > client.hiddenAdj) {
13038 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13039 myHiddenAdj = client.hiddenAdj;
13040 } else {
13041 myHiddenAdj = FOREGROUND_APP_ADJ;
13042 }
13043 }
13044 int clientAdj = computeOomAdjLocked(
13045 client, myHiddenAdj, TOP_APP);
13046 if (adj > clientAdj) {
13047 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013048 ? clientAdj : FOREGROUND_APP_ADJ;
13049 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013050 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13051 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013052 app.adjSource = client;
13053 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013054 }
13055 }
13056 }
13057 // If the provider has external (non-framework) process
13058 // dependencies, ensure that its adjustment is at least
13059 // FOREGROUND_APP_ADJ.
13060 if (cpr.externals != 0) {
13061 if (adj > FOREGROUND_APP_ADJ) {
13062 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013063 app.adjType = "provider";
13064 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013065 }
13066 }
13067 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013068
13069 // Finally, if this process has published any content providers,
13070 // then its adjustment makes it at least as important as any of the
13071 // processes using those providers, and no less important than
13072 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
13073 if (adj > CONTENT_PROVIDER_ADJ) {
13074 adj = CONTENT_PROVIDER_ADJ;
13075 app.adjType = "pub-providers";
13076 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013077 }
13078
13079 app.curRawAdj = adj;
13080
13081 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13082 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13083 if (adj > app.maxAdj) {
13084 adj = app.maxAdj;
13085 }
13086
13087 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013088 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013089 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
13090 : Process.THREAD_GROUP_DEFAULT;
13091
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013092 return adj;
13093 }
13094
13095 /**
13096 * Ask a given process to GC right now.
13097 */
13098 final void performAppGcLocked(ProcessRecord app) {
13099 try {
13100 app.lastRequestedGc = SystemClock.uptimeMillis();
13101 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013102 if (app.reportLowMemory) {
13103 app.reportLowMemory = false;
13104 app.thread.scheduleLowMemory();
13105 } else {
13106 app.thread.processInBackground();
13107 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013108 }
13109 } catch (Exception e) {
13110 // whatever.
13111 }
13112 }
13113
13114 /**
13115 * Returns true if things are idle enough to perform GCs.
13116 */
13117 private final boolean canGcNow() {
13118 return mParallelBroadcasts.size() == 0
13119 && mOrderedBroadcasts.size() == 0
13120 && (mSleeping || (mResumedActivity != null &&
13121 mResumedActivity.idle));
13122 }
13123
13124 /**
13125 * Perform GCs on all processes that are waiting for it, but only
13126 * if things are idle.
13127 */
13128 final void performAppGcsLocked() {
13129 final int N = mProcessesToGc.size();
13130 if (N <= 0) {
13131 return;
13132 }
13133 if (canGcNow()) {
13134 while (mProcessesToGc.size() > 0) {
13135 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013136 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13137 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13138 <= SystemClock.uptimeMillis()) {
13139 // To avoid spamming the system, we will GC processes one
13140 // at a time, waiting a few seconds between each.
13141 performAppGcLocked(proc);
13142 scheduleAppGcsLocked();
13143 return;
13144 } else {
13145 // It hasn't been long enough since we last GCed this
13146 // process... put it in the list to wait for its time.
13147 addProcessToGcListLocked(proc);
13148 break;
13149 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013150 }
13151 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013152
13153 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013154 }
13155 }
13156
13157 /**
13158 * If all looks good, perform GCs on all processes waiting for them.
13159 */
13160 final void performAppGcsIfAppropriateLocked() {
13161 if (canGcNow()) {
13162 performAppGcsLocked();
13163 return;
13164 }
13165 // Still not idle, wait some more.
13166 scheduleAppGcsLocked();
13167 }
13168
13169 /**
13170 * Schedule the execution of all pending app GCs.
13171 */
13172 final void scheduleAppGcsLocked() {
13173 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013174
13175 if (mProcessesToGc.size() > 0) {
13176 // Schedule a GC for the time to the next process.
13177 ProcessRecord proc = mProcessesToGc.get(0);
13178 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13179
13180 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13181 long now = SystemClock.uptimeMillis();
13182 if (when < (now+GC_TIMEOUT)) {
13183 when = now + GC_TIMEOUT;
13184 }
13185 mHandler.sendMessageAtTime(msg, when);
13186 }
13187 }
13188
13189 /**
13190 * Add a process to the array of processes waiting to be GCed. Keeps the
13191 * list in sorted order by the last GC time. The process can't already be
13192 * on the list.
13193 */
13194 final void addProcessToGcListLocked(ProcessRecord proc) {
13195 boolean added = false;
13196 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13197 if (mProcessesToGc.get(i).lastRequestedGc <
13198 proc.lastRequestedGc) {
13199 added = true;
13200 mProcessesToGc.add(i+1, proc);
13201 break;
13202 }
13203 }
13204 if (!added) {
13205 mProcessesToGc.add(0, proc);
13206 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013207 }
13208
13209 /**
13210 * Set up to ask a process to GC itself. This will either do it
13211 * immediately, or put it on the list of processes to gc the next
13212 * time things are idle.
13213 */
13214 final void scheduleAppGcLocked(ProcessRecord app) {
13215 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013216 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013217 return;
13218 }
13219 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013220 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013221 scheduleAppGcsLocked();
13222 }
13223 }
13224
13225 private final boolean updateOomAdjLocked(
13226 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13227 app.hiddenAdj = hiddenAdj;
13228
13229 if (app.thread == null) {
13230 return true;
13231 }
13232
13233 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
13234
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013235 if (app.pid != 0 && app.pid != MY_PID) {
13236 if (app.curRawAdj != app.setRawAdj) {
13237 if (app.curRawAdj > FOREGROUND_APP_ADJ
13238 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13239 // If this app is transitioning from foreground to
13240 // non-foreground, have it do a gc.
13241 scheduleAppGcLocked(app);
13242 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13243 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13244 // Likewise do a gc when an app is moving in to the
13245 // background (such as a service stopping).
13246 scheduleAppGcLocked(app);
13247 }
13248 app.setRawAdj = app.curRawAdj;
13249 }
13250 if (adj != app.setAdj) {
13251 if (Process.setOomAdj(app.pid, adj)) {
13252 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13253 TAG, "Set app " + app.processName +
13254 " oom adj to " + adj);
13255 app.setAdj = adj;
13256 } else {
13257 return false;
13258 }
13259 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013260 if (app.setSchedGroup != app.curSchedGroup) {
13261 app.setSchedGroup = app.curSchedGroup;
13262 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13263 "Setting process group of " + app.processName
13264 + " to " + app.curSchedGroup);
13265 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013266 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013267 try {
13268 Process.setProcessGroup(app.pid, app.curSchedGroup);
13269 } catch (Exception e) {
13270 Log.w(TAG, "Failed setting process group of " + app.pid
13271 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013272 e.printStackTrace();
13273 } finally {
13274 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013275 }
13276 }
13277 if (false) {
13278 if (app.thread != null) {
13279 try {
13280 app.thread.setSchedulingGroup(app.curSchedGroup);
13281 } catch (RemoteException e) {
13282 }
13283 }
13284 }
13285 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013286 }
13287
13288 return true;
13289 }
13290
13291 private final HistoryRecord resumedAppLocked() {
13292 HistoryRecord resumedActivity = mResumedActivity;
13293 if (resumedActivity == null || resumedActivity.app == null) {
13294 resumedActivity = mPausingActivity;
13295 if (resumedActivity == null || resumedActivity.app == null) {
13296 resumedActivity = topRunningActivityLocked(null);
13297 }
13298 }
13299 return resumedActivity;
13300 }
13301
13302 private final boolean updateOomAdjLocked(ProcessRecord app) {
13303 final HistoryRecord TOP_ACT = resumedAppLocked();
13304 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13305 int curAdj = app.curAdj;
13306 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13307 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13308
13309 mAdjSeq++;
13310
13311 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13312 if (res) {
13313 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13314 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13315 if (nowHidden != wasHidden) {
13316 // Changed to/from hidden state, so apps after it in the LRU
13317 // list may also be changed.
13318 updateOomAdjLocked();
13319 }
13320 }
13321 return res;
13322 }
13323
13324 private final boolean updateOomAdjLocked() {
13325 boolean didOomAdj = true;
13326 final HistoryRecord TOP_ACT = resumedAppLocked();
13327 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13328
13329 if (false) {
13330 RuntimeException e = new RuntimeException();
13331 e.fillInStackTrace();
13332 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13333 }
13334
13335 mAdjSeq++;
13336
13337 // First try updating the OOM adjustment for each of the
13338 // application processes based on their current state.
13339 int i = mLRUProcesses.size();
13340 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13341 while (i > 0) {
13342 i--;
13343 ProcessRecord app = mLRUProcesses.get(i);
13344 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13345 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13346 && app.curAdj == curHiddenAdj) {
13347 curHiddenAdj++;
13348 }
13349 } else {
13350 didOomAdj = false;
13351 }
13352 }
13353
13354 // todo: for now pretend like OOM ADJ didn't work, because things
13355 // aren't behaving as expected on Linux -- it's not killing processes.
13356 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13357 }
13358
13359 private final void trimApplications() {
13360 synchronized (this) {
13361 int i;
13362
13363 // First remove any unused application processes whose package
13364 // has been removed.
13365 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13366 final ProcessRecord app = mRemovedProcesses.get(i);
13367 if (app.activities.size() == 0
13368 && app.curReceiver == null && app.services.size() == 0) {
13369 Log.i(
13370 TAG, "Exiting empty application process "
13371 + app.processName + " ("
13372 + (app.thread != null ? app.thread.asBinder() : null)
13373 + ")\n");
13374 if (app.pid > 0 && app.pid != MY_PID) {
13375 Process.killProcess(app.pid);
13376 } else {
13377 try {
13378 app.thread.scheduleExit();
13379 } catch (Exception e) {
13380 // Ignore exceptions.
13381 }
13382 }
13383 cleanUpApplicationRecordLocked(app, false, -1);
13384 mRemovedProcesses.remove(i);
13385
13386 if (app.persistent) {
13387 if (app.persistent) {
13388 addAppLocked(app.info);
13389 }
13390 }
13391 }
13392 }
13393
13394 // Now try updating the OOM adjustment for each of the
13395 // application processes based on their current state.
13396 // If the setOomAdj() API is not supported, then go with our
13397 // back-up plan...
13398 if (!updateOomAdjLocked()) {
13399
13400 // Count how many processes are running services.
13401 int numServiceProcs = 0;
13402 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13403 final ProcessRecord app = mLRUProcesses.get(i);
13404
13405 if (app.persistent || app.services.size() != 0
13406 || app.curReceiver != null
13407 || app.persistentActivities > 0) {
13408 // Don't count processes holding services against our
13409 // maximum process count.
13410 if (localLOGV) Log.v(
13411 TAG, "Not trimming app " + app + " with services: "
13412 + app.services);
13413 numServiceProcs++;
13414 }
13415 }
13416
13417 int curMaxProcs = mProcessLimit;
13418 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13419 if (mAlwaysFinishActivities) {
13420 curMaxProcs = 1;
13421 }
13422 curMaxProcs += numServiceProcs;
13423
13424 // Quit as many processes as we can to get down to the desired
13425 // process count. First remove any processes that no longer
13426 // have activites running in them.
13427 for ( i=0;
13428 i<mLRUProcesses.size()
13429 && mLRUProcesses.size() > curMaxProcs;
13430 i++) {
13431 final ProcessRecord app = mLRUProcesses.get(i);
13432 // Quit an application only if it is not currently
13433 // running any activities.
13434 if (!app.persistent && app.activities.size() == 0
13435 && app.curReceiver == null && app.services.size() == 0) {
13436 Log.i(
13437 TAG, "Exiting empty application process "
13438 + app.processName + " ("
13439 + (app.thread != null ? app.thread.asBinder() : null)
13440 + ")\n");
13441 if (app.pid > 0 && app.pid != MY_PID) {
13442 Process.killProcess(app.pid);
13443 } else {
13444 try {
13445 app.thread.scheduleExit();
13446 } catch (Exception e) {
13447 // Ignore exceptions.
13448 }
13449 }
13450 // todo: For now we assume the application is not buggy
13451 // or evil, and will quit as a result of our request.
13452 // Eventually we need to drive this off of the death
13453 // notification, and kill the process if it takes too long.
13454 cleanUpApplicationRecordLocked(app, false, i);
13455 i--;
13456 }
13457 }
13458
13459 // If we still have too many processes, now from the least
13460 // recently used process we start finishing activities.
13461 if (Config.LOGV) Log.v(
13462 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13463 " of " + curMaxProcs + " processes");
13464 for ( i=0;
13465 i<mLRUProcesses.size()
13466 && mLRUProcesses.size() > curMaxProcs;
13467 i++) {
13468 final ProcessRecord app = mLRUProcesses.get(i);
13469 // Quit the application only if we have a state saved for
13470 // all of its activities.
13471 boolean canQuit = !app.persistent && app.curReceiver == null
13472 && app.services.size() == 0
13473 && app.persistentActivities == 0;
13474 int NUMA = app.activities.size();
13475 int j;
13476 if (Config.LOGV) Log.v(
13477 TAG, "Looking to quit " + app.processName);
13478 for (j=0; j<NUMA && canQuit; j++) {
13479 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13480 if (Config.LOGV) Log.v(
13481 TAG, " " + r.intent.getComponent().flattenToShortString()
13482 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13483 canQuit = (r.haveState || !r.stateNotNeeded)
13484 && !r.visible && r.stopped;
13485 }
13486 if (canQuit) {
13487 // Finish all of the activities, and then the app itself.
13488 for (j=0; j<NUMA; j++) {
13489 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13490 if (!r.finishing) {
13491 destroyActivityLocked(r, false);
13492 }
13493 r.resultTo = null;
13494 }
13495 Log.i(TAG, "Exiting application process "
13496 + app.processName + " ("
13497 + (app.thread != null ? app.thread.asBinder() : null)
13498 + ")\n");
13499 if (app.pid > 0 && app.pid != MY_PID) {
13500 Process.killProcess(app.pid);
13501 } else {
13502 try {
13503 app.thread.scheduleExit();
13504 } catch (Exception e) {
13505 // Ignore exceptions.
13506 }
13507 }
13508 // todo: For now we assume the application is not buggy
13509 // or evil, and will quit as a result of our request.
13510 // Eventually we need to drive this off of the death
13511 // notification, and kill the process if it takes too long.
13512 cleanUpApplicationRecordLocked(app, false, i);
13513 i--;
13514 //dump();
13515 }
13516 }
13517
13518 }
13519
13520 int curMaxActivities = MAX_ACTIVITIES;
13521 if (mAlwaysFinishActivities) {
13522 curMaxActivities = 1;
13523 }
13524
13525 // Finally, if there are too many activities now running, try to
13526 // finish as many as we can to get back down to the limit.
13527 for ( i=0;
13528 i<mLRUActivities.size()
13529 && mLRUActivities.size() > curMaxActivities;
13530 i++) {
13531 final HistoryRecord r
13532 = (HistoryRecord)mLRUActivities.get(i);
13533
13534 // We can finish this one if we have its icicle saved and
13535 // it is not persistent.
13536 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13537 && r.stopped && !r.persistent && !r.finishing) {
13538 final int origSize = mLRUActivities.size();
13539 destroyActivityLocked(r, true);
13540
13541 // This will remove it from the LRU list, so keep
13542 // our index at the same value. Note that this check to
13543 // see if the size changes is just paranoia -- if
13544 // something unexpected happens, we don't want to end up
13545 // in an infinite loop.
13546 if (origSize > mLRUActivities.size()) {
13547 i--;
13548 }
13549 }
13550 }
13551 }
13552 }
13553
13554 /** This method sends the specified signal to each of the persistent apps */
13555 public void signalPersistentProcesses(int sig) throws RemoteException {
13556 if (sig != Process.SIGNAL_USR1) {
13557 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13558 }
13559
13560 synchronized (this) {
13561 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13562 != PackageManager.PERMISSION_GRANTED) {
13563 throw new SecurityException("Requires permission "
13564 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13565 }
13566
13567 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13568 ProcessRecord r = mLRUProcesses.get(i);
13569 if (r.thread != null && r.persistent) {
13570 Process.sendSignal(r.pid, sig);
13571 }
13572 }
13573 }
13574 }
13575
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013576 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013577 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013578
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013579 try {
13580 synchronized (this) {
13581 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13582 // its own permission.
13583 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13584 != PackageManager.PERMISSION_GRANTED) {
13585 throw new SecurityException("Requires permission "
13586 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013587 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013588
13589 if (start && fd == null) {
13590 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013591 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013592
13593 ProcessRecord proc = null;
13594 try {
13595 int pid = Integer.parseInt(process);
13596 synchronized (mPidsSelfLocked) {
13597 proc = mPidsSelfLocked.get(pid);
13598 }
13599 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013600 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013601
13602 if (proc == null) {
13603 HashMap<String, SparseArray<ProcessRecord>> all
13604 = mProcessNames.getMap();
13605 SparseArray<ProcessRecord> procs = all.get(process);
13606 if (procs != null && procs.size() > 0) {
13607 proc = procs.valueAt(0);
13608 }
13609 }
13610
13611 if (proc == null || proc.thread == null) {
13612 throw new IllegalArgumentException("Unknown process: " + process);
13613 }
13614
13615 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13616 if (isSecure) {
13617 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13618 throw new SecurityException("Process not debuggable: " + proc);
13619 }
13620 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013621
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013622 proc.thread.profilerControl(start, path, fd);
13623 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013624 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013625 }
13626 } catch (RemoteException e) {
13627 throw new IllegalStateException("Process disappeared");
13628 } finally {
13629 if (fd != null) {
13630 try {
13631 fd.close();
13632 } catch (IOException e) {
13633 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013634 }
13635 }
13636 }
13637
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013638 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13639 public void monitor() {
13640 synchronized (this) { }
13641 }
13642}