blob: badfa306d9aa4b5f32b5362c6a42b449576ab2d7 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
19import com.android.internal.os.BatteryStatsImpl;
Dianne Hackbornde7faf62009-06-30 13:27:30 -070020import com.android.server.AttributeCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import com.android.server.IntentResolver;
22import com.android.server.ProcessMap;
23import com.android.server.ProcessStats;
24import com.android.server.SystemServer;
25import com.android.server.Watchdog;
26import com.android.server.WindowManagerService;
27
28import android.app.Activity;
29import android.app.ActivityManager;
30import android.app.ActivityManagerNative;
31import android.app.ActivityThread;
32import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020033import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.app.Dialog;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070035import android.app.IActivityController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.app.IActivityWatcher;
37import android.app.IApplicationThread;
38import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.app.IServiceConnection;
40import android.app.IThumbnailReceiver;
41import android.app.Instrumentation;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070042import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.app.PendingIntent;
44import android.app.ResultInfo;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070045import android.app.Service;
Christopher Tate181fafa2009-05-14 11:12:14 -070046import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020047import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.ComponentName;
49import android.content.ContentResolver;
50import android.content.Context;
51import android.content.Intent;
52import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070053import android.content.IIntentReceiver;
54import android.content.IIntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.content.pm.ActivityInfo;
56import android.content.pm.ApplicationInfo;
57import android.content.pm.ConfigurationInfo;
58import android.content.pm.IPackageDataObserver;
59import android.content.pm.IPackageManager;
60import android.content.pm.InstrumentationInfo;
61import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070062import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.content.pm.ProviderInfo;
64import android.content.pm.ResolveInfo;
65import android.content.pm.ServiceInfo;
66import android.content.res.Configuration;
67import android.graphics.Bitmap;
68import android.net.Uri;
69import android.os.Binder;
70import android.os.Bundle;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070071import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.os.Environment;
73import android.os.FileUtils;
74import android.os.Handler;
75import android.os.IBinder;
76import android.os.IPermissionController;
77import android.os.Looper;
78import android.os.Message;
79import android.os.Parcel;
80import android.os.ParcelFileDescriptor;
81import android.os.PowerManager;
82import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070083import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084import android.os.RemoteException;
85import android.os.ServiceManager;
86import android.os.SystemClock;
87import android.os.SystemProperties;
88import android.provider.Checkin;
89import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020090import android.server.data.CrashData;
91import android.server.data.StackTraceElementData;
92import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093import android.text.TextUtils;
94import android.util.Config;
95import android.util.EventLog;
96import android.util.Log;
97import android.util.PrintWriterPrinter;
98import android.util.SparseArray;
99import android.view.Gravity;
100import android.view.LayoutInflater;
101import android.view.View;
102import android.view.WindowManager;
103import android.view.WindowManagerPolicy;
104
105import dalvik.system.Zygote;
106
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200107import java.io.ByteArrayInputStream;
108import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109import java.io.File;
110import java.io.FileDescriptor;
111import java.io.FileInputStream;
112import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200113import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114import java.io.PrintWriter;
115import java.lang.IllegalStateException;
116import java.lang.ref.WeakReference;
117import java.util.ArrayList;
118import java.util.HashMap;
119import java.util.HashSet;
120import java.util.Iterator;
121import java.util.List;
122import java.util.Locale;
123import java.util.Map;
124
125public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
126 static final String TAG = "ActivityManager";
127 static final boolean DEBUG = false;
128 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
129 static final boolean DEBUG_SWITCH = localLOGV || false;
130 static final boolean DEBUG_TASKS = localLOGV || false;
131 static final boolean DEBUG_PAUSE = localLOGV || false;
132 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
133 static final boolean DEBUG_TRANSITION = localLOGV || false;
134 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700135 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 static final boolean DEBUG_SERVICE = localLOGV || false;
137 static final boolean DEBUG_VISBILITY = localLOGV || false;
138 static final boolean DEBUG_PROCESSES = localLOGV || false;
Dianne Hackborna1e989b2009-09-01 19:54:29 -0700139 static final boolean DEBUG_PROVIDER = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700141 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700142 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 static final boolean VALIDATE_TOKENS = false;
144 static final boolean SHOW_ACTIVITY_START_TIME = true;
145
146 // Control over CPU and battery monitoring.
147 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
148 static final boolean MONITOR_CPU_USAGE = true;
149 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
150 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
151 static final boolean MONITOR_THREAD_CPU_USAGE = false;
152
153 // Event log tags
154 static final int LOG_CONFIGURATION_CHANGED = 2719;
155 static final int LOG_CPU = 2721;
156 static final int LOG_AM_FINISH_ACTIVITY = 30001;
157 static final int LOG_TASK_TO_FRONT = 30002;
158 static final int LOG_AM_NEW_INTENT = 30003;
159 static final int LOG_AM_CREATE_TASK = 30004;
160 static final int LOG_AM_CREATE_ACTIVITY = 30005;
161 static final int LOG_AM_RESTART_ACTIVITY = 30006;
162 static final int LOG_AM_RESUME_ACTIVITY = 30007;
163 static final int LOG_ANR = 30008;
164 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
165 static final int LOG_AM_PROCESS_BOUND = 30010;
166 static final int LOG_AM_PROCESS_DIED = 30011;
167 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
168 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
169 static final int LOG_AM_PROCESS_START = 30014;
170 static final int LOG_AM_PROCESS_BAD = 30015;
171 static final int LOG_AM_PROCESS_GOOD = 30016;
172 static final int LOG_AM_LOW_MEMORY = 30017;
173 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
174 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
175 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
176 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
177 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
178 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
179 static final int LOG_AM_CREATE_SERVICE = 30030;
180 static final int LOG_AM_DESTROY_SERVICE = 30031;
181 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
182 static final int LOG_AM_DROP_PROCESS = 30033;
183 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
184 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
185 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
186
187 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
188 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
189
Dianne Hackborn1655be42009-05-08 14:29:01 -0700190 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700191 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 private static final String SYSTEM_SECURE = "ro.secure";
194
195 // This is the maximum number of application processes we would like
196 // to have running. Due to the asynchronous nature of things, we can
197 // temporarily go beyond this limit.
198 static final int MAX_PROCESSES = 2;
199
200 // Set to false to leave processes running indefinitely, relying on
201 // the kernel killing them as resources are required.
202 static final boolean ENFORCE_PROCESS_LIMIT = false;
203
204 // This is the maximum number of activities that we would like to have
205 // running at a given time.
206 static final int MAX_ACTIVITIES = 20;
207
208 // Maximum number of recent tasks that we can remember.
209 static final int MAX_RECENT_TASKS = 20;
210
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700211 // Amount of time after a call to stopAppSwitches() during which we will
212 // prevent further untrusted switches from happening.
213 static final long APP_SWITCH_DELAY_TIME = 5*1000;
214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 // How long until we reset a task when the user returns to it. Currently
216 // 30 minutes.
217 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
218
219 // Set to true to disable the icon that is shown while a new activity
220 // is being started.
221 static final boolean SHOW_APP_STARTING_ICON = true;
222
223 // How long we wait until giving up on the last activity to pause. This
224 // is short because it directly impacts the responsiveness of starting the
225 // next activity.
226 static final int PAUSE_TIMEOUT = 500;
227
228 /**
229 * How long we can hold the launch wake lock before giving up.
230 */
231 static final int LAUNCH_TIMEOUT = 10*1000;
232
233 // How long we wait for a launched process to attach to the activity manager
234 // before we decide it's never going to come up for real.
235 static final int PROC_START_TIMEOUT = 10*1000;
236
237 // How long we wait until giving up on the last activity telling us it
238 // is idle.
239 static final int IDLE_TIMEOUT = 10*1000;
240
241 // How long to wait after going idle before forcing apps to GC.
242 static final int GC_TIMEOUT = 5*1000;
243
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700244 // The minimum amount of time between successive GC requests for a process.
245 static final int GC_MIN_INTERVAL = 60*1000;
246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 // How long we wait until giving up on an activity telling us it has
248 // finished destroying itself.
249 static final int DESTROY_TIMEOUT = 10*1000;
250
251 // How long we allow a receiver to run before giving up on it.
252 static final int BROADCAST_TIMEOUT = 10*1000;
253
254 // How long we wait for a service to finish executing.
255 static final int SERVICE_TIMEOUT = 20*1000;
256
257 // How long a service needs to be running until restarting its process
258 // is no longer considered to be a relaunch of the service.
259 static final int SERVICE_RESTART_DURATION = 5*1000;
260
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700261 // How long a service needs to be running until it will start back at
262 // SERVICE_RESTART_DURATION after being killed.
263 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
264
265 // Multiplying factor to increase restart duration time by, for each time
266 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
267 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
268
269 // The minimum amount of time between restarting services that we allow.
270 // That is, when multiple services are restarting, we won't allow each
271 // to restart less than this amount of time from the last one.
272 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
273
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274 // Maximum amount of time for there to be no activity on a service before
275 // we consider it non-essential and allow its process to go on the
276 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700277 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278
279 // How long we wait until we timeout on key dispatching.
280 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
281
282 // The minimum time we allow between crashes, for us to consider this
283 // application to be bad and stop and its services and reject broadcasts.
284 static final int MIN_CRASH_INTERVAL = 60*1000;
285
286 // How long we wait until we timeout on key dispatching during instrumentation.
287 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
288
289 // OOM adjustments for processes in various states:
290
291 // This is a process without anything currently running in it. Definitely
292 // the first to go! Value set in system/rootdir/init.rc on startup.
293 // This value is initalized in the constructor, careful when refering to
294 // this static variable externally.
295 static int EMPTY_APP_ADJ;
296
297 // This is a process with a content provider that does not have any clients
298 // attached to it. If it did have any clients, its adjustment would be the
299 // one for the highest-priority of those processes.
300 static int CONTENT_PROVIDER_ADJ;
301
302 // This is a process only hosting activities that are not visible,
303 // so it can be killed without any disruption. Value set in
304 // system/rootdir/init.rc on startup.
305 final int HIDDEN_APP_MAX_ADJ;
306 static int HIDDEN_APP_MIN_ADJ;
307
The Android Open Source Project4df24232009-03-05 14:34:35 -0800308 // This is a process holding the home application -- we want to try
309 // avoiding killing it, even if it would normally be in the background,
310 // because the user interacts with it so much.
311 final int HOME_APP_ADJ;
312
Christopher Tate6fa95972009-06-05 18:43:55 -0700313 // This is a process currently hosting a backup operation. Killing it
314 // is not entirely fatal but is generally a bad idea.
315 final int BACKUP_APP_ADJ;
316
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317 // This is a process holding a secondary server -- killing it will not
318 // have much of an impact as far as the user is concerned. Value set in
319 // system/rootdir/init.rc on startup.
320 final int SECONDARY_SERVER_ADJ;
321
322 // This is a process only hosting activities that are visible to the
323 // user, so we'd prefer they don't disappear. Value set in
324 // system/rootdir/init.rc on startup.
325 final int VISIBLE_APP_ADJ;
326
327 // This is the process running the current foreground app. We'd really
328 // rather not kill it! Value set in system/rootdir/init.rc on startup.
329 final int FOREGROUND_APP_ADJ;
330
331 // This is a process running a core server, such as telephony. Definitely
332 // don't want to kill it, but doing so is not completely fatal.
333 static final int CORE_SERVER_ADJ = -12;
334
335 // The system process runs at the default adjustment.
336 static final int SYSTEM_ADJ = -16;
337
338 // Memory pages are 4K.
339 static final int PAGE_SIZE = 4*1024;
340
Jacek Surazski82a73df2009-06-17 14:33:18 +0200341 // System property defining error report receiver for system apps
342 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
343
344 // System property defining default error report receiver
345 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
346
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800347 // Corresponding memory levels for above adjustments.
348 final int EMPTY_APP_MEM;
349 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800350 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700351 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352 final int SECONDARY_SERVER_MEM;
353 final int VISIBLE_APP_MEM;
354 final int FOREGROUND_APP_MEM;
355
356 final int MY_PID;
357
358 static final String[] EMPTY_STRING_ARRAY = new String[0];
359
360 enum ActivityState {
361 INITIALIZING,
362 RESUMED,
363 PAUSING,
364 PAUSED,
365 STOPPING,
366 STOPPED,
367 FINISHING,
368 DESTROYING,
369 DESTROYED
370 }
371
372 /**
373 * The back history of all previous (and possibly still
374 * running) activities. It contains HistoryRecord objects.
375 */
376 final ArrayList mHistory = new ArrayList();
377
378 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700379 * Description of a request to start a new activity, which has been held
380 * due to app switches being disabled.
381 */
382 class PendingActivityLaunch {
383 HistoryRecord r;
384 HistoryRecord sourceRecord;
385 Uri[] grantedUriPermissions;
386 int grantedMode;
387 boolean onlyIfNeeded;
388 }
389
390 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
391 = new ArrayList<PendingActivityLaunch>();
392
393 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 * List of all active broadcasts that are to be executed immediately
395 * (without waiting for another broadcast to finish). Currently this only
396 * contains broadcasts to registered receivers, to avoid spinning up
397 * a bunch of processes to execute IntentReceiver components.
398 */
399 final ArrayList<BroadcastRecord> mParallelBroadcasts
400 = new ArrayList<BroadcastRecord>();
401
402 /**
403 * List of all active broadcasts that are to be executed one at a time.
404 * The object at the top of the list is the currently activity broadcasts;
405 * those after it are waiting for the top to finish..
406 */
407 final ArrayList<BroadcastRecord> mOrderedBroadcasts
408 = new ArrayList<BroadcastRecord>();
409
410 /**
411 * Set when we current have a BROADCAST_INTENT_MSG in flight.
412 */
413 boolean mBroadcastsScheduled = false;
414
415 /**
416 * Set to indicate whether to issue an onUserLeaving callback when a
417 * newly launched activity is being brought in front of us.
418 */
419 boolean mUserLeaving = false;
420
421 /**
422 * When we are in the process of pausing an activity, before starting the
423 * next one, this variable holds the activity that is currently being paused.
424 */
425 HistoryRecord mPausingActivity = null;
426
427 /**
428 * Current activity that is resumed, or null if there is none.
429 */
430 HistoryRecord mResumedActivity = null;
431
432 /**
433 * Activity we have told the window manager to have key focus.
434 */
435 HistoryRecord mFocusedActivity = null;
436
437 /**
438 * This is the last activity that we put into the paused state. This is
439 * used to determine if we need to do an activity transition while sleeping,
440 * when we normally hold the top activity paused.
441 */
442 HistoryRecord mLastPausedActivity = null;
443
444 /**
445 * List of activities that are waiting for a new activity
446 * to become visible before completing whatever operation they are
447 * supposed to do.
448 */
449 final ArrayList mWaitingVisibleActivities = new ArrayList();
450
451 /**
452 * List of activities that are ready to be stopped, but waiting
453 * for the next activity to settle down before doing so. It contains
454 * HistoryRecord objects.
455 */
456 final ArrayList<HistoryRecord> mStoppingActivities
457 = new ArrayList<HistoryRecord>();
458
459 /**
460 * List of intents that were used to start the most recent tasks.
461 */
462 final ArrayList<TaskRecord> mRecentTasks
463 = new ArrayList<TaskRecord>();
464
465 /**
466 * List of activities that are ready to be finished, but waiting
467 * for the previous activity to settle down before doing so. It contains
468 * HistoryRecord objects.
469 */
470 final ArrayList mFinishingActivities = new ArrayList();
471
472 /**
473 * All of the applications we currently have running organized by name.
474 * The keys are strings of the application package name (as
475 * returned by the package manager), and the keys are ApplicationRecord
476 * objects.
477 */
478 final ProcessMap<ProcessRecord> mProcessNames
479 = new ProcessMap<ProcessRecord>();
480
481 /**
482 * The last time that various processes have crashed.
483 */
484 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
485
486 /**
487 * Set of applications that we consider to be bad, and will reject
488 * incoming broadcasts from (which the user has no control over).
489 * Processes are added to this set when they have crashed twice within
490 * a minimum amount of time; they are removed from it when they are
491 * later restarted (hopefully due to some user action). The value is the
492 * time it was added to the list.
493 */
494 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
495
496 /**
497 * All of the processes we currently have running organized by pid.
498 * The keys are the pid running the application.
499 *
500 * <p>NOTE: This object is protected by its own lock, NOT the global
501 * activity manager lock!
502 */
503 final SparseArray<ProcessRecord> mPidsSelfLocked
504 = new SparseArray<ProcessRecord>();
505
506 /**
507 * All of the processes that have been forced to be foreground. The key
508 * is the pid of the caller who requested it (we hold a death
509 * link on it).
510 */
511 abstract class ForegroundToken implements IBinder.DeathRecipient {
512 int pid;
513 IBinder token;
514 }
515 final SparseArray<ForegroundToken> mForegroundProcesses
516 = new SparseArray<ForegroundToken>();
517
518 /**
519 * List of records for processes that someone had tried to start before the
520 * system was ready. We don't start them at that point, but ensure they
521 * are started by the time booting is complete.
522 */
523 final ArrayList<ProcessRecord> mProcessesOnHold
524 = new ArrayList<ProcessRecord>();
525
526 /**
527 * List of records for processes that we have started and are waiting
528 * for them to call back. This is really only needed when running in
529 * single processes mode, in which case we do not have a unique pid for
530 * each process.
531 */
532 final ArrayList<ProcessRecord> mStartingProcesses
533 = new ArrayList<ProcessRecord>();
534
535 /**
536 * List of persistent applications that are in the process
537 * of being started.
538 */
539 final ArrayList<ProcessRecord> mPersistentStartingProcesses
540 = new ArrayList<ProcessRecord>();
541
542 /**
543 * Processes that are being forcibly torn down.
544 */
545 final ArrayList<ProcessRecord> mRemovedProcesses
546 = new ArrayList<ProcessRecord>();
547
548 /**
549 * List of running applications, sorted by recent usage.
550 * The first entry in the list is the least recently used.
551 * It contains ApplicationRecord objects. This list does NOT include
552 * any persistent application records (since we never want to exit them).
553 */
554 final ArrayList<ProcessRecord> mLRUProcesses
555 = new ArrayList<ProcessRecord>();
556
557 /**
558 * List of processes that should gc as soon as things are idle.
559 */
560 final ArrayList<ProcessRecord> mProcessesToGc
561 = new ArrayList<ProcessRecord>();
562
563 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800564 * This is the process holding what we currently consider to be
565 * the "home" activity.
566 */
567 private ProcessRecord mHomeProcess;
568
569 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800570 * List of running activities, sorted by recent usage.
571 * The first entry in the list is the least recently used.
572 * It contains HistoryRecord objects.
573 */
574 private final ArrayList mLRUActivities = new ArrayList();
575
576 /**
577 * Set of PendingResultRecord objects that are currently active.
578 */
579 final HashSet mPendingResultRecords = new HashSet();
580
581 /**
582 * Set of IntentSenderRecord objects that are currently active.
583 */
584 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
585 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
586
587 /**
588 * Intent broadcast that we have tried to start, but are
589 * waiting for its application's process to be created. We only
590 * need one (instead of a list) because we always process broadcasts
591 * one at a time, so no others can be started while waiting for this
592 * one.
593 */
594 BroadcastRecord mPendingBroadcast = null;
595
596 /**
597 * Keeps track of all IIntentReceivers that have been registered for
598 * broadcasts. Hash keys are the receiver IBinder, hash value is
599 * a ReceiverList.
600 */
601 final HashMap mRegisteredReceivers = new HashMap();
602
603 /**
604 * Resolver for broadcast intents to registered receivers.
605 * Holds BroadcastFilter (subclass of IntentFilter).
606 */
607 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
608 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
609 @Override
610 protected boolean allowFilterResult(
611 BroadcastFilter filter, List<BroadcastFilter> dest) {
612 IBinder target = filter.receiverList.receiver.asBinder();
613 for (int i=dest.size()-1; i>=0; i--) {
614 if (dest.get(i).receiverList.receiver.asBinder() == target) {
615 return false;
616 }
617 }
618 return true;
619 }
620 };
621
622 /**
623 * State of all active sticky broadcasts. Keys are the action of the
624 * sticky Intent, values are an ArrayList of all broadcasted intents with
625 * that action (which should usually be one).
626 */
627 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
628 new HashMap<String, ArrayList<Intent>>();
629
630 /**
631 * All currently running services.
632 */
633 final HashMap<ComponentName, ServiceRecord> mServices =
634 new HashMap<ComponentName, ServiceRecord>();
635
636 /**
637 * All currently running services indexed by the Intent used to start them.
638 */
639 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
640 new HashMap<Intent.FilterComparison, ServiceRecord>();
641
642 /**
643 * All currently bound service connections. Keys are the IBinder of
644 * the client's IServiceConnection.
645 */
646 final HashMap<IBinder, ConnectionRecord> mServiceConnections
647 = new HashMap<IBinder, ConnectionRecord>();
648
649 /**
650 * List of services that we have been asked to start,
651 * but haven't yet been able to. It is used to hold start requests
652 * while waiting for their corresponding application thread to get
653 * going.
654 */
655 final ArrayList<ServiceRecord> mPendingServices
656 = new ArrayList<ServiceRecord>();
657
658 /**
659 * List of services that are scheduled to restart following a crash.
660 */
661 final ArrayList<ServiceRecord> mRestartingServices
662 = new ArrayList<ServiceRecord>();
663
664 /**
665 * List of services that are in the process of being stopped.
666 */
667 final ArrayList<ServiceRecord> mStoppingServices
668 = new ArrayList<ServiceRecord>();
669
670 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700671 * Backup/restore process management
672 */
673 String mBackupAppName = null;
674 BackupRecord mBackupTarget = null;
675
676 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 * List of PendingThumbnailsRecord objects of clients who are still
678 * waiting to receive all of the thumbnails for a task.
679 */
680 final ArrayList mPendingThumbnails = new ArrayList();
681
682 /**
683 * List of HistoryRecord objects that have been finished and must
684 * still report back to a pending thumbnail receiver.
685 */
686 final ArrayList mCancelledThumbnails = new ArrayList();
687
688 /**
689 * All of the currently running global content providers. Keys are a
690 * string containing the provider name and values are a
691 * ContentProviderRecord object containing the data about it. Note
692 * that a single provider may be published under multiple names, so
693 * there may be multiple entries here for a single one in mProvidersByClass.
694 */
695 final HashMap mProvidersByName = new HashMap();
696
697 /**
698 * All of the currently running global content providers. Keys are a
699 * string containing the provider's implementation class and values are a
700 * ContentProviderRecord object containing the data about it.
701 */
702 final HashMap mProvidersByClass = new HashMap();
703
704 /**
705 * List of content providers who have clients waiting for them. The
706 * application is currently being launched and the provider will be
707 * removed from this list once it is published.
708 */
709 final ArrayList mLaunchingProviders = new ArrayList();
710
711 /**
712 * Global set of specific Uri permissions that have been granted.
713 */
714 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
715 = new SparseArray<HashMap<Uri, UriPermission>>();
716
717 /**
718 * Thread-local storage used to carry caller permissions over through
719 * indirect content-provider access.
720 * @see #ActivityManagerService.openContentUri()
721 */
722 private class Identity {
723 public int pid;
724 public int uid;
725
726 Identity(int _pid, int _uid) {
727 pid = _pid;
728 uid = _uid;
729 }
730 }
731 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
732
733 /**
734 * All information we have collected about the runtime performance of
735 * any user id that can impact battery performance.
736 */
737 final BatteryStatsService mBatteryStatsService;
738
739 /**
740 * information about component usage
741 */
742 final UsageStatsService mUsageStatsService;
743
744 /**
745 * Current configuration information. HistoryRecord objects are given
746 * a reference to this object to indicate which configuration they are
747 * currently running in, so this object must be kept immutable.
748 */
749 Configuration mConfiguration = new Configuration();
750
751 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700752 * Hardware-reported OpenGLES version.
753 */
754 final int GL_ES_VERSION;
755
756 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757 * List of initialization arguments to pass to all processes when binding applications to them.
758 * For example, references to the commonly used services.
759 */
760 HashMap<String, IBinder> mAppBindArgs;
761
762 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700763 * Temporary to avoid allocations. Protected by main lock.
764 */
765 final StringBuilder mStringBuilder = new StringBuilder(256);
766
767 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 * Used to control how we initialize the service.
769 */
770 boolean mStartRunning = false;
771 ComponentName mTopComponent;
772 String mTopAction;
773 String mTopData;
774 boolean mSystemReady = false;
775 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700776 boolean mWaitingUpdate = false;
777 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800778
779 Context mContext;
780
781 int mFactoryTest;
782
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700783 boolean mCheckedForSetup;
784
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700786 * The time at which we will allow normal application switches again,
787 * after a call to {@link #stopAppSwitches()}.
788 */
789 long mAppSwitchesAllowedTime;
790
791 /**
792 * This is set to true after the first switch after mAppSwitchesAllowedTime
793 * is set; any switches after that will clear the time.
794 */
795 boolean mDidAppSwitch;
796
797 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 * Set while we are wanting to sleep, to prevent any
799 * activities from being started/resumed.
800 */
801 boolean mSleeping = false;
802
803 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700804 * Set if we are shutting down the system, similar to sleeping.
805 */
806 boolean mShuttingDown = false;
807
808 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 * Set when the system is going to sleep, until we have
810 * successfully paused the current activity and released our wake lock.
811 * At that point the system is allowed to actually sleep.
812 */
813 PowerManager.WakeLock mGoingToSleep;
814
815 /**
816 * We don't want to allow the device to go to sleep while in the process
817 * of launching an activity. This is primarily to allow alarm intent
818 * receivers to launch an activity and get that to run before the device
819 * goes back to sleep.
820 */
821 PowerManager.WakeLock mLaunchingActivity;
822
823 /**
824 * Task identifier that activities are currently being started
825 * in. Incremented each time a new task is created.
826 * todo: Replace this with a TokenSpace class that generates non-repeating
827 * integers that won't wrap.
828 */
829 int mCurTask = 1;
830
831 /**
832 * Current sequence id for oom_adj computation traversal.
833 */
834 int mAdjSeq = 0;
835
836 /**
837 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
838 * is set, indicating the user wants processes started in such a way
839 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
840 * running in each process (thus no pre-initialized process, etc).
841 */
842 boolean mSimpleProcessManagement = false;
843
844 /**
845 * System monitoring: number of processes that died since the last
846 * N procs were started.
847 */
848 int[] mProcDeaths = new int[20];
849
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700850 /**
851 * This is set if we had to do a delayed dexopt of an app before launching
852 * it, to increasing the ANR timeouts in that case.
853 */
854 boolean mDidDexOpt;
855
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800856 String mDebugApp = null;
857 boolean mWaitForDebugger = false;
858 boolean mDebugTransient = false;
859 String mOrigDebugApp = null;
860 boolean mOrigWaitForDebugger = false;
861 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700862 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800863
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700864 final RemoteCallbackList<IActivityWatcher> mWatchers
865 = new RemoteCallbackList<IActivityWatcher>();
866
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800867 /**
868 * Callback of last caller to {@link #requestPss}.
869 */
870 Runnable mRequestPssCallback;
871
872 /**
873 * Remaining processes for which we are waiting results from the last
874 * call to {@link #requestPss}.
875 */
876 final ArrayList<ProcessRecord> mRequestPssList
877 = new ArrayList<ProcessRecord>();
878
879 /**
880 * Runtime statistics collection thread. This object's lock is used to
881 * protect all related state.
882 */
883 final Thread mProcessStatsThread;
884
885 /**
886 * Used to collect process stats when showing not responding dialog.
887 * Protected by mProcessStatsThread.
888 */
889 final ProcessStats mProcessStats = new ProcessStats(
890 MONITOR_THREAD_CPU_USAGE);
891 long mLastCpuTime = 0;
892 long mLastWriteTime = 0;
893
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700894 long mInitialStartTime = 0;
895
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800896 /**
897 * Set to true after the system has finished booting.
898 */
899 boolean mBooted = false;
900
901 int mProcessLimit = 0;
902
903 WindowManagerService mWindowManager;
904
905 static ActivityManagerService mSelf;
906 static ActivityThread mSystemThread;
907
908 private final class AppDeathRecipient implements IBinder.DeathRecipient {
909 final ProcessRecord mApp;
910 final int mPid;
911 final IApplicationThread mAppThread;
912
913 AppDeathRecipient(ProcessRecord app, int pid,
914 IApplicationThread thread) {
915 if (localLOGV) Log.v(
916 TAG, "New death recipient " + this
917 + " for thread " + thread.asBinder());
918 mApp = app;
919 mPid = pid;
920 mAppThread = thread;
921 }
922
923 public void binderDied() {
924 if (localLOGV) Log.v(
925 TAG, "Death received in " + this
926 + " for thread " + mAppThread.asBinder());
927 removeRequestedPss(mApp);
928 synchronized(ActivityManagerService.this) {
929 appDiedLocked(mApp, mPid, mAppThread);
930 }
931 }
932 }
933
934 static final int SHOW_ERROR_MSG = 1;
935 static final int SHOW_NOT_RESPONDING_MSG = 2;
936 static final int SHOW_FACTORY_ERROR_MSG = 3;
937 static final int UPDATE_CONFIGURATION_MSG = 4;
938 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
939 static final int WAIT_FOR_DEBUGGER_MSG = 6;
940 static final int BROADCAST_INTENT_MSG = 7;
941 static final int BROADCAST_TIMEOUT_MSG = 8;
942 static final int PAUSE_TIMEOUT_MSG = 9;
943 static final int IDLE_TIMEOUT_MSG = 10;
944 static final int IDLE_NOW_MSG = 11;
945 static final int SERVICE_TIMEOUT_MSG = 12;
946 static final int UPDATE_TIME_ZONE = 13;
947 static final int SHOW_UID_ERROR_MSG = 14;
948 static final int IM_FEELING_LUCKY_MSG = 15;
949 static final int LAUNCH_TIMEOUT_MSG = 16;
950 static final int DESTROY_TIMEOUT_MSG = 17;
951 static final int SERVICE_ERROR_MSG = 18;
952 static final int RESUME_TOP_ACTIVITY_MSG = 19;
953 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700954 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700955 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956
957 AlertDialog mUidAlert;
958
959 final Handler mHandler = new Handler() {
960 //public Handler() {
961 // if (localLOGV) Log.v(TAG, "Handler started!");
962 //}
963
964 public void handleMessage(Message msg) {
965 switch (msg.what) {
966 case SHOW_ERROR_MSG: {
967 HashMap data = (HashMap) msg.obj;
968 byte[] crashData = (byte[])data.get("crashData");
969 if (crashData != null) {
970 // This needs to be *un*synchronized to avoid deadlock.
971 ContentResolver resolver = mContext.getContentResolver();
972 Checkin.reportCrash(resolver, crashData);
973 }
974 synchronized (ActivityManagerService.this) {
975 ProcessRecord proc = (ProcessRecord)data.get("app");
976 if (proc != null && proc.crashDialog != null) {
977 Log.e(TAG, "App already has crash dialog: " + proc);
978 return;
979 }
980 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700981 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 Dialog d = new AppErrorDialog(
983 mContext, res, proc,
984 (Integer)data.get("flags"),
985 (String)data.get("shortMsg"),
986 (String)data.get("longMsg"));
987 d.show();
988 proc.crashDialog = d;
989 } else {
990 // The device is asleep, so just pretend that the user
991 // saw a crash dialog and hit "force quit".
992 res.set(0);
993 }
994 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700995
996 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 } break;
998 case SHOW_NOT_RESPONDING_MSG: {
999 synchronized (ActivityManagerService.this) {
1000 HashMap data = (HashMap) msg.obj;
1001 ProcessRecord proc = (ProcessRecord)data.get("app");
1002 if (proc != null && proc.anrDialog != null) {
1003 Log.e(TAG, "App already has anr dialog: " + proc);
1004 return;
1005 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001006
1007 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1008 null, null, 0, null, null, null,
1009 false, false, MY_PID, Process.SYSTEM_UID);
1010
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001011 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1012 mContext, proc, (HistoryRecord)data.get("activity"));
1013 d.show();
1014 proc.anrDialog = d;
1015 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001016
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001017 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018 } break;
1019 case SHOW_FACTORY_ERROR_MSG: {
1020 Dialog d = new FactoryErrorDialog(
1021 mContext, msg.getData().getCharSequence("msg"));
1022 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001023 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024 } break;
1025 case UPDATE_CONFIGURATION_MSG: {
1026 final ContentResolver resolver = mContext.getContentResolver();
1027 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1028 } break;
1029 case GC_BACKGROUND_PROCESSES_MSG: {
1030 synchronized (ActivityManagerService.this) {
1031 performAppGcsIfAppropriateLocked();
1032 }
1033 } break;
1034 case WAIT_FOR_DEBUGGER_MSG: {
1035 synchronized (ActivityManagerService.this) {
1036 ProcessRecord app = (ProcessRecord)msg.obj;
1037 if (msg.arg1 != 0) {
1038 if (!app.waitedForDebugger) {
1039 Dialog d = new AppWaitingForDebuggerDialog(
1040 ActivityManagerService.this,
1041 mContext, app);
1042 app.waitDialog = d;
1043 app.waitedForDebugger = true;
1044 d.show();
1045 }
1046 } else {
1047 if (app.waitDialog != null) {
1048 app.waitDialog.dismiss();
1049 app.waitDialog = null;
1050 }
1051 }
1052 }
1053 } break;
1054 case BROADCAST_INTENT_MSG: {
1055 if (DEBUG_BROADCAST) Log.v(
1056 TAG, "Received BROADCAST_INTENT_MSG");
1057 processNextBroadcast(true);
1058 } break;
1059 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001060 if (mDidDexOpt) {
1061 mDidDexOpt = false;
1062 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1063 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1064 return;
1065 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066 broadcastTimeout();
1067 } break;
1068 case PAUSE_TIMEOUT_MSG: {
1069 IBinder token = (IBinder)msg.obj;
1070 // We don't at this point know if the activity is fullscreen,
1071 // so we need to be conservative and assume it isn't.
1072 Log.w(TAG, "Activity pause timeout for " + token);
1073 activityPaused(token, null, true);
1074 } break;
1075 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001076 if (mDidDexOpt) {
1077 mDidDexOpt = false;
1078 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1079 nmsg.obj = msg.obj;
1080 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1081 return;
1082 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 // We don't at this point know if the activity is fullscreen,
1084 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001085 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 Log.w(TAG, "Activity idle timeout for " + token);
1087 activityIdleInternal(token, true);
1088 } break;
1089 case DESTROY_TIMEOUT_MSG: {
1090 IBinder token = (IBinder)msg.obj;
1091 // We don't at this point know if the activity is fullscreen,
1092 // so we need to be conservative and assume it isn't.
1093 Log.w(TAG, "Activity destroy timeout for " + token);
1094 activityDestroyed(token);
1095 } break;
1096 case IDLE_NOW_MSG: {
1097 IBinder token = (IBinder)msg.obj;
1098 activityIdle(token);
1099 } break;
1100 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001101 if (mDidDexOpt) {
1102 mDidDexOpt = false;
1103 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1104 nmsg.obj = msg.obj;
1105 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1106 return;
1107 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001108 serviceTimeout((ProcessRecord)msg.obj);
1109 } break;
1110 case UPDATE_TIME_ZONE: {
1111 synchronized (ActivityManagerService.this) {
1112 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1113 ProcessRecord r = mLRUProcesses.get(i);
1114 if (r.thread != null) {
1115 try {
1116 r.thread.updateTimeZone();
1117 } catch (RemoteException ex) {
1118 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1119 }
1120 }
1121 }
1122 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001123 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001124 case SHOW_UID_ERROR_MSG: {
1125 // XXX This is a temporary dialog, no need to localize.
1126 AlertDialog d = new BaseErrorDialog(mContext);
1127 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1128 d.setCancelable(false);
1129 d.setTitle("System UIDs Inconsistent");
1130 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1131 d.setButton("I'm Feeling Lucky",
1132 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1133 mUidAlert = d;
1134 d.show();
1135 } break;
1136 case IM_FEELING_LUCKY_MSG: {
1137 if (mUidAlert != null) {
1138 mUidAlert.dismiss();
1139 mUidAlert = null;
1140 }
1141 } break;
1142 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001143 if (mDidDexOpt) {
1144 mDidDexOpt = false;
1145 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1146 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1147 return;
1148 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001149 synchronized (ActivityManagerService.this) {
1150 if (mLaunchingActivity.isHeld()) {
1151 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1152 mLaunchingActivity.release();
1153 }
1154 }
1155 } break;
1156 case SERVICE_ERROR_MSG: {
1157 ServiceRecord srv = (ServiceRecord)msg.obj;
1158 // This needs to be *un*synchronized to avoid deadlock.
1159 Checkin.logEvent(mContext.getContentResolver(),
1160 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1161 srv.name.toShortString());
1162 } break;
1163 case RESUME_TOP_ACTIVITY_MSG: {
1164 synchronized (ActivityManagerService.this) {
1165 resumeTopActivityLocked(null);
1166 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001167 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001168 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001169 if (mDidDexOpt) {
1170 mDidDexOpt = false;
1171 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1172 nmsg.obj = msg.obj;
1173 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1174 return;
1175 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 ProcessRecord app = (ProcessRecord)msg.obj;
1177 synchronized (ActivityManagerService.this) {
1178 processStartTimedOutLocked(app);
1179 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001180 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001181 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1182 synchronized (ActivityManagerService.this) {
1183 doPendingActivityLaunchesLocked(true);
1184 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001185 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001186 case KILL_APPLICATION_MSG: {
1187 synchronized (ActivityManagerService.this) {
1188 int uid = msg.arg1;
1189 boolean restart = (msg.arg2 == 1);
1190 String pkg = (String) msg.obj;
1191 uninstallPackageLocked(pkg, uid, restart);
1192 }
1193 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001194 }
1195 }
1196 };
1197
1198 public static void setSystemProcess() {
1199 try {
1200 ActivityManagerService m = mSelf;
1201
1202 ServiceManager.addService("activity", m);
1203 ServiceManager.addService("meminfo", new MemBinder(m));
1204 if (MONITOR_CPU_USAGE) {
1205 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1206 }
1207 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1208 ServiceManager.addService("activity.services", new ServicesBinder(m));
1209 ServiceManager.addService("activity.senders", new SendersBinder(m));
1210 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1211 ServiceManager.addService("permission", new PermissionController(m));
1212
1213 ApplicationInfo info =
1214 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001215 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 synchronized (mSelf) {
1217 ProcessRecord app = mSelf.newProcessRecordLocked(
1218 mSystemThread.getApplicationThread(), info,
1219 info.processName);
1220 app.persistent = true;
1221 app.pid = Process.myPid();
1222 app.maxAdj = SYSTEM_ADJ;
1223 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1224 synchronized (mSelf.mPidsSelfLocked) {
1225 mSelf.mPidsSelfLocked.put(app.pid, app);
1226 }
1227 mSelf.updateLRUListLocked(app, true);
1228 }
1229 } catch (PackageManager.NameNotFoundException e) {
1230 throw new RuntimeException(
1231 "Unable to find android system package", e);
1232 }
1233 }
1234
1235 public void setWindowManager(WindowManagerService wm) {
1236 mWindowManager = wm;
1237 }
1238
1239 public static final Context main(int factoryTest) {
1240 AThread thr = new AThread();
1241 thr.start();
1242
1243 synchronized (thr) {
1244 while (thr.mService == null) {
1245 try {
1246 thr.wait();
1247 } catch (InterruptedException e) {
1248 }
1249 }
1250 }
1251
1252 ActivityManagerService m = thr.mService;
1253 mSelf = m;
1254 ActivityThread at = ActivityThread.systemMain();
1255 mSystemThread = at;
1256 Context context = at.getSystemContext();
1257 m.mContext = context;
1258 m.mFactoryTest = factoryTest;
1259 PowerManager pm =
1260 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1261 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1262 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1263 m.mLaunchingActivity.setReferenceCounted(false);
1264
1265 m.mBatteryStatsService.publish(context);
1266 m.mUsageStatsService.publish(context);
1267
1268 synchronized (thr) {
1269 thr.mReady = true;
1270 thr.notifyAll();
1271 }
1272
1273 m.startRunning(null, null, null, null);
1274
1275 return context;
1276 }
1277
1278 public static ActivityManagerService self() {
1279 return mSelf;
1280 }
1281
1282 static class AThread extends Thread {
1283 ActivityManagerService mService;
1284 boolean mReady = false;
1285
1286 public AThread() {
1287 super("ActivityManager");
1288 }
1289
1290 public void run() {
1291 Looper.prepare();
1292
1293 android.os.Process.setThreadPriority(
1294 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1295
1296 ActivityManagerService m = new ActivityManagerService();
1297
1298 synchronized (this) {
1299 mService = m;
1300 notifyAll();
1301 }
1302
1303 synchronized (this) {
1304 while (!mReady) {
1305 try {
1306 wait();
1307 } catch (InterruptedException e) {
1308 }
1309 }
1310 }
1311
1312 Looper.loop();
1313 }
1314 }
1315
1316 static class BroadcastsBinder extends Binder {
1317 ActivityManagerService mActivityManagerService;
1318 BroadcastsBinder(ActivityManagerService activityManagerService) {
1319 mActivityManagerService = activityManagerService;
1320 }
1321
1322 @Override
1323 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1324 mActivityManagerService.dumpBroadcasts(pw);
1325 }
1326 }
1327
1328 static class ServicesBinder extends Binder {
1329 ActivityManagerService mActivityManagerService;
1330 ServicesBinder(ActivityManagerService activityManagerService) {
1331 mActivityManagerService = activityManagerService;
1332 }
1333
1334 @Override
1335 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1336 mActivityManagerService.dumpServices(pw);
1337 }
1338 }
1339
1340 static class SendersBinder extends Binder {
1341 ActivityManagerService mActivityManagerService;
1342 SendersBinder(ActivityManagerService activityManagerService) {
1343 mActivityManagerService = activityManagerService;
1344 }
1345
1346 @Override
1347 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1348 mActivityManagerService.dumpSenders(pw);
1349 }
1350 }
1351
1352 static class ProvidersBinder extends Binder {
1353 ActivityManagerService mActivityManagerService;
1354 ProvidersBinder(ActivityManagerService activityManagerService) {
1355 mActivityManagerService = activityManagerService;
1356 }
1357
1358 @Override
1359 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1360 mActivityManagerService.dumpProviders(pw);
1361 }
1362 }
1363
1364 static class MemBinder extends Binder {
1365 ActivityManagerService mActivityManagerService;
1366 MemBinder(ActivityManagerService activityManagerService) {
1367 mActivityManagerService = activityManagerService;
1368 }
1369
1370 @Override
1371 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1372 ActivityManagerService service = mActivityManagerService;
1373 ArrayList<ProcessRecord> procs;
1374 synchronized (mActivityManagerService) {
1375 if (args != null && args.length > 0
1376 && args[0].charAt(0) != '-') {
1377 procs = new ArrayList<ProcessRecord>();
1378 int pid = -1;
1379 try {
1380 pid = Integer.parseInt(args[0]);
1381 } catch (NumberFormatException e) {
1382
1383 }
1384 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1385 ProcessRecord proc = service.mLRUProcesses.get(i);
1386 if (proc.pid == pid) {
1387 procs.add(proc);
1388 } else if (proc.processName.equals(args[0])) {
1389 procs.add(proc);
1390 }
1391 }
1392 if (procs.size() <= 0) {
1393 pw.println("No process found for: " + args[0]);
1394 return;
1395 }
1396 } else {
1397 procs = service.mLRUProcesses;
1398 }
1399 }
1400 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1401 }
1402 }
1403
1404 static class CpuBinder extends Binder {
1405 ActivityManagerService mActivityManagerService;
1406 CpuBinder(ActivityManagerService activityManagerService) {
1407 mActivityManagerService = activityManagerService;
1408 }
1409
1410 @Override
1411 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1412 synchronized (mActivityManagerService.mProcessStatsThread) {
1413 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1414 }
1415 }
1416 }
1417
1418 private ActivityManagerService() {
1419 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1420 if (v != null && Integer.getInteger(v) != 0) {
1421 mSimpleProcessManagement = true;
1422 }
1423 v = System.getenv("ANDROID_DEBUG_APP");
1424 if (v != null) {
1425 mSimpleProcessManagement = true;
1426 }
1427
1428 MY_PID = Process.myPid();
1429
1430 File dataDir = Environment.getDataDirectory();
1431 File systemDir = new File(dataDir, "system");
1432 systemDir.mkdirs();
1433 mBatteryStatsService = new BatteryStatsService(new File(
1434 systemDir, "batterystats.bin").toString());
1435 mBatteryStatsService.getActiveStatistics().readLocked();
1436 mBatteryStatsService.getActiveStatistics().writeLocked();
1437
1438 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001439 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440
Jack Palevichb90d28c2009-07-22 15:35:24 -07001441 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1442 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1443
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001444 mConfiguration.makeDefault();
1445 mProcessStats.init();
1446
1447 // Add ourself to the Watchdog monitors.
1448 Watchdog.getInstance().addMonitor(this);
1449
1450 // These values are set in system/rootdir/init.rc on startup.
1451 FOREGROUND_APP_ADJ =
1452 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1453 VISIBLE_APP_ADJ =
1454 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1455 SECONDARY_SERVER_ADJ =
1456 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001457 BACKUP_APP_ADJ =
1458 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001459 HOME_APP_ADJ =
1460 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001461 HIDDEN_APP_MIN_ADJ =
1462 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1463 CONTENT_PROVIDER_ADJ =
1464 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1465 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1466 EMPTY_APP_ADJ =
1467 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1468 FOREGROUND_APP_MEM =
1469 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1470 VISIBLE_APP_MEM =
1471 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1472 SECONDARY_SERVER_MEM =
1473 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001474 BACKUP_APP_MEM =
1475 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001476 HOME_APP_MEM =
1477 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001478 HIDDEN_APP_MEM =
1479 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1480 EMPTY_APP_MEM =
1481 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1482
1483 mProcessStatsThread = new Thread("ProcessStats") {
1484 public void run() {
1485 while (true) {
1486 try {
1487 try {
1488 synchronized(this) {
1489 final long now = SystemClock.uptimeMillis();
1490 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1491 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1492 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1493 // + ", write delay=" + nextWriteDelay);
1494 if (nextWriteDelay < nextCpuDelay) {
1495 nextCpuDelay = nextWriteDelay;
1496 }
1497 if (nextCpuDelay > 0) {
1498 this.wait(nextCpuDelay);
1499 }
1500 }
1501 } catch (InterruptedException e) {
1502 }
1503
1504 updateCpuStatsNow();
1505 } catch (Exception e) {
1506 Log.e(TAG, "Unexpected exception collecting process stats", e);
1507 }
1508 }
1509 }
1510 };
1511 mProcessStatsThread.start();
1512 }
1513
1514 @Override
1515 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1516 throws RemoteException {
1517 try {
1518 return super.onTransact(code, data, reply, flags);
1519 } catch (RuntimeException e) {
1520 // The activity manager only throws security exceptions, so let's
1521 // log all others.
1522 if (!(e instanceof SecurityException)) {
1523 Log.e(TAG, "Activity Manager Crash", e);
1524 }
1525 throw e;
1526 }
1527 }
1528
1529 void updateCpuStats() {
1530 synchronized (mProcessStatsThread) {
1531 final long now = SystemClock.uptimeMillis();
1532 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1533 mProcessStatsThread.notify();
1534 }
1535 }
1536 }
1537
1538 void updateCpuStatsNow() {
1539 synchronized (mProcessStatsThread) {
1540 final long now = SystemClock.uptimeMillis();
1541 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001542
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001543 if (MONITOR_CPU_USAGE &&
1544 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1545 mLastCpuTime = now;
1546 haveNewCpuStats = true;
1547 mProcessStats.update();
1548 //Log.i(TAG, mProcessStats.printCurrentState());
1549 //Log.i(TAG, "Total CPU usage: "
1550 // + mProcessStats.getTotalCpuPercent() + "%");
1551
1552 // Log the cpu usage if the property is set.
1553 if ("true".equals(SystemProperties.get("events.cpu"))) {
1554 int user = mProcessStats.getLastUserTime();
1555 int system = mProcessStats.getLastSystemTime();
1556 int iowait = mProcessStats.getLastIoWaitTime();
1557 int irq = mProcessStats.getLastIrqTime();
1558 int softIrq = mProcessStats.getLastSoftIrqTime();
1559 int idle = mProcessStats.getLastIdleTime();
1560
1561 int total = user + system + iowait + irq + softIrq + idle;
1562 if (total == 0) total = 1;
1563
1564 EventLog.writeEvent(LOG_CPU,
1565 ((user+system+iowait+irq+softIrq) * 100) / total,
1566 (user * 100) / total,
1567 (system * 100) / total,
1568 (iowait * 100) / total,
1569 (irq * 100) / total,
1570 (softIrq * 100) / total);
1571 }
1572 }
1573
Amith Yamasani819f9282009-06-24 23:18:15 -07001574 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001575 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001576 synchronized(mPidsSelfLocked) {
1577 if (haveNewCpuStats) {
1578 if (mBatteryStatsService.isOnBattery()) {
1579 final int N = mProcessStats.countWorkingStats();
1580 for (int i=0; i<N; i++) {
1581 ProcessStats.Stats st
1582 = mProcessStats.getWorkingStats(i);
1583 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1584 if (pr != null) {
1585 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1586 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001587 } else {
1588 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001589 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001590 if (ps != null) {
1591 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1592 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001593 }
1594 }
1595 }
1596 }
1597 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001598
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001599 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1600 mLastWriteTime = now;
1601 mBatteryStatsService.getActiveStatistics().writeLocked();
1602 }
1603 }
1604 }
1605 }
1606
1607 /**
1608 * Initialize the application bind args. These are passed to each
1609 * process when the bindApplication() IPC is sent to the process. They're
1610 * lazily setup to make sure the services are running when they're asked for.
1611 */
1612 private HashMap<String, IBinder> getCommonServicesLocked() {
1613 if (mAppBindArgs == null) {
1614 mAppBindArgs = new HashMap<String, IBinder>();
1615
1616 // Setup the application init args
1617 mAppBindArgs.put("package", ServiceManager.getService("package"));
1618 mAppBindArgs.put("window", ServiceManager.getService("window"));
1619 mAppBindArgs.put(Context.ALARM_SERVICE,
1620 ServiceManager.getService(Context.ALARM_SERVICE));
1621 }
1622 return mAppBindArgs;
1623 }
1624
1625 private final void setFocusedActivityLocked(HistoryRecord r) {
1626 if (mFocusedActivity != r) {
1627 mFocusedActivity = r;
1628 mWindowManager.setFocusedApp(r, true);
1629 }
1630 }
1631
1632 private final void updateLRUListLocked(ProcessRecord app,
1633 boolean oomAdj) {
1634 // put it on the LRU to keep track of when it should be exited.
1635 int lrui = mLRUProcesses.indexOf(app);
1636 if (lrui >= 0) mLRUProcesses.remove(lrui);
1637 mLRUProcesses.add(app);
1638 //Log.i(TAG, "Putting proc to front: " + app.processName);
1639 if (oomAdj) {
1640 updateOomAdjLocked();
1641 }
1642 }
1643
1644 private final boolean updateLRUListLocked(HistoryRecord r) {
1645 final boolean hadit = mLRUActivities.remove(r);
1646 mLRUActivities.add(r);
1647 return hadit;
1648 }
1649
1650 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1651 int i = mHistory.size()-1;
1652 while (i >= 0) {
1653 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1654 if (!r.finishing && r != notTop) {
1655 return r;
1656 }
1657 i--;
1658 }
1659 return null;
1660 }
1661
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001662 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1663 int i = mHistory.size()-1;
1664 while (i >= 0) {
1665 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1666 if (!r.finishing && !r.delayedResume && r != notTop) {
1667 return r;
1668 }
1669 i--;
1670 }
1671 return null;
1672 }
1673
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001674 /**
1675 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001676 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001677 *
1678 * @param token If non-null, any history records matching this token will be skipped.
1679 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1680 *
1681 * @return Returns the HistoryRecord of the next activity on the stack.
1682 */
1683 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1684 int i = mHistory.size()-1;
1685 while (i >= 0) {
1686 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1687 // Note: the taskId check depends on real taskId fields being non-zero
1688 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1689 return r;
1690 }
1691 i--;
1692 }
1693 return null;
1694 }
1695
1696 private final ProcessRecord getProcessRecordLocked(
1697 String processName, int uid) {
1698 if (uid == Process.SYSTEM_UID) {
1699 // The system gets to run in any process. If there are multiple
1700 // processes with the same uid, just pick the first (this
1701 // should never happen).
1702 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1703 processName);
1704 return procs != null ? procs.valueAt(0) : null;
1705 }
1706 ProcessRecord proc = mProcessNames.get(processName, uid);
1707 return proc;
1708 }
1709
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001710 private void ensurePackageDexOpt(String packageName) {
1711 IPackageManager pm = ActivityThread.getPackageManager();
1712 try {
1713 if (pm.performDexOpt(packageName)) {
1714 mDidDexOpt = true;
1715 }
1716 } catch (RemoteException e) {
1717 }
1718 }
1719
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001720 private boolean isNextTransitionForward() {
1721 int transit = mWindowManager.getPendingAppTransition();
1722 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1723 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1724 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1725 }
1726
1727 private final boolean realStartActivityLocked(HistoryRecord r,
1728 ProcessRecord app, boolean andResume, boolean checkConfig)
1729 throws RemoteException {
1730
1731 r.startFreezingScreenLocked(app, 0);
1732 mWindowManager.setAppVisibility(r, true);
1733
1734 // Have the window manager re-evaluate the orientation of
1735 // the screen based on the new activity order. Note that
1736 // as a result of this, it can call back into the activity
1737 // manager with a new orientation. We don't care about that,
1738 // because the activity is not currently running so we are
1739 // just restarting it anyway.
1740 if (checkConfig) {
1741 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001742 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 r.mayFreezeScreenLocked(app) ? r : null);
1744 updateConfigurationLocked(config, r);
1745 }
1746
1747 r.app = app;
1748
1749 if (localLOGV) Log.v(TAG, "Launching: " + r);
1750
1751 int idx = app.activities.indexOf(r);
1752 if (idx < 0) {
1753 app.activities.add(r);
1754 }
1755 updateLRUListLocked(app, true);
1756
1757 try {
1758 if (app.thread == null) {
1759 throw new RemoteException();
1760 }
1761 List<ResultInfo> results = null;
1762 List<Intent> newIntents = null;
1763 if (andResume) {
1764 results = r.results;
1765 newIntents = r.newIntents;
1766 }
1767 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1768 + " icicle=" + r.icicle
1769 + " with results=" + results + " newIntents=" + newIntents
1770 + " andResume=" + andResume);
1771 if (andResume) {
1772 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1773 System.identityHashCode(r),
1774 r.task.taskId, r.shortComponentName);
1775 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001776 if (r.isHomeActivity) {
1777 mHomeProcess = app;
1778 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001779 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001780 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001781 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001782 r.info, r.icicle, results, newIntents, !andResume,
1783 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001784 } catch (RemoteException e) {
1785 if (r.launchFailed) {
1786 // This is the second time we failed -- finish activity
1787 // and give up.
1788 Log.e(TAG, "Second failure launching "
1789 + r.intent.getComponent().flattenToShortString()
1790 + ", giving up", e);
1791 appDiedLocked(app, app.pid, app.thread);
1792 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1793 "2nd-crash");
1794 return false;
1795 }
1796
1797 // This is the first time we failed -- restart process and
1798 // retry.
1799 app.activities.remove(r);
1800 throw e;
1801 }
1802
1803 r.launchFailed = false;
1804 if (updateLRUListLocked(r)) {
1805 Log.w(TAG, "Activity " + r
1806 + " being launched, but already in LRU list");
1807 }
1808
1809 if (andResume) {
1810 // As part of the process of launching, ActivityThread also performs
1811 // a resume.
1812 r.state = ActivityState.RESUMED;
1813 r.icicle = null;
1814 r.haveState = false;
1815 r.stopped = false;
1816 mResumedActivity = r;
1817 r.task.touchActiveTime();
1818 completeResumeLocked(r);
1819 pauseIfSleepingLocked();
1820 } else {
1821 // This activity is not starting in the resumed state... which
1822 // should look like we asked it to pause+stop (but remain visible),
1823 // and it has done so and reported back the current icicle and
1824 // other state.
1825 r.state = ActivityState.STOPPED;
1826 r.stopped = true;
1827 }
1828
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001829 // Launch the new version setup screen if needed. We do this -after-
1830 // launching the initial activity (that is, home), so that it can have
1831 // a chance to initialize itself while in the background, making the
1832 // switch back to it faster and look better.
1833 startSetupActivityLocked();
1834
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001835 return true;
1836 }
1837
1838 private final void startSpecificActivityLocked(HistoryRecord r,
1839 boolean andResume, boolean checkConfig) {
1840 // Is this activity's application already running?
1841 ProcessRecord app = getProcessRecordLocked(r.processName,
1842 r.info.applicationInfo.uid);
1843
1844 if (r.startTime == 0) {
1845 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001846 if (mInitialStartTime == 0) {
1847 mInitialStartTime = r.startTime;
1848 }
1849 } else if (mInitialStartTime == 0) {
1850 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001851 }
1852
1853 if (app != null && app.thread != null) {
1854 try {
1855 realStartActivityLocked(r, app, andResume, checkConfig);
1856 return;
1857 } catch (RemoteException e) {
1858 Log.w(TAG, "Exception when starting activity "
1859 + r.intent.getComponent().flattenToShortString(), e);
1860 }
1861
1862 // If a dead object exception was thrown -- fall through to
1863 // restart the application.
1864 }
1865
1866 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001867 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001868 }
1869
1870 private final ProcessRecord startProcessLocked(String processName,
1871 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001872 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001873 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1874 // We don't have to do anything more if:
1875 // (1) There is an existing application record; and
1876 // (2) The caller doesn't think it is dead, OR there is no thread
1877 // object attached to it so we know it couldn't have crashed; and
1878 // (3) There is a pid assigned to it, so it is either starting or
1879 // already running.
1880 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1881 + " app=" + app + " knownToBeDead=" + knownToBeDead
1882 + " thread=" + (app != null ? app.thread : null)
1883 + " pid=" + (app != null ? app.pid : -1));
1884 if (app != null &&
1885 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1886 return app;
1887 }
1888
1889 String hostingNameStr = hostingName != null
1890 ? hostingName.flattenToShortString() : null;
1891
1892 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1893 // If we are in the background, then check to see if this process
1894 // is bad. If so, we will just silently fail.
1895 if (mBadProcesses.get(info.processName, info.uid) != null) {
1896 return null;
1897 }
1898 } else {
1899 // When the user is explicitly starting a process, then clear its
1900 // crash count so that we won't make it bad until they see at
1901 // least one crash dialog again, and make the process good again
1902 // if it had been bad.
1903 mProcessCrashTimes.remove(info.processName, info.uid);
1904 if (mBadProcesses.get(info.processName, info.uid) != null) {
1905 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1906 info.processName);
1907 mBadProcesses.remove(info.processName, info.uid);
1908 if (app != null) {
1909 app.bad = false;
1910 }
1911 }
1912 }
1913
1914 if (app == null) {
1915 app = newProcessRecordLocked(null, info, processName);
1916 mProcessNames.put(processName, info.uid, app);
1917 } else {
1918 // If this is a new package in the process, add the package to the list
1919 app.addPackage(info.packageName);
1920 }
1921
1922 // If the system is not ready yet, then hold off on starting this
1923 // process until it is.
1924 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001925 && !isAllowedWhileBooting(info)
1926 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001927 if (!mProcessesOnHold.contains(app)) {
1928 mProcessesOnHold.add(app);
1929 }
1930 return app;
1931 }
1932
1933 startProcessLocked(app, hostingType, hostingNameStr);
1934 return (app.pid != 0) ? app : null;
1935 }
1936
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001937 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1938 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1939 }
1940
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001941 private final void startProcessLocked(ProcessRecord app,
1942 String hostingType, String hostingNameStr) {
1943 if (app.pid > 0 && app.pid != MY_PID) {
1944 synchronized (mPidsSelfLocked) {
1945 mPidsSelfLocked.remove(app.pid);
1946 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1947 }
1948 app.pid = 0;
1949 }
1950
1951 mProcessesOnHold.remove(app);
1952
1953 updateCpuStats();
1954
1955 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1956 mProcDeaths[0] = 0;
1957
1958 try {
1959 int uid = app.info.uid;
1960 int[] gids = null;
1961 try {
1962 gids = mContext.getPackageManager().getPackageGids(
1963 app.info.packageName);
1964 } catch (PackageManager.NameNotFoundException e) {
1965 Log.w(TAG, "Unable to retrieve gids", e);
1966 }
1967 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1968 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1969 && mTopComponent != null
1970 && app.processName.equals(mTopComponent.getPackageName())) {
1971 uid = 0;
1972 }
1973 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1974 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1975 uid = 0;
1976 }
1977 }
1978 int debugFlags = 0;
1979 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1980 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1981 }
1982 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1983 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1984 }
1985 if ("1".equals(SystemProperties.get("debug.assert"))) {
1986 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1987 }
1988 int pid = Process.start("android.app.ActivityThread",
1989 mSimpleProcessManagement ? app.processName : null, uid, uid,
1990 gids, debugFlags, null);
1991 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1992 synchronized (bs) {
1993 if (bs.isOnBattery()) {
1994 app.batteryStats.incStartsLocked();
1995 }
1996 }
1997
1998 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1999 app.processName, hostingType,
2000 hostingNameStr != null ? hostingNameStr : "");
2001
2002 if (app.persistent) {
2003 Watchdog.getInstance().processStarted(app, app.processName, pid);
2004 }
2005
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07002006 StringBuilder buf = mStringBuilder;
2007 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002008 buf.append("Start proc ");
2009 buf.append(app.processName);
2010 buf.append(" for ");
2011 buf.append(hostingType);
2012 if (hostingNameStr != null) {
2013 buf.append(" ");
2014 buf.append(hostingNameStr);
2015 }
2016 buf.append(": pid=");
2017 buf.append(pid);
2018 buf.append(" uid=");
2019 buf.append(uid);
2020 buf.append(" gids={");
2021 if (gids != null) {
2022 for (int gi=0; gi<gids.length; gi++) {
2023 if (gi != 0) buf.append(", ");
2024 buf.append(gids[gi]);
2025
2026 }
2027 }
2028 buf.append("}");
2029 Log.i(TAG, buf.toString());
2030 if (pid == 0 || pid == MY_PID) {
2031 // Processes are being emulated with threads.
2032 app.pid = MY_PID;
2033 app.removed = false;
2034 mStartingProcesses.add(app);
2035 } else if (pid > 0) {
2036 app.pid = pid;
2037 app.removed = false;
2038 synchronized (mPidsSelfLocked) {
2039 this.mPidsSelfLocked.put(pid, app);
2040 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2041 msg.obj = app;
2042 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2043 }
2044 } else {
2045 app.pid = 0;
2046 RuntimeException e = new RuntimeException(
2047 "Failure starting process " + app.processName
2048 + ": returned pid=" + pid);
2049 Log.e(TAG, e.getMessage(), e);
2050 }
2051 } catch (RuntimeException e) {
2052 // XXX do better error recovery.
2053 app.pid = 0;
2054 Log.e(TAG, "Failure starting process " + app.processName, e);
2055 }
2056 }
2057
2058 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2059 if (mPausingActivity != null) {
2060 RuntimeException e = new RuntimeException();
2061 Log.e(TAG, "Trying to pause when pause is already pending for "
2062 + mPausingActivity, e);
2063 }
2064 HistoryRecord prev = mResumedActivity;
2065 if (prev == null) {
2066 RuntimeException e = new RuntimeException();
2067 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2068 resumeTopActivityLocked(null);
2069 return;
2070 }
2071 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2072 mResumedActivity = null;
2073 mPausingActivity = prev;
2074 mLastPausedActivity = prev;
2075 prev.state = ActivityState.PAUSING;
2076 prev.task.touchActiveTime();
2077
2078 updateCpuStats();
2079
2080 if (prev.app != null && prev.app.thread != null) {
2081 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2082 try {
2083 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2084 System.identityHashCode(prev),
2085 prev.shortComponentName);
2086 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2087 prev.configChangeFlags);
2088 updateUsageStats(prev, false);
2089 } catch (Exception e) {
2090 // Ignore exception, if process died other code will cleanup.
2091 Log.w(TAG, "Exception thrown during pause", e);
2092 mPausingActivity = null;
2093 mLastPausedActivity = null;
2094 }
2095 } else {
2096 mPausingActivity = null;
2097 mLastPausedActivity = null;
2098 }
2099
2100 // If we are not going to sleep, we want to ensure the device is
2101 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002102 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002103 mLaunchingActivity.acquire();
2104 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2105 // To be safe, don't allow the wake lock to be held for too long.
2106 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2107 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2108 }
2109 }
2110
2111
2112 if (mPausingActivity != null) {
2113 // Have the window manager pause its key dispatching until the new
2114 // activity has started. If we're pausing the activity just because
2115 // the screen is being turned off and the UI is sleeping, don't interrupt
2116 // key dispatch; the same activity will pick it up again on wakeup.
2117 if (!uiSleeping) {
2118 prev.pauseKeyDispatchingLocked();
2119 } else {
2120 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2121 }
2122
2123 // Schedule a pause timeout in case the app doesn't respond.
2124 // We don't give it much time because this directly impacts the
2125 // responsiveness seen by the user.
2126 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2127 msg.obj = prev;
2128 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2129 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2130 } else {
2131 // This activity failed to schedule the
2132 // pause, so just treat it as being paused now.
2133 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2134 resumeTopActivityLocked(null);
2135 }
2136 }
2137
2138 private final void completePauseLocked() {
2139 HistoryRecord prev = mPausingActivity;
2140 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2141
2142 if (prev != null) {
2143 if (prev.finishing) {
2144 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2145 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2146 } else if (prev.app != null) {
2147 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2148 if (prev.waitingVisible) {
2149 prev.waitingVisible = false;
2150 mWaitingVisibleActivities.remove(prev);
2151 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2152 TAG, "Complete pause, no longer waiting: " + prev);
2153 }
2154 if (prev.configDestroy) {
2155 // The previous is being paused because the configuration
2156 // is changing, which means it is actually stopping...
2157 // To juggle the fact that we are also starting a new
2158 // instance right now, we need to first completely stop
2159 // the current instance before starting the new one.
2160 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2161 destroyActivityLocked(prev, true);
2162 } else {
2163 mStoppingActivities.add(prev);
2164 if (mStoppingActivities.size() > 3) {
2165 // If we already have a few activities waiting to stop,
2166 // then give up on things going idle and start clearing
2167 // them out.
2168 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2169 Message msg = Message.obtain();
2170 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2171 mHandler.sendMessage(msg);
2172 }
2173 }
2174 } else {
2175 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2176 prev = null;
2177 }
2178 mPausingActivity = null;
2179 }
2180
Dianne Hackborn55280a92009-05-07 15:53:46 -07002181 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002182 resumeTopActivityLocked(prev);
2183 } else {
2184 if (mGoingToSleep.isHeld()) {
2185 mGoingToSleep.release();
2186 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002187 if (mShuttingDown) {
2188 notifyAll();
2189 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002190 }
2191
2192 if (prev != null) {
2193 prev.resumeKeyDispatchingLocked();
2194 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002195
2196 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2197 long diff = 0;
2198 synchronized (mProcessStatsThread) {
2199 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2200 }
2201 if (diff > 0) {
2202 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2203 synchronized (bsi) {
2204 BatteryStatsImpl.Uid.Proc ps =
2205 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2206 prev.info.packageName);
2207 if (ps != null) {
2208 ps.addForegroundTimeLocked(diff);
2209 }
2210 }
2211 }
2212 }
2213 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002214 }
2215
2216 /**
2217 * Once we know that we have asked an application to put an activity in
2218 * the resumed state (either by launching it or explicitly telling it),
2219 * this function updates the rest of our state to match that fact.
2220 */
2221 private final void completeResumeLocked(HistoryRecord next) {
2222 next.idle = false;
2223 next.results = null;
2224 next.newIntents = null;
2225
2226 // schedule an idle timeout in case the app doesn't do it for us.
2227 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2228 msg.obj = next;
2229 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2230
2231 if (false) {
2232 // The activity was never told to pause, so just keep
2233 // things going as-is. To maintain our own state,
2234 // we need to emulate it coming back and saying it is
2235 // idle.
2236 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2237 msg.obj = next;
2238 mHandler.sendMessage(msg);
2239 }
2240
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002241 reportResumedActivity(next);
2242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002243 next.thumbnail = null;
2244 setFocusedActivityLocked(next);
2245 next.resumeKeyDispatchingLocked();
2246 ensureActivitiesVisibleLocked(null, 0);
2247 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002248
2249 // Mark the point when the activity is resuming
2250 // TODO: To be more accurate, the mark should be before the onCreate,
2251 // not after the onResume. But for subsequent starts, onResume is fine.
2252 if (next.app != null) {
2253 synchronized (mProcessStatsThread) {
2254 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2255 }
2256 } else {
2257 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2258 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002259 }
2260
2261 /**
2262 * Make sure that all activities that need to be visible (that is, they
2263 * currently can be seen by the user) actually are.
2264 */
2265 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2266 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2267 if (DEBUG_VISBILITY) Log.v(
2268 TAG, "ensureActivitiesVisible behind " + top
2269 + " configChanges=0x" + Integer.toHexString(configChanges));
2270
2271 // If the top activity is not fullscreen, then we need to
2272 // make sure any activities under it are now visible.
2273 final int count = mHistory.size();
2274 int i = count-1;
2275 while (mHistory.get(i) != top) {
2276 i--;
2277 }
2278 HistoryRecord r;
2279 boolean behindFullscreen = false;
2280 for (; i>=0; i--) {
2281 r = (HistoryRecord)mHistory.get(i);
2282 if (DEBUG_VISBILITY) Log.v(
2283 TAG, "Make visible? " + r + " finishing=" + r.finishing
2284 + " state=" + r.state);
2285 if (r.finishing) {
2286 continue;
2287 }
2288
2289 final boolean doThisProcess = onlyThisProcess == null
2290 || onlyThisProcess.equals(r.processName);
2291
2292 // First: if this is not the current activity being started, make
2293 // sure it matches the current configuration.
2294 if (r != starting && doThisProcess) {
2295 ensureActivityConfigurationLocked(r, 0);
2296 }
2297
2298 if (r.app == null || r.app.thread == null) {
2299 if (onlyThisProcess == null
2300 || onlyThisProcess.equals(r.processName)) {
2301 // This activity needs to be visible, but isn't even
2302 // running... get it started, but don't resume it
2303 // at this point.
2304 if (DEBUG_VISBILITY) Log.v(
2305 TAG, "Start and freeze screen for " + r);
2306 if (r != starting) {
2307 r.startFreezingScreenLocked(r.app, configChanges);
2308 }
2309 if (!r.visible) {
2310 if (DEBUG_VISBILITY) Log.v(
2311 TAG, "Starting and making visible: " + r);
2312 mWindowManager.setAppVisibility(r, true);
2313 }
2314 if (r != starting) {
2315 startSpecificActivityLocked(r, false, false);
2316 }
2317 }
2318
2319 } else if (r.visible) {
2320 // If this activity is already visible, then there is nothing
2321 // else to do here.
2322 if (DEBUG_VISBILITY) Log.v(
2323 TAG, "Skipping: already visible at " + r);
2324 r.stopFreezingScreenLocked(false);
2325
2326 } else if (onlyThisProcess == null) {
2327 // This activity is not currently visible, but is running.
2328 // Tell it to become visible.
2329 r.visible = true;
2330 if (r.state != ActivityState.RESUMED && r != starting) {
2331 // If this activity is paused, tell it
2332 // to now show its window.
2333 if (DEBUG_VISBILITY) Log.v(
2334 TAG, "Making visible and scheduling visibility: " + r);
2335 try {
2336 mWindowManager.setAppVisibility(r, true);
2337 r.app.thread.scheduleWindowVisibility(r, true);
2338 r.stopFreezingScreenLocked(false);
2339 } catch (Exception e) {
2340 // Just skip on any failure; we'll make it
2341 // visible when it next restarts.
2342 Log.w(TAG, "Exception thrown making visibile: "
2343 + r.intent.getComponent(), e);
2344 }
2345 }
2346 }
2347
2348 // Aggregate current change flags.
2349 configChanges |= r.configChangeFlags;
2350
2351 if (r.fullscreen) {
2352 // At this point, nothing else needs to be shown
2353 if (DEBUG_VISBILITY) Log.v(
2354 TAG, "Stopping: fullscreen at " + r);
2355 behindFullscreen = true;
2356 i--;
2357 break;
2358 }
2359 }
2360
2361 // Now for any activities that aren't visible to the user, make
2362 // sure they no longer are keeping the screen frozen.
2363 while (i >= 0) {
2364 r = (HistoryRecord)mHistory.get(i);
2365 if (DEBUG_VISBILITY) Log.v(
2366 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2367 + " state=" + r.state
2368 + " behindFullscreen=" + behindFullscreen);
2369 if (!r.finishing) {
2370 if (behindFullscreen) {
2371 if (r.visible) {
2372 if (DEBUG_VISBILITY) Log.v(
2373 TAG, "Making invisible: " + r);
2374 r.visible = false;
2375 try {
2376 mWindowManager.setAppVisibility(r, false);
2377 if ((r.state == ActivityState.STOPPING
2378 || r.state == ActivityState.STOPPED)
2379 && r.app != null && r.app.thread != null) {
2380 if (DEBUG_VISBILITY) Log.v(
2381 TAG, "Scheduling invisibility: " + r);
2382 r.app.thread.scheduleWindowVisibility(r, false);
2383 }
2384 } catch (Exception e) {
2385 // Just skip on any failure; we'll make it
2386 // visible when it next restarts.
2387 Log.w(TAG, "Exception thrown making hidden: "
2388 + r.intent.getComponent(), e);
2389 }
2390 } else {
2391 if (DEBUG_VISBILITY) Log.v(
2392 TAG, "Already invisible: " + r);
2393 }
2394 } else if (r.fullscreen) {
2395 if (DEBUG_VISBILITY) Log.v(
2396 TAG, "Now behindFullscreen: " + r);
2397 behindFullscreen = true;
2398 }
2399 }
2400 i--;
2401 }
2402 }
2403
2404 /**
2405 * Version of ensureActivitiesVisible that can easily be called anywhere.
2406 */
2407 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2408 int configChanges) {
2409 HistoryRecord r = topRunningActivityLocked(null);
2410 if (r != null) {
2411 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2412 }
2413 }
2414
2415 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2416 if (resumed) {
2417 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2418 } else {
2419 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2420 }
2421 }
2422
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002423 private boolean startHomeActivityLocked() {
2424 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2425 && mTopAction == null) {
2426 // We are running in factory test mode, but unable to find
2427 // the factory test app, so just sit around displaying the
2428 // error message and don't try to start anything.
2429 return false;
2430 }
2431 Intent intent = new Intent(
2432 mTopAction,
2433 mTopData != null ? Uri.parse(mTopData) : null);
2434 intent.setComponent(mTopComponent);
2435 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2436 intent.addCategory(Intent.CATEGORY_HOME);
2437 }
2438 ActivityInfo aInfo =
2439 intent.resolveActivityInfo(mContext.getPackageManager(),
2440 STOCK_PM_FLAGS);
2441 if (aInfo != null) {
2442 intent.setComponent(new ComponentName(
2443 aInfo.applicationInfo.packageName, aInfo.name));
2444 // Don't do this if the home app is currently being
2445 // instrumented.
2446 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2447 aInfo.applicationInfo.uid);
2448 if (app == null || app.instrumentationClass == null) {
2449 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2450 startActivityLocked(null, intent, null, null, 0, aInfo,
2451 null, null, 0, 0, 0, false, false);
2452 }
2453 }
2454
2455
2456 return true;
2457 }
2458
2459 /**
2460 * Starts the "new version setup screen" if appropriate.
2461 */
2462 private void startSetupActivityLocked() {
2463 // Only do this once per boot.
2464 if (mCheckedForSetup) {
2465 return;
2466 }
2467
2468 // We will show this screen if the current one is a different
2469 // version than the last one shown, and we are not running in
2470 // low-level factory test mode.
2471 final ContentResolver resolver = mContext.getContentResolver();
2472 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2473 Settings.Secure.getInt(resolver,
2474 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2475 mCheckedForSetup = true;
2476
2477 // See if we should be showing the platform update setup UI.
2478 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2479 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2480 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2481
2482 // We don't allow third party apps to replace this.
2483 ResolveInfo ri = null;
2484 for (int i=0; ris != null && i<ris.size(); i++) {
2485 if ((ris.get(i).activityInfo.applicationInfo.flags
2486 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2487 ri = ris.get(i);
2488 break;
2489 }
2490 }
2491
2492 if (ri != null) {
2493 String vers = ri.activityInfo.metaData != null
2494 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2495 : null;
2496 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2497 vers = ri.activityInfo.applicationInfo.metaData.getString(
2498 Intent.METADATA_SETUP_VERSION);
2499 }
2500 String lastVers = Settings.Secure.getString(
2501 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2502 if (vers != null && !vers.equals(lastVers)) {
2503 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2504 intent.setComponent(new ComponentName(
2505 ri.activityInfo.packageName, ri.activityInfo.name));
2506 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2507 null, null, 0, 0, 0, false, false);
2508 }
2509 }
2510 }
2511 }
2512
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002513 private void reportResumedActivity(HistoryRecord r) {
2514 //Log.i(TAG, "**** REPORT RESUME: " + r);
2515
2516 final int identHash = System.identityHashCode(r);
2517 updateUsageStats(r, true);
2518
2519 int i = mWatchers.beginBroadcast();
2520 while (i > 0) {
2521 i--;
2522 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2523 if (w != null) {
2524 try {
2525 w.activityResuming(identHash);
2526 } catch (RemoteException e) {
2527 }
2528 }
2529 }
2530 mWatchers.finishBroadcast();
2531 }
2532
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002533 /**
2534 * Ensure that the top activity in the stack is resumed.
2535 *
2536 * @param prev The previously resumed activity, for when in the process
2537 * of pausing; can be null to call from elsewhere.
2538 *
2539 * @return Returns true if something is being resumed, or false if
2540 * nothing happened.
2541 */
2542 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2543 // Find the first activity that is not finishing.
2544 HistoryRecord next = topRunningActivityLocked(null);
2545
2546 // Remember how we'll process this pause/resume situation, and ensure
2547 // that the state is reset however we wind up proceeding.
2548 final boolean userLeaving = mUserLeaving;
2549 mUserLeaving = false;
2550
2551 if (next == null) {
2552 // There are no more activities! Let's just start up the
2553 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002554 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002555 }
2556
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002557 next.delayedResume = false;
2558
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002559 // If the top activity is the resumed one, nothing to do.
2560 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2561 // Make sure we have executed any pending transitions, since there
2562 // should be nothing left to do at this point.
2563 mWindowManager.executeAppTransition();
2564 return false;
2565 }
2566
2567 // If we are sleeping, and there is no resumed activity, and the top
2568 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002569 if ((mSleeping || mShuttingDown)
2570 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002571 // Make sure we have executed any pending transitions, since there
2572 // should be nothing left to do at this point.
2573 mWindowManager.executeAppTransition();
2574 return false;
2575 }
2576
2577 // The activity may be waiting for stop, but that is no longer
2578 // appropriate for it.
2579 mStoppingActivities.remove(next);
2580 mWaitingVisibleActivities.remove(next);
2581
2582 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2583
2584 // If we are currently pausing an activity, then don't do anything
2585 // until that is done.
2586 if (mPausingActivity != null) {
2587 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2588 return false;
2589 }
2590
2591 // We need to start pausing the current activity so the top one
2592 // can be resumed...
2593 if (mResumedActivity != null) {
2594 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2595 startPausingLocked(userLeaving, false);
2596 return true;
2597 }
2598
2599 if (prev != null && prev != next) {
2600 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2601 prev.waitingVisible = true;
2602 mWaitingVisibleActivities.add(prev);
2603 if (DEBUG_SWITCH) Log.v(
2604 TAG, "Resuming top, waiting visible to hide: " + prev);
2605 } else {
2606 // The next activity is already visible, so hide the previous
2607 // activity's windows right now so we can show the new one ASAP.
2608 // We only do this if the previous is finishing, which should mean
2609 // it is on top of the one being resumed so hiding it quickly
2610 // is good. Otherwise, we want to do the normal route of allowing
2611 // the resumed activity to be shown so we can decide if the
2612 // previous should actually be hidden depending on whether the
2613 // new one is found to be full-screen or not.
2614 if (prev.finishing) {
2615 mWindowManager.setAppVisibility(prev, false);
2616 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2617 + prev + ", waitingVisible="
2618 + (prev != null ? prev.waitingVisible : null)
2619 + ", nowVisible=" + next.nowVisible);
2620 } else {
2621 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2622 + prev + ", waitingVisible="
2623 + (prev != null ? prev.waitingVisible : null)
2624 + ", nowVisible=" + next.nowVisible);
2625 }
2626 }
2627 }
2628
2629 // We are starting up the next activity, so tell the window manager
2630 // that the previous one will be hidden soon. This way it can know
2631 // to ignore it when computing the desired screen orientation.
2632 if (prev != null) {
2633 if (prev.finishing) {
2634 if (DEBUG_TRANSITION) Log.v(TAG,
2635 "Prepare close transition: prev=" + prev);
2636 mWindowManager.prepareAppTransition(prev.task == next.task
2637 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2638 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2639 mWindowManager.setAppWillBeHidden(prev);
2640 mWindowManager.setAppVisibility(prev, false);
2641 } else {
2642 if (DEBUG_TRANSITION) Log.v(TAG,
2643 "Prepare open transition: prev=" + prev);
2644 mWindowManager.prepareAppTransition(prev.task == next.task
2645 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2646 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2647 }
2648 if (false) {
2649 mWindowManager.setAppWillBeHidden(prev);
2650 mWindowManager.setAppVisibility(prev, false);
2651 }
2652 } else if (mHistory.size() > 1) {
2653 if (DEBUG_TRANSITION) Log.v(TAG,
2654 "Prepare open transition: no previous");
2655 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2656 }
2657
2658 if (next.app != null && next.app.thread != null) {
2659 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2660
2661 // This activity is now becoming visible.
2662 mWindowManager.setAppVisibility(next, true);
2663
2664 HistoryRecord lastResumedActivity = mResumedActivity;
2665 ActivityState lastState = next.state;
2666
2667 updateCpuStats();
2668
2669 next.state = ActivityState.RESUMED;
2670 mResumedActivity = next;
2671 next.task.touchActiveTime();
2672 updateLRUListLocked(next.app, true);
2673 updateLRUListLocked(next);
2674
2675 // Have the window manager re-evaluate the orientation of
2676 // the screen based on the new activity order.
2677 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002678 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002679 next.mayFreezeScreenLocked(next.app) ? next : null);
2680 if (config != null) {
2681 next.frozenBeforeDestroy = true;
2682 }
2683 if (!updateConfigurationLocked(config, next)) {
2684 // The configuration update wasn't able to keep the existing
2685 // instance of the activity, and instead started a new one.
2686 // We should be all done, but let's just make sure our activity
2687 // is still at the top and schedule another run if something
2688 // weird happened.
2689 HistoryRecord nextNext = topRunningActivityLocked(null);
2690 if (DEBUG_SWITCH) Log.i(TAG,
2691 "Activity config changed during resume: " + next
2692 + ", new next: " + nextNext);
2693 if (nextNext != next) {
2694 // Do over!
2695 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2696 }
2697 mWindowManager.executeAppTransition();
2698 return true;
2699 }
2700
2701 try {
2702 // Deliver all pending results.
2703 ArrayList a = next.results;
2704 if (a != null) {
2705 final int N = a.size();
2706 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002707 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002708 TAG, "Delivering results to " + next
2709 + ": " + a);
2710 next.app.thread.scheduleSendResult(next, a);
2711 }
2712 }
2713
2714 if (next.newIntents != null) {
2715 next.app.thread.scheduleNewIntent(next.newIntents, next);
2716 }
2717
2718 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2719 System.identityHashCode(next),
2720 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002721
2722 next.app.thread.scheduleResumeActivity(next,
2723 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002724
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002725 pauseIfSleepingLocked();
2726
2727 } catch (Exception e) {
2728 // Whoops, need to restart this activity!
2729 next.state = lastState;
2730 mResumedActivity = lastResumedActivity;
2731 if (Config.LOGD) Log.d(TAG,
2732 "Restarting because process died: " + next);
2733 if (!next.hasBeenLaunched) {
2734 next.hasBeenLaunched = true;
2735 } else {
2736 if (SHOW_APP_STARTING_ICON) {
2737 mWindowManager.setAppStartingWindow(
2738 next, next.packageName, next.theme,
2739 next.nonLocalizedLabel,
2740 next.labelRes, next.icon, null, true);
2741 }
2742 }
2743 startSpecificActivityLocked(next, true, false);
2744 return true;
2745 }
2746
2747 // From this point on, if something goes wrong there is no way
2748 // to recover the activity.
2749 try {
2750 next.visible = true;
2751 completeResumeLocked(next);
2752 } catch (Exception e) {
2753 // If any exception gets thrown, toss away this
2754 // activity and try the next one.
2755 Log.w(TAG, "Exception thrown during resume of " + next, e);
2756 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2757 "resume-exception");
2758 return true;
2759 }
2760
2761 // Didn't need to use the icicle, and it is now out of date.
2762 next.icicle = null;
2763 next.haveState = false;
2764 next.stopped = false;
2765
2766 } else {
2767 // Whoops, need to restart this activity!
2768 if (!next.hasBeenLaunched) {
2769 next.hasBeenLaunched = true;
2770 } else {
2771 if (SHOW_APP_STARTING_ICON) {
2772 mWindowManager.setAppStartingWindow(
2773 next, next.packageName, next.theme,
2774 next.nonLocalizedLabel,
2775 next.labelRes, next.icon, null, true);
2776 }
2777 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2778 }
2779 startSpecificActivityLocked(next, true, true);
2780 }
2781
2782 return true;
2783 }
2784
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002785 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2786 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002787 final int NH = mHistory.size();
2788
2789 int addPos = -1;
2790
2791 if (!newTask) {
2792 // If starting in an existing task, find where that is...
2793 HistoryRecord next = null;
2794 boolean startIt = true;
2795 for (int i = NH-1; i >= 0; i--) {
2796 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2797 if (p.finishing) {
2798 continue;
2799 }
2800 if (p.task == r.task) {
2801 // Here it is! Now, if this is not yet visible to the
2802 // user, then just add it without starting; it will
2803 // get started when the user navigates back to it.
2804 addPos = i+1;
2805 if (!startIt) {
2806 mHistory.add(addPos, r);
2807 r.inHistory = true;
2808 r.task.numActivities++;
2809 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2810 r.info.screenOrientation, r.fullscreen);
2811 if (VALIDATE_TOKENS) {
2812 mWindowManager.validateAppTokens(mHistory);
2813 }
2814 return;
2815 }
2816 break;
2817 }
2818 if (p.fullscreen) {
2819 startIt = false;
2820 }
2821 next = p;
2822 }
2823 }
2824
2825 // Place a new activity at top of stack, so it is next to interact
2826 // with the user.
2827 if (addPos < 0) {
2828 addPos = mHistory.size();
2829 }
2830
2831 // If we are not placing the new activity frontmost, we do not want
2832 // to deliver the onUserLeaving callback to the actual frontmost
2833 // activity
2834 if (addPos < NH) {
2835 mUserLeaving = false;
2836 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2837 }
2838
2839 // Slot the activity into the history stack and proceed
2840 mHistory.add(addPos, r);
2841 r.inHistory = true;
2842 r.frontOfTask = newTask;
2843 r.task.numActivities++;
2844 if (NH > 0) {
2845 // We want to show the starting preview window if we are
2846 // switching to a new task, or the next activity's process is
2847 // not currently running.
2848 boolean showStartingIcon = newTask;
2849 ProcessRecord proc = r.app;
2850 if (proc == null) {
2851 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2852 }
2853 if (proc == null || proc.thread == null) {
2854 showStartingIcon = true;
2855 }
2856 if (DEBUG_TRANSITION) Log.v(TAG,
2857 "Prepare open transition: starting " + r);
2858 mWindowManager.prepareAppTransition(newTask
2859 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2860 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2861 mWindowManager.addAppToken(
2862 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2863 boolean doShow = true;
2864 if (newTask) {
2865 // Even though this activity is starting fresh, we still need
2866 // to reset it to make sure we apply affinities to move any
2867 // existing activities from other tasks in to it.
2868 // If the caller has requested that the target task be
2869 // reset, then do so.
2870 if ((r.intent.getFlags()
2871 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2872 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002873 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002874 }
2875 }
2876 if (SHOW_APP_STARTING_ICON && doShow) {
2877 // Figure out if we are transitioning from another activity that is
2878 // "has the same starting icon" as the next one. This allows the
2879 // window manager to keep the previous window it had previously
2880 // created, if it still had one.
2881 HistoryRecord prev = mResumedActivity;
2882 if (prev != null) {
2883 // We don't want to reuse the previous starting preview if:
2884 // (1) The current activity is in a different task.
2885 if (prev.task != r.task) prev = null;
2886 // (2) The current activity is already displayed.
2887 else if (prev.nowVisible) prev = null;
2888 }
2889 mWindowManager.setAppStartingWindow(
2890 r, r.packageName, r.theme, r.nonLocalizedLabel,
2891 r.labelRes, r.icon, prev, showStartingIcon);
2892 }
2893 } else {
2894 // If this is the first activity, don't do any fancy animations,
2895 // because there is nothing for it to animate on top of.
2896 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2897 r.info.screenOrientation, r.fullscreen);
2898 }
2899 if (VALIDATE_TOKENS) {
2900 mWindowManager.validateAppTokens(mHistory);
2901 }
2902
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002903 if (doResume) {
2904 resumeTopActivityLocked(null);
2905 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002906 }
2907
2908 /**
2909 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002910 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2911 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002912 * an instance of that activity in the stack and, if found, finish all
2913 * activities on top of it and return the instance.
2914 *
2915 * @param newR Description of the new activity being started.
2916 * @return Returns the old activity that should be continue to be used,
2917 * or null if none was found.
2918 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002919 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002920 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002921 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002922
2923 // First find the requested task.
2924 while (i > 0) {
2925 i--;
2926 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2927 if (r.task.taskId == taskId) {
2928 i++;
2929 break;
2930 }
2931 }
2932
2933 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002934 while (i > 0) {
2935 i--;
2936 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2937 if (r.finishing) {
2938 continue;
2939 }
2940 if (r.task.taskId != taskId) {
2941 return null;
2942 }
2943 if (r.realActivity.equals(newR.realActivity)) {
2944 // Here it is! Now finish everything in front...
2945 HistoryRecord ret = r;
2946 if (doClear) {
2947 while (i < (mHistory.size()-1)) {
2948 i++;
2949 r = (HistoryRecord)mHistory.get(i);
2950 if (r.finishing) {
2951 continue;
2952 }
2953 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2954 null, "clear")) {
2955 i--;
2956 }
2957 }
2958 }
2959
2960 // Finally, if this is a normal launch mode (that is, not
2961 // expecting onNewIntent()), then we will finish the current
2962 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002963 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
2964 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002965 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002966 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002967 if (index >= 0) {
2968 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2969 null, "clear");
2970 }
2971 return null;
2972 }
2973 }
2974
2975 return ret;
2976 }
2977 }
2978
2979 return null;
2980 }
2981
2982 /**
2983 * Find the activity in the history stack within the given task. Returns
2984 * the index within the history at which it's found, or < 0 if not found.
2985 */
2986 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2987 int i = mHistory.size();
2988 while (i > 0) {
2989 i--;
2990 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2991 if (candidate.task.taskId != task) {
2992 break;
2993 }
2994 if (candidate.realActivity.equals(r.realActivity)) {
2995 return i;
2996 }
2997 }
2998
2999 return -1;
3000 }
3001
3002 /**
3003 * Reorder the history stack so that the activity at the given index is
3004 * brought to the front.
3005 */
3006 private final HistoryRecord moveActivityToFrontLocked(int where) {
3007 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3008 int top = mHistory.size();
3009 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3010 mHistory.add(top, newTop);
3011 oldTop.frontOfTask = false;
3012 newTop.frontOfTask = true;
3013 return newTop;
3014 }
3015
3016 /**
3017 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3018 * method will be called at the proper time.
3019 */
3020 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3021 boolean sent = false;
3022 if (r.state == ActivityState.RESUMED
3023 && r.app != null && r.app.thread != null) {
3024 try {
3025 ArrayList<Intent> ar = new ArrayList<Intent>();
3026 ar.add(new Intent(intent));
3027 r.app.thread.scheduleNewIntent(ar, r);
3028 sent = true;
3029 } catch (Exception e) {
3030 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3031 }
3032 }
3033 if (!sent) {
3034 r.addNewIntentLocked(new Intent(intent));
3035 }
3036 }
3037
3038 private final void logStartActivity(int tag, HistoryRecord r,
3039 TaskRecord task) {
3040 EventLog.writeEvent(tag,
3041 System.identityHashCode(r), task.taskId,
3042 r.shortComponentName, r.intent.getAction(),
3043 r.intent.getType(), r.intent.getDataString(),
3044 r.intent.getFlags());
3045 }
3046
3047 private final int startActivityLocked(IApplicationThread caller,
3048 Intent intent, String resolvedType,
3049 Uri[] grantedUriPermissions,
3050 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3051 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003052 int callingPid, int callingUid, boolean onlyIfNeeded,
3053 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003054 Log.i(TAG, "Starting activity: " + intent);
3055
3056 HistoryRecord sourceRecord = null;
3057 HistoryRecord resultRecord = null;
3058 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003059 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003060 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003061 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3062 if (index >= 0) {
3063 sourceRecord = (HistoryRecord)mHistory.get(index);
3064 if (requestCode >= 0 && !sourceRecord.finishing) {
3065 resultRecord = sourceRecord;
3066 }
3067 }
3068 }
3069
3070 int launchFlags = intent.getFlags();
3071
3072 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3073 && sourceRecord != null) {
3074 // Transfer the result target from the source activity to the new
3075 // one being started, including any failures.
3076 if (requestCode >= 0) {
3077 return START_FORWARD_AND_REQUEST_CONFLICT;
3078 }
3079 resultRecord = sourceRecord.resultTo;
3080 resultWho = sourceRecord.resultWho;
3081 requestCode = sourceRecord.requestCode;
3082 sourceRecord.resultTo = null;
3083 if (resultRecord != null) {
3084 resultRecord.removeResultsLocked(
3085 sourceRecord, resultWho, requestCode);
3086 }
3087 }
3088
3089 int err = START_SUCCESS;
3090
3091 if (intent.getComponent() == null) {
3092 // We couldn't find a class that can handle the given Intent.
3093 // That's the end of that!
3094 err = START_INTENT_NOT_RESOLVED;
3095 }
3096
3097 if (err == START_SUCCESS && aInfo == null) {
3098 // We couldn't find the specific class specified in the Intent.
3099 // Also the end of the line.
3100 err = START_CLASS_NOT_FOUND;
3101 }
3102
3103 ProcessRecord callerApp = null;
3104 if (err == START_SUCCESS && caller != null) {
3105 callerApp = getRecordForAppLocked(caller);
3106 if (callerApp != null) {
3107 callingPid = callerApp.pid;
3108 callingUid = callerApp.info.uid;
3109 } else {
3110 Log.w(TAG, "Unable to find app for caller " + caller
3111 + " (pid=" + callingPid + ") when starting: "
3112 + intent.toString());
3113 err = START_PERMISSION_DENIED;
3114 }
3115 }
3116
3117 if (err != START_SUCCESS) {
3118 if (resultRecord != null) {
3119 sendActivityResultLocked(-1,
3120 resultRecord, resultWho, requestCode,
3121 Activity.RESULT_CANCELED, null);
3122 }
3123 return err;
3124 }
3125
3126 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3127 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3128 if (perm != PackageManager.PERMISSION_GRANTED) {
3129 if (resultRecord != null) {
3130 sendActivityResultLocked(-1,
3131 resultRecord, resultWho, requestCode,
3132 Activity.RESULT_CANCELED, null);
3133 }
3134 String msg = "Permission Denial: starting " + intent.toString()
3135 + " from " + callerApp + " (pid=" + callingPid
3136 + ", uid=" + callingUid + ")"
3137 + " requires " + aInfo.permission;
3138 Log.w(TAG, msg);
3139 throw new SecurityException(msg);
3140 }
3141
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003142 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003143 boolean abort = false;
3144 try {
3145 // The Intent we give to the watcher has the extra data
3146 // stripped off, since it can contain private information.
3147 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003148 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003149 aInfo.applicationInfo.packageName);
3150 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003151 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003152 }
3153
3154 if (abort) {
3155 if (resultRecord != null) {
3156 sendActivityResultLocked(-1,
3157 resultRecord, resultWho, requestCode,
3158 Activity.RESULT_CANCELED, null);
3159 }
3160 // We pretend to the caller that it was really started, but
3161 // they will just get a cancel result.
3162 return START_SUCCESS;
3163 }
3164 }
3165
3166 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3167 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003168 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003169
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003170 if (mResumedActivity == null
3171 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3172 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3173 PendingActivityLaunch pal = new PendingActivityLaunch();
3174 pal.r = r;
3175 pal.sourceRecord = sourceRecord;
3176 pal.grantedUriPermissions = grantedUriPermissions;
3177 pal.grantedMode = grantedMode;
3178 pal.onlyIfNeeded = onlyIfNeeded;
3179 mPendingActivityLaunches.add(pal);
3180 return START_SWITCHES_CANCELED;
3181 }
3182 }
3183
3184 if (mDidAppSwitch) {
3185 // This is the second allowed switch since we stopped switches,
3186 // so now just generally allow switches. Use case: user presses
3187 // home (switches disabled, switch to home, mDidAppSwitch now true);
3188 // user taps a home icon (coming from home so allowed, we hit here
3189 // and now allow anyone to switch again).
3190 mAppSwitchesAllowedTime = 0;
3191 } else {
3192 mDidAppSwitch = true;
3193 }
3194
3195 doPendingActivityLaunchesLocked(false);
3196
3197 return startActivityUncheckedLocked(r, sourceRecord,
3198 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3199 }
3200
3201 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3202 final int N = mPendingActivityLaunches.size();
3203 if (N <= 0) {
3204 return;
3205 }
3206 for (int i=0; i<N; i++) {
3207 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3208 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3209 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3210 doResume && i == (N-1));
3211 }
3212 mPendingActivityLaunches.clear();
3213 }
3214
3215 private final int startActivityUncheckedLocked(HistoryRecord r,
3216 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3217 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3218 final Intent intent = r.intent;
3219 final int callingUid = r.launchedFromUid;
3220
3221 int launchFlags = intent.getFlags();
3222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003223 // We'll invoke onUserLeaving before onPause only if the launching
3224 // activity did not explicitly state that this is an automated launch.
3225 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3226 if (DEBUG_USER_LEAVING) Log.v(TAG,
3227 "startActivity() => mUserLeaving=" + mUserLeaving);
3228
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003229 // If the caller has asked not to resume at this point, we make note
3230 // of this in the record so that we can skip it when trying to find
3231 // the top running activity.
3232 if (!doResume) {
3233 r.delayedResume = true;
3234 }
3235
3236 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3237 != 0 ? r : null;
3238
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003239 // If the onlyIfNeeded flag is set, then we can do this if the activity
3240 // being launched is the same as the one making the call... or, as
3241 // a special case, if we do not know the caller then we count the
3242 // current top activity as the caller.
3243 if (onlyIfNeeded) {
3244 HistoryRecord checkedCaller = sourceRecord;
3245 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003246 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003247 }
3248 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3249 // Caller is not the same as launcher, so always needed.
3250 onlyIfNeeded = false;
3251 }
3252 }
3253
3254 if (grantedUriPermissions != null && callingUid > 0) {
3255 for (int i=0; i<grantedUriPermissions.length; i++) {
3256 grantUriPermissionLocked(callingUid, r.packageName,
3257 grantedUriPermissions[i], grantedMode, r);
3258 }
3259 }
3260
3261 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3262 intent, r);
3263
3264 if (sourceRecord == null) {
3265 // This activity is not being started from another... in this
3266 // case we -always- start a new task.
3267 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3268 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3269 + intent);
3270 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3271 }
3272 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3273 // The original activity who is starting us is running as a single
3274 // instance... this new activity it is starting must go on its
3275 // own task.
3276 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3277 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3278 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3279 // The activity being started is a single instance... it always
3280 // gets launched into its own task.
3281 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3282 }
3283
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003284 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003285 // For whatever reason this activity is being launched into a new
3286 // task... yet the caller has requested a result back. Well, that
3287 // is pretty messed up, so instead immediately send back a cancel
3288 // and let the new task continue launched as normal without a
3289 // dependency on its originator.
3290 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3291 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003292 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003293 Activity.RESULT_CANCELED, null);
3294 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003295 }
3296
3297 boolean addingToTask = false;
3298 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3299 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3300 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3301 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3302 // If bring to front is requested, and no result is requested, and
3303 // we can find a task that was started with this same
3304 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003305 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003306 // See if there is a task to bring to the front. If this is
3307 // a SINGLE_INSTANCE activity, there can be one and only one
3308 // instance of it in the history, and it is always in its own
3309 // unique task, so we do a special search.
3310 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3311 ? findTaskLocked(intent, r.info)
3312 : findActivityLocked(intent, r.info);
3313 if (taskTop != null) {
3314 if (taskTop.task.intent == null) {
3315 // This task was started because of movement of
3316 // the activity based on affinity... now that we
3317 // are actually launching it, we can assign the
3318 // base intent.
3319 taskTop.task.setIntent(intent, r.info);
3320 }
3321 // If the target task is not in the front, then we need
3322 // to bring it to the front... except... well, with
3323 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3324 // to have the same behavior as if a new instance was
3325 // being started, which means not bringing it to the front
3326 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003327 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003328 if (curTop.task != taskTop.task) {
3329 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3330 boolean callerAtFront = sourceRecord == null
3331 || curTop.task == sourceRecord.task;
3332 if (callerAtFront) {
3333 // We really do want to push this one into the
3334 // user's face, right now.
3335 moveTaskToFrontLocked(taskTop.task);
3336 }
3337 }
3338 // If the caller has requested that the target task be
3339 // reset, then do so.
3340 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3341 taskTop = resetTaskIfNeededLocked(taskTop, r);
3342 }
3343 if (onlyIfNeeded) {
3344 // We don't need to start a new activity, and
3345 // the client said not to do anything if that
3346 // is the case, so this is it! And for paranoia, make
3347 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003348 if (doResume) {
3349 resumeTopActivityLocked(null);
3350 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003351 return START_RETURN_INTENT_TO_CALLER;
3352 }
3353 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3354 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3355 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3356 // In this situation we want to remove all activities
3357 // from the task up to the one being started. In most
3358 // cases this means we are resetting the task to its
3359 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003360 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003361 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003362 if (top != null) {
3363 if (top.frontOfTask) {
3364 // Activity aliases may mean we use different
3365 // intents for the top activity, so make sure
3366 // the task now has the identity of the new
3367 // intent.
3368 top.task.setIntent(r.intent, r.info);
3369 }
3370 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3371 deliverNewIntentLocked(top, r.intent);
3372 } else {
3373 // A special case: we need to
3374 // start the activity because it is not currently
3375 // running, and the caller has asked to clear the
3376 // current task to have this activity at the top.
3377 addingToTask = true;
3378 // Now pretend like this activity is being started
3379 // by the top of its task, so it is put in the
3380 // right place.
3381 sourceRecord = taskTop;
3382 }
3383 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3384 // In this case the top activity on the task is the
3385 // same as the one being launched, so we take that
3386 // as a request to bring the task to the foreground.
3387 // If the top activity in the task is the root
3388 // activity, deliver this new intent to it if it
3389 // desires.
3390 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3391 && taskTop.realActivity.equals(r.realActivity)) {
3392 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3393 if (taskTop.frontOfTask) {
3394 taskTop.task.setIntent(r.intent, r.info);
3395 }
3396 deliverNewIntentLocked(taskTop, r.intent);
3397 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3398 // In this case we are launching the root activity
3399 // of the task, but with a different intent. We
3400 // should start a new instance on top.
3401 addingToTask = true;
3402 sourceRecord = taskTop;
3403 }
3404 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3405 // In this case an activity is being launched in to an
3406 // existing task, without resetting that task. This
3407 // is typically the situation of launching an activity
3408 // from a notification or shortcut. We want to place
3409 // the new activity on top of the current task.
3410 addingToTask = true;
3411 sourceRecord = taskTop;
3412 } else if (!taskTop.task.rootWasReset) {
3413 // In this case we are launching in to an existing task
3414 // that has not yet been started from its front door.
3415 // The current task has been brought to the front.
3416 // Ideally, we'd probably like to place this new task
3417 // at the bottom of its stack, but that's a little hard
3418 // to do with the current organization of the code so
3419 // for now we'll just drop it.
3420 taskTop.task.setIntent(r.intent, r.info);
3421 }
3422 if (!addingToTask) {
3423 // We didn't do anything... but it was needed (a.k.a., client
3424 // don't use that intent!) And for paranoia, make
3425 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003426 if (doResume) {
3427 resumeTopActivityLocked(null);
3428 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003429 return START_TASK_TO_FRONT;
3430 }
3431 }
3432 }
3433 }
3434
3435 //String uri = r.intent.toURI();
3436 //Intent intent2 = new Intent(uri);
3437 //Log.i(TAG, "Given intent: " + r.intent);
3438 //Log.i(TAG, "URI is: " + uri);
3439 //Log.i(TAG, "To intent: " + intent2);
3440
3441 if (r.packageName != null) {
3442 // If the activity being launched is the same as the one currently
3443 // at the top, then we need to check if it should only be launched
3444 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003445 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3446 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003447 if (top.realActivity.equals(r.realActivity)) {
3448 if (top.app != null && top.app.thread != null) {
3449 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3450 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3451 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3452 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3453 // For paranoia, make sure we have correctly
3454 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003455 if (doResume) {
3456 resumeTopActivityLocked(null);
3457 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003458 if (onlyIfNeeded) {
3459 // We don't need to start a new activity, and
3460 // the client said not to do anything if that
3461 // is the case, so this is it!
3462 return START_RETURN_INTENT_TO_CALLER;
3463 }
3464 deliverNewIntentLocked(top, r.intent);
3465 return START_DELIVERED_TO_TOP;
3466 }
3467 }
3468 }
3469 }
3470
3471 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003472 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003473 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003474 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003475 Activity.RESULT_CANCELED, null);
3476 }
3477 return START_CLASS_NOT_FOUND;
3478 }
3479
3480 boolean newTask = false;
3481
3482 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003483 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003484 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3485 // todo: should do better management of integers.
3486 mCurTask++;
3487 if (mCurTask <= 0) {
3488 mCurTask = 1;
3489 }
3490 r.task = new TaskRecord(mCurTask, r.info, intent,
3491 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3492 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3493 + " in new task " + r.task);
3494 newTask = true;
3495 addRecentTask(r.task);
3496
3497 } else if (sourceRecord != null) {
3498 if (!addingToTask &&
3499 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3500 // In this case, we are adding the activity to an existing
3501 // task, but the caller has asked to clear that task if the
3502 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003503 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003504 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003505 if (top != null) {
3506 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3507 deliverNewIntentLocked(top, r.intent);
3508 // For paranoia, make sure we have correctly
3509 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003510 if (doResume) {
3511 resumeTopActivityLocked(null);
3512 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003513 return START_DELIVERED_TO_TOP;
3514 }
3515 } else if (!addingToTask &&
3516 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3517 // In this case, we are launching an activity in our own task
3518 // that may already be running somewhere in the history, and
3519 // we want to shuffle it to the front of the stack if so.
3520 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3521 if (where >= 0) {
3522 HistoryRecord top = moveActivityToFrontLocked(where);
3523 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3524 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003525 if (doResume) {
3526 resumeTopActivityLocked(null);
3527 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003528 return START_DELIVERED_TO_TOP;
3529 }
3530 }
3531 // An existing activity is starting this new activity, so we want
3532 // to keep the new one in the same task as the one that is starting
3533 // it.
3534 r.task = sourceRecord.task;
3535 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3536 + " in existing task " + r.task);
3537
3538 } else {
3539 // This not being started from an existing activity, and not part
3540 // of a new task... just put it in the top task, though these days
3541 // this case should never happen.
3542 final int N = mHistory.size();
3543 HistoryRecord prev =
3544 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3545 r.task = prev != null
3546 ? prev.task
3547 : new TaskRecord(mCurTask, r.info, intent,
3548 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3549 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3550 + " in new guessed " + r.task);
3551 }
3552 if (newTask) {
3553 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3554 }
3555 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003556 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003557 return START_SUCCESS;
3558 }
3559
3560 public final int startActivity(IApplicationThread caller,
3561 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3562 int grantedMode, IBinder resultTo,
3563 String resultWho, int requestCode, boolean onlyIfNeeded,
3564 boolean debug) {
3565 // Refuse possible leaked file descriptors
3566 if (intent != null && intent.hasFileDescriptors()) {
3567 throw new IllegalArgumentException("File descriptors passed in Intent");
3568 }
3569
The Android Open Source Project4df24232009-03-05 14:34:35 -08003570 final boolean componentSpecified = intent.getComponent() != null;
3571
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003572 // Don't modify the client's object!
3573 intent = new Intent(intent);
3574
3575 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003576 ActivityInfo aInfo;
3577 try {
3578 ResolveInfo rInfo =
3579 ActivityThread.getPackageManager().resolveIntent(
3580 intent, resolvedType,
3581 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003582 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003583 aInfo = rInfo != null ? rInfo.activityInfo : null;
3584 } catch (RemoteException e) {
3585 aInfo = null;
3586 }
3587
3588 if (aInfo != null) {
3589 // Store the found target back into the intent, because now that
3590 // we have it we never want to do this again. For example, if the
3591 // user navigates back to this point in the history, we should
3592 // always restart the exact same activity.
3593 intent.setComponent(new ComponentName(
3594 aInfo.applicationInfo.packageName, aInfo.name));
3595
3596 // Don't debug things in the system process
3597 if (debug) {
3598 if (!aInfo.processName.equals("system")) {
3599 setDebugApp(aInfo.processName, true, false);
3600 }
3601 }
3602 }
3603
3604 synchronized(this) {
3605 final long origId = Binder.clearCallingIdentity();
3606 int res = startActivityLocked(caller, intent, resolvedType,
3607 grantedUriPermissions, grantedMode, aInfo,
3608 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003609 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003610 Binder.restoreCallingIdentity(origId);
3611 return res;
3612 }
3613 }
3614
3615 public boolean startNextMatchingActivity(IBinder callingActivity,
3616 Intent intent) {
3617 // Refuse possible leaked file descriptors
3618 if (intent != null && intent.hasFileDescriptors() == true) {
3619 throw new IllegalArgumentException("File descriptors passed in Intent");
3620 }
3621
3622 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003623 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003624 if (index < 0) {
3625 return false;
3626 }
3627 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3628 if (r.app == null || r.app.thread == null) {
3629 // The caller is not running... d'oh!
3630 return false;
3631 }
3632 intent = new Intent(intent);
3633 // The caller is not allowed to change the data.
3634 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3635 // And we are resetting to find the next component...
3636 intent.setComponent(null);
3637
3638 ActivityInfo aInfo = null;
3639 try {
3640 List<ResolveInfo> resolves =
3641 ActivityThread.getPackageManager().queryIntentActivities(
3642 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003643 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003644
3645 // Look for the original activity in the list...
3646 final int N = resolves != null ? resolves.size() : 0;
3647 for (int i=0; i<N; i++) {
3648 ResolveInfo rInfo = resolves.get(i);
3649 if (rInfo.activityInfo.packageName.equals(r.packageName)
3650 && rInfo.activityInfo.name.equals(r.info.name)) {
3651 // We found the current one... the next matching is
3652 // after it.
3653 i++;
3654 if (i<N) {
3655 aInfo = resolves.get(i).activityInfo;
3656 }
3657 break;
3658 }
3659 }
3660 } catch (RemoteException e) {
3661 }
3662
3663 if (aInfo == null) {
3664 // Nobody who is next!
3665 return false;
3666 }
3667
3668 intent.setComponent(new ComponentName(
3669 aInfo.applicationInfo.packageName, aInfo.name));
3670 intent.setFlags(intent.getFlags()&~(
3671 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3672 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3673 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3674 Intent.FLAG_ACTIVITY_NEW_TASK));
3675
3676 // Okay now we need to start the new activity, replacing the
3677 // currently running activity. This is a little tricky because
3678 // we want to start the new one as if the current one is finished,
3679 // but not finish the current one first so that there is no flicker.
3680 // And thus...
3681 final boolean wasFinishing = r.finishing;
3682 r.finishing = true;
3683
3684 // Propagate reply information over to the new activity.
3685 final HistoryRecord resultTo = r.resultTo;
3686 final String resultWho = r.resultWho;
3687 final int requestCode = r.requestCode;
3688 r.resultTo = null;
3689 if (resultTo != null) {
3690 resultTo.removeResultsLocked(r, resultWho, requestCode);
3691 }
3692
3693 final long origId = Binder.clearCallingIdentity();
3694 // XXX we are not dealing with propagating grantedUriPermissions...
3695 // those are not yet exposed to user code, so there is no need.
3696 int res = startActivityLocked(r.app.thread, intent,
3697 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003698 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003699 Binder.restoreCallingIdentity(origId);
3700
3701 r.finishing = wasFinishing;
3702 if (res != START_SUCCESS) {
3703 return false;
3704 }
3705 return true;
3706 }
3707 }
3708
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003709 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003710 Intent intent, String resolvedType, IBinder resultTo,
3711 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003712
3713 // This is so super not safe, that only the system (or okay root)
3714 // can do it.
3715 final int callingUid = Binder.getCallingUid();
3716 if (callingUid != 0 && callingUid != Process.myUid()) {
3717 throw new SecurityException(
3718 "startActivityInPackage only available to the system");
3719 }
3720
The Android Open Source Project4df24232009-03-05 14:34:35 -08003721 final boolean componentSpecified = intent.getComponent() != null;
3722
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003723 // Don't modify the client's object!
3724 intent = new Intent(intent);
3725
3726 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003727 ActivityInfo aInfo;
3728 try {
3729 ResolveInfo rInfo =
3730 ActivityThread.getPackageManager().resolveIntent(
3731 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003732 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003733 aInfo = rInfo != null ? rInfo.activityInfo : null;
3734 } catch (RemoteException e) {
3735 aInfo = null;
3736 }
3737
3738 if (aInfo != null) {
3739 // Store the found target back into the intent, because now that
3740 // we have it we never want to do this again. For example, if the
3741 // user navigates back to this point in the history, we should
3742 // always restart the exact same activity.
3743 intent.setComponent(new ComponentName(
3744 aInfo.applicationInfo.packageName, aInfo.name));
3745 }
3746
3747 synchronized(this) {
3748 return startActivityLocked(null, intent, resolvedType,
3749 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003750 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003751 }
3752 }
3753
3754 private final void addRecentTask(TaskRecord task) {
3755 // Remove any existing entries that are the same kind of task.
3756 int N = mRecentTasks.size();
3757 for (int i=0; i<N; i++) {
3758 TaskRecord tr = mRecentTasks.get(i);
3759 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3760 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3761 mRecentTasks.remove(i);
3762 i--;
3763 N--;
3764 if (task.intent == null) {
3765 // If the new recent task we are adding is not fully
3766 // specified, then replace it with the existing recent task.
3767 task = tr;
3768 }
3769 }
3770 }
3771 if (N >= MAX_RECENT_TASKS) {
3772 mRecentTasks.remove(N-1);
3773 }
3774 mRecentTasks.add(0, task);
3775 }
3776
3777 public void setRequestedOrientation(IBinder token,
3778 int requestedOrientation) {
3779 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003780 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003781 if (index < 0) {
3782 return;
3783 }
3784 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3785 final long origId = Binder.clearCallingIdentity();
3786 mWindowManager.setAppOrientation(r, requestedOrientation);
3787 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003788 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003789 r.mayFreezeScreenLocked(r.app) ? r : null);
3790 if (config != null) {
3791 r.frozenBeforeDestroy = true;
3792 if (!updateConfigurationLocked(config, r)) {
3793 resumeTopActivityLocked(null);
3794 }
3795 }
3796 Binder.restoreCallingIdentity(origId);
3797 }
3798 }
3799
3800 public int getRequestedOrientation(IBinder token) {
3801 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003802 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003803 if (index < 0) {
3804 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3805 }
3806 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3807 return mWindowManager.getAppOrientation(r);
3808 }
3809 }
3810
3811 private final void stopActivityLocked(HistoryRecord r) {
3812 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3813 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3814 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3815 if (!r.finishing) {
3816 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3817 "no-history");
3818 }
3819 } else if (r.app != null && r.app.thread != null) {
3820 if (mFocusedActivity == r) {
3821 setFocusedActivityLocked(topRunningActivityLocked(null));
3822 }
3823 r.resumeKeyDispatchingLocked();
3824 try {
3825 r.stopped = false;
3826 r.state = ActivityState.STOPPING;
3827 if (DEBUG_VISBILITY) Log.v(
3828 TAG, "Stopping visible=" + r.visible + " for " + r);
3829 if (!r.visible) {
3830 mWindowManager.setAppVisibility(r, false);
3831 }
3832 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3833 } catch (Exception e) {
3834 // Maybe just ignore exceptions here... if the process
3835 // has crashed, our death notification will clean things
3836 // up.
3837 Log.w(TAG, "Exception thrown during pause", e);
3838 // Just in case, assume it to be stopped.
3839 r.stopped = true;
3840 r.state = ActivityState.STOPPED;
3841 if (r.configDestroy) {
3842 destroyActivityLocked(r, true);
3843 }
3844 }
3845 }
3846 }
3847
3848 /**
3849 * @return Returns true if the activity is being finished, false if for
3850 * some reason it is being left as-is.
3851 */
3852 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3853 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003854 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003855 TAG, "Finishing activity: token=" + token
3856 + ", result=" + resultCode + ", data=" + resultData);
3857
Dianne Hackborn75b03852009-06-12 15:43:26 -07003858 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003859 if (index < 0) {
3860 return false;
3861 }
3862 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3863
3864 // Is this the last activity left?
3865 boolean lastActivity = true;
3866 for (int i=mHistory.size()-1; i>=0; i--) {
3867 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3868 if (!p.finishing && p != r) {
3869 lastActivity = false;
3870 break;
3871 }
3872 }
3873
3874 // If this is the last activity, but it is the home activity, then
3875 // just don't finish it.
3876 if (lastActivity) {
3877 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3878 return false;
3879 }
3880 }
3881
3882 finishActivityLocked(r, index, resultCode, resultData, reason);
3883 return true;
3884 }
3885
3886 /**
3887 * @return Returns true if this activity has been removed from the history
3888 * list, or false if it is still in the list and will be removed later.
3889 */
3890 private final boolean finishActivityLocked(HistoryRecord r, int index,
3891 int resultCode, Intent resultData, String reason) {
3892 if (r.finishing) {
3893 Log.w(TAG, "Duplicate finish request for " + r);
3894 return false;
3895 }
3896
3897 r.finishing = true;
3898 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3899 System.identityHashCode(r),
3900 r.task.taskId, r.shortComponentName, reason);
3901 r.task.numActivities--;
3902 if (r.frontOfTask && index < (mHistory.size()-1)) {
3903 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3904 if (next.task == r.task) {
3905 next.frontOfTask = true;
3906 }
3907 }
3908
3909 r.pauseKeyDispatchingLocked();
3910 if (mFocusedActivity == r) {
3911 setFocusedActivityLocked(topRunningActivityLocked(null));
3912 }
3913
3914 // send the result
3915 HistoryRecord resultTo = r.resultTo;
3916 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003917 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3918 + " who=" + r.resultWho + " req=" + r.requestCode
3919 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003920 if (r.info.applicationInfo.uid > 0) {
3921 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3922 r.packageName, resultData, r);
3923 }
3924 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3925 resultData);
3926 r.resultTo = null;
3927 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003928 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003929
3930 // Make sure this HistoryRecord is not holding on to other resources,
3931 // because clients have remote IPC references to this object so we
3932 // can't assume that will go away and want to avoid circular IPC refs.
3933 r.results = null;
3934 r.pendingResults = null;
3935 r.newIntents = null;
3936 r.icicle = null;
3937
3938 if (mPendingThumbnails.size() > 0) {
3939 // There are clients waiting to receive thumbnails so, in case
3940 // this is an activity that someone is waiting for, add it
3941 // to the pending list so we can correctly update the clients.
3942 mCancelledThumbnails.add(r);
3943 }
3944
3945 if (mResumedActivity == r) {
3946 boolean endTask = index <= 0
3947 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3948 if (DEBUG_TRANSITION) Log.v(TAG,
3949 "Prepare close transition: finishing " + r);
3950 mWindowManager.prepareAppTransition(endTask
3951 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3952 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3953
3954 // Tell window manager to prepare for this one to be removed.
3955 mWindowManager.setAppVisibility(r, false);
3956
3957 if (mPausingActivity == null) {
3958 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3959 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3960 startPausingLocked(false, false);
3961 }
3962
3963 } else if (r.state != ActivityState.PAUSING) {
3964 // If the activity is PAUSING, we will complete the finish once
3965 // it is done pausing; else we can just directly finish it here.
3966 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3967 return finishCurrentActivityLocked(r, index,
3968 FINISH_AFTER_PAUSE) == null;
3969 } else {
3970 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3971 }
3972
3973 return false;
3974 }
3975
3976 private static final int FINISH_IMMEDIATELY = 0;
3977 private static final int FINISH_AFTER_PAUSE = 1;
3978 private static final int FINISH_AFTER_VISIBLE = 2;
3979
3980 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3981 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003982 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003983 if (index < 0) {
3984 return null;
3985 }
3986
3987 return finishCurrentActivityLocked(r, index, mode);
3988 }
3989
3990 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3991 int index, int mode) {
3992 // First things first: if this activity is currently visible,
3993 // and the resumed activity is not yet visible, then hold off on
3994 // finishing until the resumed one becomes visible.
3995 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3996 if (!mStoppingActivities.contains(r)) {
3997 mStoppingActivities.add(r);
3998 if (mStoppingActivities.size() > 3) {
3999 // If we already have a few activities waiting to stop,
4000 // then give up on things going idle and start clearing
4001 // them out.
4002 Message msg = Message.obtain();
4003 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4004 mHandler.sendMessage(msg);
4005 }
4006 }
4007 r.state = ActivityState.STOPPING;
4008 updateOomAdjLocked();
4009 return r;
4010 }
4011
4012 // make sure the record is cleaned out of other places.
4013 mStoppingActivities.remove(r);
4014 mWaitingVisibleActivities.remove(r);
4015 if (mResumedActivity == r) {
4016 mResumedActivity = null;
4017 }
4018 final ActivityState prevState = r.state;
4019 r.state = ActivityState.FINISHING;
4020
4021 if (mode == FINISH_IMMEDIATELY
4022 || prevState == ActivityState.STOPPED
4023 || prevState == ActivityState.INITIALIZING) {
4024 // If this activity is already stopped, we can just finish
4025 // it right now.
4026 return destroyActivityLocked(r, true) ? null : r;
4027 } else {
4028 // Need to go through the full pause cycle to get this
4029 // activity into the stopped state and then finish it.
4030 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4031 mFinishingActivities.add(r);
4032 resumeTopActivityLocked(null);
4033 }
4034 return r;
4035 }
4036
4037 /**
4038 * This is the internal entry point for handling Activity.finish().
4039 *
4040 * @param token The Binder token referencing the Activity we want to finish.
4041 * @param resultCode Result code, if any, from this Activity.
4042 * @param resultData Result data (Intent), if any, from this Activity.
4043 *
4044 * @result Returns true if the activity successfully finished, or false if it is still running.
4045 */
4046 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4047 // Refuse possible leaked file descriptors
4048 if (resultData != null && resultData.hasFileDescriptors() == true) {
4049 throw new IllegalArgumentException("File descriptors passed in Intent");
4050 }
4051
4052 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004053 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004054 // Find the first activity that is not finishing.
4055 HistoryRecord next = topRunningActivityLocked(token, 0);
4056 if (next != null) {
4057 // ask watcher if this is allowed
4058 boolean resumeOK = true;
4059 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004060 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004061 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004062 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004063 }
4064
4065 if (!resumeOK) {
4066 return false;
4067 }
4068 }
4069 }
4070 final long origId = Binder.clearCallingIdentity();
4071 boolean res = requestFinishActivityLocked(token, resultCode,
4072 resultData, "app-request");
4073 Binder.restoreCallingIdentity(origId);
4074 return res;
4075 }
4076 }
4077
4078 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4079 String resultWho, int requestCode, int resultCode, Intent data) {
4080
4081 if (callingUid > 0) {
4082 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4083 data, r);
4084 }
4085
The Android Open Source Project10592532009-03-18 17:39:46 -07004086 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4087 + " : who=" + resultWho + " req=" + requestCode
4088 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004089 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4090 try {
4091 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4092 list.add(new ResultInfo(resultWho, requestCode,
4093 resultCode, data));
4094 r.app.thread.scheduleSendResult(r, list);
4095 return;
4096 } catch (Exception e) {
4097 Log.w(TAG, "Exception thrown sending result to " + r, e);
4098 }
4099 }
4100
4101 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4102 }
4103
4104 public final void finishSubActivity(IBinder token, String resultWho,
4105 int requestCode) {
4106 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004107 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004108 if (index < 0) {
4109 return;
4110 }
4111 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4112
4113 final long origId = Binder.clearCallingIdentity();
4114
4115 int i;
4116 for (i=mHistory.size()-1; i>=0; i--) {
4117 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4118 if (r.resultTo == self && r.requestCode == requestCode) {
4119 if ((r.resultWho == null && resultWho == null) ||
4120 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4121 finishActivityLocked(r, i,
4122 Activity.RESULT_CANCELED, null, "request-sub");
4123 }
4124 }
4125 }
4126
4127 Binder.restoreCallingIdentity(origId);
4128 }
4129 }
4130
4131 /**
4132 * Perform clean-up of service connections in an activity record.
4133 */
4134 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4135 // Throw away any services that have been bound by this activity.
4136 if (r.connections != null) {
4137 Iterator<ConnectionRecord> it = r.connections.iterator();
4138 while (it.hasNext()) {
4139 ConnectionRecord c = it.next();
4140 removeConnectionLocked(c, null, r);
4141 }
4142 r.connections = null;
4143 }
4144 }
4145
4146 /**
4147 * Perform the common clean-up of an activity record. This is called both
4148 * as part of destroyActivityLocked() (when destroying the client-side
4149 * representation) and cleaning things up as a result of its hosting
4150 * processing going away, in which case there is no remaining client-side
4151 * state to destroy so only the cleanup here is needed.
4152 */
4153 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4154 if (mResumedActivity == r) {
4155 mResumedActivity = null;
4156 }
4157 if (mFocusedActivity == r) {
4158 mFocusedActivity = null;
4159 }
4160
4161 r.configDestroy = false;
4162 r.frozenBeforeDestroy = false;
4163
4164 // Make sure this record is no longer in the pending finishes list.
4165 // This could happen, for example, if we are trimming activities
4166 // down to the max limit while they are still waiting to finish.
4167 mFinishingActivities.remove(r);
4168 mWaitingVisibleActivities.remove(r);
4169
4170 // Remove any pending results.
4171 if (r.finishing && r.pendingResults != null) {
4172 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4173 PendingIntentRecord rec = apr.get();
4174 if (rec != null) {
4175 cancelIntentSenderLocked(rec, false);
4176 }
4177 }
4178 r.pendingResults = null;
4179 }
4180
4181 if (cleanServices) {
4182 cleanUpActivityServicesLocked(r);
4183 }
4184
4185 if (mPendingThumbnails.size() > 0) {
4186 // There are clients waiting to receive thumbnails so, in case
4187 // this is an activity that someone is waiting for, add it
4188 // to the pending list so we can correctly update the clients.
4189 mCancelledThumbnails.add(r);
4190 }
4191
4192 // Get rid of any pending idle timeouts.
4193 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4194 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4195 }
4196
4197 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4198 if (r.state != ActivityState.DESTROYED) {
4199 mHistory.remove(r);
4200 r.inHistory = false;
4201 r.state = ActivityState.DESTROYED;
4202 mWindowManager.removeAppToken(r);
4203 if (VALIDATE_TOKENS) {
4204 mWindowManager.validateAppTokens(mHistory);
4205 }
4206 cleanUpActivityServicesLocked(r);
4207 removeActivityUriPermissionsLocked(r);
4208 }
4209 }
4210
4211 /**
4212 * Destroy the current CLIENT SIDE instance of an activity. This may be
4213 * called both when actually finishing an activity, or when performing
4214 * a configuration switch where we destroy the current client-side object
4215 * but then create a new client-side object for this same HistoryRecord.
4216 */
4217 private final boolean destroyActivityLocked(HistoryRecord r,
4218 boolean removeFromApp) {
4219 if (DEBUG_SWITCH) Log.v(
4220 TAG, "Removing activity: token=" + r
4221 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4222 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4223 System.identityHashCode(r),
4224 r.task.taskId, r.shortComponentName);
4225
4226 boolean removedFromHistory = false;
4227
4228 cleanUpActivityLocked(r, false);
4229
4230 if (r.app != null) {
4231 if (removeFromApp) {
4232 int idx = r.app.activities.indexOf(r);
4233 if (idx >= 0) {
4234 r.app.activities.remove(idx);
4235 }
4236 if (r.persistent) {
4237 decPersistentCountLocked(r.app);
4238 }
4239 }
4240
4241 boolean skipDestroy = false;
4242
4243 try {
4244 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4245 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4246 r.configChangeFlags);
4247 } catch (Exception e) {
4248 // We can just ignore exceptions here... if the process
4249 // has crashed, our death notification will clean things
4250 // up.
4251 //Log.w(TAG, "Exception thrown during finish", e);
4252 if (r.finishing) {
4253 removeActivityFromHistoryLocked(r);
4254 removedFromHistory = true;
4255 skipDestroy = true;
4256 }
4257 }
4258
4259 r.app = null;
4260 r.nowVisible = false;
4261
4262 if (r.finishing && !skipDestroy) {
4263 r.state = ActivityState.DESTROYING;
4264 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4265 msg.obj = r;
4266 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4267 } else {
4268 r.state = ActivityState.DESTROYED;
4269 }
4270 } else {
4271 // remove this record from the history.
4272 if (r.finishing) {
4273 removeActivityFromHistoryLocked(r);
4274 removedFromHistory = true;
4275 } else {
4276 r.state = ActivityState.DESTROYED;
4277 }
4278 }
4279
4280 r.configChangeFlags = 0;
4281
4282 if (!mLRUActivities.remove(r)) {
4283 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4284 }
4285
4286 return removedFromHistory;
4287 }
4288
4289 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4290 ProcessRecord app)
4291 {
4292 int i = list.size();
4293 if (localLOGV) Log.v(
4294 TAG, "Removing app " + app + " from list " + list
4295 + " with " + i + " entries");
4296 while (i > 0) {
4297 i--;
4298 HistoryRecord r = (HistoryRecord)list.get(i);
4299 if (localLOGV) Log.v(
4300 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4301 if (r.app == app) {
4302 if (localLOGV) Log.v(TAG, "Removing this entry!");
4303 list.remove(i);
4304 }
4305 }
4306 }
4307
4308 /**
4309 * Main function for removing an existing process from the activity manager
4310 * as a result of that process going away. Clears out all connections
4311 * to the process.
4312 */
4313 private final void handleAppDiedLocked(ProcessRecord app,
4314 boolean restarting) {
4315 cleanUpApplicationRecordLocked(app, restarting, -1);
4316 if (!restarting) {
4317 mLRUProcesses.remove(app);
4318 }
4319
4320 // Just in case...
4321 if (mPausingActivity != null && mPausingActivity.app == app) {
4322 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4323 mPausingActivity = null;
4324 }
4325 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4326 mLastPausedActivity = null;
4327 }
4328
4329 // Remove this application's activities from active lists.
4330 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4331 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4332 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4333 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4334
4335 boolean atTop = true;
4336 boolean hasVisibleActivities = false;
4337
4338 // Clean out the history list.
4339 int i = mHistory.size();
4340 if (localLOGV) Log.v(
4341 TAG, "Removing app " + app + " from history with " + i + " entries");
4342 while (i > 0) {
4343 i--;
4344 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4345 if (localLOGV) Log.v(
4346 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4347 if (r.app == app) {
4348 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4349 if (localLOGV) Log.v(
4350 TAG, "Removing this entry! frozen=" + r.haveState
4351 + " finishing=" + r.finishing);
4352 mHistory.remove(i);
4353
4354 r.inHistory = false;
4355 mWindowManager.removeAppToken(r);
4356 if (VALIDATE_TOKENS) {
4357 mWindowManager.validateAppTokens(mHistory);
4358 }
4359 removeActivityUriPermissionsLocked(r);
4360
4361 } else {
4362 // We have the current state for this activity, so
4363 // it can be restarted later when needed.
4364 if (localLOGV) Log.v(
4365 TAG, "Keeping entry, setting app to null");
4366 if (r.visible) {
4367 hasVisibleActivities = true;
4368 }
4369 r.app = null;
4370 r.nowVisible = false;
4371 if (!r.haveState) {
4372 r.icicle = null;
4373 }
4374 }
4375
4376 cleanUpActivityLocked(r, true);
4377 r.state = ActivityState.STOPPED;
4378 }
4379 atTop = false;
4380 }
4381
4382 app.activities.clear();
4383
4384 if (app.instrumentationClass != null) {
4385 Log.w(TAG, "Crash of app " + app.processName
4386 + " running instrumentation " + app.instrumentationClass);
4387 Bundle info = new Bundle();
4388 info.putString("shortMsg", "Process crashed.");
4389 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4390 }
4391
4392 if (!restarting) {
4393 if (!resumeTopActivityLocked(null)) {
4394 // If there was nothing to resume, and we are not already
4395 // restarting this process, but there is a visible activity that
4396 // is hosted by the process... then make sure all visible
4397 // activities are running, taking care of restarting this
4398 // process.
4399 if (hasVisibleActivities) {
4400 ensureActivitiesVisibleLocked(null, 0);
4401 }
4402 }
4403 }
4404 }
4405
4406 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4407 IBinder threadBinder = thread.asBinder();
4408
4409 // Find the application record.
4410 int count = mLRUProcesses.size();
4411 int i;
4412 for (i=0; i<count; i++) {
4413 ProcessRecord rec = mLRUProcesses.get(i);
4414 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4415 return i;
4416 }
4417 }
4418 return -1;
4419 }
4420
4421 private final ProcessRecord getRecordForAppLocked(
4422 IApplicationThread thread) {
4423 if (thread == null) {
4424 return null;
4425 }
4426
4427 int appIndex = getLRURecordIndexForAppLocked(thread);
4428 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4429 }
4430
4431 private final void appDiedLocked(ProcessRecord app, int pid,
4432 IApplicationThread thread) {
4433
4434 mProcDeaths[0]++;
4435
4436 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4437 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4438 + ") has died.");
4439 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4440 if (localLOGV) Log.v(
4441 TAG, "Dying app: " + app + ", pid: " + pid
4442 + ", thread: " + thread.asBinder());
4443 boolean doLowMem = app.instrumentationClass == null;
4444 handleAppDiedLocked(app, false);
4445
4446 if (doLowMem) {
4447 // If there are no longer any background processes running,
4448 // and the app that died was not running instrumentation,
4449 // then tell everyone we are now low on memory.
4450 boolean haveBg = false;
4451 int count = mLRUProcesses.size();
4452 int i;
4453 for (i=0; i<count; i++) {
4454 ProcessRecord rec = mLRUProcesses.get(i);
4455 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4456 haveBg = true;
4457 break;
4458 }
4459 }
4460
4461 if (!haveBg) {
4462 Log.i(TAG, "Low Memory: No more background processes.");
4463 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004464 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004465 for (i=0; i<count; i++) {
4466 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004467 if (rec.thread != null &&
4468 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4469 // The low memory report is overriding any current
4470 // state for a GC request. Make sure to do
4471 // visible/foreground processes first.
4472 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4473 rec.lastRequestedGc = 0;
4474 } else {
4475 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004476 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004477 rec.reportLowMemory = true;
4478 rec.lastLowMemory = now;
4479 mProcessesToGc.remove(rec);
4480 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004481 }
4482 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004483 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004484 }
4485 }
4486 } else if (Config.LOGD) {
4487 Log.d(TAG, "Received spurious death notification for thread "
4488 + thread.asBinder());
4489 }
4490 }
4491
4492 final String readFile(String filename) {
4493 try {
4494 FileInputStream fs = new FileInputStream(filename);
4495 byte[] inp = new byte[8192];
4496 int size = fs.read(inp);
4497 fs.close();
4498 return new String(inp, 0, 0, size);
4499 } catch (java.io.IOException e) {
4500 }
4501 return "";
4502 }
4503
4504 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004505 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004506 if (app.notResponding || app.crashing) {
4507 return;
4508 }
4509
4510 // Log the ANR to the event log.
4511 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4512
4513 // If we are on a secure build and the application is not interesting to the user (it is
4514 // not visible or in the background), just kill it instead of displaying a dialog.
4515 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4516 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4517 Process.killProcess(app.pid);
4518 return;
4519 }
4520
4521 // DeviceMonitor.start();
4522
4523 String processInfo = null;
4524 if (MONITOR_CPU_USAGE) {
4525 updateCpuStatsNow();
4526 synchronized (mProcessStatsThread) {
4527 processInfo = mProcessStats.printCurrentState();
4528 }
4529 }
4530
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004531 StringBuilder info = mStringBuilder;
4532 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004533 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004534 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004535 if (reportedActivity != null && reportedActivity.app != null) {
4536 info.append(" (last in ");
4537 info.append(reportedActivity.app.processName);
4538 info.append(")");
4539 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004540 if (annotation != null) {
4541 info.append("\nAnnotation: ");
4542 info.append(annotation);
4543 }
4544 if (MONITOR_CPU_USAGE) {
4545 info.append("\nCPU usage:\n");
4546 info.append(processInfo);
4547 }
4548 Log.i(TAG, info.toString());
4549
4550 // The application is not responding. Dump as many thread traces as we can.
4551 boolean fileDump = prepareTraceFile(true);
4552 if (!fileDump) {
4553 // Dumping traces to the log, just dump the process that isn't responding so
4554 // we don't overflow the log
4555 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4556 } else {
4557 // Dumping traces to a file so dump all active processes we know about
4558 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004559 // First, these are the most important processes.
4560 final int[] imppids = new int[3];
4561 int i=0;
4562 imppids[0] = app.pid;
4563 i++;
4564 if (reportedActivity != null && reportedActivity.app != null
4565 && reportedActivity.app.thread != null
4566 && reportedActivity.app.pid != app.pid) {
4567 imppids[i] = reportedActivity.app.pid;
4568 i++;
4569 }
4570 imppids[i] = Process.myPid();
4571 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4572 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4573 synchronized (this) {
4574 try {
4575 wait(200);
4576 } catch (InterruptedException e) {
4577 }
4578 }
4579 }
4580 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004581 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004582 boolean done = false;
4583 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4584 if (imppids[j] == r.pid) {
4585 done = true;
4586 break;
4587 }
4588 }
4589 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004590 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004591 synchronized (this) {
4592 try {
4593 wait(200);
4594 } catch (InterruptedException e) {
4595 }
4596 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004597 }
4598 }
4599 }
4600 }
4601
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004602 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004603 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004604 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004605 app.pid, info.toString());
4606 if (res != 0) {
4607 if (res < 0) {
4608 // wait until the SIGQUIT has had a chance to process before killing the
4609 // process.
4610 try {
4611 wait(2000);
4612 } catch (InterruptedException e) {
4613 }
4614
4615 Process.killProcess(app.pid);
4616 return;
4617 }
4618 }
4619 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004620 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004621 }
4622 }
4623
4624 makeAppNotRespondingLocked(app,
4625 activity != null ? activity.shortComponentName : null,
4626 annotation != null ? "ANR " + annotation : "ANR",
4627 info.toString(), null);
4628 Message msg = Message.obtain();
4629 HashMap map = new HashMap();
4630 msg.what = SHOW_NOT_RESPONDING_MSG;
4631 msg.obj = map;
4632 map.put("app", app);
4633 if (activity != null) {
4634 map.put("activity", activity);
4635 }
4636
4637 mHandler.sendMessage(msg);
4638 return;
4639 }
4640
4641 /**
4642 * If a stack trace file has been configured, prepare the filesystem
4643 * by creating the directory if it doesn't exist and optionally
4644 * removing the old trace file.
4645 *
4646 * @param removeExisting If set, the existing trace file will be removed.
4647 * @return Returns true if the trace file preparations succeeded
4648 */
4649 public static boolean prepareTraceFile(boolean removeExisting) {
4650 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4651 boolean fileReady = false;
4652 if (!TextUtils.isEmpty(tracesPath)) {
4653 File f = new File(tracesPath);
4654 if (!f.exists()) {
4655 // Ensure the enclosing directory exists
4656 File dir = f.getParentFile();
4657 if (!dir.exists()) {
4658 fileReady = dir.mkdirs();
4659 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004660 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004661 } else if (dir.isDirectory()) {
4662 fileReady = true;
4663 }
4664 } else if (removeExisting) {
4665 // Remove the previous traces file, so we don't fill the disk.
4666 // The VM will recreate it
4667 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4668 fileReady = f.delete();
4669 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004670
4671 if (removeExisting) {
4672 try {
4673 f.createNewFile();
4674 FileUtils.setPermissions(f.getAbsolutePath(),
4675 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4676 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4677 fileReady = true;
4678 } catch (IOException e) {
4679 Log.w(TAG, "Unable to make ANR traces file", e);
4680 }
4681 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004682 }
4683
4684 return fileReady;
4685 }
4686
4687
4688 private final void decPersistentCountLocked(ProcessRecord app)
4689 {
4690 app.persistentActivities--;
4691 if (app.persistentActivities > 0) {
4692 // Still more of 'em...
4693 return;
4694 }
4695 if (app.persistent) {
4696 // Ah, but the application itself is persistent. Whatever!
4697 return;
4698 }
4699
4700 // App is no longer persistent... make sure it and the ones
4701 // following it in the LRU list have the correc oom_adj.
4702 updateOomAdjLocked();
4703 }
4704
4705 public void setPersistent(IBinder token, boolean isPersistent) {
4706 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4707 != PackageManager.PERMISSION_GRANTED) {
4708 String msg = "Permission Denial: setPersistent() from pid="
4709 + Binder.getCallingPid()
4710 + ", uid=" + Binder.getCallingUid()
4711 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4712 Log.w(TAG, msg);
4713 throw new SecurityException(msg);
4714 }
4715
4716 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004717 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004718 if (index < 0) {
4719 return;
4720 }
4721 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4722 ProcessRecord app = r.app;
4723
4724 if (localLOGV) Log.v(
4725 TAG, "Setting persistence " + isPersistent + ": " + r);
4726
4727 if (isPersistent) {
4728 if (r.persistent) {
4729 // Okay okay, I heard you already!
4730 if (localLOGV) Log.v(TAG, "Already persistent!");
4731 return;
4732 }
4733 r.persistent = true;
4734 app.persistentActivities++;
4735 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4736 if (app.persistentActivities > 1) {
4737 // We aren't the first...
4738 if (localLOGV) Log.v(TAG, "Not the first!");
4739 return;
4740 }
4741 if (app.persistent) {
4742 // This would be redundant.
4743 if (localLOGV) Log.v(TAG, "App is persistent!");
4744 return;
4745 }
4746
4747 // App is now persistent... make sure it and the ones
4748 // following it now have the correct oom_adj.
4749 final long origId = Binder.clearCallingIdentity();
4750 updateOomAdjLocked();
4751 Binder.restoreCallingIdentity(origId);
4752
4753 } else {
4754 if (!r.persistent) {
4755 // Okay okay, I heard you already!
4756 return;
4757 }
4758 r.persistent = false;
4759 final long origId = Binder.clearCallingIdentity();
4760 decPersistentCountLocked(app);
4761 Binder.restoreCallingIdentity(origId);
4762
4763 }
4764 }
4765 }
4766
4767 public boolean clearApplicationUserData(final String packageName,
4768 final IPackageDataObserver observer) {
4769 int uid = Binder.getCallingUid();
4770 int pid = Binder.getCallingPid();
4771 long callingId = Binder.clearCallingIdentity();
4772 try {
4773 IPackageManager pm = ActivityThread.getPackageManager();
4774 int pkgUid = -1;
4775 synchronized(this) {
4776 try {
4777 pkgUid = pm.getPackageUid(packageName);
4778 } catch (RemoteException e) {
4779 }
4780 if (pkgUid == -1) {
4781 Log.w(TAG, "Invalid packageName:" + packageName);
4782 return false;
4783 }
4784 if (uid == pkgUid || checkComponentPermission(
4785 android.Manifest.permission.CLEAR_APP_USER_DATA,
4786 pid, uid, -1)
4787 == PackageManager.PERMISSION_GRANTED) {
4788 restartPackageLocked(packageName, pkgUid);
4789 } else {
4790 throw new SecurityException(pid+" does not have permission:"+
4791 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4792 "for process:"+packageName);
4793 }
4794 }
4795
4796 try {
4797 //clear application user data
4798 pm.clearApplicationUserData(packageName, observer);
4799 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4800 Uri.fromParts("package", packageName, null));
4801 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4802 broadcastIntentLocked(null, null, intent,
4803 null, null, 0, null, null, null,
4804 false, false, MY_PID, Process.SYSTEM_UID);
4805 } catch (RemoteException e) {
4806 }
4807 } finally {
4808 Binder.restoreCallingIdentity(callingId);
4809 }
4810 return true;
4811 }
4812
4813 public void restartPackage(final String packageName) {
4814 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4815 != PackageManager.PERMISSION_GRANTED) {
4816 String msg = "Permission Denial: restartPackage() from pid="
4817 + Binder.getCallingPid()
4818 + ", uid=" + Binder.getCallingUid()
4819 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4820 Log.w(TAG, msg);
4821 throw new SecurityException(msg);
4822 }
4823
4824 long callingId = Binder.clearCallingIdentity();
4825 try {
4826 IPackageManager pm = ActivityThread.getPackageManager();
4827 int pkgUid = -1;
4828 synchronized(this) {
4829 try {
4830 pkgUid = pm.getPackageUid(packageName);
4831 } catch (RemoteException e) {
4832 }
4833 if (pkgUid == -1) {
4834 Log.w(TAG, "Invalid packageName: " + packageName);
4835 return;
4836 }
4837 restartPackageLocked(packageName, pkgUid);
4838 }
4839 } finally {
4840 Binder.restoreCallingIdentity(callingId);
4841 }
4842 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004843
4844 /*
4845 * The pkg name and uid have to be specified.
4846 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4847 */
4848 public void killApplicationWithUid(String pkg, int uid) {
4849 if (pkg == null) {
4850 return;
4851 }
4852 // Make sure the uid is valid.
4853 if (uid < 0) {
4854 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4855 return;
4856 }
4857 int callerUid = Binder.getCallingUid();
4858 // Only the system server can kill an application
4859 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004860 // Post an aysnc message to kill the application
4861 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4862 msg.arg1 = uid;
4863 msg.arg2 = 0;
4864 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004865 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004866 } else {
4867 throw new SecurityException(callerUid + " cannot kill pkg: " +
4868 pkg);
4869 }
4870 }
4871
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004872 public void closeSystemDialogs(String reason) {
4873 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4874 if (reason != null) {
4875 intent.putExtra("reason", reason);
4876 }
4877
4878 final int uid = Binder.getCallingUid();
4879 final long origId = Binder.clearCallingIdentity();
4880 synchronized (this) {
4881 int i = mWatchers.beginBroadcast();
4882 while (i > 0) {
4883 i--;
4884 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4885 if (w != null) {
4886 try {
4887 w.closingSystemDialogs(reason);
4888 } catch (RemoteException e) {
4889 }
4890 }
4891 }
4892 mWatchers.finishBroadcast();
4893
4894 broadcastIntentLocked(null, null, intent, null,
4895 null, 0, null, null, null, false, false, -1, uid);
4896 }
4897 Binder.restoreCallingIdentity(origId);
4898 }
4899
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004900 public void getProcessMemoryInfo(int pid, Debug.MemoryInfo mi)
4901 throws RemoteException {
4902 ProcessRecord proc;
4903 synchronized (mPidsSelfLocked) {
4904 proc = mPidsSelfLocked.get(pid);
4905 }
4906
4907 if (proc == null) {
4908 throw new RemoteException();
4909 }
4910
4911 IApplicationThread thread = proc.thread;
4912 if (thread == null) {
4913 throw new RemoteException();
4914 }
4915
4916 thread.getMemoryInfo(mi);
4917 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07004918
4919 public void killApplicationProcess(String processName, int uid) {
4920 if (processName == null) {
4921 return;
4922 }
4923
4924 int callerUid = Binder.getCallingUid();
4925 // Only the system server can kill an application
4926 if (callerUid == Process.SYSTEM_UID) {
4927 synchronized (this) {
4928 ProcessRecord app = getProcessRecordLocked(processName, uid);
4929 if (app != null) {
4930 try {
4931 app.thread.scheduleSuicide();
4932 } catch (RemoteException e) {
4933 // If the other end already died, then our work here is done.
4934 }
4935 } else {
4936 Log.w(TAG, "Process/uid not found attempting kill of "
4937 + processName + " / " + uid);
4938 }
4939 }
4940 } else {
4941 throw new SecurityException(callerUid + " cannot kill app process: " +
4942 processName);
4943 }
4944 }
4945
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004946 private void restartPackageLocked(final String packageName, int uid) {
4947 uninstallPackageLocked(packageName, uid, false);
4948 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4949 Uri.fromParts("package", packageName, null));
4950 intent.putExtra(Intent.EXTRA_UID, uid);
4951 broadcastIntentLocked(null, null, intent,
4952 null, null, 0, null, null, null,
4953 false, false, MY_PID, Process.SYSTEM_UID);
4954 }
4955
4956 private final void uninstallPackageLocked(String name, int uid,
4957 boolean callerWillRestart) {
4958 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4959
4960 int i, N;
4961
4962 final String procNamePrefix = name + ":";
4963 if (uid < 0) {
4964 try {
4965 uid = ActivityThread.getPackageManager().getPackageUid(name);
4966 } catch (RemoteException e) {
4967 }
4968 }
4969
4970 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4971 while (badApps.hasNext()) {
4972 SparseArray<Long> ba = badApps.next();
4973 if (ba.get(uid) != null) {
4974 badApps.remove();
4975 }
4976 }
4977
4978 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4979
4980 // Remove all processes this package may have touched: all with the
4981 // same UID (except for the system or root user), and all whose name
4982 // matches the package name.
4983 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4984 final int NA = apps.size();
4985 for (int ia=0; ia<NA; ia++) {
4986 ProcessRecord app = apps.valueAt(ia);
4987 if (app.removed) {
4988 procs.add(app);
4989 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4990 || app.processName.equals(name)
4991 || app.processName.startsWith(procNamePrefix)) {
4992 app.removed = true;
4993 procs.add(app);
4994 }
4995 }
4996 }
4997
4998 N = procs.size();
4999 for (i=0; i<N; i++) {
5000 removeProcessLocked(procs.get(i), callerWillRestart);
5001 }
5002
5003 for (i=mHistory.size()-1; i>=0; i--) {
5004 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5005 if (r.packageName.equals(name)) {
5006 if (Config.LOGD) Log.d(
5007 TAG, " Force finishing activity "
5008 + r.intent.getComponent().flattenToShortString());
5009 if (r.app != null) {
5010 r.app.removed = true;
5011 }
5012 r.app = null;
5013 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5014 }
5015 }
5016
5017 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5018 for (ServiceRecord service : mServices.values()) {
5019 if (service.packageName.equals(name)) {
5020 if (service.app != null) {
5021 service.app.removed = true;
5022 }
5023 service.app = null;
5024 services.add(service);
5025 }
5026 }
5027
5028 N = services.size();
5029 for (i=0; i<N; i++) {
5030 bringDownServiceLocked(services.get(i), true);
5031 }
5032
5033 resumeTopActivityLocked(null);
5034 }
5035
5036 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5037 final String name = app.processName;
5038 final int uid = app.info.uid;
5039 if (Config.LOGD) Log.d(
5040 TAG, "Force removing process " + app + " (" + name
5041 + "/" + uid + ")");
5042
5043 mProcessNames.remove(name, uid);
5044 boolean needRestart = false;
5045 if (app.pid > 0 && app.pid != MY_PID) {
5046 int pid = app.pid;
5047 synchronized (mPidsSelfLocked) {
5048 mPidsSelfLocked.remove(pid);
5049 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5050 }
5051 handleAppDiedLocked(app, true);
5052 mLRUProcesses.remove(app);
5053 Process.killProcess(pid);
5054
5055 if (app.persistent) {
5056 if (!callerWillRestart) {
5057 addAppLocked(app.info);
5058 } else {
5059 needRestart = true;
5060 }
5061 }
5062 } else {
5063 mRemovedProcesses.add(app);
5064 }
5065
5066 return needRestart;
5067 }
5068
5069 private final void processStartTimedOutLocked(ProcessRecord app) {
5070 final int pid = app.pid;
5071 boolean gone = false;
5072 synchronized (mPidsSelfLocked) {
5073 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5074 if (knownApp != null && knownApp.thread == null) {
5075 mPidsSelfLocked.remove(pid);
5076 gone = true;
5077 }
5078 }
5079
5080 if (gone) {
5081 Log.w(TAG, "Process " + app + " failed to attach");
5082 mProcessNames.remove(app.processName, app.info.uid);
5083 Process.killProcess(pid);
5084 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5085 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5086 mPendingBroadcast = null;
5087 scheduleBroadcastsLocked();
5088 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005089 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5090 Log.w(TAG, "Unattached app died before backup, skipping");
5091 try {
5092 IBackupManager bm = IBackupManager.Stub.asInterface(
5093 ServiceManager.getService(Context.BACKUP_SERVICE));
5094 bm.agentDisconnected(app.info.packageName);
5095 } catch (RemoteException e) {
5096 // Can't happen; the backup manager is local
5097 }
5098 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005099 } else {
5100 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5101 }
5102 }
5103
5104 private final boolean attachApplicationLocked(IApplicationThread thread,
5105 int pid) {
5106
5107 // Find the application record that is being attached... either via
5108 // the pid if we are running in multiple processes, or just pull the
5109 // next app record if we are emulating process with anonymous threads.
5110 ProcessRecord app;
5111 if (pid != MY_PID && pid >= 0) {
5112 synchronized (mPidsSelfLocked) {
5113 app = mPidsSelfLocked.get(pid);
5114 }
5115 } else if (mStartingProcesses.size() > 0) {
5116 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005117 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005118 } else {
5119 app = null;
5120 }
5121
5122 if (app == null) {
5123 Log.w(TAG, "No pending application record for pid " + pid
5124 + " (IApplicationThread " + thread + "); dropping process");
5125 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5126 if (pid > 0 && pid != MY_PID) {
5127 Process.killProcess(pid);
5128 } else {
5129 try {
5130 thread.scheduleExit();
5131 } catch (Exception e) {
5132 // Ignore exceptions.
5133 }
5134 }
5135 return false;
5136 }
5137
5138 // If this application record is still attached to a previous
5139 // process, clean it up now.
5140 if (app.thread != null) {
5141 handleAppDiedLocked(app, true);
5142 }
5143
5144 // Tell the process all about itself.
5145
5146 if (localLOGV) Log.v(
5147 TAG, "Binding process pid " + pid + " to record " + app);
5148
5149 String processName = app.processName;
5150 try {
5151 thread.asBinder().linkToDeath(new AppDeathRecipient(
5152 app, pid, thread), 0);
5153 } catch (RemoteException e) {
5154 app.resetPackageList();
5155 startProcessLocked(app, "link fail", processName);
5156 return false;
5157 }
5158
5159 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5160
5161 app.thread = thread;
5162 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005163 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005164 app.forcingToForeground = null;
5165 app.foregroundServices = false;
5166 app.debugging = false;
5167
5168 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5169
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005170 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5171 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005172
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005173 if (!normalMode) {
5174 Log.i(TAG, "Launching preboot mode app: " + app);
5175 }
5176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005177 if (localLOGV) Log.v(
5178 TAG, "New app record " + app
5179 + " thread=" + thread.asBinder() + " pid=" + pid);
5180 try {
5181 int testMode = IApplicationThread.DEBUG_OFF;
5182 if (mDebugApp != null && mDebugApp.equals(processName)) {
5183 testMode = mWaitForDebugger
5184 ? IApplicationThread.DEBUG_WAIT
5185 : IApplicationThread.DEBUG_ON;
5186 app.debugging = true;
5187 if (mDebugTransient) {
5188 mDebugApp = mOrigDebugApp;
5189 mWaitForDebugger = mOrigWaitForDebugger;
5190 }
5191 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005192
Christopher Tate181fafa2009-05-14 11:12:14 -07005193 // If the app is being launched for restore or full backup, set it up specially
5194 boolean isRestrictedBackupMode = false;
5195 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5196 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5197 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5198 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005199
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005200 ensurePackageDexOpt(app.instrumentationInfo != null
5201 ? app.instrumentationInfo.packageName
5202 : app.info.packageName);
5203 if (app.instrumentationClass != null) {
5204 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005205 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07005206 thread.bindApplication(processName, app.instrumentationInfo != null
5207 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005208 app.instrumentationClass, app.instrumentationProfileFile,
5209 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005210 isRestrictedBackupMode || !normalMode,
5211 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005212 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005213 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005214 } catch (Exception e) {
5215 // todo: Yikes! What should we do? For now we will try to
5216 // start another process, but that could easily get us in
5217 // an infinite loop of restarting processes...
5218 Log.w(TAG, "Exception thrown during bind!", e);
5219
5220 app.resetPackageList();
5221 startProcessLocked(app, "bind fail", processName);
5222 return false;
5223 }
5224
5225 // Remove this record from the list of starting applications.
5226 mPersistentStartingProcesses.remove(app);
5227 mProcessesOnHold.remove(app);
5228
5229 boolean badApp = false;
5230 boolean didSomething = false;
5231
5232 // See if the top visible activity is waiting to run in this process...
5233 HistoryRecord hr = topRunningActivityLocked(null);
5234 if (hr != null) {
5235 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5236 && processName.equals(hr.processName)) {
5237 try {
5238 if (realStartActivityLocked(hr, app, true, true)) {
5239 didSomething = true;
5240 }
5241 } catch (Exception e) {
5242 Log.w(TAG, "Exception in new application when starting activity "
5243 + hr.intent.getComponent().flattenToShortString(), e);
5244 badApp = true;
5245 }
5246 } else {
5247 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5248 }
5249 }
5250
5251 // Find any services that should be running in this process...
5252 if (!badApp && mPendingServices.size() > 0) {
5253 ServiceRecord sr = null;
5254 try {
5255 for (int i=0; i<mPendingServices.size(); i++) {
5256 sr = mPendingServices.get(i);
5257 if (app.info.uid != sr.appInfo.uid
5258 || !processName.equals(sr.processName)) {
5259 continue;
5260 }
5261
5262 mPendingServices.remove(i);
5263 i--;
5264 realStartServiceLocked(sr, app);
5265 didSomething = true;
5266 }
5267 } catch (Exception e) {
5268 Log.w(TAG, "Exception in new application when starting service "
5269 + sr.shortName, e);
5270 badApp = true;
5271 }
5272 }
5273
5274 // Check if the next broadcast receiver is in this process...
5275 BroadcastRecord br = mPendingBroadcast;
5276 if (!badApp && br != null && br.curApp == app) {
5277 try {
5278 mPendingBroadcast = null;
5279 processCurBroadcastLocked(br, app);
5280 didSomething = true;
5281 } catch (Exception e) {
5282 Log.w(TAG, "Exception in new application when starting receiver "
5283 + br.curComponent.flattenToShortString(), e);
5284 badApp = true;
5285 logBroadcastReceiverDiscard(br);
5286 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5287 br.resultExtras, br.resultAbort, true);
5288 scheduleBroadcastsLocked();
5289 }
5290 }
5291
Christopher Tate181fafa2009-05-14 11:12:14 -07005292 // Check whether the next backup agent is in this process...
5293 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5294 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005295 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005296 try {
5297 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5298 } catch (Exception e) {
5299 Log.w(TAG, "Exception scheduling backup agent creation: ");
5300 e.printStackTrace();
5301 }
5302 }
5303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005304 if (badApp) {
5305 // todo: Also need to kill application to deal with all
5306 // kinds of exceptions.
5307 handleAppDiedLocked(app, false);
5308 return false;
5309 }
5310
5311 if (!didSomething) {
5312 updateOomAdjLocked();
5313 }
5314
5315 return true;
5316 }
5317
5318 public final void attachApplication(IApplicationThread thread) {
5319 synchronized (this) {
5320 int callingPid = Binder.getCallingPid();
5321 final long origId = Binder.clearCallingIdentity();
5322 attachApplicationLocked(thread, callingPid);
5323 Binder.restoreCallingIdentity(origId);
5324 }
5325 }
5326
5327 public final void activityIdle(IBinder token) {
5328 final long origId = Binder.clearCallingIdentity();
5329 activityIdleInternal(token, false);
5330 Binder.restoreCallingIdentity(origId);
5331 }
5332
5333 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5334 boolean remove) {
5335 int N = mStoppingActivities.size();
5336 if (N <= 0) return null;
5337
5338 ArrayList<HistoryRecord> stops = null;
5339
5340 final boolean nowVisible = mResumedActivity != null
5341 && mResumedActivity.nowVisible
5342 && !mResumedActivity.waitingVisible;
5343 for (int i=0; i<N; i++) {
5344 HistoryRecord s = mStoppingActivities.get(i);
5345 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5346 + nowVisible + " waitingVisible=" + s.waitingVisible
5347 + " finishing=" + s.finishing);
5348 if (s.waitingVisible && nowVisible) {
5349 mWaitingVisibleActivities.remove(s);
5350 s.waitingVisible = false;
5351 if (s.finishing) {
5352 // If this activity is finishing, it is sitting on top of
5353 // everyone else but we now know it is no longer needed...
5354 // so get rid of it. Otherwise, we need to go through the
5355 // normal flow and hide it once we determine that it is
5356 // hidden by the activities in front of it.
5357 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5358 mWindowManager.setAppVisibility(s, false);
5359 }
5360 }
5361 if (!s.waitingVisible && remove) {
5362 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5363 if (stops == null) {
5364 stops = new ArrayList<HistoryRecord>();
5365 }
5366 stops.add(s);
5367 mStoppingActivities.remove(i);
5368 N--;
5369 i--;
5370 }
5371 }
5372
5373 return stops;
5374 }
5375
5376 void enableScreenAfterBoot() {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005377 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5378 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005379 mWindowManager.enableScreenAfterBoot();
5380 }
5381
5382 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5383 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5384
5385 ArrayList<HistoryRecord> stops = null;
5386 ArrayList<HistoryRecord> finishes = null;
5387 ArrayList<HistoryRecord> thumbnails = null;
5388 int NS = 0;
5389 int NF = 0;
5390 int NT = 0;
5391 IApplicationThread sendThumbnail = null;
5392 boolean booting = false;
5393 boolean enableScreen = false;
5394
5395 synchronized (this) {
5396 if (token != null) {
5397 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5398 }
5399
5400 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005401 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005402 if (index >= 0) {
5403 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5404
5405 // No longer need to keep the device awake.
5406 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5407 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5408 mLaunchingActivity.release();
5409 }
5410
5411 // We are now idle. If someone is waiting for a thumbnail from
5412 // us, we can now deliver.
5413 r.idle = true;
5414 scheduleAppGcsLocked();
5415 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5416 sendThumbnail = r.app.thread;
5417 r.thumbnailNeeded = false;
5418 }
5419
5420 // If this activity is fullscreen, set up to hide those under it.
5421
5422 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5423 ensureActivitiesVisibleLocked(null, 0);
5424
5425 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5426 if (!mBooted && !fromTimeout) {
5427 mBooted = true;
5428 enableScreen = true;
5429 }
5430 }
5431
5432 // Atomically retrieve all of the other things to do.
5433 stops = processStoppingActivitiesLocked(true);
5434 NS = stops != null ? stops.size() : 0;
5435 if ((NF=mFinishingActivities.size()) > 0) {
5436 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5437 mFinishingActivities.clear();
5438 }
5439 if ((NT=mCancelledThumbnails.size()) > 0) {
5440 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5441 mCancelledThumbnails.clear();
5442 }
5443
5444 booting = mBooting;
5445 mBooting = false;
5446 }
5447
5448 int i;
5449
5450 // Send thumbnail if requested.
5451 if (sendThumbnail != null) {
5452 try {
5453 sendThumbnail.requestThumbnail(token);
5454 } catch (Exception e) {
5455 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5456 sendPendingThumbnail(null, token, null, null, true);
5457 }
5458 }
5459
5460 // Stop any activities that are scheduled to do so but have been
5461 // waiting for the next one to start.
5462 for (i=0; i<NS; i++) {
5463 HistoryRecord r = (HistoryRecord)stops.get(i);
5464 synchronized (this) {
5465 if (r.finishing) {
5466 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5467 } else {
5468 stopActivityLocked(r);
5469 }
5470 }
5471 }
5472
5473 // Finish any activities that are scheduled to do so but have been
5474 // waiting for the next one to start.
5475 for (i=0; i<NF; i++) {
5476 HistoryRecord r = (HistoryRecord)finishes.get(i);
5477 synchronized (this) {
5478 destroyActivityLocked(r, true);
5479 }
5480 }
5481
5482 // Report back to any thumbnail receivers.
5483 for (i=0; i<NT; i++) {
5484 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5485 sendPendingThumbnail(r, null, null, null, true);
5486 }
5487
5488 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005489 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005490 }
5491
5492 trimApplications();
5493 //dump();
5494 //mWindowManager.dump();
5495
5496 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005497 enableScreenAfterBoot();
5498 }
5499 }
5500
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005501 final void finishBooting() {
5502 // Ensure that any processes we had put on hold are now started
5503 // up.
5504 final int NP = mProcessesOnHold.size();
5505 if (NP > 0) {
5506 ArrayList<ProcessRecord> procs =
5507 new ArrayList<ProcessRecord>(mProcessesOnHold);
5508 for (int ip=0; ip<NP; ip++) {
5509 this.startProcessLocked(procs.get(ip), "on-hold", null);
5510 }
5511 }
5512 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5513 // Tell anyone interested that we are done booting!
5514 synchronized (this) {
5515 broadcastIntentLocked(null, null,
5516 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5517 null, null, 0, null, null,
5518 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5519 false, false, MY_PID, Process.SYSTEM_UID);
5520 }
5521 }
5522 }
5523
5524 final void ensureBootCompleted() {
5525 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005526 boolean enableScreen;
5527 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005528 booting = mBooting;
5529 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005530 enableScreen = !mBooted;
5531 mBooted = true;
5532 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005533
5534 if (booting) {
5535 finishBooting();
5536 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005537
5538 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005539 enableScreenAfterBoot();
5540 }
5541 }
5542
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005543 public final void activityPaused(IBinder token, Bundle icicle) {
5544 // Refuse possible leaked file descriptors
5545 if (icicle != null && icicle.hasFileDescriptors()) {
5546 throw new IllegalArgumentException("File descriptors passed in Bundle");
5547 }
5548
5549 final long origId = Binder.clearCallingIdentity();
5550 activityPaused(token, icicle, false);
5551 Binder.restoreCallingIdentity(origId);
5552 }
5553
5554 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5555 if (DEBUG_PAUSE) Log.v(
5556 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5557 + ", timeout=" + timeout);
5558
5559 HistoryRecord r = null;
5560
5561 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005562 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005563 if (index >= 0) {
5564 r = (HistoryRecord)mHistory.get(index);
5565 if (!timeout) {
5566 r.icicle = icicle;
5567 r.haveState = true;
5568 }
5569 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5570 if (mPausingActivity == r) {
5571 r.state = ActivityState.PAUSED;
5572 completePauseLocked();
5573 } else {
5574 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5575 System.identityHashCode(r), r.shortComponentName,
5576 mPausingActivity != null
5577 ? mPausingActivity.shortComponentName : "(none)");
5578 }
5579 }
5580 }
5581 }
5582
5583 public final void activityStopped(IBinder token, Bitmap thumbnail,
5584 CharSequence description) {
5585 if (localLOGV) Log.v(
5586 TAG, "Activity stopped: token=" + token);
5587
5588 HistoryRecord r = null;
5589
5590 final long origId = Binder.clearCallingIdentity();
5591
5592 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005593 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005594 if (index >= 0) {
5595 r = (HistoryRecord)mHistory.get(index);
5596 r.thumbnail = thumbnail;
5597 r.description = description;
5598 r.stopped = true;
5599 r.state = ActivityState.STOPPED;
5600 if (!r.finishing) {
5601 if (r.configDestroy) {
5602 destroyActivityLocked(r, true);
5603 resumeTopActivityLocked(null);
5604 }
5605 }
5606 }
5607 }
5608
5609 if (r != null) {
5610 sendPendingThumbnail(r, null, null, null, false);
5611 }
5612
5613 trimApplications();
5614
5615 Binder.restoreCallingIdentity(origId);
5616 }
5617
5618 public final void activityDestroyed(IBinder token) {
5619 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5620 synchronized (this) {
5621 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5622
Dianne Hackborn75b03852009-06-12 15:43:26 -07005623 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005624 if (index >= 0) {
5625 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5626 if (r.state == ActivityState.DESTROYING) {
5627 final long origId = Binder.clearCallingIdentity();
5628 removeActivityFromHistoryLocked(r);
5629 Binder.restoreCallingIdentity(origId);
5630 }
5631 }
5632 }
5633 }
5634
5635 public String getCallingPackage(IBinder token) {
5636 synchronized (this) {
5637 HistoryRecord r = getCallingRecordLocked(token);
5638 return r != null && r.app != null ? r.app.processName : null;
5639 }
5640 }
5641
5642 public ComponentName getCallingActivity(IBinder token) {
5643 synchronized (this) {
5644 HistoryRecord r = getCallingRecordLocked(token);
5645 return r != null ? r.intent.getComponent() : null;
5646 }
5647 }
5648
5649 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005650 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005651 if (index >= 0) {
5652 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5653 if (r != null) {
5654 return r.resultTo;
5655 }
5656 }
5657 return null;
5658 }
5659
5660 public ComponentName getActivityClassForToken(IBinder token) {
5661 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005662 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005663 if (index >= 0) {
5664 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5665 return r.intent.getComponent();
5666 }
5667 return null;
5668 }
5669 }
5670
5671 public String getPackageForToken(IBinder token) {
5672 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005673 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005674 if (index >= 0) {
5675 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5676 return r.packageName;
5677 }
5678 return null;
5679 }
5680 }
5681
5682 public IIntentSender getIntentSender(int type,
5683 String packageName, IBinder token, String resultWho,
5684 int requestCode, Intent intent, String resolvedType, int flags) {
5685 // Refuse possible leaked file descriptors
5686 if (intent != null && intent.hasFileDescriptors() == true) {
5687 throw new IllegalArgumentException("File descriptors passed in Intent");
5688 }
5689
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005690 if (type == INTENT_SENDER_BROADCAST) {
5691 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5692 throw new IllegalArgumentException(
5693 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5694 }
5695 }
5696
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005697 synchronized(this) {
5698 int callingUid = Binder.getCallingUid();
5699 try {
5700 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5701 Process.supportsProcesses()) {
5702 int uid = ActivityThread.getPackageManager()
5703 .getPackageUid(packageName);
5704 if (uid != Binder.getCallingUid()) {
5705 String msg = "Permission Denial: getIntentSender() from pid="
5706 + Binder.getCallingPid()
5707 + ", uid=" + Binder.getCallingUid()
5708 + ", (need uid=" + uid + ")"
5709 + " is not allowed to send as package " + packageName;
5710 Log.w(TAG, msg);
5711 throw new SecurityException(msg);
5712 }
5713 }
5714 } catch (RemoteException e) {
5715 throw new SecurityException(e);
5716 }
5717 HistoryRecord activity = null;
5718 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005719 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005720 if (index < 0) {
5721 return null;
5722 }
5723 activity = (HistoryRecord)mHistory.get(index);
5724 if (activity.finishing) {
5725 return null;
5726 }
5727 }
5728
5729 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5730 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5731 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5732 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5733 |PendingIntent.FLAG_UPDATE_CURRENT);
5734
5735 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5736 type, packageName, activity, resultWho,
5737 requestCode, intent, resolvedType, flags);
5738 WeakReference<PendingIntentRecord> ref;
5739 ref = mIntentSenderRecords.get(key);
5740 PendingIntentRecord rec = ref != null ? ref.get() : null;
5741 if (rec != null) {
5742 if (!cancelCurrent) {
5743 if (updateCurrent) {
5744 rec.key.requestIntent.replaceExtras(intent);
5745 }
5746 return rec;
5747 }
5748 rec.canceled = true;
5749 mIntentSenderRecords.remove(key);
5750 }
5751 if (noCreate) {
5752 return rec;
5753 }
5754 rec = new PendingIntentRecord(this, key, callingUid);
5755 mIntentSenderRecords.put(key, rec.ref);
5756 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5757 if (activity.pendingResults == null) {
5758 activity.pendingResults
5759 = new HashSet<WeakReference<PendingIntentRecord>>();
5760 }
5761 activity.pendingResults.add(rec.ref);
5762 }
5763 return rec;
5764 }
5765 }
5766
5767 public void cancelIntentSender(IIntentSender sender) {
5768 if (!(sender instanceof PendingIntentRecord)) {
5769 return;
5770 }
5771 synchronized(this) {
5772 PendingIntentRecord rec = (PendingIntentRecord)sender;
5773 try {
5774 int uid = ActivityThread.getPackageManager()
5775 .getPackageUid(rec.key.packageName);
5776 if (uid != Binder.getCallingUid()) {
5777 String msg = "Permission Denial: cancelIntentSender() from pid="
5778 + Binder.getCallingPid()
5779 + ", uid=" + Binder.getCallingUid()
5780 + " is not allowed to cancel packges "
5781 + rec.key.packageName;
5782 Log.w(TAG, msg);
5783 throw new SecurityException(msg);
5784 }
5785 } catch (RemoteException e) {
5786 throw new SecurityException(e);
5787 }
5788 cancelIntentSenderLocked(rec, true);
5789 }
5790 }
5791
5792 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5793 rec.canceled = true;
5794 mIntentSenderRecords.remove(rec.key);
5795 if (cleanActivity && rec.key.activity != null) {
5796 rec.key.activity.pendingResults.remove(rec.ref);
5797 }
5798 }
5799
5800 public String getPackageForIntentSender(IIntentSender pendingResult) {
5801 if (!(pendingResult instanceof PendingIntentRecord)) {
5802 return null;
5803 }
5804 synchronized(this) {
5805 try {
5806 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5807 return res.key.packageName;
5808 } catch (ClassCastException e) {
5809 }
5810 }
5811 return null;
5812 }
5813
5814 public void setProcessLimit(int max) {
5815 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5816 "setProcessLimit()");
5817 mProcessLimit = max;
5818 }
5819
5820 public int getProcessLimit() {
5821 return mProcessLimit;
5822 }
5823
5824 void foregroundTokenDied(ForegroundToken token) {
5825 synchronized (ActivityManagerService.this) {
5826 synchronized (mPidsSelfLocked) {
5827 ForegroundToken cur
5828 = mForegroundProcesses.get(token.pid);
5829 if (cur != token) {
5830 return;
5831 }
5832 mForegroundProcesses.remove(token.pid);
5833 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5834 if (pr == null) {
5835 return;
5836 }
5837 pr.forcingToForeground = null;
5838 pr.foregroundServices = false;
5839 }
5840 updateOomAdjLocked();
5841 }
5842 }
5843
5844 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5845 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5846 "setProcessForeground()");
5847 synchronized(this) {
5848 boolean changed = false;
5849
5850 synchronized (mPidsSelfLocked) {
5851 ProcessRecord pr = mPidsSelfLocked.get(pid);
5852 if (pr == null) {
5853 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5854 return;
5855 }
5856 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5857 if (oldToken != null) {
5858 oldToken.token.unlinkToDeath(oldToken, 0);
5859 mForegroundProcesses.remove(pid);
5860 pr.forcingToForeground = null;
5861 changed = true;
5862 }
5863 if (isForeground && token != null) {
5864 ForegroundToken newToken = new ForegroundToken() {
5865 public void binderDied() {
5866 foregroundTokenDied(this);
5867 }
5868 };
5869 newToken.pid = pid;
5870 newToken.token = token;
5871 try {
5872 token.linkToDeath(newToken, 0);
5873 mForegroundProcesses.put(pid, newToken);
5874 pr.forcingToForeground = token;
5875 changed = true;
5876 } catch (RemoteException e) {
5877 // If the process died while doing this, we will later
5878 // do the cleanup with the process death link.
5879 }
5880 }
5881 }
5882
5883 if (changed) {
5884 updateOomAdjLocked();
5885 }
5886 }
5887 }
5888
5889 // =========================================================
5890 // PERMISSIONS
5891 // =========================================================
5892
5893 static class PermissionController extends IPermissionController.Stub {
5894 ActivityManagerService mActivityManagerService;
5895 PermissionController(ActivityManagerService activityManagerService) {
5896 mActivityManagerService = activityManagerService;
5897 }
5898
5899 public boolean checkPermission(String permission, int pid, int uid) {
5900 return mActivityManagerService.checkPermission(permission, pid,
5901 uid) == PackageManager.PERMISSION_GRANTED;
5902 }
5903 }
5904
5905 /**
5906 * This can be called with or without the global lock held.
5907 */
5908 int checkComponentPermission(String permission, int pid, int uid,
5909 int reqUid) {
5910 // We might be performing an operation on behalf of an indirect binder
5911 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5912 // client identity accordingly before proceeding.
5913 Identity tlsIdentity = sCallerIdentity.get();
5914 if (tlsIdentity != null) {
5915 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5916 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5917 uid = tlsIdentity.uid;
5918 pid = tlsIdentity.pid;
5919 }
5920
5921 // Root, system server and our own process get to do everything.
5922 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5923 !Process.supportsProcesses()) {
5924 return PackageManager.PERMISSION_GRANTED;
5925 }
5926 // If the target requires a specific UID, always fail for others.
5927 if (reqUid >= 0 && uid != reqUid) {
5928 return PackageManager.PERMISSION_DENIED;
5929 }
5930 if (permission == null) {
5931 return PackageManager.PERMISSION_GRANTED;
5932 }
5933 try {
5934 return ActivityThread.getPackageManager()
5935 .checkUidPermission(permission, uid);
5936 } catch (RemoteException e) {
5937 // Should never happen, but if it does... deny!
5938 Log.e(TAG, "PackageManager is dead?!?", e);
5939 }
5940 return PackageManager.PERMISSION_DENIED;
5941 }
5942
5943 /**
5944 * As the only public entry point for permissions checking, this method
5945 * can enforce the semantic that requesting a check on a null global
5946 * permission is automatically denied. (Internally a null permission
5947 * string is used when calling {@link #checkComponentPermission} in cases
5948 * when only uid-based security is needed.)
5949 *
5950 * This can be called with or without the global lock held.
5951 */
5952 public int checkPermission(String permission, int pid, int uid) {
5953 if (permission == null) {
5954 return PackageManager.PERMISSION_DENIED;
5955 }
5956 return checkComponentPermission(permission, pid, uid, -1);
5957 }
5958
5959 /**
5960 * Binder IPC calls go through the public entry point.
5961 * This can be called with or without the global lock held.
5962 */
5963 int checkCallingPermission(String permission) {
5964 return checkPermission(permission,
5965 Binder.getCallingPid(),
5966 Binder.getCallingUid());
5967 }
5968
5969 /**
5970 * This can be called with or without the global lock held.
5971 */
5972 void enforceCallingPermission(String permission, String func) {
5973 if (checkCallingPermission(permission)
5974 == PackageManager.PERMISSION_GRANTED) {
5975 return;
5976 }
5977
5978 String msg = "Permission Denial: " + func + " from pid="
5979 + Binder.getCallingPid()
5980 + ", uid=" + Binder.getCallingUid()
5981 + " requires " + permission;
5982 Log.w(TAG, msg);
5983 throw new SecurityException(msg);
5984 }
5985
5986 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5987 ProviderInfo pi, int uid, int modeFlags) {
5988 try {
5989 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5990 if ((pi.readPermission != null) &&
5991 (pm.checkUidPermission(pi.readPermission, uid)
5992 != PackageManager.PERMISSION_GRANTED)) {
5993 return false;
5994 }
5995 }
5996 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5997 if ((pi.writePermission != null) &&
5998 (pm.checkUidPermission(pi.writePermission, uid)
5999 != PackageManager.PERMISSION_GRANTED)) {
6000 return false;
6001 }
6002 }
6003 return true;
6004 } catch (RemoteException e) {
6005 return false;
6006 }
6007 }
6008
6009 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6010 int modeFlags) {
6011 // Root gets to do everything.
6012 if (uid == 0 || !Process.supportsProcesses()) {
6013 return true;
6014 }
6015 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6016 if (perms == null) return false;
6017 UriPermission perm = perms.get(uri);
6018 if (perm == null) return false;
6019 return (modeFlags&perm.modeFlags) == modeFlags;
6020 }
6021
6022 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6023 // Another redirected-binder-call permissions check as in
6024 // {@link checkComponentPermission}.
6025 Identity tlsIdentity = sCallerIdentity.get();
6026 if (tlsIdentity != null) {
6027 uid = tlsIdentity.uid;
6028 pid = tlsIdentity.pid;
6029 }
6030
6031 // Our own process gets to do everything.
6032 if (pid == MY_PID) {
6033 return PackageManager.PERMISSION_GRANTED;
6034 }
6035 synchronized(this) {
6036 return checkUriPermissionLocked(uri, uid, modeFlags)
6037 ? PackageManager.PERMISSION_GRANTED
6038 : PackageManager.PERMISSION_DENIED;
6039 }
6040 }
6041
6042 private void grantUriPermissionLocked(int callingUid,
6043 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6044 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6045 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6046 if (modeFlags == 0) {
6047 return;
6048 }
6049
6050 final IPackageManager pm = ActivityThread.getPackageManager();
6051
6052 // If this is not a content: uri, we can't do anything with it.
6053 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6054 return;
6055 }
6056
6057 String name = uri.getAuthority();
6058 ProviderInfo pi = null;
6059 ContentProviderRecord cpr
6060 = (ContentProviderRecord)mProvidersByName.get(name);
6061 if (cpr != null) {
6062 pi = cpr.info;
6063 } else {
6064 try {
6065 pi = pm.resolveContentProvider(name,
6066 PackageManager.GET_URI_PERMISSION_PATTERNS);
6067 } catch (RemoteException ex) {
6068 }
6069 }
6070 if (pi == null) {
6071 Log.w(TAG, "No content provider found for: " + name);
6072 return;
6073 }
6074
6075 int targetUid;
6076 try {
6077 targetUid = pm.getPackageUid(targetPkg);
6078 if (targetUid < 0) {
6079 return;
6080 }
6081 } catch (RemoteException ex) {
6082 return;
6083 }
6084
6085 // First... does the target actually need this permission?
6086 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6087 // No need to grant the target this permission.
6088 return;
6089 }
6090
6091 // Second... maybe someone else has already granted the
6092 // permission?
6093 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6094 // No need to grant the target this permission.
6095 return;
6096 }
6097
6098 // Third... is the provider allowing granting of URI permissions?
6099 if (!pi.grantUriPermissions) {
6100 throw new SecurityException("Provider " + pi.packageName
6101 + "/" + pi.name
6102 + " does not allow granting of Uri permissions (uri "
6103 + uri + ")");
6104 }
6105 if (pi.uriPermissionPatterns != null) {
6106 final int N = pi.uriPermissionPatterns.length;
6107 boolean allowed = false;
6108 for (int i=0; i<N; i++) {
6109 if (pi.uriPermissionPatterns[i] != null
6110 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6111 allowed = true;
6112 break;
6113 }
6114 }
6115 if (!allowed) {
6116 throw new SecurityException("Provider " + pi.packageName
6117 + "/" + pi.name
6118 + " does not allow granting of permission to path of Uri "
6119 + uri);
6120 }
6121 }
6122
6123 // Fourth... does the caller itself have permission to access
6124 // this uri?
6125 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6126 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6127 throw new SecurityException("Uid " + callingUid
6128 + " does not have permission to uri " + uri);
6129 }
6130 }
6131
6132 // Okay! So here we are: the caller has the assumed permission
6133 // to the uri, and the target doesn't. Let's now give this to
6134 // the target.
6135
6136 HashMap<Uri, UriPermission> targetUris
6137 = mGrantedUriPermissions.get(targetUid);
6138 if (targetUris == null) {
6139 targetUris = new HashMap<Uri, UriPermission>();
6140 mGrantedUriPermissions.put(targetUid, targetUris);
6141 }
6142
6143 UriPermission perm = targetUris.get(uri);
6144 if (perm == null) {
6145 perm = new UriPermission(targetUid, uri);
6146 targetUris.put(uri, perm);
6147
6148 }
6149 perm.modeFlags |= modeFlags;
6150 if (activity == null) {
6151 perm.globalModeFlags |= modeFlags;
6152 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6153 perm.readActivities.add(activity);
6154 if (activity.readUriPermissions == null) {
6155 activity.readUriPermissions = new HashSet<UriPermission>();
6156 }
6157 activity.readUriPermissions.add(perm);
6158 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6159 perm.writeActivities.add(activity);
6160 if (activity.writeUriPermissions == null) {
6161 activity.writeUriPermissions = new HashSet<UriPermission>();
6162 }
6163 activity.writeUriPermissions.add(perm);
6164 }
6165 }
6166
6167 private void grantUriPermissionFromIntentLocked(int callingUid,
6168 String targetPkg, Intent intent, HistoryRecord activity) {
6169 if (intent == null) {
6170 return;
6171 }
6172 Uri data = intent.getData();
6173 if (data == null) {
6174 return;
6175 }
6176 grantUriPermissionLocked(callingUid, targetPkg, data,
6177 intent.getFlags(), activity);
6178 }
6179
6180 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6181 Uri uri, int modeFlags) {
6182 synchronized(this) {
6183 final ProcessRecord r = getRecordForAppLocked(caller);
6184 if (r == null) {
6185 throw new SecurityException("Unable to find app for caller "
6186 + caller
6187 + " when granting permission to uri " + uri);
6188 }
6189 if (targetPkg == null) {
6190 Log.w(TAG, "grantUriPermission: null target");
6191 return;
6192 }
6193 if (uri == null) {
6194 Log.w(TAG, "grantUriPermission: null uri");
6195 return;
6196 }
6197
6198 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6199 null);
6200 }
6201 }
6202
6203 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6204 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6205 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6206 HashMap<Uri, UriPermission> perms
6207 = mGrantedUriPermissions.get(perm.uid);
6208 if (perms != null) {
6209 perms.remove(perm.uri);
6210 if (perms.size() == 0) {
6211 mGrantedUriPermissions.remove(perm.uid);
6212 }
6213 }
6214 }
6215 }
6216
6217 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6218 if (activity.readUriPermissions != null) {
6219 for (UriPermission perm : activity.readUriPermissions) {
6220 perm.readActivities.remove(activity);
6221 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6222 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6223 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6224 removeUriPermissionIfNeededLocked(perm);
6225 }
6226 }
6227 }
6228 if (activity.writeUriPermissions != null) {
6229 for (UriPermission perm : activity.writeUriPermissions) {
6230 perm.writeActivities.remove(activity);
6231 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6232 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6233 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6234 removeUriPermissionIfNeededLocked(perm);
6235 }
6236 }
6237 }
6238 }
6239
6240 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6241 int modeFlags) {
6242 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6243 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6244 if (modeFlags == 0) {
6245 return;
6246 }
6247
6248 final IPackageManager pm = ActivityThread.getPackageManager();
6249
6250 final String authority = uri.getAuthority();
6251 ProviderInfo pi = null;
6252 ContentProviderRecord cpr
6253 = (ContentProviderRecord)mProvidersByName.get(authority);
6254 if (cpr != null) {
6255 pi = cpr.info;
6256 } else {
6257 try {
6258 pi = pm.resolveContentProvider(authority,
6259 PackageManager.GET_URI_PERMISSION_PATTERNS);
6260 } catch (RemoteException ex) {
6261 }
6262 }
6263 if (pi == null) {
6264 Log.w(TAG, "No content provider found for: " + authority);
6265 return;
6266 }
6267
6268 // Does the caller have this permission on the URI?
6269 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6270 // Right now, if you are not the original owner of the permission,
6271 // you are not allowed to revoke it.
6272 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6273 throw new SecurityException("Uid " + callingUid
6274 + " does not have permission to uri " + uri);
6275 //}
6276 }
6277
6278 // Go through all of the permissions and remove any that match.
6279 final List<String> SEGMENTS = uri.getPathSegments();
6280 if (SEGMENTS != null) {
6281 final int NS = SEGMENTS.size();
6282 int N = mGrantedUriPermissions.size();
6283 for (int i=0; i<N; i++) {
6284 HashMap<Uri, UriPermission> perms
6285 = mGrantedUriPermissions.valueAt(i);
6286 Iterator<UriPermission> it = perms.values().iterator();
6287 toploop:
6288 while (it.hasNext()) {
6289 UriPermission perm = it.next();
6290 Uri targetUri = perm.uri;
6291 if (!authority.equals(targetUri.getAuthority())) {
6292 continue;
6293 }
6294 List<String> targetSegments = targetUri.getPathSegments();
6295 if (targetSegments == null) {
6296 continue;
6297 }
6298 if (targetSegments.size() < NS) {
6299 continue;
6300 }
6301 for (int j=0; j<NS; j++) {
6302 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6303 continue toploop;
6304 }
6305 }
6306 perm.clearModes(modeFlags);
6307 if (perm.modeFlags == 0) {
6308 it.remove();
6309 }
6310 }
6311 if (perms.size() == 0) {
6312 mGrantedUriPermissions.remove(
6313 mGrantedUriPermissions.keyAt(i));
6314 N--;
6315 i--;
6316 }
6317 }
6318 }
6319 }
6320
6321 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6322 int modeFlags) {
6323 synchronized(this) {
6324 final ProcessRecord r = getRecordForAppLocked(caller);
6325 if (r == null) {
6326 throw new SecurityException("Unable to find app for caller "
6327 + caller
6328 + " when revoking permission to uri " + uri);
6329 }
6330 if (uri == null) {
6331 Log.w(TAG, "revokeUriPermission: null uri");
6332 return;
6333 }
6334
6335 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6336 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6337 if (modeFlags == 0) {
6338 return;
6339 }
6340
6341 final IPackageManager pm = ActivityThread.getPackageManager();
6342
6343 final String authority = uri.getAuthority();
6344 ProviderInfo pi = null;
6345 ContentProviderRecord cpr
6346 = (ContentProviderRecord)mProvidersByName.get(authority);
6347 if (cpr != null) {
6348 pi = cpr.info;
6349 } else {
6350 try {
6351 pi = pm.resolveContentProvider(authority,
6352 PackageManager.GET_URI_PERMISSION_PATTERNS);
6353 } catch (RemoteException ex) {
6354 }
6355 }
6356 if (pi == null) {
6357 Log.w(TAG, "No content provider found for: " + authority);
6358 return;
6359 }
6360
6361 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6362 }
6363 }
6364
6365 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6366 synchronized (this) {
6367 ProcessRecord app =
6368 who != null ? getRecordForAppLocked(who) : null;
6369 if (app == null) return;
6370
6371 Message msg = Message.obtain();
6372 msg.what = WAIT_FOR_DEBUGGER_MSG;
6373 msg.obj = app;
6374 msg.arg1 = waiting ? 1 : 0;
6375 mHandler.sendMessage(msg);
6376 }
6377 }
6378
6379 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6380 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006381 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006382 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006383 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006384 }
6385
6386 // =========================================================
6387 // TASK MANAGEMENT
6388 // =========================================================
6389
6390 public List getTasks(int maxNum, int flags,
6391 IThumbnailReceiver receiver) {
6392 ArrayList list = new ArrayList();
6393
6394 PendingThumbnailsRecord pending = null;
6395 IApplicationThread topThumbnail = null;
6396 HistoryRecord topRecord = null;
6397
6398 synchronized(this) {
6399 if (localLOGV) Log.v(
6400 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6401 + ", receiver=" + receiver);
6402
6403 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6404 != PackageManager.PERMISSION_GRANTED) {
6405 if (receiver != null) {
6406 // If the caller wants to wait for pending thumbnails,
6407 // it ain't gonna get them.
6408 try {
6409 receiver.finished();
6410 } catch (RemoteException ex) {
6411 }
6412 }
6413 String msg = "Permission Denial: getTasks() from pid="
6414 + Binder.getCallingPid()
6415 + ", uid=" + Binder.getCallingUid()
6416 + " requires " + android.Manifest.permission.GET_TASKS;
6417 Log.w(TAG, msg);
6418 throw new SecurityException(msg);
6419 }
6420
6421 int pos = mHistory.size()-1;
6422 HistoryRecord next =
6423 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6424 HistoryRecord top = null;
6425 CharSequence topDescription = null;
6426 TaskRecord curTask = null;
6427 int numActivities = 0;
6428 int numRunning = 0;
6429 while (pos >= 0 && maxNum > 0) {
6430 final HistoryRecord r = next;
6431 pos--;
6432 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6433
6434 // Initialize state for next task if needed.
6435 if (top == null ||
6436 (top.state == ActivityState.INITIALIZING
6437 && top.task == r.task)) {
6438 top = r;
6439 topDescription = r.description;
6440 curTask = r.task;
6441 numActivities = numRunning = 0;
6442 }
6443
6444 // Add 'r' into the current task.
6445 numActivities++;
6446 if (r.app != null && r.app.thread != null) {
6447 numRunning++;
6448 }
6449 if (topDescription == null) {
6450 topDescription = r.description;
6451 }
6452
6453 if (localLOGV) Log.v(
6454 TAG, r.intent.getComponent().flattenToShortString()
6455 + ": task=" + r.task);
6456
6457 // If the next one is a different task, generate a new
6458 // TaskInfo entry for what we have.
6459 if (next == null || next.task != curTask) {
6460 ActivityManager.RunningTaskInfo ci
6461 = new ActivityManager.RunningTaskInfo();
6462 ci.id = curTask.taskId;
6463 ci.baseActivity = r.intent.getComponent();
6464 ci.topActivity = top.intent.getComponent();
6465 ci.thumbnail = top.thumbnail;
6466 ci.description = topDescription;
6467 ci.numActivities = numActivities;
6468 ci.numRunning = numRunning;
6469 //System.out.println(
6470 // "#" + maxNum + ": " + " descr=" + ci.description);
6471 if (ci.thumbnail == null && receiver != null) {
6472 if (localLOGV) Log.v(
6473 TAG, "State=" + top.state + "Idle=" + top.idle
6474 + " app=" + top.app
6475 + " thr=" + (top.app != null ? top.app.thread : null));
6476 if (top.state == ActivityState.RESUMED
6477 || top.state == ActivityState.PAUSING) {
6478 if (top.idle && top.app != null
6479 && top.app.thread != null) {
6480 topRecord = top;
6481 topThumbnail = top.app.thread;
6482 } else {
6483 top.thumbnailNeeded = true;
6484 }
6485 }
6486 if (pending == null) {
6487 pending = new PendingThumbnailsRecord(receiver);
6488 }
6489 pending.pendingRecords.add(top);
6490 }
6491 list.add(ci);
6492 maxNum--;
6493 top = null;
6494 }
6495 }
6496
6497 if (pending != null) {
6498 mPendingThumbnails.add(pending);
6499 }
6500 }
6501
6502 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6503
6504 if (topThumbnail != null) {
6505 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6506 try {
6507 topThumbnail.requestThumbnail(topRecord);
6508 } catch (Exception e) {
6509 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6510 sendPendingThumbnail(null, topRecord, null, null, true);
6511 }
6512 }
6513
6514 if (pending == null && receiver != null) {
6515 // In this case all thumbnails were available and the client
6516 // is being asked to be told when the remaining ones come in...
6517 // which is unusually, since the top-most currently running
6518 // activity should never have a canned thumbnail! Oh well.
6519 try {
6520 receiver.finished();
6521 } catch (RemoteException ex) {
6522 }
6523 }
6524
6525 return list;
6526 }
6527
6528 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6529 int flags) {
6530 synchronized (this) {
6531 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6532 "getRecentTasks()");
6533
6534 final int N = mRecentTasks.size();
6535 ArrayList<ActivityManager.RecentTaskInfo> res
6536 = new ArrayList<ActivityManager.RecentTaskInfo>(
6537 maxNum < N ? maxNum : N);
6538 for (int i=0; i<N && maxNum > 0; i++) {
6539 TaskRecord tr = mRecentTasks.get(i);
6540 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6541 || (tr.intent == null)
6542 || ((tr.intent.getFlags()
6543 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6544 ActivityManager.RecentTaskInfo rti
6545 = new ActivityManager.RecentTaskInfo();
6546 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6547 rti.baseIntent = new Intent(
6548 tr.intent != null ? tr.intent : tr.affinityIntent);
6549 rti.origActivity = tr.origActivity;
6550 res.add(rti);
6551 maxNum--;
6552 }
6553 }
6554 return res;
6555 }
6556 }
6557
6558 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6559 int j;
6560 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6561 TaskRecord jt = startTask;
6562
6563 // First look backwards
6564 for (j=startIndex-1; j>=0; j--) {
6565 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6566 if (r.task != jt) {
6567 jt = r.task;
6568 if (affinity.equals(jt.affinity)) {
6569 return j;
6570 }
6571 }
6572 }
6573
6574 // Now look forwards
6575 final int N = mHistory.size();
6576 jt = startTask;
6577 for (j=startIndex+1; j<N; j++) {
6578 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6579 if (r.task != jt) {
6580 if (affinity.equals(jt.affinity)) {
6581 return j;
6582 }
6583 jt = r.task;
6584 }
6585 }
6586
6587 // Might it be at the top?
6588 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6589 return N-1;
6590 }
6591
6592 return -1;
6593 }
6594
6595 /**
6596 * Perform a reset of the given task, if needed as part of launching it.
6597 * Returns the new HistoryRecord at the top of the task.
6598 */
6599 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6600 HistoryRecord newActivity) {
6601 boolean forceReset = (newActivity.info.flags
6602 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6603 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6604 if ((newActivity.info.flags
6605 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6606 forceReset = true;
6607 }
6608 }
6609
6610 final TaskRecord task = taskTop.task;
6611
6612 // We are going to move through the history list so that we can look
6613 // at each activity 'target' with 'below' either the interesting
6614 // activity immediately below it in the stack or null.
6615 HistoryRecord target = null;
6616 int targetI = 0;
6617 int taskTopI = -1;
6618 int replyChainEnd = -1;
6619 int lastReparentPos = -1;
6620 for (int i=mHistory.size()-1; i>=-1; i--) {
6621 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6622
6623 if (below != null && below.finishing) {
6624 continue;
6625 }
6626 if (target == null) {
6627 target = below;
6628 targetI = i;
6629 // If we were in the middle of a reply chain before this
6630 // task, it doesn't appear like the root of the chain wants
6631 // anything interesting, so drop it.
6632 replyChainEnd = -1;
6633 continue;
6634 }
6635
6636 final int flags = target.info.flags;
6637
6638 final boolean finishOnTaskLaunch =
6639 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6640 final boolean allowTaskReparenting =
6641 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6642
6643 if (target.task == task) {
6644 // We are inside of the task being reset... we'll either
6645 // finish this activity, push it out for another task,
6646 // or leave it as-is. We only do this
6647 // for activities that are not the root of the task (since
6648 // if we finish the root, we may no longer have the task!).
6649 if (taskTopI < 0) {
6650 taskTopI = targetI;
6651 }
6652 if (below != null && below.task == task) {
6653 final boolean clearWhenTaskReset =
6654 (target.intent.getFlags()
6655 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006656 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006657 // If this activity is sending a reply to a previous
6658 // activity, we can't do anything with it now until
6659 // we reach the start of the reply chain.
6660 // XXX note that we are assuming the result is always
6661 // to the previous activity, which is almost always
6662 // the case but we really shouldn't count on.
6663 if (replyChainEnd < 0) {
6664 replyChainEnd = targetI;
6665 }
Ed Heyl73798232009-03-24 21:32:21 -07006666 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006667 && target.taskAffinity != null
6668 && !target.taskAffinity.equals(task.affinity)) {
6669 // If this activity has an affinity for another
6670 // task, then we need to move it out of here. We will
6671 // move it as far out of the way as possible, to the
6672 // bottom of the activity stack. This also keeps it
6673 // correctly ordered with any activities we previously
6674 // moved.
6675 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6676 if (target.taskAffinity != null
6677 && target.taskAffinity.equals(p.task.affinity)) {
6678 // If the activity currently at the bottom has the
6679 // same task affinity as the one we are moving,
6680 // then merge it into the same task.
6681 target.task = p.task;
6682 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6683 + " out to bottom task " + p.task);
6684 } else {
6685 mCurTask++;
6686 if (mCurTask <= 0) {
6687 mCurTask = 1;
6688 }
6689 target.task = new TaskRecord(mCurTask, target.info, null,
6690 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6691 target.task.affinityIntent = target.intent;
6692 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6693 + " out to new task " + target.task);
6694 }
6695 mWindowManager.setAppGroupId(target, task.taskId);
6696 if (replyChainEnd < 0) {
6697 replyChainEnd = targetI;
6698 }
6699 int dstPos = 0;
6700 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6701 p = (HistoryRecord)mHistory.get(srcPos);
6702 if (p.finishing) {
6703 continue;
6704 }
6705 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6706 + " out to target's task " + target.task);
6707 task.numActivities--;
6708 p.task = target.task;
6709 target.task.numActivities++;
6710 mHistory.remove(srcPos);
6711 mHistory.add(dstPos, p);
6712 mWindowManager.moveAppToken(dstPos, p);
6713 mWindowManager.setAppGroupId(p, p.task.taskId);
6714 dstPos++;
6715 if (VALIDATE_TOKENS) {
6716 mWindowManager.validateAppTokens(mHistory);
6717 }
6718 i++;
6719 }
6720 if (taskTop == p) {
6721 taskTop = below;
6722 }
6723 if (taskTopI == replyChainEnd) {
6724 taskTopI = -1;
6725 }
6726 replyChainEnd = -1;
6727 addRecentTask(target.task);
6728 } else if (forceReset || finishOnTaskLaunch
6729 || clearWhenTaskReset) {
6730 // If the activity should just be removed -- either
6731 // because it asks for it, or the task should be
6732 // cleared -- then finish it and anything that is
6733 // part of its reply chain.
6734 if (clearWhenTaskReset) {
6735 // In this case, we want to finish this activity
6736 // and everything above it, so be sneaky and pretend
6737 // like these are all in the reply chain.
6738 replyChainEnd = targetI+1;
6739 while (replyChainEnd < mHistory.size() &&
6740 ((HistoryRecord)mHistory.get(
6741 replyChainEnd)).task == task) {
6742 replyChainEnd++;
6743 }
6744 replyChainEnd--;
6745 } else if (replyChainEnd < 0) {
6746 replyChainEnd = targetI;
6747 }
6748 HistoryRecord p = null;
6749 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6750 p = (HistoryRecord)mHistory.get(srcPos);
6751 if (p.finishing) {
6752 continue;
6753 }
6754 if (finishActivityLocked(p, srcPos,
6755 Activity.RESULT_CANCELED, null, "reset")) {
6756 replyChainEnd--;
6757 srcPos--;
6758 }
6759 }
6760 if (taskTop == p) {
6761 taskTop = below;
6762 }
6763 if (taskTopI == replyChainEnd) {
6764 taskTopI = -1;
6765 }
6766 replyChainEnd = -1;
6767 } else {
6768 // If we were in the middle of a chain, well the
6769 // activity that started it all doesn't want anything
6770 // special, so leave it all as-is.
6771 replyChainEnd = -1;
6772 }
6773 } else {
6774 // Reached the bottom of the task -- any reply chain
6775 // should be left as-is.
6776 replyChainEnd = -1;
6777 }
6778
6779 } else if (target.resultTo != null) {
6780 // If this activity is sending a reply to a previous
6781 // activity, we can't do anything with it now until
6782 // we reach the start of the reply chain.
6783 // XXX note that we are assuming the result is always
6784 // to the previous activity, which is almost always
6785 // the case but we really shouldn't count on.
6786 if (replyChainEnd < 0) {
6787 replyChainEnd = targetI;
6788 }
6789
6790 } else if (taskTopI >= 0 && allowTaskReparenting
6791 && task.affinity != null
6792 && task.affinity.equals(target.taskAffinity)) {
6793 // We are inside of another task... if this activity has
6794 // an affinity for our task, then either remove it if we are
6795 // clearing or move it over to our task. Note that
6796 // we currently punt on the case where we are resetting a
6797 // task that is not at the top but who has activities above
6798 // with an affinity to it... this is really not a normal
6799 // case, and we will need to later pull that task to the front
6800 // and usually at that point we will do the reset and pick
6801 // up those remaining activities. (This only happens if
6802 // someone starts an activity in a new task from an activity
6803 // in a task that is not currently on top.)
6804 if (forceReset || finishOnTaskLaunch) {
6805 if (replyChainEnd < 0) {
6806 replyChainEnd = targetI;
6807 }
6808 HistoryRecord p = null;
6809 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6810 p = (HistoryRecord)mHistory.get(srcPos);
6811 if (p.finishing) {
6812 continue;
6813 }
6814 if (finishActivityLocked(p, srcPos,
6815 Activity.RESULT_CANCELED, null, "reset")) {
6816 taskTopI--;
6817 lastReparentPos--;
6818 replyChainEnd--;
6819 srcPos--;
6820 }
6821 }
6822 replyChainEnd = -1;
6823 } else {
6824 if (replyChainEnd < 0) {
6825 replyChainEnd = targetI;
6826 }
6827 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6828 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6829 if (p.finishing) {
6830 continue;
6831 }
6832 if (lastReparentPos < 0) {
6833 lastReparentPos = taskTopI;
6834 taskTop = p;
6835 } else {
6836 lastReparentPos--;
6837 }
6838 mHistory.remove(srcPos);
6839 p.task.numActivities--;
6840 p.task = task;
6841 mHistory.add(lastReparentPos, p);
6842 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6843 + " in to resetting task " + task);
6844 task.numActivities++;
6845 mWindowManager.moveAppToken(lastReparentPos, p);
6846 mWindowManager.setAppGroupId(p, p.task.taskId);
6847 if (VALIDATE_TOKENS) {
6848 mWindowManager.validateAppTokens(mHistory);
6849 }
6850 }
6851 replyChainEnd = -1;
6852
6853 // Now we've moved it in to place... but what if this is
6854 // a singleTop activity and we have put it on top of another
6855 // instance of the same activity? Then we drop the instance
6856 // below so it remains singleTop.
6857 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6858 for (int j=lastReparentPos-1; j>=0; j--) {
6859 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6860 if (p.finishing) {
6861 continue;
6862 }
6863 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6864 if (finishActivityLocked(p, j,
6865 Activity.RESULT_CANCELED, null, "replace")) {
6866 taskTopI--;
6867 lastReparentPos--;
6868 }
6869 }
6870 }
6871 }
6872 }
6873 }
6874
6875 target = below;
6876 targetI = i;
6877 }
6878
6879 return taskTop;
6880 }
6881
6882 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006883 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006884 */
6885 public void moveTaskToFront(int task) {
6886 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6887 "moveTaskToFront()");
6888
6889 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006890 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6891 Binder.getCallingUid(), "Task to front")) {
6892 return;
6893 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006894 final long origId = Binder.clearCallingIdentity();
6895 try {
6896 int N = mRecentTasks.size();
6897 for (int i=0; i<N; i++) {
6898 TaskRecord tr = mRecentTasks.get(i);
6899 if (tr.taskId == task) {
6900 moveTaskToFrontLocked(tr);
6901 return;
6902 }
6903 }
6904 for (int i=mHistory.size()-1; i>=0; i--) {
6905 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6906 if (hr.task.taskId == task) {
6907 moveTaskToFrontLocked(hr.task);
6908 return;
6909 }
6910 }
6911 } finally {
6912 Binder.restoreCallingIdentity(origId);
6913 }
6914 }
6915 }
6916
6917 private final void moveTaskToFrontLocked(TaskRecord tr) {
6918 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6919
6920 final int task = tr.taskId;
6921 int top = mHistory.size()-1;
6922
6923 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6924 // nothing to do!
6925 return;
6926 }
6927
6928 if (DEBUG_TRANSITION) Log.v(TAG,
6929 "Prepare to front transition: task=" + tr);
6930 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6931
6932 ArrayList moved = new ArrayList();
6933
6934 // Applying the affinities may have removed entries from the history,
6935 // so get the size again.
6936 top = mHistory.size()-1;
6937 int pos = top;
6938
6939 // Shift all activities with this task up to the top
6940 // of the stack, keeping them in the same internal order.
6941 while (pos >= 0) {
6942 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6943 if (localLOGV) Log.v(
6944 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6945 boolean first = true;
6946 if (r.task.taskId == task) {
6947 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6948 mHistory.remove(pos);
6949 mHistory.add(top, r);
6950 moved.add(0, r);
6951 top--;
6952 if (first) {
6953 addRecentTask(r.task);
6954 first = false;
6955 }
6956 }
6957 pos--;
6958 }
6959
6960 mWindowManager.moveAppTokensToTop(moved);
6961 if (VALIDATE_TOKENS) {
6962 mWindowManager.validateAppTokens(mHistory);
6963 }
6964
6965 finishTaskMove(task);
6966 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6967 }
6968
6969 private final void finishTaskMove(int task) {
6970 resumeTopActivityLocked(null);
6971 }
6972
6973 public void moveTaskToBack(int task) {
6974 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6975 "moveTaskToBack()");
6976
6977 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006978 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6979 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6980 Binder.getCallingUid(), "Task to back")) {
6981 return;
6982 }
6983 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006984 final long origId = Binder.clearCallingIdentity();
6985 moveTaskToBackLocked(task);
6986 Binder.restoreCallingIdentity(origId);
6987 }
6988 }
6989
6990 /**
6991 * Moves an activity, and all of the other activities within the same task, to the bottom
6992 * of the history stack. The activity's order within the task is unchanged.
6993 *
6994 * @param token A reference to the activity we wish to move
6995 * @param nonRoot If false then this only works if the activity is the root
6996 * of a task; if true it will work for any activity in a task.
6997 * @return Returns true if the move completed, false if not.
6998 */
6999 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7000 synchronized(this) {
7001 final long origId = Binder.clearCallingIdentity();
7002 int taskId = getTaskForActivityLocked(token, !nonRoot);
7003 if (taskId >= 0) {
7004 return moveTaskToBackLocked(taskId);
7005 }
7006 Binder.restoreCallingIdentity(origId);
7007 }
7008 return false;
7009 }
7010
7011 /**
7012 * Worker method for rearranging history stack. Implements the function of moving all
7013 * activities for a specific task (gathering them if disjoint) into a single group at the
7014 * bottom of the stack.
7015 *
7016 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7017 * to premeptively cancel the move.
7018 *
7019 * @param task The taskId to collect and move to the bottom.
7020 * @return Returns true if the move completed, false if not.
7021 */
7022 private final boolean moveTaskToBackLocked(int task) {
7023 Log.i(TAG, "moveTaskToBack: " + task);
7024
7025 // If we have a watcher, preflight the move before committing to it. First check
7026 // for *other* available tasks, but if none are available, then try again allowing the
7027 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007028 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007029 HistoryRecord next = topRunningActivityLocked(null, task);
7030 if (next == null) {
7031 next = topRunningActivityLocked(null, 0);
7032 }
7033 if (next != null) {
7034 // ask watcher if this is allowed
7035 boolean moveOK = true;
7036 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007037 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007038 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007039 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007040 }
7041 if (!moveOK) {
7042 return false;
7043 }
7044 }
7045 }
7046
7047 ArrayList moved = new ArrayList();
7048
7049 if (DEBUG_TRANSITION) Log.v(TAG,
7050 "Prepare to back transition: task=" + task);
7051 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
7052
7053 final int N = mHistory.size();
7054 int bottom = 0;
7055 int pos = 0;
7056
7057 // Shift all activities with this task down to the bottom
7058 // of the stack, keeping them in the same internal order.
7059 while (pos < N) {
7060 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7061 if (localLOGV) Log.v(
7062 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7063 if (r.task.taskId == task) {
7064 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7065 mHistory.remove(pos);
7066 mHistory.add(bottom, r);
7067 moved.add(r);
7068 bottom++;
7069 }
7070 pos++;
7071 }
7072
7073 mWindowManager.moveAppTokensToBottom(moved);
7074 if (VALIDATE_TOKENS) {
7075 mWindowManager.validateAppTokens(mHistory);
7076 }
7077
7078 finishTaskMove(task);
7079 return true;
7080 }
7081
7082 public void moveTaskBackwards(int task) {
7083 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7084 "moveTaskBackwards()");
7085
7086 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007087 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7088 Binder.getCallingUid(), "Task backwards")) {
7089 return;
7090 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007091 final long origId = Binder.clearCallingIdentity();
7092 moveTaskBackwardsLocked(task);
7093 Binder.restoreCallingIdentity(origId);
7094 }
7095 }
7096
7097 private final void moveTaskBackwardsLocked(int task) {
7098 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7099 }
7100
7101 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7102 synchronized(this) {
7103 return getTaskForActivityLocked(token, onlyRoot);
7104 }
7105 }
7106
7107 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7108 final int N = mHistory.size();
7109 TaskRecord lastTask = null;
7110 for (int i=0; i<N; i++) {
7111 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7112 if (r == token) {
7113 if (!onlyRoot || lastTask != r.task) {
7114 return r.task.taskId;
7115 }
7116 return -1;
7117 }
7118 lastTask = r.task;
7119 }
7120
7121 return -1;
7122 }
7123
7124 /**
7125 * Returns the top activity in any existing task matching the given
7126 * Intent. Returns null if no such task is found.
7127 */
7128 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7129 ComponentName cls = intent.getComponent();
7130 if (info.targetActivity != null) {
7131 cls = new ComponentName(info.packageName, info.targetActivity);
7132 }
7133
7134 TaskRecord cp = null;
7135
7136 final int N = mHistory.size();
7137 for (int i=(N-1); i>=0; i--) {
7138 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7139 if (!r.finishing && r.task != cp
7140 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7141 cp = r.task;
7142 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7143 // + "/aff=" + r.task.affinity + " to new cls="
7144 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7145 if (r.task.affinity != null) {
7146 if (r.task.affinity.equals(info.taskAffinity)) {
7147 //Log.i(TAG, "Found matching affinity!");
7148 return r;
7149 }
7150 } else if (r.task.intent != null
7151 && r.task.intent.getComponent().equals(cls)) {
7152 //Log.i(TAG, "Found matching class!");
7153 //dump();
7154 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7155 return r;
7156 } else if (r.task.affinityIntent != null
7157 && r.task.affinityIntent.getComponent().equals(cls)) {
7158 //Log.i(TAG, "Found matching class!");
7159 //dump();
7160 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7161 return r;
7162 }
7163 }
7164 }
7165
7166 return null;
7167 }
7168
7169 /**
7170 * Returns the first activity (starting from the top of the stack) that
7171 * is the same as the given activity. Returns null if no such activity
7172 * is found.
7173 */
7174 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7175 ComponentName cls = intent.getComponent();
7176 if (info.targetActivity != null) {
7177 cls = new ComponentName(info.packageName, info.targetActivity);
7178 }
7179
7180 final int N = mHistory.size();
7181 for (int i=(N-1); i>=0; i--) {
7182 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7183 if (!r.finishing) {
7184 if (r.intent.getComponent().equals(cls)) {
7185 //Log.i(TAG, "Found matching class!");
7186 //dump();
7187 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7188 return r;
7189 }
7190 }
7191 }
7192
7193 return null;
7194 }
7195
7196 public void finishOtherInstances(IBinder token, ComponentName className) {
7197 synchronized(this) {
7198 final long origId = Binder.clearCallingIdentity();
7199
7200 int N = mHistory.size();
7201 TaskRecord lastTask = null;
7202 for (int i=0; i<N; i++) {
7203 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7204 if (r.realActivity.equals(className)
7205 && r != token && lastTask != r.task) {
7206 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7207 null, "others")) {
7208 i--;
7209 N--;
7210 }
7211 }
7212 lastTask = r.task;
7213 }
7214
7215 Binder.restoreCallingIdentity(origId);
7216 }
7217 }
7218
7219 // =========================================================
7220 // THUMBNAILS
7221 // =========================================================
7222
7223 public void reportThumbnail(IBinder token,
7224 Bitmap thumbnail, CharSequence description) {
7225 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7226 final long origId = Binder.clearCallingIdentity();
7227 sendPendingThumbnail(null, token, thumbnail, description, true);
7228 Binder.restoreCallingIdentity(origId);
7229 }
7230
7231 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7232 Bitmap thumbnail, CharSequence description, boolean always) {
7233 TaskRecord task = null;
7234 ArrayList receivers = null;
7235
7236 //System.out.println("Send pending thumbnail: " + r);
7237
7238 synchronized(this) {
7239 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007240 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007241 if (index < 0) {
7242 return;
7243 }
7244 r = (HistoryRecord)mHistory.get(index);
7245 }
7246 if (thumbnail == null) {
7247 thumbnail = r.thumbnail;
7248 description = r.description;
7249 }
7250 if (thumbnail == null && !always) {
7251 // If there is no thumbnail, and this entry is not actually
7252 // going away, then abort for now and pick up the next
7253 // thumbnail we get.
7254 return;
7255 }
7256 task = r.task;
7257
7258 int N = mPendingThumbnails.size();
7259 int i=0;
7260 while (i<N) {
7261 PendingThumbnailsRecord pr =
7262 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7263 //System.out.println("Looking in " + pr.pendingRecords);
7264 if (pr.pendingRecords.remove(r)) {
7265 if (receivers == null) {
7266 receivers = new ArrayList();
7267 }
7268 receivers.add(pr);
7269 if (pr.pendingRecords.size() == 0) {
7270 pr.finished = true;
7271 mPendingThumbnails.remove(i);
7272 N--;
7273 continue;
7274 }
7275 }
7276 i++;
7277 }
7278 }
7279
7280 if (receivers != null) {
7281 final int N = receivers.size();
7282 for (int i=0; i<N; i++) {
7283 try {
7284 PendingThumbnailsRecord pr =
7285 (PendingThumbnailsRecord)receivers.get(i);
7286 pr.receiver.newThumbnail(
7287 task != null ? task.taskId : -1, thumbnail, description);
7288 if (pr.finished) {
7289 pr.receiver.finished();
7290 }
7291 } catch (Exception e) {
7292 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7293 }
7294 }
7295 }
7296 }
7297
7298 // =========================================================
7299 // CONTENT PROVIDERS
7300 // =========================================================
7301
7302 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7303 List providers = null;
7304 try {
7305 providers = ActivityThread.getPackageManager().
7306 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007307 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007308 } catch (RemoteException ex) {
7309 }
7310 if (providers != null) {
7311 final int N = providers.size();
7312 for (int i=0; i<N; i++) {
7313 ProviderInfo cpi =
7314 (ProviderInfo)providers.get(i);
7315 ContentProviderRecord cpr =
7316 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7317 if (cpr == null) {
7318 cpr = new ContentProviderRecord(cpi, app.info);
7319 mProvidersByClass.put(cpi.name, cpr);
7320 }
7321 app.pubProviders.put(cpi.name, cpr);
7322 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007323 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007324 }
7325 }
7326 return providers;
7327 }
7328
7329 private final String checkContentProviderPermissionLocked(
7330 ProviderInfo cpi, ProcessRecord r, int mode) {
7331 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7332 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7333 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7334 cpi.exported ? -1 : cpi.applicationInfo.uid)
7335 == PackageManager.PERMISSION_GRANTED
7336 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7337 return null;
7338 }
7339 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7340 cpi.exported ? -1 : cpi.applicationInfo.uid)
7341 == PackageManager.PERMISSION_GRANTED) {
7342 return null;
7343 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007344
7345 PathPermission[] pps = cpi.pathPermissions;
7346 if (pps != null) {
7347 int i = pps.length;
7348 while (i > 0) {
7349 i--;
7350 PathPermission pp = pps[i];
7351 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7352 cpi.exported ? -1 : cpi.applicationInfo.uid)
7353 == PackageManager.PERMISSION_GRANTED
7354 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7355 return null;
7356 }
7357 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7358 cpi.exported ? -1 : cpi.applicationInfo.uid)
7359 == PackageManager.PERMISSION_GRANTED) {
7360 return null;
7361 }
7362 }
7363 }
7364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007365 String msg = "Permission Denial: opening provider " + cpi.name
7366 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7367 + ", uid=" + callingUid + ") requires "
7368 + cpi.readPermission + " or " + cpi.writePermission;
7369 Log.w(TAG, msg);
7370 return msg;
7371 }
7372
7373 private final ContentProviderHolder getContentProviderImpl(
7374 IApplicationThread caller, String name) {
7375 ContentProviderRecord cpr;
7376 ProviderInfo cpi = null;
7377
7378 synchronized(this) {
7379 ProcessRecord r = null;
7380 if (caller != null) {
7381 r = getRecordForAppLocked(caller);
7382 if (r == null) {
7383 throw new SecurityException(
7384 "Unable to find app for caller " + caller
7385 + " (pid=" + Binder.getCallingPid()
7386 + ") when getting content provider " + name);
7387 }
7388 }
7389
7390 // First check if this content provider has been published...
7391 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7392 if (cpr != null) {
7393 cpi = cpr.info;
7394 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7395 return new ContentProviderHolder(cpi,
7396 cpi.readPermission != null
7397 ? cpi.readPermission : cpi.writePermission);
7398 }
7399
7400 if (r != null && cpr.canRunHere(r)) {
7401 // This provider has been published or is in the process
7402 // of being published... but it is also allowed to run
7403 // in the caller's process, so don't make a connection
7404 // and just let the caller instantiate its own instance.
7405 if (cpr.provider != null) {
7406 // don't give caller the provider object, it needs
7407 // to make its own.
7408 cpr = new ContentProviderRecord(cpr);
7409 }
7410 return cpr;
7411 }
7412
7413 final long origId = Binder.clearCallingIdentity();
7414
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007415 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007416 // return it right away.
7417 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007418 if (DEBUG_PROVIDER) Log.v(TAG,
7419 "Adding provider requested by "
7420 + r.processName + " from process "
7421 + cpr.info.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007422 r.conProviders.add(cpr);
7423 cpr.clients.add(r);
7424 } else {
7425 cpr.externals++;
7426 }
7427
7428 if (cpr.app != null) {
7429 updateOomAdjLocked(cpr.app);
7430 }
7431
7432 Binder.restoreCallingIdentity(origId);
7433
7434 } else {
7435 try {
7436 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007437 resolveContentProvider(name,
7438 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007439 } catch (RemoteException ex) {
7440 }
7441 if (cpi == null) {
7442 return null;
7443 }
7444
7445 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7446 return new ContentProviderHolder(cpi,
7447 cpi.readPermission != null
7448 ? cpi.readPermission : cpi.writePermission);
7449 }
7450
7451 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7452 final boolean firstClass = cpr == null;
7453 if (firstClass) {
7454 try {
7455 ApplicationInfo ai =
7456 ActivityThread.getPackageManager().
7457 getApplicationInfo(
7458 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007459 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007460 if (ai == null) {
7461 Log.w(TAG, "No package info for content provider "
7462 + cpi.name);
7463 return null;
7464 }
7465 cpr = new ContentProviderRecord(cpi, ai);
7466 } catch (RemoteException ex) {
7467 // pm is in same process, this will never happen.
7468 }
7469 }
7470
7471 if (r != null && cpr.canRunHere(r)) {
7472 // If this is a multiprocess provider, then just return its
7473 // info and allow the caller to instantiate it. Only do
7474 // this if the provider is the same user as the caller's
7475 // process, or can run as root (so can be in any process).
7476 return cpr;
7477 }
7478
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007479 if (DEBUG_PROVIDER) {
7480 RuntimeException e = new RuntimeException("here");
7481 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7482 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007483 }
7484
7485 // This is single process, and our app is now connecting to it.
7486 // See if we are already in the process of launching this
7487 // provider.
7488 final int N = mLaunchingProviders.size();
7489 int i;
7490 for (i=0; i<N; i++) {
7491 if (mLaunchingProviders.get(i) == cpr) {
7492 break;
7493 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007494 }
7495
7496 // If the provider is not already being launched, then get it
7497 // started.
7498 if (i >= N) {
7499 final long origId = Binder.clearCallingIdentity();
7500 ProcessRecord proc = startProcessLocked(cpi.processName,
7501 cpr.appInfo, false, 0, "content provider",
7502 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007503 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007504 if (proc == null) {
7505 Log.w(TAG, "Unable to launch app "
7506 + cpi.applicationInfo.packageName + "/"
7507 + cpi.applicationInfo.uid + " for provider "
7508 + name + ": process is bad");
7509 return null;
7510 }
7511 cpr.launchingApp = proc;
7512 mLaunchingProviders.add(cpr);
7513 Binder.restoreCallingIdentity(origId);
7514 }
7515
7516 // Make sure the provider is published (the same provider class
7517 // may be published under multiple names).
7518 if (firstClass) {
7519 mProvidersByClass.put(cpi.name, cpr);
7520 }
7521 mProvidersByName.put(name, cpr);
7522
7523 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007524 if (DEBUG_PROVIDER) Log.v(TAG,
7525 "Adding provider requested by "
7526 + r.processName + " from process "
7527 + cpr.info.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007528 r.conProviders.add(cpr);
7529 cpr.clients.add(r);
7530 } else {
7531 cpr.externals++;
7532 }
7533 }
7534 }
7535
7536 // Wait for the provider to be published...
7537 synchronized (cpr) {
7538 while (cpr.provider == null) {
7539 if (cpr.launchingApp == null) {
7540 Log.w(TAG, "Unable to launch app "
7541 + cpi.applicationInfo.packageName + "/"
7542 + cpi.applicationInfo.uid + " for provider "
7543 + name + ": launching app became null");
7544 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7545 cpi.applicationInfo.packageName,
7546 cpi.applicationInfo.uid, name);
7547 return null;
7548 }
7549 try {
7550 cpr.wait();
7551 } catch (InterruptedException ex) {
7552 }
7553 }
7554 }
7555 return cpr;
7556 }
7557
7558 public final ContentProviderHolder getContentProvider(
7559 IApplicationThread caller, String name) {
7560 if (caller == null) {
7561 String msg = "null IApplicationThread when getting content provider "
7562 + name;
7563 Log.w(TAG, msg);
7564 throw new SecurityException(msg);
7565 }
7566
7567 return getContentProviderImpl(caller, name);
7568 }
7569
7570 private ContentProviderHolder getContentProviderExternal(String name) {
7571 return getContentProviderImpl(null, name);
7572 }
7573
7574 /**
7575 * Drop a content provider from a ProcessRecord's bookkeeping
7576 * @param cpr
7577 */
7578 public void removeContentProvider(IApplicationThread caller, String name) {
7579 synchronized (this) {
7580 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7581 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007582 // remove from mProvidersByClass
7583 if (DEBUG_PROVIDER) Log.v(TAG, name +
7584 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007585 return;
7586 }
7587 final ProcessRecord r = getRecordForAppLocked(caller);
7588 if (r == null) {
7589 throw new SecurityException(
7590 "Unable to find app for caller " + caller +
7591 " when removing content provider " + name);
7592 }
7593 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007594 ContentProviderRecord localCpr = (ContentProviderRecord)
7595 mProvidersByClass.get(cpr.info.name);
7596 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7597 + r.info.processName + " from process "
7598 + localCpr.appInfo.processName);
7599 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007600 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007601 Log.w(TAG, "removeContentProvider called on local provider: "
7602 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007603 return;
7604 } else {
7605 localCpr.clients.remove(r);
7606 r.conProviders.remove(localCpr);
7607 }
7608 updateOomAdjLocked();
7609 }
7610 }
7611
7612 private void removeContentProviderExternal(String name) {
7613 synchronized (this) {
7614 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7615 if(cpr == null) {
7616 //remove from mProvidersByClass
7617 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7618 return;
7619 }
7620
7621 //update content provider record entry info
7622 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7623 localCpr.externals--;
7624 if (localCpr.externals < 0) {
7625 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7626 }
7627 updateOomAdjLocked();
7628 }
7629 }
7630
7631 public final void publishContentProviders(IApplicationThread caller,
7632 List<ContentProviderHolder> providers) {
7633 if (providers == null) {
7634 return;
7635 }
7636
7637 synchronized(this) {
7638 final ProcessRecord r = getRecordForAppLocked(caller);
7639 if (r == null) {
7640 throw new SecurityException(
7641 "Unable to find app for caller " + caller
7642 + " (pid=" + Binder.getCallingPid()
7643 + ") when publishing content providers");
7644 }
7645
7646 final long origId = Binder.clearCallingIdentity();
7647
7648 final int N = providers.size();
7649 for (int i=0; i<N; i++) {
7650 ContentProviderHolder src = providers.get(i);
7651 if (src == null || src.info == null || src.provider == null) {
7652 continue;
7653 }
7654 ContentProviderRecord dst =
7655 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7656 if (dst != null) {
7657 mProvidersByClass.put(dst.info.name, dst);
7658 String names[] = dst.info.authority.split(";");
7659 for (int j = 0; j < names.length; j++) {
7660 mProvidersByName.put(names[j], dst);
7661 }
7662
7663 int NL = mLaunchingProviders.size();
7664 int j;
7665 for (j=0; j<NL; j++) {
7666 if (mLaunchingProviders.get(j) == dst) {
7667 mLaunchingProviders.remove(j);
7668 j--;
7669 NL--;
7670 }
7671 }
7672 synchronized (dst) {
7673 dst.provider = src.provider;
7674 dst.app = r;
7675 dst.notifyAll();
7676 }
7677 updateOomAdjLocked(r);
7678 }
7679 }
7680
7681 Binder.restoreCallingIdentity(origId);
7682 }
7683 }
7684
7685 public static final void installSystemProviders() {
7686 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7687 List providers = mSelf.generateApplicationProvidersLocked(app);
7688 mSystemThread.installSystemProviders(providers);
7689 }
7690
7691 // =========================================================
7692 // GLOBAL MANAGEMENT
7693 // =========================================================
7694
7695 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7696 ApplicationInfo info, String customProcess) {
7697 String proc = customProcess != null ? customProcess : info.processName;
7698 BatteryStatsImpl.Uid.Proc ps = null;
7699 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7700 synchronized (stats) {
7701 ps = stats.getProcessStatsLocked(info.uid, proc);
7702 }
7703 return new ProcessRecord(ps, thread, info, proc);
7704 }
7705
7706 final ProcessRecord addAppLocked(ApplicationInfo info) {
7707 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7708
7709 if (app == null) {
7710 app = newProcessRecordLocked(null, info, null);
7711 mProcessNames.put(info.processName, info.uid, app);
7712 updateLRUListLocked(app, true);
7713 }
7714
7715 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7716 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7717 app.persistent = true;
7718 app.maxAdj = CORE_SERVER_ADJ;
7719 }
7720 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7721 mPersistentStartingProcesses.add(app);
7722 startProcessLocked(app, "added application", app.processName);
7723 }
7724
7725 return app;
7726 }
7727
7728 public void unhandledBack() {
7729 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7730 "unhandledBack()");
7731
7732 synchronized(this) {
7733 int count = mHistory.size();
7734 if (Config.LOGD) Log.d(
7735 TAG, "Performing unhandledBack(): stack size = " + count);
7736 if (count > 1) {
7737 final long origId = Binder.clearCallingIdentity();
7738 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7739 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7740 Binder.restoreCallingIdentity(origId);
7741 }
7742 }
7743 }
7744
7745 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7746 String name = uri.getAuthority();
7747 ContentProviderHolder cph = getContentProviderExternal(name);
7748 ParcelFileDescriptor pfd = null;
7749 if (cph != null) {
7750 // We record the binder invoker's uid in thread-local storage before
7751 // going to the content provider to open the file. Later, in the code
7752 // that handles all permissions checks, we look for this uid and use
7753 // that rather than the Activity Manager's own uid. The effect is that
7754 // we do the check against the caller's permissions even though it looks
7755 // to the content provider like the Activity Manager itself is making
7756 // the request.
7757 sCallerIdentity.set(new Identity(
7758 Binder.getCallingPid(), Binder.getCallingUid()));
7759 try {
7760 pfd = cph.provider.openFile(uri, "r");
7761 } catch (FileNotFoundException e) {
7762 // do nothing; pfd will be returned null
7763 } finally {
7764 // Ensure that whatever happens, we clean up the identity state
7765 sCallerIdentity.remove();
7766 }
7767
7768 // We've got the fd now, so we're done with the provider.
7769 removeContentProviderExternal(name);
7770 } else {
7771 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7772 }
7773 return pfd;
7774 }
7775
7776 public void goingToSleep() {
7777 synchronized(this) {
7778 mSleeping = true;
7779 mWindowManager.setEventDispatching(false);
7780
7781 if (mResumedActivity != null) {
7782 pauseIfSleepingLocked();
7783 } else {
7784 Log.w(TAG, "goingToSleep with no resumed activity!");
7785 }
7786 }
7787 }
7788
Dianne Hackborn55280a92009-05-07 15:53:46 -07007789 public boolean shutdown(int timeout) {
7790 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7791 != PackageManager.PERMISSION_GRANTED) {
7792 throw new SecurityException("Requires permission "
7793 + android.Manifest.permission.SHUTDOWN);
7794 }
7795
7796 boolean timedout = false;
7797
7798 synchronized(this) {
7799 mShuttingDown = true;
7800 mWindowManager.setEventDispatching(false);
7801
7802 if (mResumedActivity != null) {
7803 pauseIfSleepingLocked();
7804 final long endTime = System.currentTimeMillis() + timeout;
7805 while (mResumedActivity != null || mPausingActivity != null) {
7806 long delay = endTime - System.currentTimeMillis();
7807 if (delay <= 0) {
7808 Log.w(TAG, "Activity manager shutdown timed out");
7809 timedout = true;
7810 break;
7811 }
7812 try {
7813 this.wait();
7814 } catch (InterruptedException e) {
7815 }
7816 }
7817 }
7818 }
7819
7820 mUsageStatsService.shutdown();
7821 mBatteryStatsService.shutdown();
7822
7823 return timedout;
7824 }
7825
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007826 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007827 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007828 if (!mGoingToSleep.isHeld()) {
7829 mGoingToSleep.acquire();
7830 if (mLaunchingActivity.isHeld()) {
7831 mLaunchingActivity.release();
7832 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7833 }
7834 }
7835
7836 // If we are not currently pausing an activity, get the current
7837 // one to pause. If we are pausing one, we will just let that stuff
7838 // run and release the wake lock when all done.
7839 if (mPausingActivity == null) {
7840 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7841 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7842 startPausingLocked(false, true);
7843 }
7844 }
7845 }
7846
7847 public void wakingUp() {
7848 synchronized(this) {
7849 if (mGoingToSleep.isHeld()) {
7850 mGoingToSleep.release();
7851 }
7852 mWindowManager.setEventDispatching(true);
7853 mSleeping = false;
7854 resumeTopActivityLocked(null);
7855 }
7856 }
7857
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007858 public void stopAppSwitches() {
7859 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7860 != PackageManager.PERMISSION_GRANTED) {
7861 throw new SecurityException("Requires permission "
7862 + android.Manifest.permission.STOP_APP_SWITCHES);
7863 }
7864
7865 synchronized(this) {
7866 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7867 + APP_SWITCH_DELAY_TIME;
7868 mDidAppSwitch = false;
7869 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7870 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7871 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7872 }
7873 }
7874
7875 public void resumeAppSwitches() {
7876 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7877 != PackageManager.PERMISSION_GRANTED) {
7878 throw new SecurityException("Requires permission "
7879 + android.Manifest.permission.STOP_APP_SWITCHES);
7880 }
7881
7882 synchronized(this) {
7883 // Note that we don't execute any pending app switches... we will
7884 // let those wait until either the timeout, or the next start
7885 // activity request.
7886 mAppSwitchesAllowedTime = 0;
7887 }
7888 }
7889
7890 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7891 String name) {
7892 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7893 return true;
7894 }
7895
7896 final int perm = checkComponentPermission(
7897 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7898 callingUid, -1);
7899 if (perm == PackageManager.PERMISSION_GRANTED) {
7900 return true;
7901 }
7902
7903 Log.w(TAG, name + " request from " + callingUid + " stopped");
7904 return false;
7905 }
7906
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007907 public void setDebugApp(String packageName, boolean waitForDebugger,
7908 boolean persistent) {
7909 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7910 "setDebugApp()");
7911
7912 // Note that this is not really thread safe if there are multiple
7913 // callers into it at the same time, but that's not a situation we
7914 // care about.
7915 if (persistent) {
7916 final ContentResolver resolver = mContext.getContentResolver();
7917 Settings.System.putString(
7918 resolver, Settings.System.DEBUG_APP,
7919 packageName);
7920 Settings.System.putInt(
7921 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7922 waitForDebugger ? 1 : 0);
7923 }
7924
7925 synchronized (this) {
7926 if (!persistent) {
7927 mOrigDebugApp = mDebugApp;
7928 mOrigWaitForDebugger = mWaitForDebugger;
7929 }
7930 mDebugApp = packageName;
7931 mWaitForDebugger = waitForDebugger;
7932 mDebugTransient = !persistent;
7933 if (packageName != null) {
7934 final long origId = Binder.clearCallingIdentity();
7935 uninstallPackageLocked(packageName, -1, false);
7936 Binder.restoreCallingIdentity(origId);
7937 }
7938 }
7939 }
7940
7941 public void setAlwaysFinish(boolean enabled) {
7942 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7943 "setAlwaysFinish()");
7944
7945 Settings.System.putInt(
7946 mContext.getContentResolver(),
7947 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7948
7949 synchronized (this) {
7950 mAlwaysFinishActivities = enabled;
7951 }
7952 }
7953
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007954 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007955 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007956 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007957 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007958 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007959 }
7960 }
7961
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007962 public void registerActivityWatcher(IActivityWatcher watcher) {
7963 mWatchers.register(watcher);
7964 }
7965
7966 public void unregisterActivityWatcher(IActivityWatcher watcher) {
7967 mWatchers.unregister(watcher);
7968 }
7969
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007970 public final void enterSafeMode() {
7971 synchronized(this) {
7972 // It only makes sense to do this before the system is ready
7973 // and started launching other packages.
7974 if (!mSystemReady) {
7975 try {
7976 ActivityThread.getPackageManager().enterSafeMode();
7977 } catch (RemoteException e) {
7978 }
7979
7980 View v = LayoutInflater.from(mContext).inflate(
7981 com.android.internal.R.layout.safe_mode, null);
7982 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7983 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7984 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7985 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7986 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7987 lp.format = v.getBackground().getOpacity();
7988 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7989 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7990 ((WindowManager)mContext.getSystemService(
7991 Context.WINDOW_SERVICE)).addView(v, lp);
7992 }
7993 }
7994 }
7995
7996 public void noteWakeupAlarm(IIntentSender sender) {
7997 if (!(sender instanceof PendingIntentRecord)) {
7998 return;
7999 }
8000 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8001 synchronized (stats) {
8002 if (mBatteryStatsService.isOnBattery()) {
8003 mBatteryStatsService.enforceCallingPermission();
8004 PendingIntentRecord rec = (PendingIntentRecord)sender;
8005 int MY_UID = Binder.getCallingUid();
8006 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8007 BatteryStatsImpl.Uid.Pkg pkg =
8008 stats.getPackageStatsLocked(uid, rec.key.packageName);
8009 pkg.incWakeupsLocked();
8010 }
8011 }
8012 }
8013
8014 public boolean killPidsForMemory(int[] pids) {
8015 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8016 throw new SecurityException("killPidsForMemory only available to the system");
8017 }
8018
8019 // XXX Note: don't acquire main activity lock here, because the window
8020 // manager calls in with its locks held.
8021
8022 boolean killed = false;
8023 synchronized (mPidsSelfLocked) {
8024 int[] types = new int[pids.length];
8025 int worstType = 0;
8026 for (int i=0; i<pids.length; i++) {
8027 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8028 if (proc != null) {
8029 int type = proc.setAdj;
8030 types[i] = type;
8031 if (type > worstType) {
8032 worstType = type;
8033 }
8034 }
8035 }
8036
8037 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8038 // then constrain it so we will kill all hidden procs.
8039 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8040 worstType = HIDDEN_APP_MIN_ADJ;
8041 }
8042 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8043 for (int i=0; i<pids.length; i++) {
8044 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8045 if (proc == null) {
8046 continue;
8047 }
8048 int adj = proc.setAdj;
8049 if (adj >= worstType) {
8050 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8051 + adj + ")");
8052 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
8053 proc.processName, adj);
8054 killed = true;
8055 Process.killProcess(pids[i]);
8056 }
8057 }
8058 }
8059 return killed;
8060 }
8061
8062 public void reportPss(IApplicationThread caller, int pss) {
8063 Watchdog.PssRequestor req;
8064 String name;
8065 ProcessRecord callerApp;
8066 synchronized (this) {
8067 if (caller == null) {
8068 return;
8069 }
8070 callerApp = getRecordForAppLocked(caller);
8071 if (callerApp == null) {
8072 return;
8073 }
8074 callerApp.lastPss = pss;
8075 req = callerApp;
8076 name = callerApp.processName;
8077 }
8078 Watchdog.getInstance().reportPss(req, name, pss);
8079 if (!callerApp.persistent) {
8080 removeRequestedPss(callerApp);
8081 }
8082 }
8083
8084 public void requestPss(Runnable completeCallback) {
8085 ArrayList<ProcessRecord> procs;
8086 synchronized (this) {
8087 mRequestPssCallback = completeCallback;
8088 mRequestPssList.clear();
8089 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8090 ProcessRecord proc = mLRUProcesses.get(i);
8091 if (!proc.persistent) {
8092 mRequestPssList.add(proc);
8093 }
8094 }
8095 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8096 }
8097
8098 int oldPri = Process.getThreadPriority(Process.myTid());
8099 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8100 for (int i=procs.size()-1; i>=0; i--) {
8101 ProcessRecord proc = procs.get(i);
8102 proc.lastPss = 0;
8103 proc.requestPss();
8104 }
8105 Process.setThreadPriority(oldPri);
8106 }
8107
8108 void removeRequestedPss(ProcessRecord proc) {
8109 Runnable callback = null;
8110 synchronized (this) {
8111 if (mRequestPssList.remove(proc)) {
8112 if (mRequestPssList.size() == 0) {
8113 callback = mRequestPssCallback;
8114 mRequestPssCallback = null;
8115 }
8116 }
8117 }
8118
8119 if (callback != null) {
8120 callback.run();
8121 }
8122 }
8123
8124 public void collectPss(Watchdog.PssStats stats) {
8125 stats.mEmptyPss = 0;
8126 stats.mEmptyCount = 0;
8127 stats.mBackgroundPss = 0;
8128 stats.mBackgroundCount = 0;
8129 stats.mServicePss = 0;
8130 stats.mServiceCount = 0;
8131 stats.mVisiblePss = 0;
8132 stats.mVisibleCount = 0;
8133 stats.mForegroundPss = 0;
8134 stats.mForegroundCount = 0;
8135 stats.mNoPssCount = 0;
8136 synchronized (this) {
8137 int i;
8138 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8139 ? mProcDeaths.length : stats.mProcDeaths.length;
8140 int aggr = 0;
8141 for (i=0; i<NPD; i++) {
8142 aggr += mProcDeaths[i];
8143 stats.mProcDeaths[i] = aggr;
8144 }
8145 while (i<stats.mProcDeaths.length) {
8146 stats.mProcDeaths[i] = 0;
8147 i++;
8148 }
8149
8150 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8151 ProcessRecord proc = mLRUProcesses.get(i);
8152 if (proc.persistent) {
8153 continue;
8154 }
8155 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8156 if (proc.lastPss == 0) {
8157 stats.mNoPssCount++;
8158 continue;
8159 }
8160 if (proc.setAdj == EMPTY_APP_ADJ) {
8161 stats.mEmptyPss += proc.lastPss;
8162 stats.mEmptyCount++;
8163 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8164 stats.mEmptyPss += proc.lastPss;
8165 stats.mEmptyCount++;
8166 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8167 stats.mBackgroundPss += proc.lastPss;
8168 stats.mBackgroundCount++;
8169 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8170 stats.mVisiblePss += proc.lastPss;
8171 stats.mVisibleCount++;
8172 } else {
8173 stats.mForegroundPss += proc.lastPss;
8174 stats.mForegroundCount++;
8175 }
8176 }
8177 }
8178 }
8179
8180 public final void startRunning(String pkg, String cls, String action,
8181 String data) {
8182 synchronized(this) {
8183 if (mStartRunning) {
8184 return;
8185 }
8186 mStartRunning = true;
8187 mTopComponent = pkg != null && cls != null
8188 ? new ComponentName(pkg, cls) : null;
8189 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8190 mTopData = data;
8191 if (!mSystemReady) {
8192 return;
8193 }
8194 }
8195
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008196 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008197 }
8198
8199 private void retrieveSettings() {
8200 final ContentResolver resolver = mContext.getContentResolver();
8201 String debugApp = Settings.System.getString(
8202 resolver, Settings.System.DEBUG_APP);
8203 boolean waitForDebugger = Settings.System.getInt(
8204 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8205 boolean alwaysFinishActivities = Settings.System.getInt(
8206 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8207
8208 Configuration configuration = new Configuration();
8209 Settings.System.getConfiguration(resolver, configuration);
8210
8211 synchronized (this) {
8212 mDebugApp = mOrigDebugApp = debugApp;
8213 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8214 mAlwaysFinishActivities = alwaysFinishActivities;
8215 // This happens before any activities are started, so we can
8216 // change mConfiguration in-place.
8217 mConfiguration.updateFrom(configuration);
8218 }
8219 }
8220
8221 public boolean testIsSystemReady() {
8222 // no need to synchronize(this) just to read & return the value
8223 return mSystemReady;
8224 }
8225
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008226 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008227 // In the simulator, startRunning will never have been called, which
8228 // normally sets a few crucial variables. Do it here instead.
8229 if (!Process.supportsProcesses()) {
8230 mStartRunning = true;
8231 mTopAction = Intent.ACTION_MAIN;
8232 }
8233
8234 synchronized(this) {
8235 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008236 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008237 return;
8238 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008239
8240 // Check to see if there are any update receivers to run.
8241 if (!mDidUpdate) {
8242 if (mWaitingUpdate) {
8243 return;
8244 }
8245 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8246 List<ResolveInfo> ris = null;
8247 try {
8248 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8249 intent, null, 0);
8250 } catch (RemoteException e) {
8251 }
8252 if (ris != null) {
8253 for (int i=ris.size()-1; i>=0; i--) {
8254 if ((ris.get(i).activityInfo.applicationInfo.flags
8255 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8256 ris.remove(i);
8257 }
8258 }
8259 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8260 for (int i=0; i<ris.size(); i++) {
8261 ActivityInfo ai = ris.get(i).activityInfo;
8262 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8263 IIntentReceiver finisher = null;
8264 if (i == 0) {
8265 finisher = new IIntentReceiver.Stub() {
8266 public void performReceive(Intent intent, int resultCode,
8267 String data, Bundle extras, boolean ordered)
8268 throws RemoteException {
8269 synchronized (ActivityManagerService.this) {
8270 mDidUpdate = true;
8271 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008272 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008273 }
8274 };
8275 }
8276 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8277 broadcastIntentLocked(null, null, intent, null, finisher,
8278 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8279 if (i == 0) {
8280 mWaitingUpdate = true;
8281 }
8282 }
8283 }
8284 if (mWaitingUpdate) {
8285 return;
8286 }
8287 mDidUpdate = true;
8288 }
8289
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008290 mSystemReady = true;
8291 if (!mStartRunning) {
8292 return;
8293 }
8294 }
8295
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008296 ArrayList<ProcessRecord> procsToKill = null;
8297 synchronized(mPidsSelfLocked) {
8298 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8299 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8300 if (!isAllowedWhileBooting(proc.info)){
8301 if (procsToKill == null) {
8302 procsToKill = new ArrayList<ProcessRecord>();
8303 }
8304 procsToKill.add(proc);
8305 }
8306 }
8307 }
8308
8309 if (procsToKill != null) {
8310 synchronized(this) {
8311 for (int i=procsToKill.size()-1; i>=0; i--) {
8312 ProcessRecord proc = procsToKill.get(i);
8313 Log.i(TAG, "Removing system update proc: " + proc);
8314 removeProcessLocked(proc, true);
8315 }
8316 }
8317 }
8318
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008319 Log.i(TAG, "System now ready");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008320 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8321 SystemClock.uptimeMillis());
8322
8323 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008324 // Make sure we have no pre-ready processes sitting around.
8325
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008326 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8327 ResolveInfo ri = mContext.getPackageManager()
8328 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008329 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008330 CharSequence errorMsg = null;
8331 if (ri != null) {
8332 ActivityInfo ai = ri.activityInfo;
8333 ApplicationInfo app = ai.applicationInfo;
8334 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8335 mTopAction = Intent.ACTION_FACTORY_TEST;
8336 mTopData = null;
8337 mTopComponent = new ComponentName(app.packageName,
8338 ai.name);
8339 } else {
8340 errorMsg = mContext.getResources().getText(
8341 com.android.internal.R.string.factorytest_not_system);
8342 }
8343 } else {
8344 errorMsg = mContext.getResources().getText(
8345 com.android.internal.R.string.factorytest_no_action);
8346 }
8347 if (errorMsg != null) {
8348 mTopAction = null;
8349 mTopData = null;
8350 mTopComponent = null;
8351 Message msg = Message.obtain();
8352 msg.what = SHOW_FACTORY_ERROR_MSG;
8353 msg.getData().putCharSequence("msg", errorMsg);
8354 mHandler.sendMessage(msg);
8355 }
8356 }
8357 }
8358
8359 retrieveSettings();
8360
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008361 if (goingCallback != null) goingCallback.run();
8362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008363 synchronized (this) {
8364 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8365 try {
8366 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008367 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008368 if (apps != null) {
8369 int N = apps.size();
8370 int i;
8371 for (i=0; i<N; i++) {
8372 ApplicationInfo info
8373 = (ApplicationInfo)apps.get(i);
8374 if (info != null &&
8375 !info.packageName.equals("android")) {
8376 addAppLocked(info);
8377 }
8378 }
8379 }
8380 } catch (RemoteException ex) {
8381 // pm is in same process, this will never happen.
8382 }
8383 }
8384
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008385 // Start up initial activity.
8386 mBooting = true;
8387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008388 try {
8389 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8390 Message msg = Message.obtain();
8391 msg.what = SHOW_UID_ERROR_MSG;
8392 mHandler.sendMessage(msg);
8393 }
8394 } catch (RemoteException e) {
8395 }
8396
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008397 resumeTopActivityLocked(null);
8398 }
8399 }
8400
8401 boolean makeAppCrashingLocked(ProcessRecord app,
8402 String tag, String shortMsg, String longMsg, byte[] crashData) {
8403 app.crashing = true;
8404 app.crashingReport = generateProcessError(app,
8405 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8406 startAppProblemLocked(app);
8407 app.stopFreezingAllLocked();
8408 return handleAppCrashLocked(app);
8409 }
8410
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008411 private ComponentName getErrorReportReceiver(ProcessRecord app) {
8412 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008413
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008414 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008415 // look for receiver in the installer package
8416 String candidate = pm.getInstallerPackageName(app.info.packageName);
8417 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8418 if (result != null) {
8419 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008420 }
8421
Jacek Surazski82a73df2009-06-17 14:33:18 +02008422 // if the error app is on the system image, look for system apps
8423 // error receiver
8424 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8425 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8426 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8427 if (result != null) {
8428 return result;
8429 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008430 }
8431
Jacek Surazski82a73df2009-06-17 14:33:18 +02008432 // if there is a default receiver, try that
8433 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8434 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008435 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008436 // should not happen
8437 Log.e(TAG, "error talking to PackageManager", e);
8438 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008439 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008440 }
8441
8442 /**
8443 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8444 *
8445 * @param pm PackageManager isntance
8446 * @param errorPackage package which caused the error
8447 * @param receiverPackage candidate package to receive the error
8448 * @return activity component within receiverPackage which handles
8449 * ACTION_APP_ERROR, or null if not found
8450 */
8451 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8452 String receiverPackage) throws RemoteException {
8453 if (receiverPackage == null || receiverPackage.length() == 0) {
8454 return null;
8455 }
8456
8457 // break the loop if it's the error report receiver package that crashed
8458 if (receiverPackage.equals(errorPackage)) {
8459 return null;
8460 }
8461
8462 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8463 intent.setPackage(receiverPackage);
8464 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8465 if (info == null || info.activityInfo == null) {
8466 return null;
8467 }
8468 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008469 }
8470
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008471 void makeAppNotRespondingLocked(ProcessRecord app,
8472 String tag, String shortMsg, String longMsg, byte[] crashData) {
8473 app.notResponding = true;
8474 app.notRespondingReport = generateProcessError(app,
8475 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8476 crashData);
8477 startAppProblemLocked(app);
8478 app.stopFreezingAllLocked();
8479 }
8480
8481 /**
8482 * Generate a process error record, suitable for attachment to a ProcessRecord.
8483 *
8484 * @param app The ProcessRecord in which the error occurred.
8485 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8486 * ActivityManager.AppErrorStateInfo
8487 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8488 * @param shortMsg Short message describing the crash.
8489 * @param longMsg Long message describing the crash.
8490 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8491 *
8492 * @return Returns a fully-formed AppErrorStateInfo record.
8493 */
8494 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8495 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8496 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8497
8498 report.condition = condition;
8499 report.processName = app.processName;
8500 report.pid = app.pid;
8501 report.uid = app.info.uid;
8502 report.tag = tag;
8503 report.shortMsg = shortMsg;
8504 report.longMsg = longMsg;
8505 report.crashData = crashData;
8506
8507 return report;
8508 }
8509
8510 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8511 boolean crashed) {
8512 synchronized (this) {
8513 app.crashing = false;
8514 app.crashingReport = null;
8515 app.notResponding = false;
8516 app.notRespondingReport = null;
8517 if (app.anrDialog == fromDialog) {
8518 app.anrDialog = null;
8519 }
8520 if (app.waitDialog == fromDialog) {
8521 app.waitDialog = null;
8522 }
8523 if (app.pid > 0 && app.pid != MY_PID) {
8524 if (crashed) {
8525 handleAppCrashLocked(app);
8526 }
8527 Log.i(ActivityManagerService.TAG, "Killing process "
8528 + app.processName
8529 + " (pid=" + app.pid + ") at user's request");
8530 Process.killProcess(app.pid);
8531 }
8532
8533 }
8534 }
8535
8536 boolean handleAppCrashLocked(ProcessRecord app) {
8537 long now = SystemClock.uptimeMillis();
8538
8539 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8540 app.info.uid);
8541 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8542 // This process loses!
8543 Log.w(TAG, "Process " + app.info.processName
8544 + " has crashed too many times: killing!");
8545 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8546 app.info.processName, app.info.uid);
8547 killServicesLocked(app, false);
8548 for (int i=mHistory.size()-1; i>=0; i--) {
8549 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8550 if (r.app == app) {
8551 if (Config.LOGD) Log.d(
8552 TAG, " Force finishing activity "
8553 + r.intent.getComponent().flattenToShortString());
8554 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8555 }
8556 }
8557 if (!app.persistent) {
8558 // We don't want to start this process again until the user
8559 // explicitly does so... but for persistent process, we really
8560 // need to keep it running. If a persistent process is actually
8561 // repeatedly crashing, then badness for everyone.
8562 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8563 app.info.processName);
8564 mBadProcesses.put(app.info.processName, app.info.uid, now);
8565 app.bad = true;
8566 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8567 app.removed = true;
8568 removeProcessLocked(app, false);
8569 return false;
8570 }
8571 }
8572
8573 // Bump up the crash count of any services currently running in the proc.
8574 if (app.services.size() != 0) {
8575 // Any services running in the application need to be placed
8576 // back in the pending list.
8577 Iterator it = app.services.iterator();
8578 while (it.hasNext()) {
8579 ServiceRecord sr = (ServiceRecord)it.next();
8580 sr.crashCount++;
8581 }
8582 }
8583
8584 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8585 return true;
8586 }
8587
8588 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008589 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008590 skipCurrentReceiverLocked(app);
8591 }
8592
8593 void skipCurrentReceiverLocked(ProcessRecord app) {
8594 boolean reschedule = false;
8595 BroadcastRecord r = app.curReceiver;
8596 if (r != null) {
8597 // The current broadcast is waiting for this app's receiver
8598 // to be finished. Looks like that's not going to happen, so
8599 // let the broadcast continue.
8600 logBroadcastReceiverDiscard(r);
8601 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8602 r.resultExtras, r.resultAbort, true);
8603 reschedule = true;
8604 }
8605 r = mPendingBroadcast;
8606 if (r != null && r.curApp == app) {
8607 if (DEBUG_BROADCAST) Log.v(TAG,
8608 "skip & discard pending app " + r);
8609 logBroadcastReceiverDiscard(r);
8610 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8611 r.resultExtras, r.resultAbort, true);
8612 reschedule = true;
8613 }
8614 if (reschedule) {
8615 scheduleBroadcastsLocked();
8616 }
8617 }
8618
8619 public int handleApplicationError(IBinder app, int flags,
8620 String tag, String shortMsg, String longMsg, byte[] crashData) {
8621 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008622 ProcessRecord r = null;
8623 synchronized (this) {
8624 if (app != null) {
8625 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8626 final int NA = apps.size();
8627 for (int ia=0; ia<NA; ia++) {
8628 ProcessRecord p = apps.valueAt(ia);
8629 if (p.thread != null && p.thread.asBinder() == app) {
8630 r = p;
8631 break;
8632 }
8633 }
8634 }
8635 }
8636
8637 if (r != null) {
8638 // The application has crashed. Send the SIGQUIT to the process so
8639 // that it can dump its state.
8640 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8641 //Log.i(TAG, "Current system threads:");
8642 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8643 }
8644
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008645 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008646 try {
8647 String name = r != null ? r.processName : null;
8648 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008649 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008650 shortMsg, longMsg, crashData)) {
8651 Log.w(TAG, "Force-killing crashed app " + name
8652 + " at watcher's request");
8653 Process.killProcess(pid);
8654 return 0;
8655 }
8656 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008657 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008658 }
8659 }
8660
8661 final long origId = Binder.clearCallingIdentity();
8662
8663 // If this process is running instrumentation, finish it.
8664 if (r != null && r.instrumentationClass != null) {
8665 Log.w(TAG, "Error in app " + r.processName
8666 + " running instrumentation " + r.instrumentationClass + ":");
8667 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8668 if (longMsg != null) Log.w(TAG, " " + longMsg);
8669 Bundle info = new Bundle();
8670 info.putString("shortMsg", shortMsg);
8671 info.putString("longMsg", longMsg);
8672 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8673 Binder.restoreCallingIdentity(origId);
8674 return 0;
8675 }
8676
8677 if (r != null) {
8678 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8679 return 0;
8680 }
8681 } else {
8682 Log.w(TAG, "Some application object " + app + " tag " + tag
8683 + " has crashed, but I don't know who it is.");
8684 Log.w(TAG, "ShortMsg:" + shortMsg);
8685 Log.w(TAG, "LongMsg:" + longMsg);
8686 Binder.restoreCallingIdentity(origId);
8687 return 0;
8688 }
8689
8690 Message msg = Message.obtain();
8691 msg.what = SHOW_ERROR_MSG;
8692 HashMap data = new HashMap();
8693 data.put("result", result);
8694 data.put("app", r);
8695 data.put("flags", flags);
8696 data.put("shortMsg", shortMsg);
8697 data.put("longMsg", longMsg);
8698 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8699 // For system processes, submit crash data to the server.
8700 data.put("crashData", crashData);
8701 }
8702 msg.obj = data;
8703 mHandler.sendMessage(msg);
8704
8705 Binder.restoreCallingIdentity(origId);
8706 }
8707
8708 int res = result.get();
8709
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008710 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008711 synchronized (this) {
8712 if (r != null) {
8713 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8714 SystemClock.uptimeMillis());
8715 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008716 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8717 appErrorIntent = createAppErrorIntentLocked(r);
8718 res = AppErrorDialog.FORCE_QUIT;
8719 }
8720 }
8721
8722 if (appErrorIntent != null) {
8723 try {
8724 mContext.startActivity(appErrorIntent);
8725 } catch (ActivityNotFoundException e) {
8726 Log.w(TAG, "bug report receiver dissappeared", e);
8727 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008728 }
8729
8730 return res;
8731 }
8732
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008733 Intent createAppErrorIntentLocked(ProcessRecord r) {
8734 ApplicationErrorReport report = createAppErrorReportLocked(r);
8735 if (report == null) {
8736 return null;
8737 }
8738 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8739 result.setComponent(r.errorReportReceiver);
8740 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8741 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8742 return result;
8743 }
8744
8745 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8746 if (r.errorReportReceiver == null) {
8747 return null;
8748 }
8749
8750 if (!r.crashing && !r.notResponding) {
8751 return null;
8752 }
8753
8754 try {
8755 ApplicationErrorReport report = new ApplicationErrorReport();
8756 report.packageName = r.info.packageName;
8757 report.installerPackageName = r.errorReportReceiver.getPackageName();
8758 report.processName = r.processName;
8759
8760 if (r.crashing) {
8761 report.type = ApplicationErrorReport.TYPE_CRASH;
8762 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8763
8764 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8765 r.crashingReport.crashData);
8766 DataInputStream dataStream = new DataInputStream(byteStream);
8767 CrashData crashData = new CrashData(dataStream);
8768 ThrowableData throwData = crashData.getThrowableData();
8769
8770 report.time = crashData.getTime();
8771 report.crashInfo.stackTrace = throwData.toString();
8772
Jacek Surazskif829a782009-06-11 22:47:02 +02008773 // Extract the source of the exception, useful for report
8774 // clustering. Also extract the "deepest" non-null exception
8775 // message.
8776 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008777 while (throwData.getCause() != null) {
8778 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008779 String msg = throwData.getMessage();
8780 if (msg != null && msg.length() > 0) {
8781 exceptionMessage = msg;
8782 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008783 }
8784 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008785 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008786 report.crashInfo.exceptionClassName = throwData.getType();
8787 report.crashInfo.throwFileName = trace.getFileName();
8788 report.crashInfo.throwClassName = trace.getClassName();
8789 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008790 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008791 } else if (r.notResponding) {
8792 report.type = ApplicationErrorReport.TYPE_ANR;
8793 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8794
8795 report.anrInfo.activity = r.notRespondingReport.tag;
8796 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8797 report.anrInfo.info = r.notRespondingReport.longMsg;
8798 }
8799
8800 return report;
8801 } catch (IOException e) {
8802 // we don't send it
8803 }
8804
8805 return null;
8806 }
8807
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008808 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8809 // assume our apps are happy - lazy create the list
8810 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8811
8812 synchronized (this) {
8813
8814 // iterate across all processes
8815 final int N = mLRUProcesses.size();
8816 for (int i = 0; i < N; i++) {
8817 ProcessRecord app = mLRUProcesses.get(i);
8818 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8819 // This one's in trouble, so we'll generate a report for it
8820 // crashes are higher priority (in case there's a crash *and* an anr)
8821 ActivityManager.ProcessErrorStateInfo report = null;
8822 if (app.crashing) {
8823 report = app.crashingReport;
8824 } else if (app.notResponding) {
8825 report = app.notRespondingReport;
8826 }
8827
8828 if (report != null) {
8829 if (errList == null) {
8830 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8831 }
8832 errList.add(report);
8833 } else {
8834 Log.w(TAG, "Missing app error report, app = " + app.processName +
8835 " crashing = " + app.crashing +
8836 " notResponding = " + app.notResponding);
8837 }
8838 }
8839 }
8840 }
8841
8842 return errList;
8843 }
8844
8845 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8846 // Lazy instantiation of list
8847 List<ActivityManager.RunningAppProcessInfo> runList = null;
8848 synchronized (this) {
8849 // Iterate across all processes
8850 final int N = mLRUProcesses.size();
8851 for (int i = 0; i < N; i++) {
8852 ProcessRecord app = mLRUProcesses.get(i);
8853 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8854 // Generate process state info for running application
8855 ActivityManager.RunningAppProcessInfo currApp =
8856 new ActivityManager.RunningAppProcessInfo(app.processName,
8857 app.pid, app.getPackageList());
8858 int adj = app.curAdj;
8859 if (adj >= CONTENT_PROVIDER_ADJ) {
8860 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8861 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8862 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008863 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8864 } else if (adj >= HOME_APP_ADJ) {
8865 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8866 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008867 } else if (adj >= SECONDARY_SERVER_ADJ) {
8868 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8869 } else if (adj >= VISIBLE_APP_ADJ) {
8870 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8871 } else {
8872 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8873 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07008874 currApp.importanceReasonCode = app.adjTypeCode;
8875 if (app.adjSource instanceof ProcessRecord) {
8876 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
8877 } else if (app.adjSource instanceof HistoryRecord) {
8878 HistoryRecord r = (HistoryRecord)app.adjSource;
8879 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
8880 }
8881 if (app.adjTarget instanceof ComponentName) {
8882 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
8883 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008884 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8885 // + " lru=" + currApp.lru);
8886 if (runList == null) {
8887 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8888 }
8889 runList.add(currApp);
8890 }
8891 }
8892 }
8893 return runList;
8894 }
8895
8896 @Override
8897 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8898 synchronized (this) {
8899 if (checkCallingPermission(android.Manifest.permission.DUMP)
8900 != PackageManager.PERMISSION_GRANTED) {
8901 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8902 + Binder.getCallingPid()
8903 + ", uid=" + Binder.getCallingUid()
8904 + " without permission "
8905 + android.Manifest.permission.DUMP);
8906 return;
8907 }
8908 if (args.length != 0 && "service".equals(args[0])) {
8909 dumpService(fd, pw, args);
8910 return;
8911 }
8912 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008913 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008914 pw.println(" ");
8915 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008916 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008917 if (mWaitingVisibleActivities.size() > 0) {
8918 pw.println(" ");
8919 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008920 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008921 }
8922 if (mStoppingActivities.size() > 0) {
8923 pw.println(" ");
8924 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008925 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008926 }
8927 if (mFinishingActivities.size() > 0) {
8928 pw.println(" ");
8929 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008930 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008931 }
8932
8933 pw.println(" ");
8934 pw.println(" mPausingActivity: " + mPausingActivity);
8935 pw.println(" mResumedActivity: " + mResumedActivity);
8936 pw.println(" mFocusedActivity: " + mFocusedActivity);
8937 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8938
8939 if (mRecentTasks.size() > 0) {
8940 pw.println(" ");
8941 pw.println("Recent tasks in Current Activity Manager State:");
8942
8943 final int N = mRecentTasks.size();
8944 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008945 TaskRecord tr = mRecentTasks.get(i);
8946 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8947 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008948 mRecentTasks.get(i).dump(pw, " ");
8949 }
8950 }
8951
8952 pw.println(" ");
8953 pw.println(" mCurTask: " + mCurTask);
8954
8955 pw.println(" ");
8956 pw.println("Processes in Current Activity Manager State:");
8957
8958 boolean needSep = false;
8959 int numPers = 0;
8960
8961 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8962 final int NA = procs.size();
8963 for (int ia=0; ia<NA; ia++) {
8964 if (!needSep) {
8965 pw.println(" All known processes:");
8966 needSep = true;
8967 }
8968 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008969 pw.print(r.persistent ? " *PERS*" : " *APP*");
8970 pw.print(" UID "); pw.print(procs.keyAt(ia));
8971 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008972 r.dump(pw, " ");
8973 if (r.persistent) {
8974 numPers++;
8975 }
8976 }
8977 }
8978
8979 if (mLRUProcesses.size() > 0) {
8980 if (needSep) pw.println(" ");
8981 needSep = true;
8982 pw.println(" Running processes (most recent first):");
8983 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008984 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008985 needSep = true;
8986 }
8987
8988 synchronized (mPidsSelfLocked) {
8989 if (mPidsSelfLocked.size() > 0) {
8990 if (needSep) pw.println(" ");
8991 needSep = true;
8992 pw.println(" PID mappings:");
8993 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008994 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8995 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008996 }
8997 }
8998 }
8999
9000 if (mForegroundProcesses.size() > 0) {
9001 if (needSep) pw.println(" ");
9002 needSep = true;
9003 pw.println(" Foreground Processes:");
9004 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009005 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9006 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009007 }
9008 }
9009
9010 if (mPersistentStartingProcesses.size() > 0) {
9011 if (needSep) pw.println(" ");
9012 needSep = true;
9013 pw.println(" Persisent processes that are starting:");
9014 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009015 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009016 }
9017
9018 if (mStartingProcesses.size() > 0) {
9019 if (needSep) pw.println(" ");
9020 needSep = true;
9021 pw.println(" Processes that are starting:");
9022 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009023 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009024 }
9025
9026 if (mRemovedProcesses.size() > 0) {
9027 if (needSep) pw.println(" ");
9028 needSep = true;
9029 pw.println(" Processes that are being removed:");
9030 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009031 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009032 }
9033
9034 if (mProcessesOnHold.size() > 0) {
9035 if (needSep) pw.println(" ");
9036 needSep = true;
9037 pw.println(" Processes that are on old until the system is ready:");
9038 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009039 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009040 }
9041
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009042 if (mProcessesToGc.size() > 0) {
9043 if (needSep) pw.println(" ");
9044 needSep = true;
9045 pw.println(" Processes that are waiting to GC:");
9046 long now = SystemClock.uptimeMillis();
9047 for (int i=0; i<mProcessesToGc.size(); i++) {
9048 ProcessRecord proc = mProcessesToGc.get(i);
9049 pw.print(" Process "); pw.println(proc);
9050 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9051 pw.print(", last gced=");
9052 pw.print(now-proc.lastRequestedGc);
9053 pw.print(" ms ago, last lowMwm=");
9054 pw.print(now-proc.lastLowMemory);
9055 pw.println(" ms ago");
9056
9057 }
9058 }
9059
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009060 if (mProcessCrashTimes.getMap().size() > 0) {
9061 if (needSep) pw.println(" ");
9062 needSep = true;
9063 pw.println(" Time since processes crashed:");
9064 long now = SystemClock.uptimeMillis();
9065 for (Map.Entry<String, SparseArray<Long>> procs
9066 : mProcessCrashTimes.getMap().entrySet()) {
9067 SparseArray<Long> uids = procs.getValue();
9068 final int N = uids.size();
9069 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009070 pw.print(" Process "); pw.print(procs.getKey());
9071 pw.print(" uid "); pw.print(uids.keyAt(i));
9072 pw.print(": last crashed ");
9073 pw.print((now-uids.valueAt(i)));
9074 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009075 }
9076 }
9077 }
9078
9079 if (mBadProcesses.getMap().size() > 0) {
9080 if (needSep) pw.println(" ");
9081 needSep = true;
9082 pw.println(" Bad processes:");
9083 for (Map.Entry<String, SparseArray<Long>> procs
9084 : mBadProcesses.getMap().entrySet()) {
9085 SparseArray<Long> uids = procs.getValue();
9086 final int N = uids.size();
9087 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009088 pw.print(" Bad process "); pw.print(procs.getKey());
9089 pw.print(" uid "); pw.print(uids.keyAt(i));
9090 pw.print(": crashed at time ");
9091 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009092 }
9093 }
9094 }
9095
9096 pw.println(" ");
9097 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009098 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009099 pw.println(" mConfiguration: " + mConfiguration);
9100 pw.println(" mStartRunning=" + mStartRunning
9101 + " mSystemReady=" + mSystemReady
9102 + " mBooting=" + mBooting
9103 + " mBooted=" + mBooted
9104 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009105 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009106 pw.println(" mGoingToSleep=" + mGoingToSleep);
9107 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9108 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9109 + " mDebugTransient=" + mDebugTransient
9110 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9111 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009112 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009113 }
9114 }
9115
9116 /**
9117 * There are three ways to call this:
9118 * - no service specified: dump all the services
9119 * - a flattened component name that matched an existing service was specified as the
9120 * first arg: dump that one service
9121 * - the first arg isn't the flattened component name of an existing service:
9122 * dump all services whose component contains the first arg as a substring
9123 */
9124 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9125 String[] newArgs;
9126 String componentNameString;
9127 ServiceRecord r;
9128 if (args.length == 1) {
9129 componentNameString = null;
9130 newArgs = EMPTY_STRING_ARRAY;
9131 r = null;
9132 } else {
9133 componentNameString = args[1];
9134 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9135 r = componentName != null ? mServices.get(componentName) : null;
9136 newArgs = new String[args.length - 2];
9137 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9138 }
9139
9140 if (r != null) {
9141 dumpService(fd, pw, r, newArgs);
9142 } else {
9143 for (ServiceRecord r1 : mServices.values()) {
9144 if (componentNameString == null
9145 || r1.name.flattenToString().contains(componentNameString)) {
9146 dumpService(fd, pw, r1, newArgs);
9147 }
9148 }
9149 }
9150 }
9151
9152 /**
9153 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9154 * there is a thread associated with the service.
9155 */
9156 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9157 pw.println(" Service " + r.name.flattenToString());
9158 if (r.app != null && r.app.thread != null) {
9159 try {
9160 // flush anything that is already in the PrintWriter since the thread is going
9161 // to write to the file descriptor directly
9162 pw.flush();
9163 r.app.thread.dumpService(fd, r, args);
9164 pw.print("\n");
9165 } catch (RemoteException e) {
9166 pw.println("got a RemoteException while dumping the service");
9167 }
9168 }
9169 }
9170
9171 void dumpBroadcasts(PrintWriter pw) {
9172 synchronized (this) {
9173 if (checkCallingPermission(android.Manifest.permission.DUMP)
9174 != PackageManager.PERMISSION_GRANTED) {
9175 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9176 + Binder.getCallingPid()
9177 + ", uid=" + Binder.getCallingUid()
9178 + " without permission "
9179 + android.Manifest.permission.DUMP);
9180 return;
9181 }
9182 pw.println("Broadcasts in Current Activity Manager State:");
9183
9184 if (mRegisteredReceivers.size() > 0) {
9185 pw.println(" ");
9186 pw.println(" Registered Receivers:");
9187 Iterator it = mRegisteredReceivers.values().iterator();
9188 while (it.hasNext()) {
9189 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009190 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009191 r.dump(pw, " ");
9192 }
9193 }
9194
9195 pw.println(" ");
9196 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009197 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009198
9199 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9200 || mPendingBroadcast != null) {
9201 if (mParallelBroadcasts.size() > 0) {
9202 pw.println(" ");
9203 pw.println(" Active broadcasts:");
9204 }
9205 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9206 pw.println(" Broadcast #" + i + ":");
9207 mParallelBroadcasts.get(i).dump(pw, " ");
9208 }
9209 if (mOrderedBroadcasts.size() > 0) {
9210 pw.println(" ");
9211 pw.println(" Active serialized broadcasts:");
9212 }
9213 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9214 pw.println(" Serialized Broadcast #" + i + ":");
9215 mOrderedBroadcasts.get(i).dump(pw, " ");
9216 }
9217 pw.println(" ");
9218 pw.println(" Pending broadcast:");
9219 if (mPendingBroadcast != null) {
9220 mPendingBroadcast.dump(pw, " ");
9221 } else {
9222 pw.println(" (null)");
9223 }
9224 }
9225
9226 pw.println(" ");
9227 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9228 if (mStickyBroadcasts != null) {
9229 pw.println(" ");
9230 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009231 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009232 for (Map.Entry<String, ArrayList<Intent>> ent
9233 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009234 pw.print(" * Sticky action "); pw.print(ent.getKey());
9235 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009236 ArrayList<Intent> intents = ent.getValue();
9237 final int N = intents.size();
9238 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009239 sb.setLength(0);
9240 sb.append(" Intent: ");
9241 intents.get(i).toShortString(sb, true, false);
9242 pw.println(sb.toString());
9243 Bundle bundle = intents.get(i).getExtras();
9244 if (bundle != null) {
9245 pw.print(" ");
9246 pw.println(bundle.toString());
9247 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009248 }
9249 }
9250 }
9251
9252 pw.println(" ");
9253 pw.println(" mHandler:");
9254 mHandler.dump(new PrintWriterPrinter(pw), " ");
9255 }
9256 }
9257
9258 void dumpServices(PrintWriter pw) {
9259 synchronized (this) {
9260 if (checkCallingPermission(android.Manifest.permission.DUMP)
9261 != PackageManager.PERMISSION_GRANTED) {
9262 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9263 + Binder.getCallingPid()
9264 + ", uid=" + Binder.getCallingUid()
9265 + " without permission "
9266 + android.Manifest.permission.DUMP);
9267 return;
9268 }
9269 pw.println("Services in Current Activity Manager State:");
9270
9271 boolean needSep = false;
9272
9273 if (mServices.size() > 0) {
9274 pw.println(" Active services:");
9275 Iterator<ServiceRecord> it = mServices.values().iterator();
9276 while (it.hasNext()) {
9277 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009278 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009279 r.dump(pw, " ");
9280 }
9281 needSep = true;
9282 }
9283
9284 if (mPendingServices.size() > 0) {
9285 if (needSep) pw.println(" ");
9286 pw.println(" Pending services:");
9287 for (int i=0; i<mPendingServices.size(); i++) {
9288 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009289 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009290 r.dump(pw, " ");
9291 }
9292 needSep = true;
9293 }
9294
9295 if (mRestartingServices.size() > 0) {
9296 if (needSep) pw.println(" ");
9297 pw.println(" Restarting services:");
9298 for (int i=0; i<mRestartingServices.size(); i++) {
9299 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009300 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009301 r.dump(pw, " ");
9302 }
9303 needSep = true;
9304 }
9305
9306 if (mStoppingServices.size() > 0) {
9307 if (needSep) pw.println(" ");
9308 pw.println(" Stopping services:");
9309 for (int i=0; i<mStoppingServices.size(); i++) {
9310 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009311 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009312 r.dump(pw, " ");
9313 }
9314 needSep = true;
9315 }
9316
9317 if (mServiceConnections.size() > 0) {
9318 if (needSep) pw.println(" ");
9319 pw.println(" Connection bindings to services:");
9320 Iterator<ConnectionRecord> it
9321 = mServiceConnections.values().iterator();
9322 while (it.hasNext()) {
9323 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009324 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009325 r.dump(pw, " ");
9326 }
9327 }
9328 }
9329 }
9330
9331 void dumpProviders(PrintWriter pw) {
9332 synchronized (this) {
9333 if (checkCallingPermission(android.Manifest.permission.DUMP)
9334 != PackageManager.PERMISSION_GRANTED) {
9335 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9336 + Binder.getCallingPid()
9337 + ", uid=" + Binder.getCallingUid()
9338 + " without permission "
9339 + android.Manifest.permission.DUMP);
9340 return;
9341 }
9342
9343 pw.println("Content Providers in Current Activity Manager State:");
9344
9345 boolean needSep = false;
9346
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009347 if (mProvidersByClass.size() > 0) {
9348 if (needSep) pw.println(" ");
9349 pw.println(" Published content providers (by class):");
9350 Iterator it = mProvidersByClass.entrySet().iterator();
9351 while (it.hasNext()) {
9352 Map.Entry e = (Map.Entry)it.next();
9353 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009354 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009355 r.dump(pw, " ");
9356 }
9357 needSep = true;
9358 }
9359
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009360 if (mProvidersByName.size() > 0) {
9361 pw.println(" ");
9362 pw.println(" Authority to provider mappings:");
9363 Iterator it = mProvidersByName.entrySet().iterator();
9364 while (it.hasNext()) {
9365 Map.Entry e = (Map.Entry)it.next();
9366 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9367 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9368 pw.println(r);
9369 }
9370 needSep = true;
9371 }
9372
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009373 if (mLaunchingProviders.size() > 0) {
9374 if (needSep) pw.println(" ");
9375 pw.println(" Launching content providers:");
9376 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009377 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9378 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009379 }
9380 needSep = true;
9381 }
9382
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009383 if (mGrantedUriPermissions.size() > 0) {
9384 pw.println();
9385 pw.println("Granted Uri Permissions:");
9386 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9387 int uid = mGrantedUriPermissions.keyAt(i);
9388 HashMap<Uri, UriPermission> perms
9389 = mGrantedUriPermissions.valueAt(i);
9390 pw.print(" * UID "); pw.print(uid);
9391 pw.println(" holds:");
9392 for (UriPermission perm : perms.values()) {
9393 pw.print(" "); pw.println(perm);
9394 perm.dump(pw, " ");
9395 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009396 }
9397 }
9398 }
9399 }
9400
9401 void dumpSenders(PrintWriter pw) {
9402 synchronized (this) {
9403 if (checkCallingPermission(android.Manifest.permission.DUMP)
9404 != PackageManager.PERMISSION_GRANTED) {
9405 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9406 + Binder.getCallingPid()
9407 + ", uid=" + Binder.getCallingUid()
9408 + " without permission "
9409 + android.Manifest.permission.DUMP);
9410 return;
9411 }
9412
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009413 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009414
9415 if (this.mIntentSenderRecords.size() > 0) {
9416 Iterator<WeakReference<PendingIntentRecord>> it
9417 = mIntentSenderRecords.values().iterator();
9418 while (it.hasNext()) {
9419 WeakReference<PendingIntentRecord> ref = it.next();
9420 PendingIntentRecord rec = ref != null ? ref.get(): null;
9421 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009422 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009423 rec.dump(pw, " ");
9424 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009425 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009426 }
9427 }
9428 }
9429 }
9430 }
9431
9432 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009433 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009434 TaskRecord lastTask = null;
9435 for (int i=list.size()-1; i>=0; i--) {
9436 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009437 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009438 if (lastTask != r.task) {
9439 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009440 pw.print(prefix);
9441 pw.print(full ? "* " : " ");
9442 pw.println(lastTask);
9443 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009444 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009445 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009446 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009447 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9448 pw.print(" #"); pw.print(i); pw.print(": ");
9449 pw.println(r);
9450 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009451 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009452 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009453 }
9454 }
9455
9456 private static final int dumpProcessList(PrintWriter pw, List list,
9457 String prefix, String normalLabel, String persistentLabel,
9458 boolean inclOomAdj) {
9459 int numPers = 0;
9460 for (int i=list.size()-1; i>=0; i--) {
9461 ProcessRecord r = (ProcessRecord)list.get(i);
9462 if (false) {
9463 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9464 + " #" + i + ":");
9465 r.dump(pw, prefix + " ");
9466 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009467 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009468 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009469 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9470 if (r.adjSource != null || r.adjTarget != null) {
9471 pw.println(prefix + " " + r.adjTarget
9472 + " used by " + r.adjSource);
9473 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009474 } else {
9475 pw.println(String.format("%s%s #%2d: %s",
9476 prefix, (r.persistent ? persistentLabel : normalLabel),
9477 i, r.toString()));
9478 }
9479 if (r.persistent) {
9480 numPers++;
9481 }
9482 }
9483 return numPers;
9484 }
9485
9486 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9487 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009488 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009489 long uptime = SystemClock.uptimeMillis();
9490 long realtime = SystemClock.elapsedRealtime();
9491
9492 if (isCheckinRequest) {
9493 // short checkin version
9494 pw.println(uptime + "," + realtime);
9495 pw.flush();
9496 } else {
9497 pw.println("Applications Memory Usage (kB):");
9498 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9499 }
9500 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9501 ProcessRecord r = (ProcessRecord)list.get(i);
9502 if (r.thread != null) {
9503 if (!isCheckinRequest) {
9504 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9505 pw.flush();
9506 }
9507 try {
9508 r.thread.asBinder().dump(fd, args);
9509 } catch (RemoteException e) {
9510 if (!isCheckinRequest) {
9511 pw.println("Got RemoteException!");
9512 pw.flush();
9513 }
9514 }
9515 }
9516 }
9517 }
9518
9519 /**
9520 * Searches array of arguments for the specified string
9521 * @param args array of argument strings
9522 * @param value value to search for
9523 * @return true if the value is contained in the array
9524 */
9525 private static boolean scanArgs(String[] args, String value) {
9526 if (args != null) {
9527 for (String arg : args) {
9528 if (value.equals(arg)) {
9529 return true;
9530 }
9531 }
9532 }
9533 return false;
9534 }
9535
Dianne Hackborn75b03852009-06-12 15:43:26 -07009536 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009537 int count = mHistory.size();
9538
9539 // convert the token to an entry in the history.
9540 HistoryRecord r = null;
9541 int index = -1;
9542 for (int i=count-1; i>=0; i--) {
9543 Object o = mHistory.get(i);
9544 if (o == token) {
9545 r = (HistoryRecord)o;
9546 index = i;
9547 break;
9548 }
9549 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009550
9551 return index;
9552 }
9553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009554 private final void killServicesLocked(ProcessRecord app,
9555 boolean allowRestart) {
9556 // Report disconnected services.
9557 if (false) {
9558 // XXX we are letting the client link to the service for
9559 // death notifications.
9560 if (app.services.size() > 0) {
9561 Iterator it = app.services.iterator();
9562 while (it.hasNext()) {
9563 ServiceRecord r = (ServiceRecord)it.next();
9564 if (r.connections.size() > 0) {
9565 Iterator<ConnectionRecord> jt
9566 = r.connections.values().iterator();
9567 while (jt.hasNext()) {
9568 ConnectionRecord c = jt.next();
9569 if (c.binding.client != app) {
9570 try {
9571 //c.conn.connected(r.className, null);
9572 } catch (Exception e) {
9573 // todo: this should be asynchronous!
9574 Log.w(TAG, "Exception thrown disconnected servce "
9575 + r.shortName
9576 + " from app " + app.processName, e);
9577 }
9578 }
9579 }
9580 }
9581 }
9582 }
9583 }
9584
9585 // Clean up any connections this application has to other services.
9586 if (app.connections.size() > 0) {
9587 Iterator<ConnectionRecord> it = app.connections.iterator();
9588 while (it.hasNext()) {
9589 ConnectionRecord r = it.next();
9590 removeConnectionLocked(r, app, null);
9591 }
9592 }
9593 app.connections.clear();
9594
9595 if (app.services.size() != 0) {
9596 // Any services running in the application need to be placed
9597 // back in the pending list.
9598 Iterator it = app.services.iterator();
9599 while (it.hasNext()) {
9600 ServiceRecord sr = (ServiceRecord)it.next();
9601 synchronized (sr.stats.getBatteryStats()) {
9602 sr.stats.stopLaunchedLocked();
9603 }
9604 sr.app = null;
9605 sr.executeNesting = 0;
9606 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009607
9608 boolean hasClients = sr.bindings.size() > 0;
9609 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009610 Iterator<IntentBindRecord> bindings
9611 = sr.bindings.values().iterator();
9612 while (bindings.hasNext()) {
9613 IntentBindRecord b = bindings.next();
9614 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9615 + ": shouldUnbind=" + b.hasBound);
9616 b.binder = null;
9617 b.requested = b.received = b.hasBound = false;
9618 }
9619 }
9620
9621 if (sr.crashCount >= 2) {
9622 Log.w(TAG, "Service crashed " + sr.crashCount
9623 + " times, stopping: " + sr);
9624 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9625 sr.crashCount, sr.shortName, app.pid);
9626 bringDownServiceLocked(sr, true);
9627 } else if (!allowRestart) {
9628 bringDownServiceLocked(sr, true);
9629 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009630 boolean canceled = scheduleServiceRestartLocked(sr, true);
9631
9632 // Should the service remain running? Note that in the
9633 // extreme case of so many attempts to deliver a command
9634 // that it failed, that we also will stop it here.
9635 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9636 if (sr.pendingStarts.size() == 0) {
9637 sr.startRequested = false;
9638 if (!hasClients) {
9639 // Whoops, no reason to restart!
9640 bringDownServiceLocked(sr, true);
9641 }
9642 }
9643 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009644 }
9645 }
9646
9647 if (!allowRestart) {
9648 app.services.clear();
9649 }
9650 }
9651
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009652 // Make sure we have no more records on the stopping list.
9653 int i = mStoppingServices.size();
9654 while (i > 0) {
9655 i--;
9656 ServiceRecord sr = mStoppingServices.get(i);
9657 if (sr.app == app) {
9658 mStoppingServices.remove(i);
9659 }
9660 }
9661
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009662 app.executingServices.clear();
9663 }
9664
9665 private final void removeDyingProviderLocked(ProcessRecord proc,
9666 ContentProviderRecord cpr) {
9667 synchronized (cpr) {
9668 cpr.launchingApp = null;
9669 cpr.notifyAll();
9670 }
9671
9672 mProvidersByClass.remove(cpr.info.name);
9673 String names[] = cpr.info.authority.split(";");
9674 for (int j = 0; j < names.length; j++) {
9675 mProvidersByName.remove(names[j]);
9676 }
9677
9678 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9679 while (cit.hasNext()) {
9680 ProcessRecord capp = cit.next();
9681 if (!capp.persistent && capp.thread != null
9682 && capp.pid != 0
9683 && capp.pid != MY_PID) {
9684 Log.i(TAG, "Killing app " + capp.processName
9685 + " (pid " + capp.pid
9686 + ") because provider " + cpr.info.name
9687 + " is in dying process " + proc.processName);
9688 Process.killProcess(capp.pid);
9689 }
9690 }
9691
9692 mLaunchingProviders.remove(cpr);
9693 }
9694
9695 /**
9696 * Main code for cleaning up a process when it has gone away. This is
9697 * called both as a result of the process dying, or directly when stopping
9698 * a process when running in single process mode.
9699 */
9700 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9701 boolean restarting, int index) {
9702 if (index >= 0) {
9703 mLRUProcesses.remove(index);
9704 }
9705
9706 // Dismiss any open dialogs.
9707 if (app.crashDialog != null) {
9708 app.crashDialog.dismiss();
9709 app.crashDialog = null;
9710 }
9711 if (app.anrDialog != null) {
9712 app.anrDialog.dismiss();
9713 app.anrDialog = null;
9714 }
9715 if (app.waitDialog != null) {
9716 app.waitDialog.dismiss();
9717 app.waitDialog = null;
9718 }
9719
9720 app.crashing = false;
9721 app.notResponding = false;
9722
9723 app.resetPackageList();
9724 app.thread = null;
9725 app.forcingToForeground = null;
9726 app.foregroundServices = false;
9727
9728 killServicesLocked(app, true);
9729
9730 boolean restart = false;
9731
9732 int NL = mLaunchingProviders.size();
9733
9734 // Remove published content providers.
9735 if (!app.pubProviders.isEmpty()) {
9736 Iterator it = app.pubProviders.values().iterator();
9737 while (it.hasNext()) {
9738 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9739 cpr.provider = null;
9740 cpr.app = null;
9741
9742 // See if someone is waiting for this provider... in which
9743 // case we don't remove it, but just let it restart.
9744 int i = 0;
9745 if (!app.bad) {
9746 for (; i<NL; i++) {
9747 if (mLaunchingProviders.get(i) == cpr) {
9748 restart = true;
9749 break;
9750 }
9751 }
9752 } else {
9753 i = NL;
9754 }
9755
9756 if (i >= NL) {
9757 removeDyingProviderLocked(app, cpr);
9758 NL = mLaunchingProviders.size();
9759 }
9760 }
9761 app.pubProviders.clear();
9762 }
9763
9764 // Look through the content providers we are waiting to have launched,
9765 // and if any run in this process then either schedule a restart of
9766 // the process or kill the client waiting for it if this process has
9767 // gone bad.
9768 for (int i=0; i<NL; i++) {
9769 ContentProviderRecord cpr = (ContentProviderRecord)
9770 mLaunchingProviders.get(i);
9771 if (cpr.launchingApp == app) {
9772 if (!app.bad) {
9773 restart = true;
9774 } else {
9775 removeDyingProviderLocked(app, cpr);
9776 NL = mLaunchingProviders.size();
9777 }
9778 }
9779 }
9780
9781 // Unregister from connected content providers.
9782 if (!app.conProviders.isEmpty()) {
9783 Iterator it = app.conProviders.iterator();
9784 while (it.hasNext()) {
9785 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9786 cpr.clients.remove(app);
9787 }
9788 app.conProviders.clear();
9789 }
9790
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009791 // At this point there may be remaining entries in mLaunchingProviders
9792 // where we were the only one waiting, so they are no longer of use.
9793 // Look for these and clean up if found.
9794 // XXX Commented out for now. Trying to figure out a way to reproduce
9795 // the actual situation to identify what is actually going on.
9796 if (false) {
9797 for (int i=0; i<NL; i++) {
9798 ContentProviderRecord cpr = (ContentProviderRecord)
9799 mLaunchingProviders.get(i);
9800 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9801 synchronized (cpr) {
9802 cpr.launchingApp = null;
9803 cpr.notifyAll();
9804 }
9805 }
9806 }
9807 }
9808
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009809 skipCurrentReceiverLocked(app);
9810
9811 // Unregister any receivers.
9812 if (app.receivers.size() > 0) {
9813 Iterator<ReceiverList> it = app.receivers.iterator();
9814 while (it.hasNext()) {
9815 removeReceiverLocked(it.next());
9816 }
9817 app.receivers.clear();
9818 }
9819
Christopher Tate181fafa2009-05-14 11:12:14 -07009820 // If the app is undergoing backup, tell the backup manager about it
9821 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9822 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9823 try {
9824 IBackupManager bm = IBackupManager.Stub.asInterface(
9825 ServiceManager.getService(Context.BACKUP_SERVICE));
9826 bm.agentDisconnected(app.info.packageName);
9827 } catch (RemoteException e) {
9828 // can't happen; backup manager is local
9829 }
9830 }
9831
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009832 // If the caller is restarting this app, then leave it in its
9833 // current lists and let the caller take care of it.
9834 if (restarting) {
9835 return;
9836 }
9837
9838 if (!app.persistent) {
9839 if (DEBUG_PROCESSES) Log.v(TAG,
9840 "Removing non-persistent process during cleanup: " + app);
9841 mProcessNames.remove(app.processName, app.info.uid);
9842 } else if (!app.removed) {
9843 // This app is persistent, so we need to keep its record around.
9844 // If it is not already on the pending app list, add it there
9845 // and start a new process for it.
9846 app.thread = null;
9847 app.forcingToForeground = null;
9848 app.foregroundServices = false;
9849 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9850 mPersistentStartingProcesses.add(app);
9851 restart = true;
9852 }
9853 }
9854 mProcessesOnHold.remove(app);
9855
The Android Open Source Project4df24232009-03-05 14:34:35 -08009856 if (app == mHomeProcess) {
9857 mHomeProcess = null;
9858 }
9859
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009860 if (restart) {
9861 // We have components that still need to be running in the
9862 // process, so re-launch it.
9863 mProcessNames.put(app.processName, app.info.uid, app);
9864 startProcessLocked(app, "restart", app.processName);
9865 } else if (app.pid > 0 && app.pid != MY_PID) {
9866 // Goodbye!
9867 synchronized (mPidsSelfLocked) {
9868 mPidsSelfLocked.remove(app.pid);
9869 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9870 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009871 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009872 }
9873 }
9874
9875 // =========================================================
9876 // SERVICES
9877 // =========================================================
9878
9879 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9880 ActivityManager.RunningServiceInfo info =
9881 new ActivityManager.RunningServiceInfo();
9882 info.service = r.name;
9883 if (r.app != null) {
9884 info.pid = r.app.pid;
9885 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -07009886 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009887 info.process = r.processName;
9888 info.foreground = r.isForeground;
9889 info.activeSince = r.createTime;
9890 info.started = r.startRequested;
9891 info.clientCount = r.connections.size();
9892 info.crashCount = r.crashCount;
9893 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07009894 if (r.isForeground) {
9895 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
9896 }
9897 if (r.startRequested) {
9898 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
9899 }
9900 if (r.app != null && r.app.pid == Process.myPid()) {
9901 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
9902 }
9903 if (r.app != null && r.app.persistent) {
9904 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
9905 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009906 for (ConnectionRecord conn : r.connections.values()) {
9907 if (conn.clientLabel != 0) {
9908 info.clientPackage = conn.binding.client.info.packageName;
9909 info.clientLabel = conn.clientLabel;
9910 break;
9911 }
9912 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009913 return info;
9914 }
9915
9916 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9917 int flags) {
9918 synchronized (this) {
9919 ArrayList<ActivityManager.RunningServiceInfo> res
9920 = new ArrayList<ActivityManager.RunningServiceInfo>();
9921
9922 if (mServices.size() > 0) {
9923 Iterator<ServiceRecord> it = mServices.values().iterator();
9924 while (it.hasNext() && res.size() < maxNum) {
9925 res.add(makeRunningServiceInfoLocked(it.next()));
9926 }
9927 }
9928
9929 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9930 ServiceRecord r = mRestartingServices.get(i);
9931 ActivityManager.RunningServiceInfo info =
9932 makeRunningServiceInfoLocked(r);
9933 info.restarting = r.nextRestartTime;
9934 res.add(info);
9935 }
9936
9937 return res;
9938 }
9939 }
9940
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009941 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
9942 synchronized (this) {
9943 ServiceRecord r = mServices.get(name);
9944 if (r != null) {
9945 for (ConnectionRecord conn : r.connections.values()) {
9946 if (conn.clientIntent != null) {
9947 return conn.clientIntent;
9948 }
9949 }
9950 }
9951 }
9952 return null;
9953 }
9954
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009955 private final ServiceRecord findServiceLocked(ComponentName name,
9956 IBinder token) {
9957 ServiceRecord r = mServices.get(name);
9958 return r == token ? r : null;
9959 }
9960
9961 private final class ServiceLookupResult {
9962 final ServiceRecord record;
9963 final String permission;
9964
9965 ServiceLookupResult(ServiceRecord _record, String _permission) {
9966 record = _record;
9967 permission = _permission;
9968 }
9969 };
9970
9971 private ServiceLookupResult findServiceLocked(Intent service,
9972 String resolvedType) {
9973 ServiceRecord r = null;
9974 if (service.getComponent() != null) {
9975 r = mServices.get(service.getComponent());
9976 }
9977 if (r == null) {
9978 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9979 r = mServicesByIntent.get(filter);
9980 }
9981
9982 if (r == null) {
9983 try {
9984 ResolveInfo rInfo =
9985 ActivityThread.getPackageManager().resolveService(
9986 service, resolvedType, 0);
9987 ServiceInfo sInfo =
9988 rInfo != null ? rInfo.serviceInfo : null;
9989 if (sInfo == null) {
9990 return null;
9991 }
9992
9993 ComponentName name = new ComponentName(
9994 sInfo.applicationInfo.packageName, sInfo.name);
9995 r = mServices.get(name);
9996 } catch (RemoteException ex) {
9997 // pm is in same process, this will never happen.
9998 }
9999 }
10000 if (r != null) {
10001 int callingPid = Binder.getCallingPid();
10002 int callingUid = Binder.getCallingUid();
10003 if (checkComponentPermission(r.permission,
10004 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10005 != PackageManager.PERMISSION_GRANTED) {
10006 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10007 + " from pid=" + callingPid
10008 + ", uid=" + callingUid
10009 + " requires " + r.permission);
10010 return new ServiceLookupResult(null, r.permission);
10011 }
10012 return new ServiceLookupResult(r, null);
10013 }
10014 return null;
10015 }
10016
10017 private class ServiceRestarter implements Runnable {
10018 private ServiceRecord mService;
10019
10020 void setService(ServiceRecord service) {
10021 mService = service;
10022 }
10023
10024 public void run() {
10025 synchronized(ActivityManagerService.this) {
10026 performServiceRestartLocked(mService);
10027 }
10028 }
10029 }
10030
10031 private ServiceLookupResult retrieveServiceLocked(Intent service,
10032 String resolvedType, int callingPid, int callingUid) {
10033 ServiceRecord r = null;
10034 if (service.getComponent() != null) {
10035 r = mServices.get(service.getComponent());
10036 }
10037 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10038 r = mServicesByIntent.get(filter);
10039 if (r == null) {
10040 try {
10041 ResolveInfo rInfo =
10042 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010043 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010044 ServiceInfo sInfo =
10045 rInfo != null ? rInfo.serviceInfo : null;
10046 if (sInfo == null) {
10047 Log.w(TAG, "Unable to start service " + service +
10048 ": not found");
10049 return null;
10050 }
10051
10052 ComponentName name = new ComponentName(
10053 sInfo.applicationInfo.packageName, sInfo.name);
10054 r = mServices.get(name);
10055 if (r == null) {
10056 filter = new Intent.FilterComparison(service.cloneFilter());
10057 ServiceRestarter res = new ServiceRestarter();
10058 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10059 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10060 synchronized (stats) {
10061 ss = stats.getServiceStatsLocked(
10062 sInfo.applicationInfo.uid, sInfo.packageName,
10063 sInfo.name);
10064 }
10065 r = new ServiceRecord(ss, name, filter, sInfo, res);
10066 res.setService(r);
10067 mServices.put(name, r);
10068 mServicesByIntent.put(filter, r);
10069
10070 // Make sure this component isn't in the pending list.
10071 int N = mPendingServices.size();
10072 for (int i=0; i<N; i++) {
10073 ServiceRecord pr = mPendingServices.get(i);
10074 if (pr.name.equals(name)) {
10075 mPendingServices.remove(i);
10076 i--;
10077 N--;
10078 }
10079 }
10080 }
10081 } catch (RemoteException ex) {
10082 // pm is in same process, this will never happen.
10083 }
10084 }
10085 if (r != null) {
10086 if (checkComponentPermission(r.permission,
10087 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10088 != PackageManager.PERMISSION_GRANTED) {
10089 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10090 + " from pid=" + Binder.getCallingPid()
10091 + ", uid=" + Binder.getCallingUid()
10092 + " requires " + r.permission);
10093 return new ServiceLookupResult(null, r.permission);
10094 }
10095 return new ServiceLookupResult(r, null);
10096 }
10097 return null;
10098 }
10099
10100 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10101 long now = SystemClock.uptimeMillis();
10102 if (r.executeNesting == 0 && r.app != null) {
10103 if (r.app.executingServices.size() == 0) {
10104 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10105 msg.obj = r.app;
10106 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10107 }
10108 r.app.executingServices.add(r);
10109 }
10110 r.executeNesting++;
10111 r.executingStart = now;
10112 }
10113
10114 private final void sendServiceArgsLocked(ServiceRecord r,
10115 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010116 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010117 if (N == 0) {
10118 return;
10119 }
10120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010121 int i = 0;
10122 while (i < N) {
10123 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010124 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010125 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010126 + r.name + " " + r.intent + " args=" + si.intent);
10127 if (si.intent == null && N > 0) {
10128 // If somehow we got a dummy start at the front, then
10129 // just drop it here.
10130 i++;
10131 continue;
10132 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010133 bumpServiceExecutingLocked(r);
10134 if (!oomAdjusted) {
10135 oomAdjusted = true;
10136 updateOomAdjLocked(r.app);
10137 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010138 int flags = 0;
10139 if (si.deliveryCount > 0) {
10140 flags |= Service.START_FLAG_RETRY;
10141 }
10142 if (si.doneExecutingCount > 0) {
10143 flags |= Service.START_FLAG_REDELIVERY;
10144 }
10145 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10146 si.deliveredTime = SystemClock.uptimeMillis();
10147 r.deliveredStarts.add(si);
10148 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010149 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010150 } catch (RemoteException e) {
10151 // Remote process gone... we'll let the normal cleanup take
10152 // care of this.
10153 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010154 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010155 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010156 break;
10157 }
10158 }
10159 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010160 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010161 } else {
10162 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010163 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010164 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010165 }
10166 }
10167 }
10168
10169 private final boolean requestServiceBindingLocked(ServiceRecord r,
10170 IntentBindRecord i, boolean rebind) {
10171 if (r.app == null || r.app.thread == null) {
10172 // If service is not currently running, can't yet bind.
10173 return false;
10174 }
10175 if ((!i.requested || rebind) && i.apps.size() > 0) {
10176 try {
10177 bumpServiceExecutingLocked(r);
10178 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10179 + ": shouldUnbind=" + i.hasBound);
10180 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10181 if (!rebind) {
10182 i.requested = true;
10183 }
10184 i.hasBound = true;
10185 i.doRebind = false;
10186 } catch (RemoteException e) {
10187 return false;
10188 }
10189 }
10190 return true;
10191 }
10192
10193 private final void requestServiceBindingsLocked(ServiceRecord r) {
10194 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10195 while (bindings.hasNext()) {
10196 IntentBindRecord i = bindings.next();
10197 if (!requestServiceBindingLocked(r, i, false)) {
10198 break;
10199 }
10200 }
10201 }
10202
10203 private final void realStartServiceLocked(ServiceRecord r,
10204 ProcessRecord app) throws RemoteException {
10205 if (app.thread == null) {
10206 throw new RemoteException();
10207 }
10208
10209 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010210 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010211
10212 app.services.add(r);
10213 bumpServiceExecutingLocked(r);
10214 updateLRUListLocked(app, true);
10215
10216 boolean created = false;
10217 try {
10218 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10219 + r.name + " " + r.intent);
10220 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
10221 System.identityHashCode(r), r.shortName,
10222 r.intent.getIntent().toString(), r.app.pid);
10223 synchronized (r.stats.getBatteryStats()) {
10224 r.stats.startLaunchedLocked();
10225 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010226 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010227 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010228 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010229 created = true;
10230 } finally {
10231 if (!created) {
10232 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010233 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010234 }
10235 }
10236
10237 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010238
10239 // If the service is in the started state, and there are no
10240 // pending arguments, then fake up one so its onStartCommand() will
10241 // be called.
10242 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10243 r.lastStartId++;
10244 if (r.lastStartId < 1) {
10245 r.lastStartId = 1;
10246 }
10247 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10248 }
10249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010250 sendServiceArgsLocked(r, true);
10251 }
10252
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010253 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10254 boolean allowCancel) {
10255 boolean canceled = false;
10256
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010257 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010258 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010259 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010260
10261 // Any delivered but not yet finished starts should be put back
10262 // on the pending list.
10263 final int N = r.deliveredStarts.size();
10264 if (N > 0) {
10265 for (int i=N-1; i>=0; i--) {
10266 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10267 if (si.intent == null) {
10268 // We'll generate this again if needed.
10269 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10270 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10271 r.pendingStarts.add(0, si);
10272 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10273 dur *= 2;
10274 if (minDuration < dur) minDuration = dur;
10275 if (resetTime < dur) resetTime = dur;
10276 } else {
10277 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10278 + r.name);
10279 canceled = true;
10280 }
10281 }
10282 r.deliveredStarts.clear();
10283 }
10284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010285 r.totalRestartCount++;
10286 if (r.restartDelay == 0) {
10287 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010288 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010289 } else {
10290 // If it has been a "reasonably long time" since the service
10291 // was started, then reset our restart duration back to
10292 // the beginning, so we don't infinitely increase the duration
10293 // on a service that just occasionally gets killed (which is
10294 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010295 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010296 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010297 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010298 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010299 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010300 if (r.restartDelay < minDuration) {
10301 r.restartDelay = minDuration;
10302 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010303 }
10304 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010305
10306 r.nextRestartTime = now + r.restartDelay;
10307
10308 // Make sure that we don't end up restarting a bunch of services
10309 // all at the same time.
10310 boolean repeat;
10311 do {
10312 repeat = false;
10313 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10314 ServiceRecord r2 = mRestartingServices.get(i);
10315 if (r2 != r && r.nextRestartTime
10316 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10317 && r.nextRestartTime
10318 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10319 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10320 r.restartDelay = r.nextRestartTime - now;
10321 repeat = true;
10322 break;
10323 }
10324 }
10325 } while (repeat);
10326
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010327 if (!mRestartingServices.contains(r)) {
10328 mRestartingServices.add(r);
10329 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010330
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010331 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010332
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010333 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010334 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010335 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10336 Log.w(TAG, "Scheduling restart of crashed service "
10337 + r.shortName + " in " + r.restartDelay + "ms");
10338 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10339 r.shortName, r.restartDelay);
10340
10341 Message msg = Message.obtain();
10342 msg.what = SERVICE_ERROR_MSG;
10343 msg.obj = r;
10344 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010345
10346 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010347 }
10348
10349 final void performServiceRestartLocked(ServiceRecord r) {
10350 if (!mRestartingServices.contains(r)) {
10351 return;
10352 }
10353 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10354 }
10355
10356 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10357 if (r.restartDelay == 0) {
10358 return false;
10359 }
10360 r.resetRestartCounter();
10361 mRestartingServices.remove(r);
10362 mHandler.removeCallbacks(r.restarter);
10363 return true;
10364 }
10365
10366 private final boolean bringUpServiceLocked(ServiceRecord r,
10367 int intentFlags, boolean whileRestarting) {
10368 //Log.i(TAG, "Bring up service:");
10369 //r.dump(" ");
10370
10371 if (r.app != null) {
10372 sendServiceArgsLocked(r, false);
10373 return true;
10374 }
10375
10376 if (!whileRestarting && r.restartDelay > 0) {
10377 // If waiting for a restart, then do nothing.
10378 return true;
10379 }
10380
10381 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10382 + " " + r.intent);
10383
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010384 // We are now bringing the service up, so no longer in the
10385 // restarting state.
10386 mRestartingServices.remove(r);
10387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010388 final String appName = r.processName;
10389 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10390 if (app != null && app.thread != null) {
10391 try {
10392 realStartServiceLocked(r, app);
10393 return true;
10394 } catch (RemoteException e) {
10395 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10396 }
10397
10398 // If a dead object exception was thrown -- fall through to
10399 // restart the application.
10400 }
10401
10402 if (!mPendingServices.contains(r)) {
10403 // Not running -- get it started, and enqueue this service record
10404 // to be executed when the app comes up.
10405 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070010406 "service", r.name, false) == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010407 Log.w(TAG, "Unable to launch app "
10408 + r.appInfo.packageName + "/"
10409 + r.appInfo.uid + " for service "
10410 + r.intent.getIntent() + ": process is bad");
10411 bringDownServiceLocked(r, true);
10412 return false;
10413 }
10414 mPendingServices.add(r);
10415 }
10416 return true;
10417 }
10418
10419 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10420 //Log.i(TAG, "Bring down service:");
10421 //r.dump(" ");
10422
10423 // Does it still need to run?
10424 if (!force && r.startRequested) {
10425 return;
10426 }
10427 if (r.connections.size() > 0) {
10428 if (!force) {
10429 // XXX should probably keep a count of the number of auto-create
10430 // connections directly in the service.
10431 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10432 while (it.hasNext()) {
10433 ConnectionRecord cr = it.next();
10434 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10435 return;
10436 }
10437 }
10438 }
10439
10440 // Report to all of the connections that the service is no longer
10441 // available.
10442 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10443 while (it.hasNext()) {
10444 ConnectionRecord c = it.next();
10445 try {
10446 // todo: shouldn't be a synchronous call!
10447 c.conn.connected(r.name, null);
10448 } catch (Exception e) {
10449 Log.w(TAG, "Failure disconnecting service " + r.name +
10450 " to connection " + c.conn.asBinder() +
10451 " (in " + c.binding.client.processName + ")", e);
10452 }
10453 }
10454 }
10455
10456 // Tell the service that it has been unbound.
10457 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10458 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10459 while (it.hasNext()) {
10460 IntentBindRecord ibr = it.next();
10461 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10462 + ": hasBound=" + ibr.hasBound);
10463 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10464 try {
10465 bumpServiceExecutingLocked(r);
10466 updateOomAdjLocked(r.app);
10467 ibr.hasBound = false;
10468 r.app.thread.scheduleUnbindService(r,
10469 ibr.intent.getIntent());
10470 } catch (Exception e) {
10471 Log.w(TAG, "Exception when unbinding service "
10472 + r.shortName, e);
10473 serviceDoneExecutingLocked(r, true);
10474 }
10475 }
10476 }
10477 }
10478
10479 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10480 + " " + r.intent);
10481 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10482 System.identityHashCode(r), r.shortName,
10483 (r.app != null) ? r.app.pid : -1);
10484
10485 mServices.remove(r.name);
10486 mServicesByIntent.remove(r.intent);
10487 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10488 r.totalRestartCount = 0;
10489 unscheduleServiceRestartLocked(r);
10490
10491 // Also make sure it is not on the pending list.
10492 int N = mPendingServices.size();
10493 for (int i=0; i<N; i++) {
10494 if (mPendingServices.get(i) == r) {
10495 mPendingServices.remove(i);
10496 if (DEBUG_SERVICE) Log.v(
10497 TAG, "Removed pending service: " + r.shortName);
10498 i--;
10499 N--;
10500 }
10501 }
10502
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010503 r.cancelNotification();
10504 r.isForeground = false;
10505 r.foregroundId = 0;
10506 r.foregroundNoti = null;
10507
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010508 // Clear start entries.
10509 r.deliveredStarts.clear();
10510 r.pendingStarts.clear();
10511
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010512 if (r.app != null) {
10513 synchronized (r.stats.getBatteryStats()) {
10514 r.stats.stopLaunchedLocked();
10515 }
10516 r.app.services.remove(r);
10517 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010518 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010519 if (DEBUG_SERVICE) Log.v(TAG,
10520 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010521 bumpServiceExecutingLocked(r);
10522 mStoppingServices.add(r);
10523 updateOomAdjLocked(r.app);
10524 r.app.thread.scheduleStopService(r);
10525 } catch (Exception e) {
10526 Log.w(TAG, "Exception when stopping service "
10527 + r.shortName, e);
10528 serviceDoneExecutingLocked(r, true);
10529 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010530 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010531 } else {
10532 if (DEBUG_SERVICE) Log.v(
10533 TAG, "Removed service that has no process: " + r.shortName);
10534 }
10535 } else {
10536 if (DEBUG_SERVICE) Log.v(
10537 TAG, "Removed service that is not running: " + r.shortName);
10538 }
10539 }
10540
10541 ComponentName startServiceLocked(IApplicationThread caller,
10542 Intent service, String resolvedType,
10543 int callingPid, int callingUid) {
10544 synchronized(this) {
10545 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10546 + " type=" + resolvedType + " args=" + service.getExtras());
10547
10548 if (caller != null) {
10549 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10550 if (callerApp == null) {
10551 throw new SecurityException(
10552 "Unable to find app for caller " + caller
10553 + " (pid=" + Binder.getCallingPid()
10554 + ") when starting service " + service);
10555 }
10556 }
10557
10558 ServiceLookupResult res =
10559 retrieveServiceLocked(service, resolvedType,
10560 callingPid, callingUid);
10561 if (res == null) {
10562 return null;
10563 }
10564 if (res.record == null) {
10565 return new ComponentName("!", res.permission != null
10566 ? res.permission : "private to package");
10567 }
10568 ServiceRecord r = res.record;
10569 if (unscheduleServiceRestartLocked(r)) {
10570 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10571 + r.shortName);
10572 }
10573 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010574 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010575 r.lastStartId++;
10576 if (r.lastStartId < 1) {
10577 r.lastStartId = 1;
10578 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010579 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010580 r.lastActivity = SystemClock.uptimeMillis();
10581 synchronized (r.stats.getBatteryStats()) {
10582 r.stats.startRunningLocked();
10583 }
10584 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10585 return new ComponentName("!", "Service process is bad");
10586 }
10587 return r.name;
10588 }
10589 }
10590
10591 public ComponentName startService(IApplicationThread caller, Intent service,
10592 String resolvedType) {
10593 // Refuse possible leaked file descriptors
10594 if (service != null && service.hasFileDescriptors() == true) {
10595 throw new IllegalArgumentException("File descriptors passed in Intent");
10596 }
10597
10598 synchronized(this) {
10599 final int callingPid = Binder.getCallingPid();
10600 final int callingUid = Binder.getCallingUid();
10601 final long origId = Binder.clearCallingIdentity();
10602 ComponentName res = startServiceLocked(caller, service,
10603 resolvedType, callingPid, callingUid);
10604 Binder.restoreCallingIdentity(origId);
10605 return res;
10606 }
10607 }
10608
10609 ComponentName startServiceInPackage(int uid,
10610 Intent service, String resolvedType) {
10611 synchronized(this) {
10612 final long origId = Binder.clearCallingIdentity();
10613 ComponentName res = startServiceLocked(null, service,
10614 resolvedType, -1, uid);
10615 Binder.restoreCallingIdentity(origId);
10616 return res;
10617 }
10618 }
10619
10620 public int stopService(IApplicationThread caller, Intent service,
10621 String resolvedType) {
10622 // Refuse possible leaked file descriptors
10623 if (service != null && service.hasFileDescriptors() == true) {
10624 throw new IllegalArgumentException("File descriptors passed in Intent");
10625 }
10626
10627 synchronized(this) {
10628 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10629 + " type=" + resolvedType);
10630
10631 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10632 if (caller != null && callerApp == null) {
10633 throw new SecurityException(
10634 "Unable to find app for caller " + caller
10635 + " (pid=" + Binder.getCallingPid()
10636 + ") when stopping service " + service);
10637 }
10638
10639 // If this service is active, make sure it is stopped.
10640 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10641 if (r != null) {
10642 if (r.record != null) {
10643 synchronized (r.record.stats.getBatteryStats()) {
10644 r.record.stats.stopRunningLocked();
10645 }
10646 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010647 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010648 final long origId = Binder.clearCallingIdentity();
10649 bringDownServiceLocked(r.record, false);
10650 Binder.restoreCallingIdentity(origId);
10651 return 1;
10652 }
10653 return -1;
10654 }
10655 }
10656
10657 return 0;
10658 }
10659
10660 public IBinder peekService(Intent service, String resolvedType) {
10661 // Refuse possible leaked file descriptors
10662 if (service != null && service.hasFileDescriptors() == true) {
10663 throw new IllegalArgumentException("File descriptors passed in Intent");
10664 }
10665
10666 IBinder ret = null;
10667
10668 synchronized(this) {
10669 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10670
10671 if (r != null) {
10672 // r.record is null if findServiceLocked() failed the caller permission check
10673 if (r.record == null) {
10674 throw new SecurityException(
10675 "Permission Denial: Accessing service " + r.record.name
10676 + " from pid=" + Binder.getCallingPid()
10677 + ", uid=" + Binder.getCallingUid()
10678 + " requires " + r.permission);
10679 }
10680 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10681 if (ib != null) {
10682 ret = ib.binder;
10683 }
10684 }
10685 }
10686
10687 return ret;
10688 }
10689
10690 public boolean stopServiceToken(ComponentName className, IBinder token,
10691 int startId) {
10692 synchronized(this) {
10693 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10694 + " " + token + " startId=" + startId);
10695 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010696 if (r != null) {
10697 if (startId >= 0) {
10698 // Asked to only stop if done with all work. Note that
10699 // to avoid leaks, we will take this as dropping all
10700 // start items up to and including this one.
10701 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10702 if (si != null) {
10703 while (r.deliveredStarts.size() > 0) {
10704 if (r.deliveredStarts.remove(0) == si) {
10705 break;
10706 }
10707 }
10708 }
10709
10710 if (r.lastStartId != startId) {
10711 return false;
10712 }
10713
10714 if (r.deliveredStarts.size() > 0) {
10715 Log.w(TAG, "stopServiceToken startId " + startId
10716 + " is last, but have " + r.deliveredStarts.size()
10717 + " remaining args");
10718 }
10719 }
10720
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010721 synchronized (r.stats.getBatteryStats()) {
10722 r.stats.stopRunningLocked();
10723 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010724 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010725 }
10726 final long origId = Binder.clearCallingIdentity();
10727 bringDownServiceLocked(r, false);
10728 Binder.restoreCallingIdentity(origId);
10729 return true;
10730 }
10731 }
10732 return false;
10733 }
10734
10735 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010736 int id, Notification notification, boolean removeNotification) {
10737 final long origId = Binder.clearCallingIdentity();
10738 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010739 synchronized(this) {
10740 ServiceRecord r = findServiceLocked(className, token);
10741 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010742 if (id != 0) {
10743 if (notification == null) {
10744 throw new IllegalArgumentException("null notification");
10745 }
10746 if (r.foregroundId != id) {
10747 r.cancelNotification();
10748 r.foregroundId = id;
10749 }
10750 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10751 r.foregroundNoti = notification;
10752 r.isForeground = true;
10753 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010754 if (r.app != null) {
10755 updateServiceForegroundLocked(r.app, true);
10756 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010757 } else {
10758 if (r.isForeground) {
10759 r.isForeground = false;
10760 if (r.app != null) {
10761 updateServiceForegroundLocked(r.app, true);
10762 }
10763 }
10764 if (removeNotification) {
10765 r.cancelNotification();
10766 r.foregroundId = 0;
10767 r.foregroundNoti = null;
10768 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010769 }
10770 }
10771 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010772 } finally {
10773 Binder.restoreCallingIdentity(origId);
10774 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010775 }
10776
10777 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10778 boolean anyForeground = false;
10779 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10780 if (sr.isForeground) {
10781 anyForeground = true;
10782 break;
10783 }
10784 }
10785 if (anyForeground != proc.foregroundServices) {
10786 proc.foregroundServices = anyForeground;
10787 if (oomAdj) {
10788 updateOomAdjLocked();
10789 }
10790 }
10791 }
10792
10793 public int bindService(IApplicationThread caller, IBinder token,
10794 Intent service, String resolvedType,
10795 IServiceConnection connection, int flags) {
10796 // Refuse possible leaked file descriptors
10797 if (service != null && service.hasFileDescriptors() == true) {
10798 throw new IllegalArgumentException("File descriptors passed in Intent");
10799 }
10800
10801 synchronized(this) {
10802 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10803 + " type=" + resolvedType + " conn=" + connection.asBinder()
10804 + " flags=0x" + Integer.toHexString(flags));
10805 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10806 if (callerApp == null) {
10807 throw new SecurityException(
10808 "Unable to find app for caller " + caller
10809 + " (pid=" + Binder.getCallingPid()
10810 + ") when binding service " + service);
10811 }
10812
10813 HistoryRecord activity = null;
10814 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010815 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010816 if (aindex < 0) {
10817 Log.w(TAG, "Binding with unknown activity: " + token);
10818 return 0;
10819 }
10820 activity = (HistoryRecord)mHistory.get(aindex);
10821 }
10822
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010823 int clientLabel = 0;
10824 PendingIntent clientIntent = null;
10825
10826 if (callerApp.info.uid == Process.SYSTEM_UID) {
10827 // Hacky kind of thing -- allow system stuff to tell us
10828 // what they are, so we can report this elsewhere for
10829 // others to know why certain services are running.
10830 try {
10831 clientIntent = (PendingIntent)service.getParcelableExtra(
10832 Intent.EXTRA_CLIENT_INTENT);
10833 } catch (RuntimeException e) {
10834 }
10835 if (clientIntent != null) {
10836 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
10837 if (clientLabel != 0) {
10838 // There are no useful extras in the intent, trash them.
10839 // System code calling with this stuff just needs to know
10840 // this will happen.
10841 service = service.cloneFilter();
10842 }
10843 }
10844 }
10845
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010846 ServiceLookupResult res =
10847 retrieveServiceLocked(service, resolvedType,
10848 Binder.getCallingPid(), Binder.getCallingUid());
10849 if (res == null) {
10850 return 0;
10851 }
10852 if (res.record == null) {
10853 return -1;
10854 }
10855 ServiceRecord s = res.record;
10856
10857 final long origId = Binder.clearCallingIdentity();
10858
10859 if (unscheduleServiceRestartLocked(s)) {
10860 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10861 + s.shortName);
10862 }
10863
10864 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10865 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010866 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010867
10868 IBinder binder = connection.asBinder();
10869 s.connections.put(binder, c);
10870 b.connections.add(c);
10871 if (activity != null) {
10872 if (activity.connections == null) {
10873 activity.connections = new HashSet<ConnectionRecord>();
10874 }
10875 activity.connections.add(c);
10876 }
10877 b.client.connections.add(c);
10878 mServiceConnections.put(binder, c);
10879
10880 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10881 s.lastActivity = SystemClock.uptimeMillis();
10882 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10883 return 0;
10884 }
10885 }
10886
10887 if (s.app != null) {
10888 // This could have made the service more important.
10889 updateOomAdjLocked(s.app);
10890 }
10891
10892 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10893 + ": received=" + b.intent.received
10894 + " apps=" + b.intent.apps.size()
10895 + " doRebind=" + b.intent.doRebind);
10896
10897 if (s.app != null && b.intent.received) {
10898 // Service is already running, so we can immediately
10899 // publish the connection.
10900 try {
10901 c.conn.connected(s.name, b.intent.binder);
10902 } catch (Exception e) {
10903 Log.w(TAG, "Failure sending service " + s.shortName
10904 + " to connection " + c.conn.asBinder()
10905 + " (in " + c.binding.client.processName + ")", e);
10906 }
10907
10908 // If this is the first app connected back to this binding,
10909 // and the service had previously asked to be told when
10910 // rebound, then do so.
10911 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10912 requestServiceBindingLocked(s, b.intent, true);
10913 }
10914 } else if (!b.intent.requested) {
10915 requestServiceBindingLocked(s, b.intent, false);
10916 }
10917
10918 Binder.restoreCallingIdentity(origId);
10919 }
10920
10921 return 1;
10922 }
10923
10924 private void removeConnectionLocked(
10925 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10926 IBinder binder = c.conn.asBinder();
10927 AppBindRecord b = c.binding;
10928 ServiceRecord s = b.service;
10929 s.connections.remove(binder);
10930 b.connections.remove(c);
10931 if (c.activity != null && c.activity != skipAct) {
10932 if (c.activity.connections != null) {
10933 c.activity.connections.remove(c);
10934 }
10935 }
10936 if (b.client != skipApp) {
10937 b.client.connections.remove(c);
10938 }
10939 mServiceConnections.remove(binder);
10940
10941 if (b.connections.size() == 0) {
10942 b.intent.apps.remove(b.client);
10943 }
10944
10945 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10946 + ": shouldUnbind=" + b.intent.hasBound);
10947 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10948 && b.intent.hasBound) {
10949 try {
10950 bumpServiceExecutingLocked(s);
10951 updateOomAdjLocked(s.app);
10952 b.intent.hasBound = false;
10953 // Assume the client doesn't want to know about a rebind;
10954 // we will deal with that later if it asks for one.
10955 b.intent.doRebind = false;
10956 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10957 } catch (Exception e) {
10958 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10959 serviceDoneExecutingLocked(s, true);
10960 }
10961 }
10962
10963 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10964 bringDownServiceLocked(s, false);
10965 }
10966 }
10967
10968 public boolean unbindService(IServiceConnection connection) {
10969 synchronized (this) {
10970 IBinder binder = connection.asBinder();
10971 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10972 ConnectionRecord r = mServiceConnections.get(binder);
10973 if (r == null) {
10974 Log.w(TAG, "Unbind failed: could not find connection for "
10975 + connection.asBinder());
10976 return false;
10977 }
10978
10979 final long origId = Binder.clearCallingIdentity();
10980
10981 removeConnectionLocked(r, null, null);
10982
10983 if (r.binding.service.app != null) {
10984 // This could have made the service less important.
10985 updateOomAdjLocked(r.binding.service.app);
10986 }
10987
10988 Binder.restoreCallingIdentity(origId);
10989 }
10990
10991 return true;
10992 }
10993
10994 public void publishService(IBinder token, Intent intent, IBinder service) {
10995 // Refuse possible leaked file descriptors
10996 if (intent != null && intent.hasFileDescriptors() == true) {
10997 throw new IllegalArgumentException("File descriptors passed in Intent");
10998 }
10999
11000 synchronized(this) {
11001 if (!(token instanceof ServiceRecord)) {
11002 throw new IllegalArgumentException("Invalid service token");
11003 }
11004 ServiceRecord r = (ServiceRecord)token;
11005
11006 final long origId = Binder.clearCallingIdentity();
11007
11008 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11009 + " " + intent + ": " + service);
11010 if (r != null) {
11011 Intent.FilterComparison filter
11012 = new Intent.FilterComparison(intent);
11013 IntentBindRecord b = r.bindings.get(filter);
11014 if (b != null && !b.received) {
11015 b.binder = service;
11016 b.requested = true;
11017 b.received = true;
11018 if (r.connections.size() > 0) {
11019 Iterator<ConnectionRecord> it
11020 = r.connections.values().iterator();
11021 while (it.hasNext()) {
11022 ConnectionRecord c = it.next();
11023 if (!filter.equals(c.binding.intent.intent)) {
11024 if (DEBUG_SERVICE) Log.v(
11025 TAG, "Not publishing to: " + c);
11026 if (DEBUG_SERVICE) Log.v(
11027 TAG, "Bound intent: " + c.binding.intent.intent);
11028 if (DEBUG_SERVICE) Log.v(
11029 TAG, "Published intent: " + intent);
11030 continue;
11031 }
11032 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11033 try {
11034 c.conn.connected(r.name, service);
11035 } catch (Exception e) {
11036 Log.w(TAG, "Failure sending service " + r.name +
11037 " to connection " + c.conn.asBinder() +
11038 " (in " + c.binding.client.processName + ")", e);
11039 }
11040 }
11041 }
11042 }
11043
11044 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11045
11046 Binder.restoreCallingIdentity(origId);
11047 }
11048 }
11049 }
11050
11051 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11052 // Refuse possible leaked file descriptors
11053 if (intent != null && intent.hasFileDescriptors() == true) {
11054 throw new IllegalArgumentException("File descriptors passed in Intent");
11055 }
11056
11057 synchronized(this) {
11058 if (!(token instanceof ServiceRecord)) {
11059 throw new IllegalArgumentException("Invalid service token");
11060 }
11061 ServiceRecord r = (ServiceRecord)token;
11062
11063 final long origId = Binder.clearCallingIdentity();
11064
11065 if (r != null) {
11066 Intent.FilterComparison filter
11067 = new Intent.FilterComparison(intent);
11068 IntentBindRecord b = r.bindings.get(filter);
11069 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11070 + " at " + b + ": apps="
11071 + (b != null ? b.apps.size() : 0));
11072 if (b != null) {
11073 if (b.apps.size() > 0) {
11074 // Applications have already bound since the last
11075 // unbind, so just rebind right here.
11076 requestServiceBindingLocked(r, b, true);
11077 } else {
11078 // Note to tell the service the next time there is
11079 // a new client.
11080 b.doRebind = true;
11081 }
11082 }
11083
11084 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11085
11086 Binder.restoreCallingIdentity(origId);
11087 }
11088 }
11089 }
11090
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011091 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011092 synchronized(this) {
11093 if (!(token instanceof ServiceRecord)) {
11094 throw new IllegalArgumentException("Invalid service token");
11095 }
11096 ServiceRecord r = (ServiceRecord)token;
11097 boolean inStopping = mStoppingServices.contains(token);
11098 if (r != null) {
11099 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11100 + ": nesting=" + r.executeNesting
11101 + ", inStopping=" + inStopping);
11102 if (r != token) {
11103 Log.w(TAG, "Done executing service " + r.name
11104 + " with incorrect token: given " + token
11105 + ", expected " + r);
11106 return;
11107 }
11108
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011109 if (type == 1) {
11110 // This is a call from a service start... take care of
11111 // book-keeping.
11112 r.callStart = true;
11113 switch (res) {
11114 case Service.START_STICKY_COMPATIBILITY:
11115 case Service.START_STICKY: {
11116 // We are done with the associated start arguments.
11117 r.findDeliveredStart(startId, true);
11118 // Don't stop if killed.
11119 r.stopIfKilled = false;
11120 break;
11121 }
11122 case Service.START_NOT_STICKY: {
11123 // We are done with the associated start arguments.
11124 r.findDeliveredStart(startId, true);
11125 if (r.lastStartId == startId) {
11126 // There is no more work, and this service
11127 // doesn't want to hang around if killed.
11128 r.stopIfKilled = true;
11129 }
11130 break;
11131 }
11132 case Service.START_REDELIVER_INTENT: {
11133 // We'll keep this item until they explicitly
11134 // call stop for it, but keep track of the fact
11135 // that it was delivered.
11136 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11137 if (si != null) {
11138 si.deliveryCount = 0;
11139 si.doneExecutingCount++;
11140 // Don't stop if killed.
11141 r.stopIfKilled = true;
11142 }
11143 break;
11144 }
11145 default:
11146 throw new IllegalArgumentException(
11147 "Unknown service start result: " + res);
11148 }
11149 if (res == Service.START_STICKY_COMPATIBILITY) {
11150 r.callStart = false;
11151 }
11152 }
11153
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011154 final long origId = Binder.clearCallingIdentity();
11155 serviceDoneExecutingLocked(r, inStopping);
11156 Binder.restoreCallingIdentity(origId);
11157 } else {
11158 Log.w(TAG, "Done executing unknown service " + r.name
11159 + " with token " + token);
11160 }
11161 }
11162 }
11163
11164 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11165 r.executeNesting--;
11166 if (r.executeNesting <= 0 && r.app != null) {
11167 r.app.executingServices.remove(r);
11168 if (r.app.executingServices.size() == 0) {
11169 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11170 }
11171 if (inStopping) {
11172 mStoppingServices.remove(r);
11173 }
11174 updateOomAdjLocked(r.app);
11175 }
11176 }
11177
11178 void serviceTimeout(ProcessRecord proc) {
11179 synchronized(this) {
11180 if (proc.executingServices.size() == 0 || proc.thread == null) {
11181 return;
11182 }
11183 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11184 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11185 ServiceRecord timeout = null;
11186 long nextTime = 0;
11187 while (it.hasNext()) {
11188 ServiceRecord sr = it.next();
11189 if (sr.executingStart < maxTime) {
11190 timeout = sr;
11191 break;
11192 }
11193 if (sr.executingStart > nextTime) {
11194 nextTime = sr.executingStart;
11195 }
11196 }
11197 if (timeout != null && mLRUProcesses.contains(proc)) {
11198 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011199 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011200 + timeout.name);
11201 } else {
11202 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11203 msg.obj = proc;
11204 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11205 }
11206 }
11207 }
11208
11209 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011210 // BACKUP AND RESTORE
11211 // =========================================================
11212
11213 // Cause the target app to be launched if necessary and its backup agent
11214 // instantiated. The backup agent will invoke backupAgentCreated() on the
11215 // activity manager to announce its creation.
11216 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11217 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11218 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11219
11220 synchronized(this) {
11221 // !!! TODO: currently no check here that we're already bound
11222 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11223 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11224 synchronized (stats) {
11225 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11226 }
11227
11228 BackupRecord r = new BackupRecord(ss, app, backupMode);
11229 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11230 // startProcessLocked() returns existing proc's record if it's already running
11231 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011232 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011233 if (proc == null) {
11234 Log.e(TAG, "Unable to start backup agent process " + r);
11235 return false;
11236 }
11237
11238 r.app = proc;
11239 mBackupTarget = r;
11240 mBackupAppName = app.packageName;
11241
Christopher Tate6fa95972009-06-05 18:43:55 -070011242 // Try not to kill the process during backup
11243 updateOomAdjLocked(proc);
11244
Christopher Tate181fafa2009-05-14 11:12:14 -070011245 // If the process is already attached, schedule the creation of the backup agent now.
11246 // If it is not yet live, this will be done when it attaches to the framework.
11247 if (proc.thread != null) {
11248 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11249 try {
11250 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11251 } catch (RemoteException e) {
11252 // !!! TODO: notify the backup manager that we crashed, or rely on
11253 // death notices, or...?
11254 }
11255 } else {
11256 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11257 }
11258 // Invariants: at this point, the target app process exists and the application
11259 // is either already running or in the process of coming up. mBackupTarget and
11260 // mBackupAppName describe the app, so that when it binds back to the AM we
11261 // know that it's scheduled for a backup-agent operation.
11262 }
11263
11264 return true;
11265 }
11266
11267 // A backup agent has just come up
11268 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11269 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11270 + " = " + agent);
11271
11272 synchronized(this) {
11273 if (!agentPackageName.equals(mBackupAppName)) {
11274 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11275 return;
11276 }
11277
Christopher Tate043dadc2009-06-02 16:11:00 -070011278 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011279 try {
11280 IBackupManager bm = IBackupManager.Stub.asInterface(
11281 ServiceManager.getService(Context.BACKUP_SERVICE));
11282 bm.agentConnected(agentPackageName, agent);
11283 } catch (RemoteException e) {
11284 // can't happen; the backup manager service is local
11285 } catch (Exception e) {
11286 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11287 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011288 } finally {
11289 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011290 }
11291 }
11292 }
11293
11294 // done with this agent
11295 public void unbindBackupAgent(ApplicationInfo appInfo) {
11296 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011297 if (appInfo == null) {
11298 Log.w(TAG, "unbind backup agent for null app");
11299 return;
11300 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011301
11302 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011303 if (mBackupAppName == null) {
11304 Log.w(TAG, "Unbinding backup agent with no active backup");
11305 return;
11306 }
11307
Christopher Tate181fafa2009-05-14 11:12:14 -070011308 if (!mBackupAppName.equals(appInfo.packageName)) {
11309 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11310 return;
11311 }
11312
Christopher Tate6fa95972009-06-05 18:43:55 -070011313 ProcessRecord proc = mBackupTarget.app;
11314 mBackupTarget = null;
11315 mBackupAppName = null;
11316
11317 // Not backing this app up any more; reset its OOM adjustment
11318 updateOomAdjLocked(proc);
11319
Christopher Tatec7b31e32009-06-10 15:49:30 -070011320 // If the app crashed during backup, 'thread' will be null here
11321 if (proc.thread != null) {
11322 try {
11323 proc.thread.scheduleDestroyBackupAgent(appInfo);
11324 } catch (Exception e) {
11325 Log.e(TAG, "Exception when unbinding backup agent:");
11326 e.printStackTrace();
11327 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011328 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011329 }
11330 }
11331 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011332 // BROADCASTS
11333 // =========================================================
11334
11335 private final List getStickies(String action, IntentFilter filter,
11336 List cur) {
11337 final ContentResolver resolver = mContext.getContentResolver();
11338 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11339 if (list == null) {
11340 return cur;
11341 }
11342 int N = list.size();
11343 for (int i=0; i<N; i++) {
11344 Intent intent = list.get(i);
11345 if (filter.match(resolver, intent, true, TAG) >= 0) {
11346 if (cur == null) {
11347 cur = new ArrayList<Intent>();
11348 }
11349 cur.add(intent);
11350 }
11351 }
11352 return cur;
11353 }
11354
11355 private final void scheduleBroadcastsLocked() {
11356 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11357 + mBroadcastsScheduled);
11358
11359 if (mBroadcastsScheduled) {
11360 return;
11361 }
11362 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11363 mBroadcastsScheduled = true;
11364 }
11365
11366 public Intent registerReceiver(IApplicationThread caller,
11367 IIntentReceiver receiver, IntentFilter filter, String permission) {
11368 synchronized(this) {
11369 ProcessRecord callerApp = null;
11370 if (caller != null) {
11371 callerApp = getRecordForAppLocked(caller);
11372 if (callerApp == null) {
11373 throw new SecurityException(
11374 "Unable to find app for caller " + caller
11375 + " (pid=" + Binder.getCallingPid()
11376 + ") when registering receiver " + receiver);
11377 }
11378 }
11379
11380 List allSticky = null;
11381
11382 // Look for any matching sticky broadcasts...
11383 Iterator actions = filter.actionsIterator();
11384 if (actions != null) {
11385 while (actions.hasNext()) {
11386 String action = (String)actions.next();
11387 allSticky = getStickies(action, filter, allSticky);
11388 }
11389 } else {
11390 allSticky = getStickies(null, filter, allSticky);
11391 }
11392
11393 // The first sticky in the list is returned directly back to
11394 // the client.
11395 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11396
11397 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11398 + ": " + sticky);
11399
11400 if (receiver == null) {
11401 return sticky;
11402 }
11403
11404 ReceiverList rl
11405 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11406 if (rl == null) {
11407 rl = new ReceiverList(this, callerApp,
11408 Binder.getCallingPid(),
11409 Binder.getCallingUid(), receiver);
11410 if (rl.app != null) {
11411 rl.app.receivers.add(rl);
11412 } else {
11413 try {
11414 receiver.asBinder().linkToDeath(rl, 0);
11415 } catch (RemoteException e) {
11416 return sticky;
11417 }
11418 rl.linkedToDeath = true;
11419 }
11420 mRegisteredReceivers.put(receiver.asBinder(), rl);
11421 }
11422 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11423 rl.add(bf);
11424 if (!bf.debugCheck()) {
11425 Log.w(TAG, "==> For Dynamic broadast");
11426 }
11427 mReceiverResolver.addFilter(bf);
11428
11429 // Enqueue broadcasts for all existing stickies that match
11430 // this filter.
11431 if (allSticky != null) {
11432 ArrayList receivers = new ArrayList();
11433 receivers.add(bf);
11434
11435 int N = allSticky.size();
11436 for (int i=0; i<N; i++) {
11437 Intent intent = (Intent)allSticky.get(i);
11438 BroadcastRecord r = new BroadcastRecord(intent, null,
11439 null, -1, -1, null, receivers, null, 0, null, null,
11440 false);
11441 if (mParallelBroadcasts.size() == 0) {
11442 scheduleBroadcastsLocked();
11443 }
11444 mParallelBroadcasts.add(r);
11445 }
11446 }
11447
11448 return sticky;
11449 }
11450 }
11451
11452 public void unregisterReceiver(IIntentReceiver receiver) {
11453 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11454
11455 boolean doNext = false;
11456
11457 synchronized(this) {
11458 ReceiverList rl
11459 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11460 if (rl != null) {
11461 if (rl.curBroadcast != null) {
11462 BroadcastRecord r = rl.curBroadcast;
11463 doNext = finishReceiverLocked(
11464 receiver.asBinder(), r.resultCode, r.resultData,
11465 r.resultExtras, r.resultAbort, true);
11466 }
11467
11468 if (rl.app != null) {
11469 rl.app.receivers.remove(rl);
11470 }
11471 removeReceiverLocked(rl);
11472 if (rl.linkedToDeath) {
11473 rl.linkedToDeath = false;
11474 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11475 }
11476 }
11477 }
11478
11479 if (!doNext) {
11480 return;
11481 }
11482
11483 final long origId = Binder.clearCallingIdentity();
11484 processNextBroadcast(false);
11485 trimApplications();
11486 Binder.restoreCallingIdentity(origId);
11487 }
11488
11489 void removeReceiverLocked(ReceiverList rl) {
11490 mRegisteredReceivers.remove(rl.receiver.asBinder());
11491 int N = rl.size();
11492 for (int i=0; i<N; i++) {
11493 mReceiverResolver.removeFilter(rl.get(i));
11494 }
11495 }
11496
11497 private final int broadcastIntentLocked(ProcessRecord callerApp,
11498 String callerPackage, Intent intent, String resolvedType,
11499 IIntentReceiver resultTo, int resultCode, String resultData,
11500 Bundle map, String requiredPermission,
11501 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11502 intent = new Intent(intent);
11503
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011504 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011505 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11506 + " ordered=" + ordered);
11507 if ((resultTo != null) && !ordered) {
11508 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11509 }
11510
11511 // Handle special intents: if this broadcast is from the package
11512 // manager about a package being removed, we need to remove all of
11513 // its activities from the history stack.
11514 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11515 intent.getAction());
11516 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11517 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11518 || uidRemoved) {
11519 if (checkComponentPermission(
11520 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11521 callingPid, callingUid, -1)
11522 == PackageManager.PERMISSION_GRANTED) {
11523 if (uidRemoved) {
11524 final Bundle intentExtras = intent.getExtras();
11525 final int uid = intentExtras != null
11526 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11527 if (uid >= 0) {
11528 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11529 synchronized (bs) {
11530 bs.removeUidStatsLocked(uid);
11531 }
11532 }
11533 } else {
11534 Uri data = intent.getData();
11535 String ssp;
11536 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11537 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11538 uninstallPackageLocked(ssp,
11539 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011540 AttributeCache ac = AttributeCache.instance();
11541 if (ac != null) {
11542 ac.removePackage(ssp);
11543 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011544 }
11545 }
11546 }
11547 } else {
11548 String msg = "Permission Denial: " + intent.getAction()
11549 + " broadcast from " + callerPackage + " (pid=" + callingPid
11550 + ", uid=" + callingUid + ")"
11551 + " requires "
11552 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11553 Log.w(TAG, msg);
11554 throw new SecurityException(msg);
11555 }
11556 }
11557
11558 /*
11559 * If this is the time zone changed action, queue up a message that will reset the timezone
11560 * of all currently running processes. This message will get queued up before the broadcast
11561 * happens.
11562 */
11563 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11564 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11565 }
11566
Dianne Hackborn854060af2009-07-09 18:14:31 -070011567 /*
11568 * Prevent non-system code (defined here to be non-persistent
11569 * processes) from sending protected broadcasts.
11570 */
11571 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11572 || callingUid == Process.SHELL_UID || callingUid == 0) {
11573 // Always okay.
11574 } else if (callerApp == null || !callerApp.persistent) {
11575 try {
11576 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11577 intent.getAction())) {
11578 String msg = "Permission Denial: not allowed to send broadcast "
11579 + intent.getAction() + " from pid="
11580 + callingPid + ", uid=" + callingUid;
11581 Log.w(TAG, msg);
11582 throw new SecurityException(msg);
11583 }
11584 } catch (RemoteException e) {
11585 Log.w(TAG, "Remote exception", e);
11586 return BROADCAST_SUCCESS;
11587 }
11588 }
11589
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011590 // Add to the sticky list if requested.
11591 if (sticky) {
11592 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11593 callingPid, callingUid)
11594 != PackageManager.PERMISSION_GRANTED) {
11595 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11596 + callingPid + ", uid=" + callingUid
11597 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11598 Log.w(TAG, msg);
11599 throw new SecurityException(msg);
11600 }
11601 if (requiredPermission != null) {
11602 Log.w(TAG, "Can't broadcast sticky intent " + intent
11603 + " and enforce permission " + requiredPermission);
11604 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11605 }
11606 if (intent.getComponent() != null) {
11607 throw new SecurityException(
11608 "Sticky broadcasts can't target a specific component");
11609 }
11610 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11611 if (list == null) {
11612 list = new ArrayList<Intent>();
11613 mStickyBroadcasts.put(intent.getAction(), list);
11614 }
11615 int N = list.size();
11616 int i;
11617 for (i=0; i<N; i++) {
11618 if (intent.filterEquals(list.get(i))) {
11619 // This sticky already exists, replace it.
11620 list.set(i, new Intent(intent));
11621 break;
11622 }
11623 }
11624 if (i >= N) {
11625 list.add(new Intent(intent));
11626 }
11627 }
11628
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011629 // Figure out who all will receive this broadcast.
11630 List receivers = null;
11631 List<BroadcastFilter> registeredReceivers = null;
11632 try {
11633 if (intent.getComponent() != null) {
11634 // Broadcast is going to one specific receiver class...
11635 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011636 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011637 if (ai != null) {
11638 receivers = new ArrayList();
11639 ResolveInfo ri = new ResolveInfo();
11640 ri.activityInfo = ai;
11641 receivers.add(ri);
11642 }
11643 } else {
11644 // Need to resolve the intent to interested receivers...
11645 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11646 == 0) {
11647 receivers =
11648 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011649 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011650 }
Mihai Preda074edef2009-05-18 17:13:31 +020011651 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011652 }
11653 } catch (RemoteException ex) {
11654 // pm is in same process, this will never happen.
11655 }
11656
11657 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11658 if (!ordered && NR > 0) {
11659 // If we are not serializing this broadcast, then send the
11660 // registered receivers separately so they don't wait for the
11661 // components to be launched.
11662 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11663 callerPackage, callingPid, callingUid, requiredPermission,
11664 registeredReceivers, resultTo, resultCode, resultData, map,
11665 ordered);
11666 if (DEBUG_BROADCAST) Log.v(
11667 TAG, "Enqueueing parallel broadcast " + r
11668 + ": prev had " + mParallelBroadcasts.size());
11669 mParallelBroadcasts.add(r);
11670 scheduleBroadcastsLocked();
11671 registeredReceivers = null;
11672 NR = 0;
11673 }
11674
11675 // Merge into one list.
11676 int ir = 0;
11677 if (receivers != null) {
11678 // A special case for PACKAGE_ADDED: do not allow the package
11679 // being added to see this broadcast. This prevents them from
11680 // using this as a back door to get run as soon as they are
11681 // installed. Maybe in the future we want to have a special install
11682 // broadcast or such for apps, but we'd like to deliberately make
11683 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011684 boolean skip = false;
11685 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011686 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011687 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11688 skip = true;
11689 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11690 skip = true;
11691 }
11692 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011693 ? intent.getData().getSchemeSpecificPart()
11694 : null;
11695 if (skipPackage != null && receivers != null) {
11696 int NT = receivers.size();
11697 for (int it=0; it<NT; it++) {
11698 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11699 if (curt.activityInfo.packageName.equals(skipPackage)) {
11700 receivers.remove(it);
11701 it--;
11702 NT--;
11703 }
11704 }
11705 }
11706
11707 int NT = receivers != null ? receivers.size() : 0;
11708 int it = 0;
11709 ResolveInfo curt = null;
11710 BroadcastFilter curr = null;
11711 while (it < NT && ir < NR) {
11712 if (curt == null) {
11713 curt = (ResolveInfo)receivers.get(it);
11714 }
11715 if (curr == null) {
11716 curr = registeredReceivers.get(ir);
11717 }
11718 if (curr.getPriority() >= curt.priority) {
11719 // Insert this broadcast record into the final list.
11720 receivers.add(it, curr);
11721 ir++;
11722 curr = null;
11723 it++;
11724 NT++;
11725 } else {
11726 // Skip to the next ResolveInfo in the final list.
11727 it++;
11728 curt = null;
11729 }
11730 }
11731 }
11732 while (ir < NR) {
11733 if (receivers == null) {
11734 receivers = new ArrayList();
11735 }
11736 receivers.add(registeredReceivers.get(ir));
11737 ir++;
11738 }
11739
11740 if ((receivers != null && receivers.size() > 0)
11741 || resultTo != null) {
11742 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11743 callerPackage, callingPid, callingUid, requiredPermission,
11744 receivers, resultTo, resultCode, resultData, map, ordered);
11745 if (DEBUG_BROADCAST) Log.v(
11746 TAG, "Enqueueing ordered broadcast " + r
11747 + ": prev had " + mOrderedBroadcasts.size());
11748 if (DEBUG_BROADCAST) {
11749 int seq = r.intent.getIntExtra("seq", -1);
11750 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11751 }
11752 mOrderedBroadcasts.add(r);
11753 scheduleBroadcastsLocked();
11754 }
11755
11756 return BROADCAST_SUCCESS;
11757 }
11758
11759 public final int broadcastIntent(IApplicationThread caller,
11760 Intent intent, String resolvedType, IIntentReceiver resultTo,
11761 int resultCode, String resultData, Bundle map,
11762 String requiredPermission, boolean serialized, boolean sticky) {
11763 // Refuse possible leaked file descriptors
11764 if (intent != null && intent.hasFileDescriptors() == true) {
11765 throw new IllegalArgumentException("File descriptors passed in Intent");
11766 }
11767
11768 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011769 int flags = intent.getFlags();
11770
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011771 if (!mSystemReady) {
11772 // if the caller really truly claims to know what they're doing, go
11773 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011774 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11775 intent = new Intent(intent);
11776 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11777 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11778 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11779 + " before boot completion");
11780 throw new IllegalStateException("Cannot broadcast before boot completed");
11781 }
11782 }
11783
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011784 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
11785 throw new IllegalArgumentException(
11786 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
11787 }
11788
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011789 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11790 final int callingPid = Binder.getCallingPid();
11791 final int callingUid = Binder.getCallingUid();
11792 final long origId = Binder.clearCallingIdentity();
11793 int res = broadcastIntentLocked(callerApp,
11794 callerApp != null ? callerApp.info.packageName : null,
11795 intent, resolvedType, resultTo,
11796 resultCode, resultData, map, requiredPermission, serialized,
11797 sticky, callingPid, callingUid);
11798 Binder.restoreCallingIdentity(origId);
11799 return res;
11800 }
11801 }
11802
11803 int broadcastIntentInPackage(String packageName, int uid,
11804 Intent intent, String resolvedType, IIntentReceiver resultTo,
11805 int resultCode, String resultData, Bundle map,
11806 String requiredPermission, boolean serialized, boolean sticky) {
11807 synchronized(this) {
11808 final long origId = Binder.clearCallingIdentity();
11809 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11810 resultTo, resultCode, resultData, map, requiredPermission,
11811 serialized, sticky, -1, uid);
11812 Binder.restoreCallingIdentity(origId);
11813 return res;
11814 }
11815 }
11816
11817 public final void unbroadcastIntent(IApplicationThread caller,
11818 Intent intent) {
11819 // Refuse possible leaked file descriptors
11820 if (intent != null && intent.hasFileDescriptors() == true) {
11821 throw new IllegalArgumentException("File descriptors passed in Intent");
11822 }
11823
11824 synchronized(this) {
11825 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11826 != PackageManager.PERMISSION_GRANTED) {
11827 String msg = "Permission Denial: unbroadcastIntent() from pid="
11828 + Binder.getCallingPid()
11829 + ", uid=" + Binder.getCallingUid()
11830 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11831 Log.w(TAG, msg);
11832 throw new SecurityException(msg);
11833 }
11834 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11835 if (list != null) {
11836 int N = list.size();
11837 int i;
11838 for (i=0; i<N; i++) {
11839 if (intent.filterEquals(list.get(i))) {
11840 list.remove(i);
11841 break;
11842 }
11843 }
11844 }
11845 }
11846 }
11847
11848 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11849 String resultData, Bundle resultExtras, boolean resultAbort,
11850 boolean explicit) {
11851 if (mOrderedBroadcasts.size() == 0) {
11852 if (explicit) {
11853 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11854 }
11855 return false;
11856 }
11857 BroadcastRecord r = mOrderedBroadcasts.get(0);
11858 if (r.receiver == null) {
11859 if (explicit) {
11860 Log.w(TAG, "finishReceiver called but none active");
11861 }
11862 return false;
11863 }
11864 if (r.receiver != receiver) {
11865 Log.w(TAG, "finishReceiver called but active receiver is different");
11866 return false;
11867 }
11868 int state = r.state;
11869 r.state = r.IDLE;
11870 if (state == r.IDLE) {
11871 if (explicit) {
11872 Log.w(TAG, "finishReceiver called but state is IDLE");
11873 }
11874 }
11875 r.receiver = null;
11876 r.intent.setComponent(null);
11877 if (r.curApp != null) {
11878 r.curApp.curReceiver = null;
11879 }
11880 if (r.curFilter != null) {
11881 r.curFilter.receiverList.curBroadcast = null;
11882 }
11883 r.curFilter = null;
11884 r.curApp = null;
11885 r.curComponent = null;
11886 r.curReceiver = null;
11887 mPendingBroadcast = null;
11888
11889 r.resultCode = resultCode;
11890 r.resultData = resultData;
11891 r.resultExtras = resultExtras;
11892 r.resultAbort = resultAbort;
11893
11894 // We will process the next receiver right now if this is finishing
11895 // an app receiver (which is always asynchronous) or after we have
11896 // come back from calling a receiver.
11897 return state == BroadcastRecord.APP_RECEIVE
11898 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11899 }
11900
11901 public void finishReceiver(IBinder who, int resultCode, String resultData,
11902 Bundle resultExtras, boolean resultAbort) {
11903 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11904
11905 // Refuse possible leaked file descriptors
11906 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11907 throw new IllegalArgumentException("File descriptors passed in Bundle");
11908 }
11909
11910 boolean doNext;
11911
11912 final long origId = Binder.clearCallingIdentity();
11913
11914 synchronized(this) {
11915 doNext = finishReceiverLocked(
11916 who, resultCode, resultData, resultExtras, resultAbort, true);
11917 }
11918
11919 if (doNext) {
11920 processNextBroadcast(false);
11921 }
11922 trimApplications();
11923
11924 Binder.restoreCallingIdentity(origId);
11925 }
11926
11927 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11928 if (r.nextReceiver > 0) {
11929 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11930 if (curReceiver instanceof BroadcastFilter) {
11931 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11932 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11933 System.identityHashCode(r),
11934 r.intent.getAction(),
11935 r.nextReceiver - 1,
11936 System.identityHashCode(bf));
11937 } else {
11938 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11939 System.identityHashCode(r),
11940 r.intent.getAction(),
11941 r.nextReceiver - 1,
11942 ((ResolveInfo)curReceiver).toString());
11943 }
11944 } else {
11945 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11946 + r);
11947 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11948 System.identityHashCode(r),
11949 r.intent.getAction(),
11950 r.nextReceiver,
11951 "NONE");
11952 }
11953 }
11954
11955 private final void broadcastTimeout() {
11956 synchronized (this) {
11957 if (mOrderedBroadcasts.size() == 0) {
11958 return;
11959 }
11960 long now = SystemClock.uptimeMillis();
11961 BroadcastRecord r = mOrderedBroadcasts.get(0);
11962 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11963 if (DEBUG_BROADCAST) Log.v(TAG,
11964 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11965 + (r.startTime + BROADCAST_TIMEOUT));
11966 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11967 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11968 return;
11969 }
11970
11971 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11972 r.startTime = now;
11973 r.anrCount++;
11974
11975 // Current receiver has passed its expiration date.
11976 if (r.nextReceiver <= 0) {
11977 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11978 return;
11979 }
11980
11981 ProcessRecord app = null;
11982
11983 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11984 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11985 logBroadcastReceiverDiscard(r);
11986 if (curReceiver instanceof BroadcastFilter) {
11987 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11988 if (bf.receiverList.pid != 0
11989 && bf.receiverList.pid != MY_PID) {
11990 synchronized (this.mPidsSelfLocked) {
11991 app = this.mPidsSelfLocked.get(
11992 bf.receiverList.pid);
11993 }
11994 }
11995 } else {
11996 app = r.curApp;
11997 }
11998
11999 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070012000 appNotRespondingLocked(app, null, null,
12001 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012002 }
12003
12004 if (mPendingBroadcast == r) {
12005 mPendingBroadcast = null;
12006 }
12007
12008 // Move on to the next receiver.
12009 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12010 r.resultExtras, r.resultAbort, true);
12011 scheduleBroadcastsLocked();
12012 }
12013 }
12014
12015 private final void processCurBroadcastLocked(BroadcastRecord r,
12016 ProcessRecord app) throws RemoteException {
12017 if (app.thread == null) {
12018 throw new RemoteException();
12019 }
12020 r.receiver = app.thread.asBinder();
12021 r.curApp = app;
12022 app.curReceiver = r;
12023 updateLRUListLocked(app, true);
12024
12025 // Tell the application to launch this receiver.
12026 r.intent.setComponent(r.curComponent);
12027
12028 boolean started = false;
12029 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012030 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012031 "Delivering to component " + r.curComponent
12032 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012033 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012034 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12035 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12036 started = true;
12037 } finally {
12038 if (!started) {
12039 r.receiver = null;
12040 r.curApp = null;
12041 app.curReceiver = null;
12042 }
12043 }
12044
12045 }
12046
12047 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
12048 Intent intent, int resultCode, String data,
12049 Bundle extras, boolean ordered) throws RemoteException {
12050 if (app != null && app.thread != null) {
12051 // If we have an app thread, do the call through that so it is
12052 // correctly ordered with other one-way calls.
12053 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
12054 data, extras, ordered);
12055 } else {
12056 receiver.performReceive(intent, resultCode, data, extras, ordered);
12057 }
12058 }
12059
12060 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12061 BroadcastFilter filter, boolean ordered) {
12062 boolean skip = false;
12063 if (filter.requiredPermission != null) {
12064 int perm = checkComponentPermission(filter.requiredPermission,
12065 r.callingPid, r.callingUid, -1);
12066 if (perm != PackageManager.PERMISSION_GRANTED) {
12067 Log.w(TAG, "Permission Denial: broadcasting "
12068 + r.intent.toString()
12069 + " from " + r.callerPackage + " (pid="
12070 + r.callingPid + ", uid=" + r.callingUid + ")"
12071 + " requires " + filter.requiredPermission
12072 + " due to registered receiver " + filter);
12073 skip = true;
12074 }
12075 }
12076 if (r.requiredPermission != null) {
12077 int perm = checkComponentPermission(r.requiredPermission,
12078 filter.receiverList.pid, filter.receiverList.uid, -1);
12079 if (perm != PackageManager.PERMISSION_GRANTED) {
12080 Log.w(TAG, "Permission Denial: receiving "
12081 + r.intent.toString()
12082 + " to " + filter.receiverList.app
12083 + " (pid=" + filter.receiverList.pid
12084 + ", uid=" + filter.receiverList.uid + ")"
12085 + " requires " + r.requiredPermission
12086 + " due to sender " + r.callerPackage
12087 + " (uid " + r.callingUid + ")");
12088 skip = true;
12089 }
12090 }
12091
12092 if (!skip) {
12093 // If this is not being sent as an ordered broadcast, then we
12094 // don't want to touch the fields that keep track of the current
12095 // state of ordered broadcasts.
12096 if (ordered) {
12097 r.receiver = filter.receiverList.receiver.asBinder();
12098 r.curFilter = filter;
12099 filter.receiverList.curBroadcast = r;
12100 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012101 if (filter.receiverList.app != null) {
12102 // Bump hosting application to no longer be in background
12103 // scheduling class. Note that we can't do that if there
12104 // isn't an app... but we can only be in that case for
12105 // things that directly call the IActivityManager API, which
12106 // are already core system stuff so don't matter for this.
12107 r.curApp = filter.receiverList.app;
12108 filter.receiverList.app.curReceiver = r;
12109 updateOomAdjLocked();
12110 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012111 }
12112 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012113 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012114 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012115 Log.i(TAG, "Delivering to " + filter.receiverList.app
12116 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012117 }
12118 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12119 new Intent(r.intent), r.resultCode,
12120 r.resultData, r.resultExtras, r.ordered);
12121 if (ordered) {
12122 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12123 }
12124 } catch (RemoteException e) {
12125 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12126 if (ordered) {
12127 r.receiver = null;
12128 r.curFilter = null;
12129 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012130 if (filter.receiverList.app != null) {
12131 filter.receiverList.app.curReceiver = null;
12132 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012133 }
12134 }
12135 }
12136 }
12137
12138 private final void processNextBroadcast(boolean fromMsg) {
12139 synchronized(this) {
12140 BroadcastRecord r;
12141
12142 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12143 + mParallelBroadcasts.size() + " broadcasts, "
12144 + mOrderedBroadcasts.size() + " serialized broadcasts");
12145
12146 updateCpuStats();
12147
12148 if (fromMsg) {
12149 mBroadcastsScheduled = false;
12150 }
12151
12152 // First, deliver any non-serialized broadcasts right away.
12153 while (mParallelBroadcasts.size() > 0) {
12154 r = mParallelBroadcasts.remove(0);
12155 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012156 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12157 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012158 for (int i=0; i<N; i++) {
12159 Object target = r.receivers.get(i);
12160 if (DEBUG_BROADCAST) Log.v(TAG,
12161 "Delivering non-serialized to registered "
12162 + target + ": " + r);
12163 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12164 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012165 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12166 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012167 }
12168
12169 // Now take care of the next serialized one...
12170
12171 // If we are waiting for a process to come up to handle the next
12172 // broadcast, then do nothing at this point. Just in case, we
12173 // check that the process we're waiting for still exists.
12174 if (mPendingBroadcast != null) {
12175 Log.i(TAG, "processNextBroadcast: waiting for "
12176 + mPendingBroadcast.curApp);
12177
12178 boolean isDead;
12179 synchronized (mPidsSelfLocked) {
12180 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12181 }
12182 if (!isDead) {
12183 // It's still alive, so keep waiting
12184 return;
12185 } else {
12186 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12187 + " died before responding to broadcast");
12188 mPendingBroadcast = null;
12189 }
12190 }
12191
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012192 boolean looped = false;
12193
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012194 do {
12195 if (mOrderedBroadcasts.size() == 0) {
12196 // No more broadcasts pending, so all done!
12197 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012198 if (looped) {
12199 // If we had finished the last ordered broadcast, then
12200 // make sure all processes have correct oom and sched
12201 // adjustments.
12202 updateOomAdjLocked();
12203 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012204 return;
12205 }
12206 r = mOrderedBroadcasts.get(0);
12207 boolean forceReceive = false;
12208
12209 // Ensure that even if something goes awry with the timeout
12210 // detection, we catch "hung" broadcasts here, discard them,
12211 // and continue to make progress.
12212 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12213 long now = SystemClock.uptimeMillis();
12214 if (r.dispatchTime > 0) {
12215 if ((numReceivers > 0) &&
12216 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12217 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12218 + " now=" + now
12219 + " dispatchTime=" + r.dispatchTime
12220 + " startTime=" + r.startTime
12221 + " intent=" + r.intent
12222 + " numReceivers=" + numReceivers
12223 + " nextReceiver=" + r.nextReceiver
12224 + " state=" + r.state);
12225 broadcastTimeout(); // forcibly finish this broadcast
12226 forceReceive = true;
12227 r.state = BroadcastRecord.IDLE;
12228 }
12229 }
12230
12231 if (r.state != BroadcastRecord.IDLE) {
12232 if (DEBUG_BROADCAST) Log.d(TAG,
12233 "processNextBroadcast() called when not idle (state="
12234 + r.state + ")");
12235 return;
12236 }
12237
12238 if (r.receivers == null || r.nextReceiver >= numReceivers
12239 || r.resultAbort || forceReceive) {
12240 // No more receivers for this broadcast! Send the final
12241 // result if requested...
12242 if (r.resultTo != null) {
12243 try {
12244 if (DEBUG_BROADCAST) {
12245 int seq = r.intent.getIntExtra("seq", -1);
12246 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12247 + " seq=" + seq + " app=" + r.callerApp);
12248 }
12249 performReceive(r.callerApp, r.resultTo,
12250 new Intent(r.intent), r.resultCode,
12251 r.resultData, r.resultExtras, false);
12252 } catch (RemoteException e) {
12253 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12254 }
12255 }
12256
12257 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12258 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12259
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012260 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12261 + r);
12262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012263 // ... and on to the next...
12264 mOrderedBroadcasts.remove(0);
12265 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012266 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012267 continue;
12268 }
12269 } while (r == null);
12270
12271 // Get the next receiver...
12272 int recIdx = r.nextReceiver++;
12273
12274 // Keep track of when this receiver started, and make sure there
12275 // is a timeout message pending to kill it if need be.
12276 r.startTime = SystemClock.uptimeMillis();
12277 if (recIdx == 0) {
12278 r.dispatchTime = r.startTime;
12279
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012280 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12281 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012282 if (DEBUG_BROADCAST) Log.v(TAG,
12283 "Submitting BROADCAST_TIMEOUT_MSG for "
12284 + (r.startTime + BROADCAST_TIMEOUT));
12285 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12286 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12287 }
12288
12289 Object nextReceiver = r.receivers.get(recIdx);
12290 if (nextReceiver instanceof BroadcastFilter) {
12291 // Simple case: this is a registered receiver who gets
12292 // a direct call.
12293 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12294 if (DEBUG_BROADCAST) Log.v(TAG,
12295 "Delivering serialized to registered "
12296 + filter + ": " + r);
12297 deliverToRegisteredReceiver(r, filter, r.ordered);
12298 if (r.receiver == null || !r.ordered) {
12299 // The receiver has already finished, so schedule to
12300 // process the next one.
12301 r.state = BroadcastRecord.IDLE;
12302 scheduleBroadcastsLocked();
12303 }
12304 return;
12305 }
12306
12307 // Hard case: need to instantiate the receiver, possibly
12308 // starting its application process to host it.
12309
12310 ResolveInfo info =
12311 (ResolveInfo)nextReceiver;
12312
12313 boolean skip = false;
12314 int perm = checkComponentPermission(info.activityInfo.permission,
12315 r.callingPid, r.callingUid,
12316 info.activityInfo.exported
12317 ? -1 : info.activityInfo.applicationInfo.uid);
12318 if (perm != PackageManager.PERMISSION_GRANTED) {
12319 Log.w(TAG, "Permission Denial: broadcasting "
12320 + r.intent.toString()
12321 + " from " + r.callerPackage + " (pid=" + r.callingPid
12322 + ", uid=" + r.callingUid + ")"
12323 + " requires " + info.activityInfo.permission
12324 + " due to receiver " + info.activityInfo.packageName
12325 + "/" + info.activityInfo.name);
12326 skip = true;
12327 }
12328 if (r.callingUid != Process.SYSTEM_UID &&
12329 r.requiredPermission != null) {
12330 try {
12331 perm = ActivityThread.getPackageManager().
12332 checkPermission(r.requiredPermission,
12333 info.activityInfo.applicationInfo.packageName);
12334 } catch (RemoteException e) {
12335 perm = PackageManager.PERMISSION_DENIED;
12336 }
12337 if (perm != PackageManager.PERMISSION_GRANTED) {
12338 Log.w(TAG, "Permission Denial: receiving "
12339 + r.intent + " to "
12340 + info.activityInfo.applicationInfo.packageName
12341 + " requires " + r.requiredPermission
12342 + " due to sender " + r.callerPackage
12343 + " (uid " + r.callingUid + ")");
12344 skip = true;
12345 }
12346 }
12347 if (r.curApp != null && r.curApp.crashing) {
12348 // If the target process is crashing, just skip it.
12349 skip = true;
12350 }
12351
12352 if (skip) {
12353 r.receiver = null;
12354 r.curFilter = null;
12355 r.state = BroadcastRecord.IDLE;
12356 scheduleBroadcastsLocked();
12357 return;
12358 }
12359
12360 r.state = BroadcastRecord.APP_RECEIVE;
12361 String targetProcess = info.activityInfo.processName;
12362 r.curComponent = new ComponentName(
12363 info.activityInfo.applicationInfo.packageName,
12364 info.activityInfo.name);
12365 r.curReceiver = info.activityInfo;
12366
12367 // Is this receiver's application already running?
12368 ProcessRecord app = getProcessRecordLocked(targetProcess,
12369 info.activityInfo.applicationInfo.uid);
12370 if (app != null && app.thread != null) {
12371 try {
12372 processCurBroadcastLocked(r, app);
12373 return;
12374 } catch (RemoteException e) {
12375 Log.w(TAG, "Exception when sending broadcast to "
12376 + r.curComponent, e);
12377 }
12378
12379 // If a dead object exception was thrown -- fall through to
12380 // restart the application.
12381 }
12382
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012383 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012384 if ((r.curApp=startProcessLocked(targetProcess,
12385 info.activityInfo.applicationInfo, true,
12386 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012387 "broadcast", r.curComponent,
12388 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12389 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012390 // Ah, this recipient is unavailable. Finish it if necessary,
12391 // and mark the broadcast record as ready for the next.
12392 Log.w(TAG, "Unable to launch app "
12393 + info.activityInfo.applicationInfo.packageName + "/"
12394 + info.activityInfo.applicationInfo.uid + " for broadcast "
12395 + r.intent + ": process is bad");
12396 logBroadcastReceiverDiscard(r);
12397 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12398 r.resultExtras, r.resultAbort, true);
12399 scheduleBroadcastsLocked();
12400 r.state = BroadcastRecord.IDLE;
12401 return;
12402 }
12403
12404 mPendingBroadcast = r;
12405 }
12406 }
12407
12408 // =========================================================
12409 // INSTRUMENTATION
12410 // =========================================================
12411
12412 public boolean startInstrumentation(ComponentName className,
12413 String profileFile, int flags, Bundle arguments,
12414 IInstrumentationWatcher watcher) {
12415 // Refuse possible leaked file descriptors
12416 if (arguments != null && arguments.hasFileDescriptors()) {
12417 throw new IllegalArgumentException("File descriptors passed in Bundle");
12418 }
12419
12420 synchronized(this) {
12421 InstrumentationInfo ii = null;
12422 ApplicationInfo ai = null;
12423 try {
12424 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012425 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012426 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012427 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012428 } catch (PackageManager.NameNotFoundException e) {
12429 }
12430 if (ii == null) {
12431 reportStartInstrumentationFailure(watcher, className,
12432 "Unable to find instrumentation info for: " + className);
12433 return false;
12434 }
12435 if (ai == null) {
12436 reportStartInstrumentationFailure(watcher, className,
12437 "Unable to find instrumentation target package: " + ii.targetPackage);
12438 return false;
12439 }
12440
12441 int match = mContext.getPackageManager().checkSignatures(
12442 ii.targetPackage, ii.packageName);
12443 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12444 String msg = "Permission Denial: starting instrumentation "
12445 + className + " from pid="
12446 + Binder.getCallingPid()
12447 + ", uid=" + Binder.getCallingPid()
12448 + " not allowed because package " + ii.packageName
12449 + " does not have a signature matching the target "
12450 + ii.targetPackage;
12451 reportStartInstrumentationFailure(watcher, className, msg);
12452 throw new SecurityException(msg);
12453 }
12454
12455 final long origId = Binder.clearCallingIdentity();
12456 uninstallPackageLocked(ii.targetPackage, -1, true);
12457 ProcessRecord app = addAppLocked(ai);
12458 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012459 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012460 app.instrumentationProfileFile = profileFile;
12461 app.instrumentationArguments = arguments;
12462 app.instrumentationWatcher = watcher;
12463 app.instrumentationResultClass = className;
12464 Binder.restoreCallingIdentity(origId);
12465 }
12466
12467 return true;
12468 }
12469
12470 /**
12471 * Report errors that occur while attempting to start Instrumentation. Always writes the
12472 * error to the logs, but if somebody is watching, send the report there too. This enables
12473 * the "am" command to report errors with more information.
12474 *
12475 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12476 * @param cn The component name of the instrumentation.
12477 * @param report The error report.
12478 */
12479 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12480 ComponentName cn, String report) {
12481 Log.w(TAG, report);
12482 try {
12483 if (watcher != null) {
12484 Bundle results = new Bundle();
12485 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12486 results.putString("Error", report);
12487 watcher.instrumentationStatus(cn, -1, results);
12488 }
12489 } catch (RemoteException e) {
12490 Log.w(TAG, e);
12491 }
12492 }
12493
12494 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12495 if (app.instrumentationWatcher != null) {
12496 try {
12497 // NOTE: IInstrumentationWatcher *must* be oneway here
12498 app.instrumentationWatcher.instrumentationFinished(
12499 app.instrumentationClass,
12500 resultCode,
12501 results);
12502 } catch (RemoteException e) {
12503 }
12504 }
12505 app.instrumentationWatcher = null;
12506 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012507 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012508 app.instrumentationProfileFile = null;
12509 app.instrumentationArguments = null;
12510
12511 uninstallPackageLocked(app.processName, -1, false);
12512 }
12513
12514 public void finishInstrumentation(IApplicationThread target,
12515 int resultCode, Bundle results) {
12516 // Refuse possible leaked file descriptors
12517 if (results != null && results.hasFileDescriptors()) {
12518 throw new IllegalArgumentException("File descriptors passed in Intent");
12519 }
12520
12521 synchronized(this) {
12522 ProcessRecord app = getRecordForAppLocked(target);
12523 if (app == null) {
12524 Log.w(TAG, "finishInstrumentation: no app for " + target);
12525 return;
12526 }
12527 final long origId = Binder.clearCallingIdentity();
12528 finishInstrumentationLocked(app, resultCode, results);
12529 Binder.restoreCallingIdentity(origId);
12530 }
12531 }
12532
12533 // =========================================================
12534 // CONFIGURATION
12535 // =========================================================
12536
12537 public ConfigurationInfo getDeviceConfigurationInfo() {
12538 ConfigurationInfo config = new ConfigurationInfo();
12539 synchronized (this) {
12540 config.reqTouchScreen = mConfiguration.touchscreen;
12541 config.reqKeyboardType = mConfiguration.keyboard;
12542 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012543 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12544 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012545 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12546 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012547 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12548 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012549 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12550 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012551 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012552 }
12553 return config;
12554 }
12555
12556 public Configuration getConfiguration() {
12557 Configuration ci;
12558 synchronized(this) {
12559 ci = new Configuration(mConfiguration);
12560 }
12561 return ci;
12562 }
12563
12564 public void updateConfiguration(Configuration values) {
12565 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12566 "updateConfiguration()");
12567
12568 synchronized(this) {
12569 if (values == null && mWindowManager != null) {
12570 // sentinel: fetch the current configuration from the window manager
12571 values = mWindowManager.computeNewConfiguration();
12572 }
12573
12574 final long origId = Binder.clearCallingIdentity();
12575 updateConfigurationLocked(values, null);
12576 Binder.restoreCallingIdentity(origId);
12577 }
12578 }
12579
12580 /**
12581 * Do either or both things: (1) change the current configuration, and (2)
12582 * make sure the given activity is running with the (now) current
12583 * configuration. Returns true if the activity has been left running, or
12584 * false if <var>starting</var> is being destroyed to match the new
12585 * configuration.
12586 */
12587 public boolean updateConfigurationLocked(Configuration values,
12588 HistoryRecord starting) {
12589 int changes = 0;
12590
12591 boolean kept = true;
12592
12593 if (values != null) {
12594 Configuration newConfig = new Configuration(mConfiguration);
12595 changes = newConfig.updateFrom(values);
12596 if (changes != 0) {
12597 if (DEBUG_SWITCH) {
12598 Log.i(TAG, "Updating configuration to: " + values);
12599 }
12600
12601 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12602
12603 if (values.locale != null) {
12604 saveLocaleLocked(values.locale,
12605 !values.locale.equals(mConfiguration.locale),
12606 values.userSetLocale);
12607 }
12608
12609 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012610 Log.i(TAG, "Config changed: " + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012611
12612 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12613 msg.obj = new Configuration(mConfiguration);
12614 mHandler.sendMessage(msg);
12615
12616 final int N = mLRUProcesses.size();
12617 for (int i=0; i<N; i++) {
12618 ProcessRecord app = mLRUProcesses.get(i);
12619 try {
12620 if (app.thread != null) {
12621 app.thread.scheduleConfigurationChanged(mConfiguration);
12622 }
12623 } catch (Exception e) {
12624 }
12625 }
12626 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12627 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12628 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012629
12630 AttributeCache ac = AttributeCache.instance();
12631 if (ac != null) {
12632 ac.updateConfiguration(mConfiguration);
12633 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012634 }
12635 }
12636
12637 if (changes != 0 && starting == null) {
12638 // If the configuration changed, and the caller is not already
12639 // in the process of starting an activity, then find the top
12640 // activity to check if its configuration needs to change.
12641 starting = topRunningActivityLocked(null);
12642 }
12643
12644 if (starting != null) {
12645 kept = ensureActivityConfigurationLocked(starting, changes);
12646 if (kept) {
12647 // If this didn't result in the starting activity being
12648 // destroyed, then we need to make sure at this point that all
12649 // other activities are made visible.
12650 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12651 + ", ensuring others are correct.");
12652 ensureActivitiesVisibleLocked(starting, changes);
12653 }
12654 }
12655
12656 return kept;
12657 }
12658
12659 private final boolean relaunchActivityLocked(HistoryRecord r,
12660 int changes, boolean andResume) {
12661 List<ResultInfo> results = null;
12662 List<Intent> newIntents = null;
12663 if (andResume) {
12664 results = r.results;
12665 newIntents = r.newIntents;
12666 }
12667 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12668 + " with results=" + results + " newIntents=" + newIntents
12669 + " andResume=" + andResume);
12670 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12671 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12672 r.task.taskId, r.shortComponentName);
12673
12674 r.startFreezingScreenLocked(r.app, 0);
12675
12676 try {
12677 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12678 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12679 changes, !andResume);
12680 // Note: don't need to call pauseIfSleepingLocked() here, because
12681 // the caller will only pass in 'andResume' if this activity is
12682 // currently resumed, which implies we aren't sleeping.
12683 } catch (RemoteException e) {
12684 return false;
12685 }
12686
12687 if (andResume) {
12688 r.results = null;
12689 r.newIntents = null;
12690 }
12691
12692 return true;
12693 }
12694
12695 /**
12696 * Make sure the given activity matches the current configuration. Returns
12697 * false if the activity had to be destroyed. Returns true if the
12698 * configuration is the same, or the activity will remain running as-is
12699 * for whatever reason. Ensures the HistoryRecord is updated with the
12700 * correct configuration and all other bookkeeping is handled.
12701 */
12702 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12703 int globalChanges) {
12704 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12705
12706 // Short circuit: if the two configurations are the exact same
12707 // object (the common case), then there is nothing to do.
12708 Configuration newConfig = mConfiguration;
12709 if (r.configuration == newConfig) {
12710 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12711 return true;
12712 }
12713
12714 // We don't worry about activities that are finishing.
12715 if (r.finishing) {
12716 if (DEBUG_SWITCH) Log.i(TAG,
12717 "Configuration doesn't matter in finishing " + r);
12718 r.stopFreezingScreenLocked(false);
12719 return true;
12720 }
12721
12722 // Okay we now are going to make this activity have the new config.
12723 // But then we need to figure out how it needs to deal with that.
12724 Configuration oldConfig = r.configuration;
12725 r.configuration = newConfig;
12726
12727 // If the activity isn't currently running, just leave the new
12728 // configuration and it will pick that up next time it starts.
12729 if (r.app == null || r.app.thread == null) {
12730 if (DEBUG_SWITCH) Log.i(TAG,
12731 "Configuration doesn't matter not running " + r);
12732 r.stopFreezingScreenLocked(false);
12733 return true;
12734 }
12735
12736 // If the activity isn't persistent, there is a chance we will
12737 // need to restart it.
12738 if (!r.persistent) {
12739
12740 // Figure out what has changed between the two configurations.
12741 int changes = oldConfig.diff(newConfig);
12742 if (DEBUG_SWITCH) {
12743 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12744 + Integer.toHexString(changes) + ", handles=0x"
12745 + Integer.toHexString(r.info.configChanges));
12746 }
12747 if ((changes&(~r.info.configChanges)) != 0) {
12748 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12749 r.configChangeFlags |= changes;
12750 r.startFreezingScreenLocked(r.app, globalChanges);
12751 if (r.app == null || r.app.thread == null) {
12752 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12753 destroyActivityLocked(r, true);
12754 } else if (r.state == ActivityState.PAUSING) {
12755 // A little annoying: we are waiting for this activity to
12756 // finish pausing. Let's not do anything now, but just
12757 // flag that it needs to be restarted when done pausing.
12758 r.configDestroy = true;
12759 return true;
12760 } else if (r.state == ActivityState.RESUMED) {
12761 // Try to optimize this case: the configuration is changing
12762 // and we need to restart the top, resumed activity.
12763 // Instead of doing the normal handshaking, just say
12764 // "restart!".
12765 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12766 relaunchActivityLocked(r, r.configChangeFlags, true);
12767 r.configChangeFlags = 0;
12768 } else {
12769 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12770 relaunchActivityLocked(r, r.configChangeFlags, false);
12771 r.configChangeFlags = 0;
12772 }
12773
12774 // All done... tell the caller we weren't able to keep this
12775 // activity around.
12776 return false;
12777 }
12778 }
12779
12780 // Default case: the activity can handle this new configuration, so
12781 // hand it over. Note that we don't need to give it the new
12782 // configuration, since we always send configuration changes to all
12783 // process when they happen so it can just use whatever configuration
12784 // it last got.
12785 if (r.app != null && r.app.thread != null) {
12786 try {
12787 r.app.thread.scheduleActivityConfigurationChanged(r);
12788 } catch (RemoteException e) {
12789 // If process died, whatever.
12790 }
12791 }
12792 r.stopFreezingScreenLocked(false);
12793
12794 return true;
12795 }
12796
12797 /**
12798 * Save the locale. You must be inside a synchronized (this) block.
12799 */
12800 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12801 if(isDiff) {
12802 SystemProperties.set("user.language", l.getLanguage());
12803 SystemProperties.set("user.region", l.getCountry());
12804 }
12805
12806 if(isPersist) {
12807 SystemProperties.set("persist.sys.language", l.getLanguage());
12808 SystemProperties.set("persist.sys.country", l.getCountry());
12809 SystemProperties.set("persist.sys.localevar", l.getVariant());
12810 }
12811 }
12812
12813 // =========================================================
12814 // LIFETIME MANAGEMENT
12815 // =========================================================
12816
12817 private final int computeOomAdjLocked(
12818 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12819 if (mAdjSeq == app.adjSeq) {
12820 // This adjustment has already been computed.
12821 return app.curAdj;
12822 }
12823
12824 if (app.thread == null) {
12825 app.adjSeq = mAdjSeq;
12826 return (app.curAdj=EMPTY_APP_ADJ);
12827 }
12828
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012829 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
12830 // The max adjustment doesn't allow this app to be anything
12831 // below foreground, so it is not worth doing work for it.
12832 app.adjType = "fixed";
12833 app.adjSeq = mAdjSeq;
12834 app.curRawAdj = app.maxAdj;
12835 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
12836 return (app.curAdj=app.maxAdj);
12837 }
12838
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070012839 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012840 app.adjSource = null;
12841 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012842
The Android Open Source Project4df24232009-03-05 14:34:35 -080012843 // Determine the importance of the process, starting with most
12844 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012845 int adj;
12846 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012847 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012848 // The last app on the list is the foreground app.
12849 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012850 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012851 } else if (app.instrumentationClass != null) {
12852 // Don't want to kill running instrumentation.
12853 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012854 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012855 } else if (app.persistentActivities > 0) {
12856 // Special persistent activities... shouldn't be used these days.
12857 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012858 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012859 } else if (app.curReceiver != null ||
12860 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12861 // An app that is currently receiving a broadcast also
12862 // counts as being in the foreground.
12863 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012864 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012865 } else if (app.executingServices.size() > 0) {
12866 // An app that is currently executing a service callback also
12867 // counts as being in the foreground.
12868 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012869 app.adjType = "exec-service";
12870 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012871 // The user is aware of this app, so make it visible.
12872 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012873 app.adjType = "foreground-service";
12874 } else if (app.forcingToForeground != null) {
12875 // The user is aware of this app, so make it visible.
12876 adj = VISIBLE_APP_ADJ;
12877 app.adjType = "force-foreground";
12878 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012879 } else if (app == mHomeProcess) {
12880 // This process is hosting what we currently consider to be the
12881 // home app, so we don't want to let it go into the background.
12882 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012883 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012884 } else if ((N=app.activities.size()) != 0) {
12885 // This app is in the background with paused activities.
12886 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012887 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012888 for (int j=0; j<N; j++) {
12889 if (((HistoryRecord)app.activities.get(j)).visible) {
12890 // This app has a visible activity!
12891 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012892 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012893 break;
12894 }
12895 }
12896 } else {
12897 // A very not-needed process.
12898 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012899 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012900 }
12901
The Android Open Source Project4df24232009-03-05 14:34:35 -080012902 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012903 // there are applications dependent on our services or providers, but
12904 // this gives us a baseline and makes sure we don't get into an
12905 // infinite recursion.
12906 app.adjSeq = mAdjSeq;
12907 app.curRawAdj = adj;
12908 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12909
Christopher Tate6fa95972009-06-05 18:43:55 -070012910 if (mBackupTarget != null && app == mBackupTarget.app) {
12911 // If possible we want to avoid killing apps while they're being backed up
12912 if (adj > BACKUP_APP_ADJ) {
12913 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12914 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012915 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070012916 }
12917 }
12918
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012919 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12920 // If this process has active services running in it, we would
12921 // like to avoid killing it unless it would prevent the current
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012922 // application from running. By default we put the process in
12923 // with the rest of the background processes; as we scan through
12924 // its services we may bump it up from there.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012925 if (adj > hiddenAdj) {
12926 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012927 app.adjType = "bg-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012928 }
12929 final long now = SystemClock.uptimeMillis();
12930 // This process is more important if the top activity is
12931 // bound to the service.
12932 Iterator jt = app.services.iterator();
12933 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12934 ServiceRecord s = (ServiceRecord)jt.next();
12935 if (s.startRequested) {
12936 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12937 // This service has seen some activity within
12938 // recent memory, so we will keep its process ahead
12939 // of the background processes.
12940 if (adj > SECONDARY_SERVER_ADJ) {
12941 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012942 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012943 }
12944 }
12945 }
12946 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12947 Iterator<ConnectionRecord> kt
12948 = s.connections.values().iterator();
12949 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12950 // XXX should compute this based on the max of
12951 // all connected clients.
12952 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012953 if (cr.binding.client == app) {
12954 // Binding to ourself is not interesting.
12955 continue;
12956 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012957 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12958 ProcessRecord client = cr.binding.client;
12959 int myHiddenAdj = hiddenAdj;
12960 if (myHiddenAdj > client.hiddenAdj) {
12961 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12962 myHiddenAdj = client.hiddenAdj;
12963 } else {
12964 myHiddenAdj = VISIBLE_APP_ADJ;
12965 }
12966 }
12967 int clientAdj = computeOomAdjLocked(
12968 client, myHiddenAdj, TOP_APP);
12969 if (adj > clientAdj) {
12970 adj = clientAdj > VISIBLE_APP_ADJ
12971 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012972 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070012973 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
12974 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012975 app.adjSource = cr.binding.client;
12976 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012977 }
12978 }
12979 HistoryRecord a = cr.activity;
12980 //if (a != null) {
12981 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12982 //}
12983 if (a != null && adj > FOREGROUND_APP_ADJ &&
12984 (a.state == ActivityState.RESUMED
12985 || a.state == ActivityState.PAUSING)) {
12986 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012987 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070012988 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
12989 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012990 app.adjSource = a;
12991 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012992 }
12993 }
12994 }
12995 }
12996 }
12997
12998 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12999 // If this process has published any content providers, then
13000 // its adjustment makes it at least as important as any of the
13001 // processes using those providers, and no less important than
13002 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
13003 if (adj > CONTENT_PROVIDER_ADJ) {
13004 adj = CONTENT_PROVIDER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013005 app.adjType = "pub-providers";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013006 }
13007 Iterator jt = app.pubProviders.values().iterator();
13008 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13009 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13010 if (cpr.clients.size() != 0) {
13011 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13012 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13013 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013014 if (client == app) {
13015 // Being our own client is not interesting.
13016 continue;
13017 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013018 int myHiddenAdj = hiddenAdj;
13019 if (myHiddenAdj > client.hiddenAdj) {
13020 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13021 myHiddenAdj = client.hiddenAdj;
13022 } else {
13023 myHiddenAdj = FOREGROUND_APP_ADJ;
13024 }
13025 }
13026 int clientAdj = computeOomAdjLocked(
13027 client, myHiddenAdj, TOP_APP);
13028 if (adj > clientAdj) {
13029 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013030 ? clientAdj : FOREGROUND_APP_ADJ;
13031 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013032 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13033 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013034 app.adjSource = client;
13035 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013036 }
13037 }
13038 }
13039 // If the provider has external (non-framework) process
13040 // dependencies, ensure that its adjustment is at least
13041 // FOREGROUND_APP_ADJ.
13042 if (cpr.externals != 0) {
13043 if (adj > FOREGROUND_APP_ADJ) {
13044 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013045 app.adjType = "provider";
13046 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013047 }
13048 }
13049 }
13050 }
13051
13052 app.curRawAdj = adj;
13053
13054 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13055 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13056 if (adj > app.maxAdj) {
13057 adj = app.maxAdj;
13058 }
13059
13060 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013061 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013062 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
13063 : Process.THREAD_GROUP_DEFAULT;
13064
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013065 return adj;
13066 }
13067
13068 /**
13069 * Ask a given process to GC right now.
13070 */
13071 final void performAppGcLocked(ProcessRecord app) {
13072 try {
13073 app.lastRequestedGc = SystemClock.uptimeMillis();
13074 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013075 if (app.reportLowMemory) {
13076 app.reportLowMemory = false;
13077 app.thread.scheduleLowMemory();
13078 } else {
13079 app.thread.processInBackground();
13080 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013081 }
13082 } catch (Exception e) {
13083 // whatever.
13084 }
13085 }
13086
13087 /**
13088 * Returns true if things are idle enough to perform GCs.
13089 */
13090 private final boolean canGcNow() {
13091 return mParallelBroadcasts.size() == 0
13092 && mOrderedBroadcasts.size() == 0
13093 && (mSleeping || (mResumedActivity != null &&
13094 mResumedActivity.idle));
13095 }
13096
13097 /**
13098 * Perform GCs on all processes that are waiting for it, but only
13099 * if things are idle.
13100 */
13101 final void performAppGcsLocked() {
13102 final int N = mProcessesToGc.size();
13103 if (N <= 0) {
13104 return;
13105 }
13106 if (canGcNow()) {
13107 while (mProcessesToGc.size() > 0) {
13108 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013109 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13110 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13111 <= SystemClock.uptimeMillis()) {
13112 // To avoid spamming the system, we will GC processes one
13113 // at a time, waiting a few seconds between each.
13114 performAppGcLocked(proc);
13115 scheduleAppGcsLocked();
13116 return;
13117 } else {
13118 // It hasn't been long enough since we last GCed this
13119 // process... put it in the list to wait for its time.
13120 addProcessToGcListLocked(proc);
13121 break;
13122 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013123 }
13124 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013125
13126 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013127 }
13128 }
13129
13130 /**
13131 * If all looks good, perform GCs on all processes waiting for them.
13132 */
13133 final void performAppGcsIfAppropriateLocked() {
13134 if (canGcNow()) {
13135 performAppGcsLocked();
13136 return;
13137 }
13138 // Still not idle, wait some more.
13139 scheduleAppGcsLocked();
13140 }
13141
13142 /**
13143 * Schedule the execution of all pending app GCs.
13144 */
13145 final void scheduleAppGcsLocked() {
13146 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013147
13148 if (mProcessesToGc.size() > 0) {
13149 // Schedule a GC for the time to the next process.
13150 ProcessRecord proc = mProcessesToGc.get(0);
13151 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13152
13153 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13154 long now = SystemClock.uptimeMillis();
13155 if (when < (now+GC_TIMEOUT)) {
13156 when = now + GC_TIMEOUT;
13157 }
13158 mHandler.sendMessageAtTime(msg, when);
13159 }
13160 }
13161
13162 /**
13163 * Add a process to the array of processes waiting to be GCed. Keeps the
13164 * list in sorted order by the last GC time. The process can't already be
13165 * on the list.
13166 */
13167 final void addProcessToGcListLocked(ProcessRecord proc) {
13168 boolean added = false;
13169 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13170 if (mProcessesToGc.get(i).lastRequestedGc <
13171 proc.lastRequestedGc) {
13172 added = true;
13173 mProcessesToGc.add(i+1, proc);
13174 break;
13175 }
13176 }
13177 if (!added) {
13178 mProcessesToGc.add(0, proc);
13179 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013180 }
13181
13182 /**
13183 * Set up to ask a process to GC itself. This will either do it
13184 * immediately, or put it on the list of processes to gc the next
13185 * time things are idle.
13186 */
13187 final void scheduleAppGcLocked(ProcessRecord app) {
13188 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013189 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013190 return;
13191 }
13192 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013193 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013194 scheduleAppGcsLocked();
13195 }
13196 }
13197
13198 private final boolean updateOomAdjLocked(
13199 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13200 app.hiddenAdj = hiddenAdj;
13201
13202 if (app.thread == null) {
13203 return true;
13204 }
13205
13206 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
13207
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013208 if (app.pid != 0 && app.pid != MY_PID) {
13209 if (app.curRawAdj != app.setRawAdj) {
13210 if (app.curRawAdj > FOREGROUND_APP_ADJ
13211 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13212 // If this app is transitioning from foreground to
13213 // non-foreground, have it do a gc.
13214 scheduleAppGcLocked(app);
13215 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13216 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13217 // Likewise do a gc when an app is moving in to the
13218 // background (such as a service stopping).
13219 scheduleAppGcLocked(app);
13220 }
13221 app.setRawAdj = app.curRawAdj;
13222 }
13223 if (adj != app.setAdj) {
13224 if (Process.setOomAdj(app.pid, adj)) {
13225 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13226 TAG, "Set app " + app.processName +
13227 " oom adj to " + adj);
13228 app.setAdj = adj;
13229 } else {
13230 return false;
13231 }
13232 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013233 if (app.setSchedGroup != app.curSchedGroup) {
13234 app.setSchedGroup = app.curSchedGroup;
13235 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13236 "Setting process group of " + app.processName
13237 + " to " + app.curSchedGroup);
13238 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013239 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013240 try {
13241 Process.setProcessGroup(app.pid, app.curSchedGroup);
13242 } catch (Exception e) {
13243 Log.w(TAG, "Failed setting process group of " + app.pid
13244 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013245 e.printStackTrace();
13246 } finally {
13247 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013248 }
13249 }
13250 if (false) {
13251 if (app.thread != null) {
13252 try {
13253 app.thread.setSchedulingGroup(app.curSchedGroup);
13254 } catch (RemoteException e) {
13255 }
13256 }
13257 }
13258 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013259 }
13260
13261 return true;
13262 }
13263
13264 private final HistoryRecord resumedAppLocked() {
13265 HistoryRecord resumedActivity = mResumedActivity;
13266 if (resumedActivity == null || resumedActivity.app == null) {
13267 resumedActivity = mPausingActivity;
13268 if (resumedActivity == null || resumedActivity.app == null) {
13269 resumedActivity = topRunningActivityLocked(null);
13270 }
13271 }
13272 return resumedActivity;
13273 }
13274
13275 private final boolean updateOomAdjLocked(ProcessRecord app) {
13276 final HistoryRecord TOP_ACT = resumedAppLocked();
13277 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13278 int curAdj = app.curAdj;
13279 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13280 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13281
13282 mAdjSeq++;
13283
13284 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13285 if (res) {
13286 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13287 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13288 if (nowHidden != wasHidden) {
13289 // Changed to/from hidden state, so apps after it in the LRU
13290 // list may also be changed.
13291 updateOomAdjLocked();
13292 }
13293 }
13294 return res;
13295 }
13296
13297 private final boolean updateOomAdjLocked() {
13298 boolean didOomAdj = true;
13299 final HistoryRecord TOP_ACT = resumedAppLocked();
13300 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13301
13302 if (false) {
13303 RuntimeException e = new RuntimeException();
13304 e.fillInStackTrace();
13305 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13306 }
13307
13308 mAdjSeq++;
13309
13310 // First try updating the OOM adjustment for each of the
13311 // application processes based on their current state.
13312 int i = mLRUProcesses.size();
13313 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13314 while (i > 0) {
13315 i--;
13316 ProcessRecord app = mLRUProcesses.get(i);
13317 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13318 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13319 && app.curAdj == curHiddenAdj) {
13320 curHiddenAdj++;
13321 }
13322 } else {
13323 didOomAdj = false;
13324 }
13325 }
13326
13327 // todo: for now pretend like OOM ADJ didn't work, because things
13328 // aren't behaving as expected on Linux -- it's not killing processes.
13329 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13330 }
13331
13332 private final void trimApplications() {
13333 synchronized (this) {
13334 int i;
13335
13336 // First remove any unused application processes whose package
13337 // has been removed.
13338 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13339 final ProcessRecord app = mRemovedProcesses.get(i);
13340 if (app.activities.size() == 0
13341 && app.curReceiver == null && app.services.size() == 0) {
13342 Log.i(
13343 TAG, "Exiting empty application process "
13344 + app.processName + " ("
13345 + (app.thread != null ? app.thread.asBinder() : null)
13346 + ")\n");
13347 if (app.pid > 0 && app.pid != MY_PID) {
13348 Process.killProcess(app.pid);
13349 } else {
13350 try {
13351 app.thread.scheduleExit();
13352 } catch (Exception e) {
13353 // Ignore exceptions.
13354 }
13355 }
13356 cleanUpApplicationRecordLocked(app, false, -1);
13357 mRemovedProcesses.remove(i);
13358
13359 if (app.persistent) {
13360 if (app.persistent) {
13361 addAppLocked(app.info);
13362 }
13363 }
13364 }
13365 }
13366
13367 // Now try updating the OOM adjustment for each of the
13368 // application processes based on their current state.
13369 // If the setOomAdj() API is not supported, then go with our
13370 // back-up plan...
13371 if (!updateOomAdjLocked()) {
13372
13373 // Count how many processes are running services.
13374 int numServiceProcs = 0;
13375 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13376 final ProcessRecord app = mLRUProcesses.get(i);
13377
13378 if (app.persistent || app.services.size() != 0
13379 || app.curReceiver != null
13380 || app.persistentActivities > 0) {
13381 // Don't count processes holding services against our
13382 // maximum process count.
13383 if (localLOGV) Log.v(
13384 TAG, "Not trimming app " + app + " with services: "
13385 + app.services);
13386 numServiceProcs++;
13387 }
13388 }
13389
13390 int curMaxProcs = mProcessLimit;
13391 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13392 if (mAlwaysFinishActivities) {
13393 curMaxProcs = 1;
13394 }
13395 curMaxProcs += numServiceProcs;
13396
13397 // Quit as many processes as we can to get down to the desired
13398 // process count. First remove any processes that no longer
13399 // have activites running in them.
13400 for ( i=0;
13401 i<mLRUProcesses.size()
13402 && mLRUProcesses.size() > curMaxProcs;
13403 i++) {
13404 final ProcessRecord app = mLRUProcesses.get(i);
13405 // Quit an application only if it is not currently
13406 // running any activities.
13407 if (!app.persistent && app.activities.size() == 0
13408 && app.curReceiver == null && app.services.size() == 0) {
13409 Log.i(
13410 TAG, "Exiting empty application process "
13411 + app.processName + " ("
13412 + (app.thread != null ? app.thread.asBinder() : null)
13413 + ")\n");
13414 if (app.pid > 0 && app.pid != MY_PID) {
13415 Process.killProcess(app.pid);
13416 } else {
13417 try {
13418 app.thread.scheduleExit();
13419 } catch (Exception e) {
13420 // Ignore exceptions.
13421 }
13422 }
13423 // todo: For now we assume the application is not buggy
13424 // or evil, and will quit as a result of our request.
13425 // Eventually we need to drive this off of the death
13426 // notification, and kill the process if it takes too long.
13427 cleanUpApplicationRecordLocked(app, false, i);
13428 i--;
13429 }
13430 }
13431
13432 // If we still have too many processes, now from the least
13433 // recently used process we start finishing activities.
13434 if (Config.LOGV) Log.v(
13435 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13436 " of " + curMaxProcs + " processes");
13437 for ( i=0;
13438 i<mLRUProcesses.size()
13439 && mLRUProcesses.size() > curMaxProcs;
13440 i++) {
13441 final ProcessRecord app = mLRUProcesses.get(i);
13442 // Quit the application only if we have a state saved for
13443 // all of its activities.
13444 boolean canQuit = !app.persistent && app.curReceiver == null
13445 && app.services.size() == 0
13446 && app.persistentActivities == 0;
13447 int NUMA = app.activities.size();
13448 int j;
13449 if (Config.LOGV) Log.v(
13450 TAG, "Looking to quit " + app.processName);
13451 for (j=0; j<NUMA && canQuit; j++) {
13452 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13453 if (Config.LOGV) Log.v(
13454 TAG, " " + r.intent.getComponent().flattenToShortString()
13455 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13456 canQuit = (r.haveState || !r.stateNotNeeded)
13457 && !r.visible && r.stopped;
13458 }
13459 if (canQuit) {
13460 // Finish all of the activities, and then the app itself.
13461 for (j=0; j<NUMA; j++) {
13462 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13463 if (!r.finishing) {
13464 destroyActivityLocked(r, false);
13465 }
13466 r.resultTo = null;
13467 }
13468 Log.i(TAG, "Exiting application process "
13469 + app.processName + " ("
13470 + (app.thread != null ? app.thread.asBinder() : null)
13471 + ")\n");
13472 if (app.pid > 0 && app.pid != MY_PID) {
13473 Process.killProcess(app.pid);
13474 } else {
13475 try {
13476 app.thread.scheduleExit();
13477 } catch (Exception e) {
13478 // Ignore exceptions.
13479 }
13480 }
13481 // todo: For now we assume the application is not buggy
13482 // or evil, and will quit as a result of our request.
13483 // Eventually we need to drive this off of the death
13484 // notification, and kill the process if it takes too long.
13485 cleanUpApplicationRecordLocked(app, false, i);
13486 i--;
13487 //dump();
13488 }
13489 }
13490
13491 }
13492
13493 int curMaxActivities = MAX_ACTIVITIES;
13494 if (mAlwaysFinishActivities) {
13495 curMaxActivities = 1;
13496 }
13497
13498 // Finally, if there are too many activities now running, try to
13499 // finish as many as we can to get back down to the limit.
13500 for ( i=0;
13501 i<mLRUActivities.size()
13502 && mLRUActivities.size() > curMaxActivities;
13503 i++) {
13504 final HistoryRecord r
13505 = (HistoryRecord)mLRUActivities.get(i);
13506
13507 // We can finish this one if we have its icicle saved and
13508 // it is not persistent.
13509 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13510 && r.stopped && !r.persistent && !r.finishing) {
13511 final int origSize = mLRUActivities.size();
13512 destroyActivityLocked(r, true);
13513
13514 // This will remove it from the LRU list, so keep
13515 // our index at the same value. Note that this check to
13516 // see if the size changes is just paranoia -- if
13517 // something unexpected happens, we don't want to end up
13518 // in an infinite loop.
13519 if (origSize > mLRUActivities.size()) {
13520 i--;
13521 }
13522 }
13523 }
13524 }
13525 }
13526
13527 /** This method sends the specified signal to each of the persistent apps */
13528 public void signalPersistentProcesses(int sig) throws RemoteException {
13529 if (sig != Process.SIGNAL_USR1) {
13530 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13531 }
13532
13533 synchronized (this) {
13534 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13535 != PackageManager.PERMISSION_GRANTED) {
13536 throw new SecurityException("Requires permission "
13537 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13538 }
13539
13540 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13541 ProcessRecord r = mLRUProcesses.get(i);
13542 if (r.thread != null && r.persistent) {
13543 Process.sendSignal(r.pid, sig);
13544 }
13545 }
13546 }
13547 }
13548
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013549 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013550 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013551
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013552 try {
13553 synchronized (this) {
13554 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13555 // its own permission.
13556 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13557 != PackageManager.PERMISSION_GRANTED) {
13558 throw new SecurityException("Requires permission "
13559 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013560 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013561
13562 if (start && fd == null) {
13563 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013564 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013565
13566 ProcessRecord proc = null;
13567 try {
13568 int pid = Integer.parseInt(process);
13569 synchronized (mPidsSelfLocked) {
13570 proc = mPidsSelfLocked.get(pid);
13571 }
13572 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013573 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013574
13575 if (proc == null) {
13576 HashMap<String, SparseArray<ProcessRecord>> all
13577 = mProcessNames.getMap();
13578 SparseArray<ProcessRecord> procs = all.get(process);
13579 if (procs != null && procs.size() > 0) {
13580 proc = procs.valueAt(0);
13581 }
13582 }
13583
13584 if (proc == null || proc.thread == null) {
13585 throw new IllegalArgumentException("Unknown process: " + process);
13586 }
13587
13588 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13589 if (isSecure) {
13590 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13591 throw new SecurityException("Process not debuggable: " + proc);
13592 }
13593 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013594
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013595 proc.thread.profilerControl(start, path, fd);
13596 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013597 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013598 }
13599 } catch (RemoteException e) {
13600 throw new IllegalStateException("Process disappeared");
13601 } finally {
13602 if (fd != null) {
13603 try {
13604 fd.close();
13605 } catch (IOException e) {
13606 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013607 }
13608 }
13609 }
13610
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013611 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13612 public void monitor() {
13613 synchronized (this) { }
13614 }
13615}