blob: 6dfd781517654f0ad06449aa80481c31469e80cc [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
19import com.android.internal.os.BatteryStatsImpl;
Dianne Hackbornde7faf62009-06-30 13:27:30 -070020import com.android.server.AttributeCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import com.android.server.IntentResolver;
22import com.android.server.ProcessMap;
23import com.android.server.ProcessStats;
24import com.android.server.SystemServer;
25import com.android.server.Watchdog;
26import com.android.server.WindowManagerService;
27
28import android.app.Activity;
29import android.app.ActivityManager;
30import android.app.ActivityManagerNative;
31import android.app.ActivityThread;
32import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020033import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.app.Dialog;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070035import android.app.IActivityController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.app.IActivityWatcher;
37import android.app.IApplicationThread;
38import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.app.IServiceConnection;
40import android.app.IThumbnailReceiver;
41import android.app.Instrumentation;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070042import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.app.PendingIntent;
44import android.app.ResultInfo;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070045import android.app.Service;
Christopher Tate181fafa2009-05-14 11:12:14 -070046import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020047import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.ComponentName;
49import android.content.ContentResolver;
50import android.content.Context;
51import android.content.Intent;
52import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070053import android.content.IIntentReceiver;
54import android.content.IIntentSender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -070055import android.content.IntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.content.pm.ActivityInfo;
57import android.content.pm.ApplicationInfo;
58import android.content.pm.ConfigurationInfo;
59import android.content.pm.IPackageDataObserver;
60import android.content.pm.IPackageManager;
61import android.content.pm.InstrumentationInfo;
62import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070063import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import android.content.pm.ProviderInfo;
65import android.content.pm.ResolveInfo;
66import android.content.pm.ServiceInfo;
67import android.content.res.Configuration;
68import android.graphics.Bitmap;
69import android.net.Uri;
70import android.os.Binder;
71import android.os.Bundle;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070072import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.os.Environment;
74import android.os.FileUtils;
75import android.os.Handler;
76import android.os.IBinder;
77import android.os.IPermissionController;
78import android.os.Looper;
79import android.os.Message;
80import android.os.Parcel;
81import android.os.ParcelFileDescriptor;
82import android.os.PowerManager;
83import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070084import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.os.RemoteException;
86import android.os.ServiceManager;
87import android.os.SystemClock;
88import android.os.SystemProperties;
89import android.provider.Checkin;
90import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020091import android.server.data.CrashData;
92import android.server.data.StackTraceElementData;
93import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094import android.text.TextUtils;
95import android.util.Config;
96import android.util.EventLog;
97import android.util.Log;
98import android.util.PrintWriterPrinter;
99import android.util.SparseArray;
100import android.view.Gravity;
101import android.view.LayoutInflater;
102import android.view.View;
103import android.view.WindowManager;
104import android.view.WindowManagerPolicy;
105
106import dalvik.system.Zygote;
107
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200108import java.io.ByteArrayInputStream;
109import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110import java.io.File;
111import java.io.FileDescriptor;
112import java.io.FileInputStream;
113import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200114import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115import java.io.PrintWriter;
116import java.lang.IllegalStateException;
117import java.lang.ref.WeakReference;
118import java.util.ArrayList;
119import java.util.HashMap;
120import java.util.HashSet;
121import java.util.Iterator;
122import java.util.List;
123import java.util.Locale;
124import java.util.Map;
125
126public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
127 static final String TAG = "ActivityManager";
128 static final boolean DEBUG = false;
129 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
130 static final boolean DEBUG_SWITCH = localLOGV || false;
131 static final boolean DEBUG_TASKS = localLOGV || false;
132 static final boolean DEBUG_PAUSE = localLOGV || false;
133 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
134 static final boolean DEBUG_TRANSITION = localLOGV || false;
135 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700136 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 static final boolean DEBUG_SERVICE = localLOGV || false;
138 static final boolean DEBUG_VISBILITY = localLOGV || false;
139 static final boolean DEBUG_PROCESSES = localLOGV || false;
Dianne Hackborna1e989b2009-09-01 19:54:29 -0700140 static final boolean DEBUG_PROVIDER = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700142 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700143 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 static final boolean VALIDATE_TOKENS = false;
145 static final boolean SHOW_ACTIVITY_START_TIME = true;
146
147 // Control over CPU and battery monitoring.
148 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
149 static final boolean MONITOR_CPU_USAGE = true;
150 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
151 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
152 static final boolean MONITOR_THREAD_CPU_USAGE = false;
153
154 // Event log tags
155 static final int LOG_CONFIGURATION_CHANGED = 2719;
156 static final int LOG_CPU = 2721;
157 static final int LOG_AM_FINISH_ACTIVITY = 30001;
158 static final int LOG_TASK_TO_FRONT = 30002;
159 static final int LOG_AM_NEW_INTENT = 30003;
160 static final int LOG_AM_CREATE_TASK = 30004;
161 static final int LOG_AM_CREATE_ACTIVITY = 30005;
162 static final int LOG_AM_RESTART_ACTIVITY = 30006;
163 static final int LOG_AM_RESUME_ACTIVITY = 30007;
164 static final int LOG_ANR = 30008;
165 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
166 static final int LOG_AM_PROCESS_BOUND = 30010;
167 static final int LOG_AM_PROCESS_DIED = 30011;
168 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
169 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
170 static final int LOG_AM_PROCESS_START = 30014;
171 static final int LOG_AM_PROCESS_BAD = 30015;
172 static final int LOG_AM_PROCESS_GOOD = 30016;
173 static final int LOG_AM_LOW_MEMORY = 30017;
174 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
175 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
176 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
177 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
178 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
179 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
180 static final int LOG_AM_CREATE_SERVICE = 30030;
181 static final int LOG_AM_DESTROY_SERVICE = 30031;
182 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
183 static final int LOG_AM_DROP_PROCESS = 30033;
184 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
185 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
186 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
187
188 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
189 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
190
Dianne Hackborn1655be42009-05-08 14:29:01 -0700191 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700192 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700193
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 private static final String SYSTEM_SECURE = "ro.secure";
195
196 // This is the maximum number of application processes we would like
197 // to have running. Due to the asynchronous nature of things, we can
198 // temporarily go beyond this limit.
199 static final int MAX_PROCESSES = 2;
200
201 // Set to false to leave processes running indefinitely, relying on
202 // the kernel killing them as resources are required.
203 static final boolean ENFORCE_PROCESS_LIMIT = false;
204
205 // This is the maximum number of activities that we would like to have
206 // running at a given time.
207 static final int MAX_ACTIVITIES = 20;
208
209 // Maximum number of recent tasks that we can remember.
210 static final int MAX_RECENT_TASKS = 20;
211
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700212 // Amount of time after a call to stopAppSwitches() during which we will
213 // prevent further untrusted switches from happening.
214 static final long APP_SWITCH_DELAY_TIME = 5*1000;
215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 // How long until we reset a task when the user returns to it. Currently
217 // 30 minutes.
218 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
219
220 // Set to true to disable the icon that is shown while a new activity
221 // is being started.
222 static final boolean SHOW_APP_STARTING_ICON = true;
223
224 // How long we wait until giving up on the last activity to pause. This
225 // is short because it directly impacts the responsiveness of starting the
226 // next activity.
227 static final int PAUSE_TIMEOUT = 500;
228
229 /**
230 * How long we can hold the launch wake lock before giving up.
231 */
232 static final int LAUNCH_TIMEOUT = 10*1000;
233
234 // How long we wait for a launched process to attach to the activity manager
235 // before we decide it's never going to come up for real.
236 static final int PROC_START_TIMEOUT = 10*1000;
237
238 // How long we wait until giving up on the last activity telling us it
239 // is idle.
240 static final int IDLE_TIMEOUT = 10*1000;
241
242 // How long to wait after going idle before forcing apps to GC.
243 static final int GC_TIMEOUT = 5*1000;
244
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700245 // The minimum amount of time between successive GC requests for a process.
246 static final int GC_MIN_INTERVAL = 60*1000;
247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 // How long we wait until giving up on an activity telling us it has
249 // finished destroying itself.
250 static final int DESTROY_TIMEOUT = 10*1000;
251
252 // How long we allow a receiver to run before giving up on it.
253 static final int BROADCAST_TIMEOUT = 10*1000;
254
255 // How long we wait for a service to finish executing.
256 static final int SERVICE_TIMEOUT = 20*1000;
257
258 // How long a service needs to be running until restarting its process
259 // is no longer considered to be a relaunch of the service.
260 static final int SERVICE_RESTART_DURATION = 5*1000;
261
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700262 // How long a service needs to be running until it will start back at
263 // SERVICE_RESTART_DURATION after being killed.
264 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
265
266 // Multiplying factor to increase restart duration time by, for each time
267 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
268 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
269
270 // The minimum amount of time between restarting services that we allow.
271 // That is, when multiple services are restarting, we won't allow each
272 // to restart less than this amount of time from the last one.
273 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
274
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 // Maximum amount of time for there to be no activity on a service before
276 // we consider it non-essential and allow its process to go on the
277 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700278 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279
280 // How long we wait until we timeout on key dispatching.
281 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
282
283 // The minimum time we allow between crashes, for us to consider this
284 // application to be bad and stop and its services and reject broadcasts.
285 static final int MIN_CRASH_INTERVAL = 60*1000;
286
287 // How long we wait until we timeout on key dispatching during instrumentation.
288 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
289
290 // OOM adjustments for processes in various states:
291
292 // This is a process without anything currently running in it. Definitely
293 // the first to go! Value set in system/rootdir/init.rc on startup.
294 // This value is initalized in the constructor, careful when refering to
295 // this static variable externally.
296 static int EMPTY_APP_ADJ;
297
298 // This is a process with a content provider that does not have any clients
299 // attached to it. If it did have any clients, its adjustment would be the
300 // one for the highest-priority of those processes.
301 static int CONTENT_PROVIDER_ADJ;
302
303 // This is a process only hosting activities that are not visible,
304 // so it can be killed without any disruption. Value set in
305 // system/rootdir/init.rc on startup.
306 final int HIDDEN_APP_MAX_ADJ;
307 static int HIDDEN_APP_MIN_ADJ;
308
The Android Open Source Project4df24232009-03-05 14:34:35 -0800309 // This is a process holding the home application -- we want to try
310 // avoiding killing it, even if it would normally be in the background,
311 // because the user interacts with it so much.
312 final int HOME_APP_ADJ;
313
Christopher Tate6fa95972009-06-05 18:43:55 -0700314 // This is a process currently hosting a backup operation. Killing it
315 // is not entirely fatal but is generally a bad idea.
316 final int BACKUP_APP_ADJ;
317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 // This is a process holding a secondary server -- killing it will not
319 // have much of an impact as far as the user is concerned. Value set in
320 // system/rootdir/init.rc on startup.
321 final int SECONDARY_SERVER_ADJ;
322
323 // This is a process only hosting activities that are visible to the
324 // user, so we'd prefer they don't disappear. Value set in
325 // system/rootdir/init.rc on startup.
326 final int VISIBLE_APP_ADJ;
327
328 // This is the process running the current foreground app. We'd really
329 // rather not kill it! Value set in system/rootdir/init.rc on startup.
330 final int FOREGROUND_APP_ADJ;
331
332 // This is a process running a core server, such as telephony. Definitely
333 // don't want to kill it, but doing so is not completely fatal.
334 static final int CORE_SERVER_ADJ = -12;
335
336 // The system process runs at the default adjustment.
337 static final int SYSTEM_ADJ = -16;
338
339 // Memory pages are 4K.
340 static final int PAGE_SIZE = 4*1024;
341
Jacek Surazski82a73df2009-06-17 14:33:18 +0200342 // System property defining error report receiver for system apps
343 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
344
345 // System property defining default error report receiver
346 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 // Corresponding memory levels for above adjustments.
349 final int EMPTY_APP_MEM;
350 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800351 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700352 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 final int SECONDARY_SERVER_MEM;
354 final int VISIBLE_APP_MEM;
355 final int FOREGROUND_APP_MEM;
356
357 final int MY_PID;
358
359 static final String[] EMPTY_STRING_ARRAY = new String[0];
360
361 enum ActivityState {
362 INITIALIZING,
363 RESUMED,
364 PAUSING,
365 PAUSED,
366 STOPPING,
367 STOPPED,
368 FINISHING,
369 DESTROYING,
370 DESTROYED
371 }
372
373 /**
374 * The back history of all previous (and possibly still
375 * running) activities. It contains HistoryRecord objects.
376 */
377 final ArrayList mHistory = new ArrayList();
378
379 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700380 * Description of a request to start a new activity, which has been held
381 * due to app switches being disabled.
382 */
383 class PendingActivityLaunch {
384 HistoryRecord r;
385 HistoryRecord sourceRecord;
386 Uri[] grantedUriPermissions;
387 int grantedMode;
388 boolean onlyIfNeeded;
389 }
390
391 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
392 = new ArrayList<PendingActivityLaunch>();
393
394 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 * List of all active broadcasts that are to be executed immediately
396 * (without waiting for another broadcast to finish). Currently this only
397 * contains broadcasts to registered receivers, to avoid spinning up
398 * a bunch of processes to execute IntentReceiver components.
399 */
400 final ArrayList<BroadcastRecord> mParallelBroadcasts
401 = new ArrayList<BroadcastRecord>();
402
403 /**
404 * List of all active broadcasts that are to be executed one at a time.
405 * The object at the top of the list is the currently activity broadcasts;
406 * those after it are waiting for the top to finish..
407 */
408 final ArrayList<BroadcastRecord> mOrderedBroadcasts
409 = new ArrayList<BroadcastRecord>();
410
411 /**
412 * Set when we current have a BROADCAST_INTENT_MSG in flight.
413 */
414 boolean mBroadcastsScheduled = false;
415
416 /**
417 * Set to indicate whether to issue an onUserLeaving callback when a
418 * newly launched activity is being brought in front of us.
419 */
420 boolean mUserLeaving = false;
421
422 /**
423 * When we are in the process of pausing an activity, before starting the
424 * next one, this variable holds the activity that is currently being paused.
425 */
426 HistoryRecord mPausingActivity = null;
427
428 /**
429 * Current activity that is resumed, or null if there is none.
430 */
431 HistoryRecord mResumedActivity = null;
432
433 /**
434 * Activity we have told the window manager to have key focus.
435 */
436 HistoryRecord mFocusedActivity = null;
437
438 /**
439 * This is the last activity that we put into the paused state. This is
440 * used to determine if we need to do an activity transition while sleeping,
441 * when we normally hold the top activity paused.
442 */
443 HistoryRecord mLastPausedActivity = null;
444
445 /**
446 * List of activities that are waiting for a new activity
447 * to become visible before completing whatever operation they are
448 * supposed to do.
449 */
450 final ArrayList mWaitingVisibleActivities = new ArrayList();
451
452 /**
453 * List of activities that are ready to be stopped, but waiting
454 * for the next activity to settle down before doing so. It contains
455 * HistoryRecord objects.
456 */
457 final ArrayList<HistoryRecord> mStoppingActivities
458 = new ArrayList<HistoryRecord>();
459
460 /**
461 * List of intents that were used to start the most recent tasks.
462 */
463 final ArrayList<TaskRecord> mRecentTasks
464 = new ArrayList<TaskRecord>();
465
466 /**
467 * List of activities that are ready to be finished, but waiting
468 * for the previous activity to settle down before doing so. It contains
469 * HistoryRecord objects.
470 */
471 final ArrayList mFinishingActivities = new ArrayList();
472
473 /**
474 * All of the applications we currently have running organized by name.
475 * The keys are strings of the application package name (as
476 * returned by the package manager), and the keys are ApplicationRecord
477 * objects.
478 */
479 final ProcessMap<ProcessRecord> mProcessNames
480 = new ProcessMap<ProcessRecord>();
481
482 /**
483 * The last time that various processes have crashed.
484 */
485 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
486
487 /**
488 * Set of applications that we consider to be bad, and will reject
489 * incoming broadcasts from (which the user has no control over).
490 * Processes are added to this set when they have crashed twice within
491 * a minimum amount of time; they are removed from it when they are
492 * later restarted (hopefully due to some user action). The value is the
493 * time it was added to the list.
494 */
495 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
496
497 /**
498 * All of the processes we currently have running organized by pid.
499 * The keys are the pid running the application.
500 *
501 * <p>NOTE: This object is protected by its own lock, NOT the global
502 * activity manager lock!
503 */
504 final SparseArray<ProcessRecord> mPidsSelfLocked
505 = new SparseArray<ProcessRecord>();
506
507 /**
508 * All of the processes that have been forced to be foreground. The key
509 * is the pid of the caller who requested it (we hold a death
510 * link on it).
511 */
512 abstract class ForegroundToken implements IBinder.DeathRecipient {
513 int pid;
514 IBinder token;
515 }
516 final SparseArray<ForegroundToken> mForegroundProcesses
517 = new SparseArray<ForegroundToken>();
518
519 /**
520 * List of records for processes that someone had tried to start before the
521 * system was ready. We don't start them at that point, but ensure they
522 * are started by the time booting is complete.
523 */
524 final ArrayList<ProcessRecord> mProcessesOnHold
525 = new ArrayList<ProcessRecord>();
526
527 /**
528 * List of records for processes that we have started and are waiting
529 * for them to call back. This is really only needed when running in
530 * single processes mode, in which case we do not have a unique pid for
531 * each process.
532 */
533 final ArrayList<ProcessRecord> mStartingProcesses
534 = new ArrayList<ProcessRecord>();
535
536 /**
537 * List of persistent applications that are in the process
538 * of being started.
539 */
540 final ArrayList<ProcessRecord> mPersistentStartingProcesses
541 = new ArrayList<ProcessRecord>();
542
543 /**
544 * Processes that are being forcibly torn down.
545 */
546 final ArrayList<ProcessRecord> mRemovedProcesses
547 = new ArrayList<ProcessRecord>();
548
549 /**
550 * List of running applications, sorted by recent usage.
551 * The first entry in the list is the least recently used.
552 * It contains ApplicationRecord objects. This list does NOT include
553 * any persistent application records (since we never want to exit them).
554 */
555 final ArrayList<ProcessRecord> mLRUProcesses
556 = new ArrayList<ProcessRecord>();
557
558 /**
559 * List of processes that should gc as soon as things are idle.
560 */
561 final ArrayList<ProcessRecord> mProcessesToGc
562 = new ArrayList<ProcessRecord>();
563
564 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800565 * This is the process holding what we currently consider to be
566 * the "home" activity.
567 */
568 private ProcessRecord mHomeProcess;
569
570 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 * List of running activities, sorted by recent usage.
572 * The first entry in the list is the least recently used.
573 * It contains HistoryRecord objects.
574 */
575 private final ArrayList mLRUActivities = new ArrayList();
576
577 /**
578 * Set of PendingResultRecord objects that are currently active.
579 */
580 final HashSet mPendingResultRecords = new HashSet();
581
582 /**
583 * Set of IntentSenderRecord objects that are currently active.
584 */
585 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
586 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
587
588 /**
589 * Intent broadcast that we have tried to start, but are
590 * waiting for its application's process to be created. We only
591 * need one (instead of a list) because we always process broadcasts
592 * one at a time, so no others can be started while waiting for this
593 * one.
594 */
595 BroadcastRecord mPendingBroadcast = null;
596
597 /**
598 * Keeps track of all IIntentReceivers that have been registered for
599 * broadcasts. Hash keys are the receiver IBinder, hash value is
600 * a ReceiverList.
601 */
602 final HashMap mRegisteredReceivers = new HashMap();
603
604 /**
605 * Resolver for broadcast intents to registered receivers.
606 * Holds BroadcastFilter (subclass of IntentFilter).
607 */
608 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
609 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
610 @Override
611 protected boolean allowFilterResult(
612 BroadcastFilter filter, List<BroadcastFilter> dest) {
613 IBinder target = filter.receiverList.receiver.asBinder();
614 for (int i=dest.size()-1; i>=0; i--) {
615 if (dest.get(i).receiverList.receiver.asBinder() == target) {
616 return false;
617 }
618 }
619 return true;
620 }
621 };
622
623 /**
624 * State of all active sticky broadcasts. Keys are the action of the
625 * sticky Intent, values are an ArrayList of all broadcasted intents with
626 * that action (which should usually be one).
627 */
628 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
629 new HashMap<String, ArrayList<Intent>>();
630
631 /**
632 * All currently running services.
633 */
634 final HashMap<ComponentName, ServiceRecord> mServices =
635 new HashMap<ComponentName, ServiceRecord>();
636
637 /**
638 * All currently running services indexed by the Intent used to start them.
639 */
640 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
641 new HashMap<Intent.FilterComparison, ServiceRecord>();
642
643 /**
644 * All currently bound service connections. Keys are the IBinder of
645 * the client's IServiceConnection.
646 */
647 final HashMap<IBinder, ConnectionRecord> mServiceConnections
648 = new HashMap<IBinder, ConnectionRecord>();
649
650 /**
651 * List of services that we have been asked to start,
652 * but haven't yet been able to. It is used to hold start requests
653 * while waiting for their corresponding application thread to get
654 * going.
655 */
656 final ArrayList<ServiceRecord> mPendingServices
657 = new ArrayList<ServiceRecord>();
658
659 /**
660 * List of services that are scheduled to restart following a crash.
661 */
662 final ArrayList<ServiceRecord> mRestartingServices
663 = new ArrayList<ServiceRecord>();
664
665 /**
666 * List of services that are in the process of being stopped.
667 */
668 final ArrayList<ServiceRecord> mStoppingServices
669 = new ArrayList<ServiceRecord>();
670
671 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700672 * Backup/restore process management
673 */
674 String mBackupAppName = null;
675 BackupRecord mBackupTarget = null;
676
677 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 * List of PendingThumbnailsRecord objects of clients who are still
679 * waiting to receive all of the thumbnails for a task.
680 */
681 final ArrayList mPendingThumbnails = new ArrayList();
682
683 /**
684 * List of HistoryRecord objects that have been finished and must
685 * still report back to a pending thumbnail receiver.
686 */
687 final ArrayList mCancelledThumbnails = new ArrayList();
688
689 /**
690 * All of the currently running global content providers. Keys are a
691 * string containing the provider name and values are a
692 * ContentProviderRecord object containing the data about it. Note
693 * that a single provider may be published under multiple names, so
694 * there may be multiple entries here for a single one in mProvidersByClass.
695 */
696 final HashMap mProvidersByName = new HashMap();
697
698 /**
699 * All of the currently running global content providers. Keys are a
700 * string containing the provider's implementation class and values are a
701 * ContentProviderRecord object containing the data about it.
702 */
703 final HashMap mProvidersByClass = new HashMap();
704
705 /**
706 * List of content providers who have clients waiting for them. The
707 * application is currently being launched and the provider will be
708 * removed from this list once it is published.
709 */
710 final ArrayList mLaunchingProviders = new ArrayList();
711
712 /**
713 * Global set of specific Uri permissions that have been granted.
714 */
715 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
716 = new SparseArray<HashMap<Uri, UriPermission>>();
717
718 /**
719 * Thread-local storage used to carry caller permissions over through
720 * indirect content-provider access.
721 * @see #ActivityManagerService.openContentUri()
722 */
723 private class Identity {
724 public int pid;
725 public int uid;
726
727 Identity(int _pid, int _uid) {
728 pid = _pid;
729 uid = _uid;
730 }
731 }
732 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
733
734 /**
735 * All information we have collected about the runtime performance of
736 * any user id that can impact battery performance.
737 */
738 final BatteryStatsService mBatteryStatsService;
739
740 /**
741 * information about component usage
742 */
743 final UsageStatsService mUsageStatsService;
744
745 /**
746 * Current configuration information. HistoryRecord objects are given
747 * a reference to this object to indicate which configuration they are
748 * currently running in, so this object must be kept immutable.
749 */
750 Configuration mConfiguration = new Configuration();
751
752 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700753 * Hardware-reported OpenGLES version.
754 */
755 final int GL_ES_VERSION;
756
757 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 * List of initialization arguments to pass to all processes when binding applications to them.
759 * For example, references to the commonly used services.
760 */
761 HashMap<String, IBinder> mAppBindArgs;
762
763 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700764 * Temporary to avoid allocations. Protected by main lock.
765 */
766 final StringBuilder mStringBuilder = new StringBuilder(256);
767
768 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 * Used to control how we initialize the service.
770 */
771 boolean mStartRunning = false;
772 ComponentName mTopComponent;
773 String mTopAction;
774 String mTopData;
775 boolean mSystemReady = false;
776 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700777 boolean mWaitingUpdate = false;
778 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779
780 Context mContext;
781
782 int mFactoryTest;
783
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700784 boolean mCheckedForSetup;
785
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700787 * The time at which we will allow normal application switches again,
788 * after a call to {@link #stopAppSwitches()}.
789 */
790 long mAppSwitchesAllowedTime;
791
792 /**
793 * This is set to true after the first switch after mAppSwitchesAllowedTime
794 * is set; any switches after that will clear the time.
795 */
796 boolean mDidAppSwitch;
797
798 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 * Set while we are wanting to sleep, to prevent any
800 * activities from being started/resumed.
801 */
802 boolean mSleeping = false;
803
804 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700805 * Set if we are shutting down the system, similar to sleeping.
806 */
807 boolean mShuttingDown = false;
808
809 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 * Set when the system is going to sleep, until we have
811 * successfully paused the current activity and released our wake lock.
812 * At that point the system is allowed to actually sleep.
813 */
814 PowerManager.WakeLock mGoingToSleep;
815
816 /**
817 * We don't want to allow the device to go to sleep while in the process
818 * of launching an activity. This is primarily to allow alarm intent
819 * receivers to launch an activity and get that to run before the device
820 * goes back to sleep.
821 */
822 PowerManager.WakeLock mLaunchingActivity;
823
824 /**
825 * Task identifier that activities are currently being started
826 * in. Incremented each time a new task is created.
827 * todo: Replace this with a TokenSpace class that generates non-repeating
828 * integers that won't wrap.
829 */
830 int mCurTask = 1;
831
832 /**
833 * Current sequence id for oom_adj computation traversal.
834 */
835 int mAdjSeq = 0;
836
837 /**
838 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
839 * is set, indicating the user wants processes started in such a way
840 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
841 * running in each process (thus no pre-initialized process, etc).
842 */
843 boolean mSimpleProcessManagement = false;
844
845 /**
846 * System monitoring: number of processes that died since the last
847 * N procs were started.
848 */
849 int[] mProcDeaths = new int[20];
850
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700851 /**
852 * This is set if we had to do a delayed dexopt of an app before launching
853 * it, to increasing the ANR timeouts in that case.
854 */
855 boolean mDidDexOpt;
856
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 String mDebugApp = null;
858 boolean mWaitForDebugger = false;
859 boolean mDebugTransient = false;
860 String mOrigDebugApp = null;
861 boolean mOrigWaitForDebugger = false;
862 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700863 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700865 final RemoteCallbackList<IActivityWatcher> mWatchers
866 = new RemoteCallbackList<IActivityWatcher>();
867
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 /**
869 * Callback of last caller to {@link #requestPss}.
870 */
871 Runnable mRequestPssCallback;
872
873 /**
874 * Remaining processes for which we are waiting results from the last
875 * call to {@link #requestPss}.
876 */
877 final ArrayList<ProcessRecord> mRequestPssList
878 = new ArrayList<ProcessRecord>();
879
880 /**
881 * Runtime statistics collection thread. This object's lock is used to
882 * protect all related state.
883 */
884 final Thread mProcessStatsThread;
885
886 /**
887 * Used to collect process stats when showing not responding dialog.
888 * Protected by mProcessStatsThread.
889 */
890 final ProcessStats mProcessStats = new ProcessStats(
891 MONITOR_THREAD_CPU_USAGE);
892 long mLastCpuTime = 0;
893 long mLastWriteTime = 0;
894
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700895 long mInitialStartTime = 0;
896
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 /**
898 * Set to true after the system has finished booting.
899 */
900 boolean mBooted = false;
901
902 int mProcessLimit = 0;
903
904 WindowManagerService mWindowManager;
905
906 static ActivityManagerService mSelf;
907 static ActivityThread mSystemThread;
908
909 private final class AppDeathRecipient implements IBinder.DeathRecipient {
910 final ProcessRecord mApp;
911 final int mPid;
912 final IApplicationThread mAppThread;
913
914 AppDeathRecipient(ProcessRecord app, int pid,
915 IApplicationThread thread) {
916 if (localLOGV) Log.v(
917 TAG, "New death recipient " + this
918 + " for thread " + thread.asBinder());
919 mApp = app;
920 mPid = pid;
921 mAppThread = thread;
922 }
923
924 public void binderDied() {
925 if (localLOGV) Log.v(
926 TAG, "Death received in " + this
927 + " for thread " + mAppThread.asBinder());
928 removeRequestedPss(mApp);
929 synchronized(ActivityManagerService.this) {
930 appDiedLocked(mApp, mPid, mAppThread);
931 }
932 }
933 }
934
935 static final int SHOW_ERROR_MSG = 1;
936 static final int SHOW_NOT_RESPONDING_MSG = 2;
937 static final int SHOW_FACTORY_ERROR_MSG = 3;
938 static final int UPDATE_CONFIGURATION_MSG = 4;
939 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
940 static final int WAIT_FOR_DEBUGGER_MSG = 6;
941 static final int BROADCAST_INTENT_MSG = 7;
942 static final int BROADCAST_TIMEOUT_MSG = 8;
943 static final int PAUSE_TIMEOUT_MSG = 9;
944 static final int IDLE_TIMEOUT_MSG = 10;
945 static final int IDLE_NOW_MSG = 11;
946 static final int SERVICE_TIMEOUT_MSG = 12;
947 static final int UPDATE_TIME_ZONE = 13;
948 static final int SHOW_UID_ERROR_MSG = 14;
949 static final int IM_FEELING_LUCKY_MSG = 15;
950 static final int LAUNCH_TIMEOUT_MSG = 16;
951 static final int DESTROY_TIMEOUT_MSG = 17;
952 static final int SERVICE_ERROR_MSG = 18;
953 static final int RESUME_TOP_ACTIVITY_MSG = 19;
954 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700955 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700956 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957
958 AlertDialog mUidAlert;
959
960 final Handler mHandler = new Handler() {
961 //public Handler() {
962 // if (localLOGV) Log.v(TAG, "Handler started!");
963 //}
964
965 public void handleMessage(Message msg) {
966 switch (msg.what) {
967 case SHOW_ERROR_MSG: {
968 HashMap data = (HashMap) msg.obj;
969 byte[] crashData = (byte[])data.get("crashData");
970 if (crashData != null) {
971 // This needs to be *un*synchronized to avoid deadlock.
972 ContentResolver resolver = mContext.getContentResolver();
973 Checkin.reportCrash(resolver, crashData);
974 }
975 synchronized (ActivityManagerService.this) {
976 ProcessRecord proc = (ProcessRecord)data.get("app");
977 if (proc != null && proc.crashDialog != null) {
978 Log.e(TAG, "App already has crash dialog: " + proc);
979 return;
980 }
981 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700982 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 Dialog d = new AppErrorDialog(
984 mContext, res, proc,
985 (Integer)data.get("flags"),
986 (String)data.get("shortMsg"),
987 (String)data.get("longMsg"));
988 d.show();
989 proc.crashDialog = d;
990 } else {
991 // The device is asleep, so just pretend that the user
992 // saw a crash dialog and hit "force quit".
993 res.set(0);
994 }
995 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700996
997 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 } break;
999 case SHOW_NOT_RESPONDING_MSG: {
1000 synchronized (ActivityManagerService.this) {
1001 HashMap data = (HashMap) msg.obj;
1002 ProcessRecord proc = (ProcessRecord)data.get("app");
1003 if (proc != null && proc.anrDialog != null) {
1004 Log.e(TAG, "App already has anr dialog: " + proc);
1005 return;
1006 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001007
1008 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1009 null, null, 0, null, null, null,
1010 false, false, MY_PID, Process.SYSTEM_UID);
1011
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1013 mContext, proc, (HistoryRecord)data.get("activity"));
1014 d.show();
1015 proc.anrDialog = d;
1016 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001017
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001018 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 } break;
1020 case SHOW_FACTORY_ERROR_MSG: {
1021 Dialog d = new FactoryErrorDialog(
1022 mContext, msg.getData().getCharSequence("msg"));
1023 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001024 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 } break;
1026 case UPDATE_CONFIGURATION_MSG: {
1027 final ContentResolver resolver = mContext.getContentResolver();
1028 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1029 } break;
1030 case GC_BACKGROUND_PROCESSES_MSG: {
1031 synchronized (ActivityManagerService.this) {
1032 performAppGcsIfAppropriateLocked();
1033 }
1034 } break;
1035 case WAIT_FOR_DEBUGGER_MSG: {
1036 synchronized (ActivityManagerService.this) {
1037 ProcessRecord app = (ProcessRecord)msg.obj;
1038 if (msg.arg1 != 0) {
1039 if (!app.waitedForDebugger) {
1040 Dialog d = new AppWaitingForDebuggerDialog(
1041 ActivityManagerService.this,
1042 mContext, app);
1043 app.waitDialog = d;
1044 app.waitedForDebugger = true;
1045 d.show();
1046 }
1047 } else {
1048 if (app.waitDialog != null) {
1049 app.waitDialog.dismiss();
1050 app.waitDialog = null;
1051 }
1052 }
1053 }
1054 } break;
1055 case BROADCAST_INTENT_MSG: {
1056 if (DEBUG_BROADCAST) Log.v(
1057 TAG, "Received BROADCAST_INTENT_MSG");
1058 processNextBroadcast(true);
1059 } break;
1060 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001061 if (mDidDexOpt) {
1062 mDidDexOpt = false;
1063 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1064 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1065 return;
1066 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 broadcastTimeout();
1068 } break;
1069 case PAUSE_TIMEOUT_MSG: {
1070 IBinder token = (IBinder)msg.obj;
1071 // We don't at this point know if the activity is fullscreen,
1072 // so we need to be conservative and assume it isn't.
1073 Log.w(TAG, "Activity pause timeout for " + token);
1074 activityPaused(token, null, true);
1075 } break;
1076 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001077 if (mDidDexOpt) {
1078 mDidDexOpt = false;
1079 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1080 nmsg.obj = msg.obj;
1081 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1082 return;
1083 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001084 // We don't at this point know if the activity is fullscreen,
1085 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001086 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 Log.w(TAG, "Activity idle timeout for " + token);
1088 activityIdleInternal(token, true);
1089 } break;
1090 case DESTROY_TIMEOUT_MSG: {
1091 IBinder token = (IBinder)msg.obj;
1092 // We don't at this point know if the activity is fullscreen,
1093 // so we need to be conservative and assume it isn't.
1094 Log.w(TAG, "Activity destroy timeout for " + token);
1095 activityDestroyed(token);
1096 } break;
1097 case IDLE_NOW_MSG: {
1098 IBinder token = (IBinder)msg.obj;
1099 activityIdle(token);
1100 } break;
1101 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001102 if (mDidDexOpt) {
1103 mDidDexOpt = false;
1104 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1105 nmsg.obj = msg.obj;
1106 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1107 return;
1108 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 serviceTimeout((ProcessRecord)msg.obj);
1110 } break;
1111 case UPDATE_TIME_ZONE: {
1112 synchronized (ActivityManagerService.this) {
1113 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1114 ProcessRecord r = mLRUProcesses.get(i);
1115 if (r.thread != null) {
1116 try {
1117 r.thread.updateTimeZone();
1118 } catch (RemoteException ex) {
1119 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1120 }
1121 }
1122 }
1123 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001124 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 case SHOW_UID_ERROR_MSG: {
1126 // XXX This is a temporary dialog, no need to localize.
1127 AlertDialog d = new BaseErrorDialog(mContext);
1128 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1129 d.setCancelable(false);
1130 d.setTitle("System UIDs Inconsistent");
1131 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1132 d.setButton("I'm Feeling Lucky",
1133 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1134 mUidAlert = d;
1135 d.show();
1136 } break;
1137 case IM_FEELING_LUCKY_MSG: {
1138 if (mUidAlert != null) {
1139 mUidAlert.dismiss();
1140 mUidAlert = null;
1141 }
1142 } break;
1143 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001144 if (mDidDexOpt) {
1145 mDidDexOpt = false;
1146 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1147 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1148 return;
1149 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 synchronized (ActivityManagerService.this) {
1151 if (mLaunchingActivity.isHeld()) {
1152 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1153 mLaunchingActivity.release();
1154 }
1155 }
1156 } break;
1157 case SERVICE_ERROR_MSG: {
1158 ServiceRecord srv = (ServiceRecord)msg.obj;
1159 // This needs to be *un*synchronized to avoid deadlock.
1160 Checkin.logEvent(mContext.getContentResolver(),
1161 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1162 srv.name.toShortString());
1163 } break;
1164 case RESUME_TOP_ACTIVITY_MSG: {
1165 synchronized (ActivityManagerService.this) {
1166 resumeTopActivityLocked(null);
1167 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001168 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001170 if (mDidDexOpt) {
1171 mDidDexOpt = false;
1172 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1173 nmsg.obj = msg.obj;
1174 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1175 return;
1176 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177 ProcessRecord app = (ProcessRecord)msg.obj;
1178 synchronized (ActivityManagerService.this) {
1179 processStartTimedOutLocked(app);
1180 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001181 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001182 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1183 synchronized (ActivityManagerService.this) {
1184 doPendingActivityLaunchesLocked(true);
1185 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001186 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001187 case KILL_APPLICATION_MSG: {
1188 synchronized (ActivityManagerService.this) {
1189 int uid = msg.arg1;
1190 boolean restart = (msg.arg2 == 1);
1191 String pkg = (String) msg.obj;
1192 uninstallPackageLocked(pkg, uid, restart);
1193 }
1194 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195 }
1196 }
1197 };
1198
1199 public static void setSystemProcess() {
1200 try {
1201 ActivityManagerService m = mSelf;
1202
1203 ServiceManager.addService("activity", m);
1204 ServiceManager.addService("meminfo", new MemBinder(m));
1205 if (MONITOR_CPU_USAGE) {
1206 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1207 }
1208 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1209 ServiceManager.addService("activity.services", new ServicesBinder(m));
1210 ServiceManager.addService("activity.senders", new SendersBinder(m));
1211 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1212 ServiceManager.addService("permission", new PermissionController(m));
1213
1214 ApplicationInfo info =
1215 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001216 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217 synchronized (mSelf) {
1218 ProcessRecord app = mSelf.newProcessRecordLocked(
1219 mSystemThread.getApplicationThread(), info,
1220 info.processName);
1221 app.persistent = true;
1222 app.pid = Process.myPid();
1223 app.maxAdj = SYSTEM_ADJ;
1224 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1225 synchronized (mSelf.mPidsSelfLocked) {
1226 mSelf.mPidsSelfLocked.put(app.pid, app);
1227 }
1228 mSelf.updateLRUListLocked(app, true);
1229 }
1230 } catch (PackageManager.NameNotFoundException e) {
1231 throw new RuntimeException(
1232 "Unable to find android system package", e);
1233 }
1234 }
1235
1236 public void setWindowManager(WindowManagerService wm) {
1237 mWindowManager = wm;
1238 }
1239
1240 public static final Context main(int factoryTest) {
1241 AThread thr = new AThread();
1242 thr.start();
1243
1244 synchronized (thr) {
1245 while (thr.mService == null) {
1246 try {
1247 thr.wait();
1248 } catch (InterruptedException e) {
1249 }
1250 }
1251 }
1252
1253 ActivityManagerService m = thr.mService;
1254 mSelf = m;
1255 ActivityThread at = ActivityThread.systemMain();
1256 mSystemThread = at;
1257 Context context = at.getSystemContext();
1258 m.mContext = context;
1259 m.mFactoryTest = factoryTest;
1260 PowerManager pm =
1261 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1262 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1263 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1264 m.mLaunchingActivity.setReferenceCounted(false);
1265
1266 m.mBatteryStatsService.publish(context);
1267 m.mUsageStatsService.publish(context);
1268
1269 synchronized (thr) {
1270 thr.mReady = true;
1271 thr.notifyAll();
1272 }
1273
1274 m.startRunning(null, null, null, null);
1275
1276 return context;
1277 }
1278
1279 public static ActivityManagerService self() {
1280 return mSelf;
1281 }
1282
1283 static class AThread extends Thread {
1284 ActivityManagerService mService;
1285 boolean mReady = false;
1286
1287 public AThread() {
1288 super("ActivityManager");
1289 }
1290
1291 public void run() {
1292 Looper.prepare();
1293
1294 android.os.Process.setThreadPriority(
1295 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1296
1297 ActivityManagerService m = new ActivityManagerService();
1298
1299 synchronized (this) {
1300 mService = m;
1301 notifyAll();
1302 }
1303
1304 synchronized (this) {
1305 while (!mReady) {
1306 try {
1307 wait();
1308 } catch (InterruptedException e) {
1309 }
1310 }
1311 }
1312
1313 Looper.loop();
1314 }
1315 }
1316
1317 static class BroadcastsBinder extends Binder {
1318 ActivityManagerService mActivityManagerService;
1319 BroadcastsBinder(ActivityManagerService activityManagerService) {
1320 mActivityManagerService = activityManagerService;
1321 }
1322
1323 @Override
1324 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1325 mActivityManagerService.dumpBroadcasts(pw);
1326 }
1327 }
1328
1329 static class ServicesBinder extends Binder {
1330 ActivityManagerService mActivityManagerService;
1331 ServicesBinder(ActivityManagerService activityManagerService) {
1332 mActivityManagerService = activityManagerService;
1333 }
1334
1335 @Override
1336 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1337 mActivityManagerService.dumpServices(pw);
1338 }
1339 }
1340
1341 static class SendersBinder extends Binder {
1342 ActivityManagerService mActivityManagerService;
1343 SendersBinder(ActivityManagerService activityManagerService) {
1344 mActivityManagerService = activityManagerService;
1345 }
1346
1347 @Override
1348 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1349 mActivityManagerService.dumpSenders(pw);
1350 }
1351 }
1352
1353 static class ProvidersBinder extends Binder {
1354 ActivityManagerService mActivityManagerService;
1355 ProvidersBinder(ActivityManagerService activityManagerService) {
1356 mActivityManagerService = activityManagerService;
1357 }
1358
1359 @Override
1360 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1361 mActivityManagerService.dumpProviders(pw);
1362 }
1363 }
1364
1365 static class MemBinder extends Binder {
1366 ActivityManagerService mActivityManagerService;
1367 MemBinder(ActivityManagerService activityManagerService) {
1368 mActivityManagerService = activityManagerService;
1369 }
1370
1371 @Override
1372 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1373 ActivityManagerService service = mActivityManagerService;
1374 ArrayList<ProcessRecord> procs;
1375 synchronized (mActivityManagerService) {
1376 if (args != null && args.length > 0
1377 && args[0].charAt(0) != '-') {
1378 procs = new ArrayList<ProcessRecord>();
1379 int pid = -1;
1380 try {
1381 pid = Integer.parseInt(args[0]);
1382 } catch (NumberFormatException e) {
1383
1384 }
1385 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1386 ProcessRecord proc = service.mLRUProcesses.get(i);
1387 if (proc.pid == pid) {
1388 procs.add(proc);
1389 } else if (proc.processName.equals(args[0])) {
1390 procs.add(proc);
1391 }
1392 }
1393 if (procs.size() <= 0) {
1394 pw.println("No process found for: " + args[0]);
1395 return;
1396 }
1397 } else {
1398 procs = service.mLRUProcesses;
1399 }
1400 }
1401 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1402 }
1403 }
1404
1405 static class CpuBinder extends Binder {
1406 ActivityManagerService mActivityManagerService;
1407 CpuBinder(ActivityManagerService activityManagerService) {
1408 mActivityManagerService = activityManagerService;
1409 }
1410
1411 @Override
1412 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1413 synchronized (mActivityManagerService.mProcessStatsThread) {
1414 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1415 }
1416 }
1417 }
1418
1419 private ActivityManagerService() {
1420 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1421 if (v != null && Integer.getInteger(v) != 0) {
1422 mSimpleProcessManagement = true;
1423 }
1424 v = System.getenv("ANDROID_DEBUG_APP");
1425 if (v != null) {
1426 mSimpleProcessManagement = true;
1427 }
1428
1429 MY_PID = Process.myPid();
1430
1431 File dataDir = Environment.getDataDirectory();
1432 File systemDir = new File(dataDir, "system");
1433 systemDir.mkdirs();
1434 mBatteryStatsService = new BatteryStatsService(new File(
1435 systemDir, "batterystats.bin").toString());
1436 mBatteryStatsService.getActiveStatistics().readLocked();
1437 mBatteryStatsService.getActiveStatistics().writeLocked();
1438
1439 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001440 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001441
Jack Palevichb90d28c2009-07-22 15:35:24 -07001442 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1443 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001445 mConfiguration.makeDefault();
1446 mProcessStats.init();
1447
1448 // Add ourself to the Watchdog monitors.
1449 Watchdog.getInstance().addMonitor(this);
1450
1451 // These values are set in system/rootdir/init.rc on startup.
1452 FOREGROUND_APP_ADJ =
1453 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1454 VISIBLE_APP_ADJ =
1455 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1456 SECONDARY_SERVER_ADJ =
1457 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001458 BACKUP_APP_ADJ =
1459 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001460 HOME_APP_ADJ =
1461 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001462 HIDDEN_APP_MIN_ADJ =
1463 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1464 CONTENT_PROVIDER_ADJ =
1465 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1466 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1467 EMPTY_APP_ADJ =
1468 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1469 FOREGROUND_APP_MEM =
1470 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1471 VISIBLE_APP_MEM =
1472 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1473 SECONDARY_SERVER_MEM =
1474 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001475 BACKUP_APP_MEM =
1476 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001477 HOME_APP_MEM =
1478 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001479 HIDDEN_APP_MEM =
1480 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1481 EMPTY_APP_MEM =
1482 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1483
1484 mProcessStatsThread = new Thread("ProcessStats") {
1485 public void run() {
1486 while (true) {
1487 try {
1488 try {
1489 synchronized(this) {
1490 final long now = SystemClock.uptimeMillis();
1491 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1492 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1493 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1494 // + ", write delay=" + nextWriteDelay);
1495 if (nextWriteDelay < nextCpuDelay) {
1496 nextCpuDelay = nextWriteDelay;
1497 }
1498 if (nextCpuDelay > 0) {
1499 this.wait(nextCpuDelay);
1500 }
1501 }
1502 } catch (InterruptedException e) {
1503 }
1504
1505 updateCpuStatsNow();
1506 } catch (Exception e) {
1507 Log.e(TAG, "Unexpected exception collecting process stats", e);
1508 }
1509 }
1510 }
1511 };
1512 mProcessStatsThread.start();
1513 }
1514
1515 @Override
1516 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1517 throws RemoteException {
1518 try {
1519 return super.onTransact(code, data, reply, flags);
1520 } catch (RuntimeException e) {
1521 // The activity manager only throws security exceptions, so let's
1522 // log all others.
1523 if (!(e instanceof SecurityException)) {
1524 Log.e(TAG, "Activity Manager Crash", e);
1525 }
1526 throw e;
1527 }
1528 }
1529
1530 void updateCpuStats() {
1531 synchronized (mProcessStatsThread) {
1532 final long now = SystemClock.uptimeMillis();
1533 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1534 mProcessStatsThread.notify();
1535 }
1536 }
1537 }
1538
1539 void updateCpuStatsNow() {
1540 synchronized (mProcessStatsThread) {
1541 final long now = SystemClock.uptimeMillis();
1542 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001544 if (MONITOR_CPU_USAGE &&
1545 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1546 mLastCpuTime = now;
1547 haveNewCpuStats = true;
1548 mProcessStats.update();
1549 //Log.i(TAG, mProcessStats.printCurrentState());
1550 //Log.i(TAG, "Total CPU usage: "
1551 // + mProcessStats.getTotalCpuPercent() + "%");
1552
1553 // Log the cpu usage if the property is set.
1554 if ("true".equals(SystemProperties.get("events.cpu"))) {
1555 int user = mProcessStats.getLastUserTime();
1556 int system = mProcessStats.getLastSystemTime();
1557 int iowait = mProcessStats.getLastIoWaitTime();
1558 int irq = mProcessStats.getLastIrqTime();
1559 int softIrq = mProcessStats.getLastSoftIrqTime();
1560 int idle = mProcessStats.getLastIdleTime();
1561
1562 int total = user + system + iowait + irq + softIrq + idle;
1563 if (total == 0) total = 1;
1564
1565 EventLog.writeEvent(LOG_CPU,
1566 ((user+system+iowait+irq+softIrq) * 100) / total,
1567 (user * 100) / total,
1568 (system * 100) / total,
1569 (iowait * 100) / total,
1570 (irq * 100) / total,
1571 (softIrq * 100) / total);
1572 }
1573 }
1574
Amith Yamasani819f9282009-06-24 23:18:15 -07001575 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001576 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001577 synchronized(mPidsSelfLocked) {
1578 if (haveNewCpuStats) {
1579 if (mBatteryStatsService.isOnBattery()) {
1580 final int N = mProcessStats.countWorkingStats();
1581 for (int i=0; i<N; i++) {
1582 ProcessStats.Stats st
1583 = mProcessStats.getWorkingStats(i);
1584 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1585 if (pr != null) {
1586 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1587 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001588 } else {
1589 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001590 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001591 if (ps != null) {
1592 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1593 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001594 }
1595 }
1596 }
1597 }
1598 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001599
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001600 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1601 mLastWriteTime = now;
1602 mBatteryStatsService.getActiveStatistics().writeLocked();
1603 }
1604 }
1605 }
1606 }
1607
1608 /**
1609 * Initialize the application bind args. These are passed to each
1610 * process when the bindApplication() IPC is sent to the process. They're
1611 * lazily setup to make sure the services are running when they're asked for.
1612 */
1613 private HashMap<String, IBinder> getCommonServicesLocked() {
1614 if (mAppBindArgs == null) {
1615 mAppBindArgs = new HashMap<String, IBinder>();
1616
1617 // Setup the application init args
1618 mAppBindArgs.put("package", ServiceManager.getService("package"));
1619 mAppBindArgs.put("window", ServiceManager.getService("window"));
1620 mAppBindArgs.put(Context.ALARM_SERVICE,
1621 ServiceManager.getService(Context.ALARM_SERVICE));
1622 }
1623 return mAppBindArgs;
1624 }
1625
1626 private final void setFocusedActivityLocked(HistoryRecord r) {
1627 if (mFocusedActivity != r) {
1628 mFocusedActivity = r;
1629 mWindowManager.setFocusedApp(r, true);
1630 }
1631 }
1632
1633 private final void updateLRUListLocked(ProcessRecord app,
1634 boolean oomAdj) {
1635 // put it on the LRU to keep track of when it should be exited.
1636 int lrui = mLRUProcesses.indexOf(app);
1637 if (lrui >= 0) mLRUProcesses.remove(lrui);
1638 mLRUProcesses.add(app);
1639 //Log.i(TAG, "Putting proc to front: " + app.processName);
1640 if (oomAdj) {
1641 updateOomAdjLocked();
1642 }
1643 }
1644
1645 private final boolean updateLRUListLocked(HistoryRecord r) {
1646 final boolean hadit = mLRUActivities.remove(r);
1647 mLRUActivities.add(r);
1648 return hadit;
1649 }
1650
1651 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1652 int i = mHistory.size()-1;
1653 while (i >= 0) {
1654 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1655 if (!r.finishing && r != notTop) {
1656 return r;
1657 }
1658 i--;
1659 }
1660 return null;
1661 }
1662
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001663 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1664 int i = mHistory.size()-1;
1665 while (i >= 0) {
1666 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1667 if (!r.finishing && !r.delayedResume && r != notTop) {
1668 return r;
1669 }
1670 i--;
1671 }
1672 return null;
1673 }
1674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001675 /**
1676 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001677 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001678 *
1679 * @param token If non-null, any history records matching this token will be skipped.
1680 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1681 *
1682 * @return Returns the HistoryRecord of the next activity on the stack.
1683 */
1684 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1685 int i = mHistory.size()-1;
1686 while (i >= 0) {
1687 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1688 // Note: the taskId check depends on real taskId fields being non-zero
1689 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1690 return r;
1691 }
1692 i--;
1693 }
1694 return null;
1695 }
1696
1697 private final ProcessRecord getProcessRecordLocked(
1698 String processName, int uid) {
1699 if (uid == Process.SYSTEM_UID) {
1700 // The system gets to run in any process. If there are multiple
1701 // processes with the same uid, just pick the first (this
1702 // should never happen).
1703 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1704 processName);
1705 return procs != null ? procs.valueAt(0) : null;
1706 }
1707 ProcessRecord proc = mProcessNames.get(processName, uid);
1708 return proc;
1709 }
1710
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001711 private void ensurePackageDexOpt(String packageName) {
1712 IPackageManager pm = ActivityThread.getPackageManager();
1713 try {
1714 if (pm.performDexOpt(packageName)) {
1715 mDidDexOpt = true;
1716 }
1717 } catch (RemoteException e) {
1718 }
1719 }
1720
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001721 private boolean isNextTransitionForward() {
1722 int transit = mWindowManager.getPendingAppTransition();
1723 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1724 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1725 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1726 }
1727
1728 private final boolean realStartActivityLocked(HistoryRecord r,
1729 ProcessRecord app, boolean andResume, boolean checkConfig)
1730 throws RemoteException {
1731
1732 r.startFreezingScreenLocked(app, 0);
1733 mWindowManager.setAppVisibility(r, true);
1734
1735 // Have the window manager re-evaluate the orientation of
1736 // the screen based on the new activity order. Note that
1737 // as a result of this, it can call back into the activity
1738 // manager with a new orientation. We don't care about that,
1739 // because the activity is not currently running so we are
1740 // just restarting it anyway.
1741 if (checkConfig) {
1742 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001743 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001744 r.mayFreezeScreenLocked(app) ? r : null);
1745 updateConfigurationLocked(config, r);
1746 }
1747
1748 r.app = app;
1749
1750 if (localLOGV) Log.v(TAG, "Launching: " + r);
1751
1752 int idx = app.activities.indexOf(r);
1753 if (idx < 0) {
1754 app.activities.add(r);
1755 }
1756 updateLRUListLocked(app, true);
1757
1758 try {
1759 if (app.thread == null) {
1760 throw new RemoteException();
1761 }
1762 List<ResultInfo> results = null;
1763 List<Intent> newIntents = null;
1764 if (andResume) {
1765 results = r.results;
1766 newIntents = r.newIntents;
1767 }
1768 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1769 + " icicle=" + r.icicle
1770 + " with results=" + results + " newIntents=" + newIntents
1771 + " andResume=" + andResume);
1772 if (andResume) {
1773 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1774 System.identityHashCode(r),
1775 r.task.taskId, r.shortComponentName);
1776 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001777 if (r.isHomeActivity) {
1778 mHomeProcess = app;
1779 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001780 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001781 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001782 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001783 r.info, r.icicle, results, newIntents, !andResume,
1784 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001785 } catch (RemoteException e) {
1786 if (r.launchFailed) {
1787 // This is the second time we failed -- finish activity
1788 // and give up.
1789 Log.e(TAG, "Second failure launching "
1790 + r.intent.getComponent().flattenToShortString()
1791 + ", giving up", e);
1792 appDiedLocked(app, app.pid, app.thread);
1793 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1794 "2nd-crash");
1795 return false;
1796 }
1797
1798 // This is the first time we failed -- restart process and
1799 // retry.
1800 app.activities.remove(r);
1801 throw e;
1802 }
1803
1804 r.launchFailed = false;
1805 if (updateLRUListLocked(r)) {
1806 Log.w(TAG, "Activity " + r
1807 + " being launched, but already in LRU list");
1808 }
1809
1810 if (andResume) {
1811 // As part of the process of launching, ActivityThread also performs
1812 // a resume.
1813 r.state = ActivityState.RESUMED;
1814 r.icicle = null;
1815 r.haveState = false;
1816 r.stopped = false;
1817 mResumedActivity = r;
1818 r.task.touchActiveTime();
1819 completeResumeLocked(r);
1820 pauseIfSleepingLocked();
1821 } else {
1822 // This activity is not starting in the resumed state... which
1823 // should look like we asked it to pause+stop (but remain visible),
1824 // and it has done so and reported back the current icicle and
1825 // other state.
1826 r.state = ActivityState.STOPPED;
1827 r.stopped = true;
1828 }
1829
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001830 // Launch the new version setup screen if needed. We do this -after-
1831 // launching the initial activity (that is, home), so that it can have
1832 // a chance to initialize itself while in the background, making the
1833 // switch back to it faster and look better.
1834 startSetupActivityLocked();
1835
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001836 return true;
1837 }
1838
1839 private final void startSpecificActivityLocked(HistoryRecord r,
1840 boolean andResume, boolean checkConfig) {
1841 // Is this activity's application already running?
1842 ProcessRecord app = getProcessRecordLocked(r.processName,
1843 r.info.applicationInfo.uid);
1844
1845 if (r.startTime == 0) {
1846 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001847 if (mInitialStartTime == 0) {
1848 mInitialStartTime = r.startTime;
1849 }
1850 } else if (mInitialStartTime == 0) {
1851 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001852 }
1853
1854 if (app != null && app.thread != null) {
1855 try {
1856 realStartActivityLocked(r, app, andResume, checkConfig);
1857 return;
1858 } catch (RemoteException e) {
1859 Log.w(TAG, "Exception when starting activity "
1860 + r.intent.getComponent().flattenToShortString(), e);
1861 }
1862
1863 // If a dead object exception was thrown -- fall through to
1864 // restart the application.
1865 }
1866
1867 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001868 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001869 }
1870
1871 private final ProcessRecord startProcessLocked(String processName,
1872 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001873 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001874 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1875 // We don't have to do anything more if:
1876 // (1) There is an existing application record; and
1877 // (2) The caller doesn't think it is dead, OR there is no thread
1878 // object attached to it so we know it couldn't have crashed; and
1879 // (3) There is a pid assigned to it, so it is either starting or
1880 // already running.
1881 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1882 + " app=" + app + " knownToBeDead=" + knownToBeDead
1883 + " thread=" + (app != null ? app.thread : null)
1884 + " pid=" + (app != null ? app.pid : -1));
1885 if (app != null &&
1886 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1887 return app;
1888 }
1889
1890 String hostingNameStr = hostingName != null
1891 ? hostingName.flattenToShortString() : null;
1892
1893 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1894 // If we are in the background, then check to see if this process
1895 // is bad. If so, we will just silently fail.
1896 if (mBadProcesses.get(info.processName, info.uid) != null) {
1897 return null;
1898 }
1899 } else {
1900 // When the user is explicitly starting a process, then clear its
1901 // crash count so that we won't make it bad until they see at
1902 // least one crash dialog again, and make the process good again
1903 // if it had been bad.
1904 mProcessCrashTimes.remove(info.processName, info.uid);
1905 if (mBadProcesses.get(info.processName, info.uid) != null) {
1906 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1907 info.processName);
1908 mBadProcesses.remove(info.processName, info.uid);
1909 if (app != null) {
1910 app.bad = false;
1911 }
1912 }
1913 }
1914
1915 if (app == null) {
1916 app = newProcessRecordLocked(null, info, processName);
1917 mProcessNames.put(processName, info.uid, app);
1918 } else {
1919 // If this is a new package in the process, add the package to the list
1920 app.addPackage(info.packageName);
1921 }
1922
1923 // If the system is not ready yet, then hold off on starting this
1924 // process until it is.
1925 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001926 && !isAllowedWhileBooting(info)
1927 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001928 if (!mProcessesOnHold.contains(app)) {
1929 mProcessesOnHold.add(app);
1930 }
1931 return app;
1932 }
1933
1934 startProcessLocked(app, hostingType, hostingNameStr);
1935 return (app.pid != 0) ? app : null;
1936 }
1937
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001938 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1939 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1940 }
1941
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001942 private final void startProcessLocked(ProcessRecord app,
1943 String hostingType, String hostingNameStr) {
1944 if (app.pid > 0 && app.pid != MY_PID) {
1945 synchronized (mPidsSelfLocked) {
1946 mPidsSelfLocked.remove(app.pid);
1947 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1948 }
1949 app.pid = 0;
1950 }
1951
1952 mProcessesOnHold.remove(app);
1953
1954 updateCpuStats();
1955
1956 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1957 mProcDeaths[0] = 0;
1958
1959 try {
1960 int uid = app.info.uid;
1961 int[] gids = null;
1962 try {
1963 gids = mContext.getPackageManager().getPackageGids(
1964 app.info.packageName);
1965 } catch (PackageManager.NameNotFoundException e) {
1966 Log.w(TAG, "Unable to retrieve gids", e);
1967 }
1968 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1969 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1970 && mTopComponent != null
1971 && app.processName.equals(mTopComponent.getPackageName())) {
1972 uid = 0;
1973 }
1974 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1975 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1976 uid = 0;
1977 }
1978 }
1979 int debugFlags = 0;
1980 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1981 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1982 }
1983 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1984 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1985 }
1986 if ("1".equals(SystemProperties.get("debug.assert"))) {
1987 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1988 }
1989 int pid = Process.start("android.app.ActivityThread",
1990 mSimpleProcessManagement ? app.processName : null, uid, uid,
1991 gids, debugFlags, null);
1992 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1993 synchronized (bs) {
1994 if (bs.isOnBattery()) {
1995 app.batteryStats.incStartsLocked();
1996 }
1997 }
1998
1999 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
2000 app.processName, hostingType,
2001 hostingNameStr != null ? hostingNameStr : "");
2002
2003 if (app.persistent) {
2004 Watchdog.getInstance().processStarted(app, app.processName, pid);
2005 }
2006
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07002007 StringBuilder buf = mStringBuilder;
2008 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002009 buf.append("Start proc ");
2010 buf.append(app.processName);
2011 buf.append(" for ");
2012 buf.append(hostingType);
2013 if (hostingNameStr != null) {
2014 buf.append(" ");
2015 buf.append(hostingNameStr);
2016 }
2017 buf.append(": pid=");
2018 buf.append(pid);
2019 buf.append(" uid=");
2020 buf.append(uid);
2021 buf.append(" gids={");
2022 if (gids != null) {
2023 for (int gi=0; gi<gids.length; gi++) {
2024 if (gi != 0) buf.append(", ");
2025 buf.append(gids[gi]);
2026
2027 }
2028 }
2029 buf.append("}");
2030 Log.i(TAG, buf.toString());
2031 if (pid == 0 || pid == MY_PID) {
2032 // Processes are being emulated with threads.
2033 app.pid = MY_PID;
2034 app.removed = false;
2035 mStartingProcesses.add(app);
2036 } else if (pid > 0) {
2037 app.pid = pid;
2038 app.removed = false;
2039 synchronized (mPidsSelfLocked) {
2040 this.mPidsSelfLocked.put(pid, app);
2041 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2042 msg.obj = app;
2043 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2044 }
2045 } else {
2046 app.pid = 0;
2047 RuntimeException e = new RuntimeException(
2048 "Failure starting process " + app.processName
2049 + ": returned pid=" + pid);
2050 Log.e(TAG, e.getMessage(), e);
2051 }
2052 } catch (RuntimeException e) {
2053 // XXX do better error recovery.
2054 app.pid = 0;
2055 Log.e(TAG, "Failure starting process " + app.processName, e);
2056 }
2057 }
2058
2059 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2060 if (mPausingActivity != null) {
2061 RuntimeException e = new RuntimeException();
2062 Log.e(TAG, "Trying to pause when pause is already pending for "
2063 + mPausingActivity, e);
2064 }
2065 HistoryRecord prev = mResumedActivity;
2066 if (prev == null) {
2067 RuntimeException e = new RuntimeException();
2068 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2069 resumeTopActivityLocked(null);
2070 return;
2071 }
2072 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2073 mResumedActivity = null;
2074 mPausingActivity = prev;
2075 mLastPausedActivity = prev;
2076 prev.state = ActivityState.PAUSING;
2077 prev.task.touchActiveTime();
2078
2079 updateCpuStats();
2080
2081 if (prev.app != null && prev.app.thread != null) {
2082 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2083 try {
2084 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2085 System.identityHashCode(prev),
2086 prev.shortComponentName);
2087 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2088 prev.configChangeFlags);
2089 updateUsageStats(prev, false);
2090 } catch (Exception e) {
2091 // Ignore exception, if process died other code will cleanup.
2092 Log.w(TAG, "Exception thrown during pause", e);
2093 mPausingActivity = null;
2094 mLastPausedActivity = null;
2095 }
2096 } else {
2097 mPausingActivity = null;
2098 mLastPausedActivity = null;
2099 }
2100
2101 // If we are not going to sleep, we want to ensure the device is
2102 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002103 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002104 mLaunchingActivity.acquire();
2105 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2106 // To be safe, don't allow the wake lock to be held for too long.
2107 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2108 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2109 }
2110 }
2111
2112
2113 if (mPausingActivity != null) {
2114 // Have the window manager pause its key dispatching until the new
2115 // activity has started. If we're pausing the activity just because
2116 // the screen is being turned off and the UI is sleeping, don't interrupt
2117 // key dispatch; the same activity will pick it up again on wakeup.
2118 if (!uiSleeping) {
2119 prev.pauseKeyDispatchingLocked();
2120 } else {
2121 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2122 }
2123
2124 // Schedule a pause timeout in case the app doesn't respond.
2125 // We don't give it much time because this directly impacts the
2126 // responsiveness seen by the user.
2127 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2128 msg.obj = prev;
2129 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2130 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2131 } else {
2132 // This activity failed to schedule the
2133 // pause, so just treat it as being paused now.
2134 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2135 resumeTopActivityLocked(null);
2136 }
2137 }
2138
2139 private final void completePauseLocked() {
2140 HistoryRecord prev = mPausingActivity;
2141 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2142
2143 if (prev != null) {
2144 if (prev.finishing) {
2145 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2146 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2147 } else if (prev.app != null) {
2148 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2149 if (prev.waitingVisible) {
2150 prev.waitingVisible = false;
2151 mWaitingVisibleActivities.remove(prev);
2152 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2153 TAG, "Complete pause, no longer waiting: " + prev);
2154 }
2155 if (prev.configDestroy) {
2156 // The previous is being paused because the configuration
2157 // is changing, which means it is actually stopping...
2158 // To juggle the fact that we are also starting a new
2159 // instance right now, we need to first completely stop
2160 // the current instance before starting the new one.
2161 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2162 destroyActivityLocked(prev, true);
2163 } else {
2164 mStoppingActivities.add(prev);
2165 if (mStoppingActivities.size() > 3) {
2166 // If we already have a few activities waiting to stop,
2167 // then give up on things going idle and start clearing
2168 // them out.
2169 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2170 Message msg = Message.obtain();
2171 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2172 mHandler.sendMessage(msg);
2173 }
2174 }
2175 } else {
2176 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2177 prev = null;
2178 }
2179 mPausingActivity = null;
2180 }
2181
Dianne Hackborn55280a92009-05-07 15:53:46 -07002182 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002183 resumeTopActivityLocked(prev);
2184 } else {
2185 if (mGoingToSleep.isHeld()) {
2186 mGoingToSleep.release();
2187 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002188 if (mShuttingDown) {
2189 notifyAll();
2190 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002191 }
2192
2193 if (prev != null) {
2194 prev.resumeKeyDispatchingLocked();
2195 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002196
2197 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2198 long diff = 0;
2199 synchronized (mProcessStatsThread) {
2200 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2201 }
2202 if (diff > 0) {
2203 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2204 synchronized (bsi) {
2205 BatteryStatsImpl.Uid.Proc ps =
2206 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2207 prev.info.packageName);
2208 if (ps != null) {
2209 ps.addForegroundTimeLocked(diff);
2210 }
2211 }
2212 }
2213 }
2214 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002215 }
2216
2217 /**
2218 * Once we know that we have asked an application to put an activity in
2219 * the resumed state (either by launching it or explicitly telling it),
2220 * this function updates the rest of our state to match that fact.
2221 */
2222 private final void completeResumeLocked(HistoryRecord next) {
2223 next.idle = false;
2224 next.results = null;
2225 next.newIntents = null;
2226
2227 // schedule an idle timeout in case the app doesn't do it for us.
2228 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2229 msg.obj = next;
2230 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2231
2232 if (false) {
2233 // The activity was never told to pause, so just keep
2234 // things going as-is. To maintain our own state,
2235 // we need to emulate it coming back and saying it is
2236 // idle.
2237 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2238 msg.obj = next;
2239 mHandler.sendMessage(msg);
2240 }
2241
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002242 reportResumedActivity(next);
2243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002244 next.thumbnail = null;
2245 setFocusedActivityLocked(next);
2246 next.resumeKeyDispatchingLocked();
2247 ensureActivitiesVisibleLocked(null, 0);
2248 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002249
2250 // Mark the point when the activity is resuming
2251 // TODO: To be more accurate, the mark should be before the onCreate,
2252 // not after the onResume. But for subsequent starts, onResume is fine.
2253 if (next.app != null) {
2254 synchronized (mProcessStatsThread) {
2255 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2256 }
2257 } else {
2258 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2259 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002260 }
2261
2262 /**
2263 * Make sure that all activities that need to be visible (that is, they
2264 * currently can be seen by the user) actually are.
2265 */
2266 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2267 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2268 if (DEBUG_VISBILITY) Log.v(
2269 TAG, "ensureActivitiesVisible behind " + top
2270 + " configChanges=0x" + Integer.toHexString(configChanges));
2271
2272 // If the top activity is not fullscreen, then we need to
2273 // make sure any activities under it are now visible.
2274 final int count = mHistory.size();
2275 int i = count-1;
2276 while (mHistory.get(i) != top) {
2277 i--;
2278 }
2279 HistoryRecord r;
2280 boolean behindFullscreen = false;
2281 for (; i>=0; i--) {
2282 r = (HistoryRecord)mHistory.get(i);
2283 if (DEBUG_VISBILITY) Log.v(
2284 TAG, "Make visible? " + r + " finishing=" + r.finishing
2285 + " state=" + r.state);
2286 if (r.finishing) {
2287 continue;
2288 }
2289
2290 final boolean doThisProcess = onlyThisProcess == null
2291 || onlyThisProcess.equals(r.processName);
2292
2293 // First: if this is not the current activity being started, make
2294 // sure it matches the current configuration.
2295 if (r != starting && doThisProcess) {
2296 ensureActivityConfigurationLocked(r, 0);
2297 }
2298
2299 if (r.app == null || r.app.thread == null) {
2300 if (onlyThisProcess == null
2301 || onlyThisProcess.equals(r.processName)) {
2302 // This activity needs to be visible, but isn't even
2303 // running... get it started, but don't resume it
2304 // at this point.
2305 if (DEBUG_VISBILITY) Log.v(
2306 TAG, "Start and freeze screen for " + r);
2307 if (r != starting) {
2308 r.startFreezingScreenLocked(r.app, configChanges);
2309 }
2310 if (!r.visible) {
2311 if (DEBUG_VISBILITY) Log.v(
2312 TAG, "Starting and making visible: " + r);
2313 mWindowManager.setAppVisibility(r, true);
2314 }
2315 if (r != starting) {
2316 startSpecificActivityLocked(r, false, false);
2317 }
2318 }
2319
2320 } else if (r.visible) {
2321 // If this activity is already visible, then there is nothing
2322 // else to do here.
2323 if (DEBUG_VISBILITY) Log.v(
2324 TAG, "Skipping: already visible at " + r);
2325 r.stopFreezingScreenLocked(false);
2326
2327 } else if (onlyThisProcess == null) {
2328 // This activity is not currently visible, but is running.
2329 // Tell it to become visible.
2330 r.visible = true;
2331 if (r.state != ActivityState.RESUMED && r != starting) {
2332 // If this activity is paused, tell it
2333 // to now show its window.
2334 if (DEBUG_VISBILITY) Log.v(
2335 TAG, "Making visible and scheduling visibility: " + r);
2336 try {
2337 mWindowManager.setAppVisibility(r, true);
2338 r.app.thread.scheduleWindowVisibility(r, true);
2339 r.stopFreezingScreenLocked(false);
2340 } catch (Exception e) {
2341 // Just skip on any failure; we'll make it
2342 // visible when it next restarts.
2343 Log.w(TAG, "Exception thrown making visibile: "
2344 + r.intent.getComponent(), e);
2345 }
2346 }
2347 }
2348
2349 // Aggregate current change flags.
2350 configChanges |= r.configChangeFlags;
2351
2352 if (r.fullscreen) {
2353 // At this point, nothing else needs to be shown
2354 if (DEBUG_VISBILITY) Log.v(
2355 TAG, "Stopping: fullscreen at " + r);
2356 behindFullscreen = true;
2357 i--;
2358 break;
2359 }
2360 }
2361
2362 // Now for any activities that aren't visible to the user, make
2363 // sure they no longer are keeping the screen frozen.
2364 while (i >= 0) {
2365 r = (HistoryRecord)mHistory.get(i);
2366 if (DEBUG_VISBILITY) Log.v(
2367 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2368 + " state=" + r.state
2369 + " behindFullscreen=" + behindFullscreen);
2370 if (!r.finishing) {
2371 if (behindFullscreen) {
2372 if (r.visible) {
2373 if (DEBUG_VISBILITY) Log.v(
2374 TAG, "Making invisible: " + r);
2375 r.visible = false;
2376 try {
2377 mWindowManager.setAppVisibility(r, false);
2378 if ((r.state == ActivityState.STOPPING
2379 || r.state == ActivityState.STOPPED)
2380 && r.app != null && r.app.thread != null) {
2381 if (DEBUG_VISBILITY) Log.v(
2382 TAG, "Scheduling invisibility: " + r);
2383 r.app.thread.scheduleWindowVisibility(r, false);
2384 }
2385 } catch (Exception e) {
2386 // Just skip on any failure; we'll make it
2387 // visible when it next restarts.
2388 Log.w(TAG, "Exception thrown making hidden: "
2389 + r.intent.getComponent(), e);
2390 }
2391 } else {
2392 if (DEBUG_VISBILITY) Log.v(
2393 TAG, "Already invisible: " + r);
2394 }
2395 } else if (r.fullscreen) {
2396 if (DEBUG_VISBILITY) Log.v(
2397 TAG, "Now behindFullscreen: " + r);
2398 behindFullscreen = true;
2399 }
2400 }
2401 i--;
2402 }
2403 }
2404
2405 /**
2406 * Version of ensureActivitiesVisible that can easily be called anywhere.
2407 */
2408 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2409 int configChanges) {
2410 HistoryRecord r = topRunningActivityLocked(null);
2411 if (r != null) {
2412 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2413 }
2414 }
2415
2416 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2417 if (resumed) {
2418 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2419 } else {
2420 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2421 }
2422 }
2423
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002424 private boolean startHomeActivityLocked() {
2425 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2426 && mTopAction == null) {
2427 // We are running in factory test mode, but unable to find
2428 // the factory test app, so just sit around displaying the
2429 // error message and don't try to start anything.
2430 return false;
2431 }
2432 Intent intent = new Intent(
2433 mTopAction,
2434 mTopData != null ? Uri.parse(mTopData) : null);
2435 intent.setComponent(mTopComponent);
2436 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2437 intent.addCategory(Intent.CATEGORY_HOME);
2438 }
2439 ActivityInfo aInfo =
2440 intent.resolveActivityInfo(mContext.getPackageManager(),
2441 STOCK_PM_FLAGS);
2442 if (aInfo != null) {
2443 intent.setComponent(new ComponentName(
2444 aInfo.applicationInfo.packageName, aInfo.name));
2445 // Don't do this if the home app is currently being
2446 // instrumented.
2447 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2448 aInfo.applicationInfo.uid);
2449 if (app == null || app.instrumentationClass == null) {
2450 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2451 startActivityLocked(null, intent, null, null, 0, aInfo,
2452 null, null, 0, 0, 0, false, false);
2453 }
2454 }
2455
2456
2457 return true;
2458 }
2459
2460 /**
2461 * Starts the "new version setup screen" if appropriate.
2462 */
2463 private void startSetupActivityLocked() {
2464 // Only do this once per boot.
2465 if (mCheckedForSetup) {
2466 return;
2467 }
2468
2469 // We will show this screen if the current one is a different
2470 // version than the last one shown, and we are not running in
2471 // low-level factory test mode.
2472 final ContentResolver resolver = mContext.getContentResolver();
2473 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2474 Settings.Secure.getInt(resolver,
2475 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2476 mCheckedForSetup = true;
2477
2478 // See if we should be showing the platform update setup UI.
2479 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2480 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2481 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2482
2483 // We don't allow third party apps to replace this.
2484 ResolveInfo ri = null;
2485 for (int i=0; ris != null && i<ris.size(); i++) {
2486 if ((ris.get(i).activityInfo.applicationInfo.flags
2487 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2488 ri = ris.get(i);
2489 break;
2490 }
2491 }
2492
2493 if (ri != null) {
2494 String vers = ri.activityInfo.metaData != null
2495 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2496 : null;
2497 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2498 vers = ri.activityInfo.applicationInfo.metaData.getString(
2499 Intent.METADATA_SETUP_VERSION);
2500 }
2501 String lastVers = Settings.Secure.getString(
2502 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2503 if (vers != null && !vers.equals(lastVers)) {
2504 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2505 intent.setComponent(new ComponentName(
2506 ri.activityInfo.packageName, ri.activityInfo.name));
2507 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2508 null, null, 0, 0, 0, false, false);
2509 }
2510 }
2511 }
2512 }
2513
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002514 private void reportResumedActivity(HistoryRecord r) {
2515 //Log.i(TAG, "**** REPORT RESUME: " + r);
2516
2517 final int identHash = System.identityHashCode(r);
2518 updateUsageStats(r, true);
2519
2520 int i = mWatchers.beginBroadcast();
2521 while (i > 0) {
2522 i--;
2523 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2524 if (w != null) {
2525 try {
2526 w.activityResuming(identHash);
2527 } catch (RemoteException e) {
2528 }
2529 }
2530 }
2531 mWatchers.finishBroadcast();
2532 }
2533
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002534 /**
2535 * Ensure that the top activity in the stack is resumed.
2536 *
2537 * @param prev The previously resumed activity, for when in the process
2538 * of pausing; can be null to call from elsewhere.
2539 *
2540 * @return Returns true if something is being resumed, or false if
2541 * nothing happened.
2542 */
2543 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2544 // Find the first activity that is not finishing.
2545 HistoryRecord next = topRunningActivityLocked(null);
2546
2547 // Remember how we'll process this pause/resume situation, and ensure
2548 // that the state is reset however we wind up proceeding.
2549 final boolean userLeaving = mUserLeaving;
2550 mUserLeaving = false;
2551
2552 if (next == null) {
2553 // There are no more activities! Let's just start up the
2554 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002555 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002556 }
2557
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002558 next.delayedResume = false;
2559
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002560 // If the top activity is the resumed one, nothing to do.
2561 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2562 // Make sure we have executed any pending transitions, since there
2563 // should be nothing left to do at this point.
2564 mWindowManager.executeAppTransition();
2565 return false;
2566 }
2567
2568 // If we are sleeping, and there is no resumed activity, and the top
2569 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002570 if ((mSleeping || mShuttingDown)
2571 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002572 // Make sure we have executed any pending transitions, since there
2573 // should be nothing left to do at this point.
2574 mWindowManager.executeAppTransition();
2575 return false;
2576 }
2577
2578 // The activity may be waiting for stop, but that is no longer
2579 // appropriate for it.
2580 mStoppingActivities.remove(next);
2581 mWaitingVisibleActivities.remove(next);
2582
2583 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2584
2585 // If we are currently pausing an activity, then don't do anything
2586 // until that is done.
2587 if (mPausingActivity != null) {
2588 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2589 return false;
2590 }
2591
2592 // We need to start pausing the current activity so the top one
2593 // can be resumed...
2594 if (mResumedActivity != null) {
2595 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2596 startPausingLocked(userLeaving, false);
2597 return true;
2598 }
2599
2600 if (prev != null && prev != next) {
2601 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2602 prev.waitingVisible = true;
2603 mWaitingVisibleActivities.add(prev);
2604 if (DEBUG_SWITCH) Log.v(
2605 TAG, "Resuming top, waiting visible to hide: " + prev);
2606 } else {
2607 // The next activity is already visible, so hide the previous
2608 // activity's windows right now so we can show the new one ASAP.
2609 // We only do this if the previous is finishing, which should mean
2610 // it is on top of the one being resumed so hiding it quickly
2611 // is good. Otherwise, we want to do the normal route of allowing
2612 // the resumed activity to be shown so we can decide if the
2613 // previous should actually be hidden depending on whether the
2614 // new one is found to be full-screen or not.
2615 if (prev.finishing) {
2616 mWindowManager.setAppVisibility(prev, false);
2617 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2618 + prev + ", waitingVisible="
2619 + (prev != null ? prev.waitingVisible : null)
2620 + ", nowVisible=" + next.nowVisible);
2621 } else {
2622 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2623 + prev + ", waitingVisible="
2624 + (prev != null ? prev.waitingVisible : null)
2625 + ", nowVisible=" + next.nowVisible);
2626 }
2627 }
2628 }
2629
2630 // We are starting up the next activity, so tell the window manager
2631 // that the previous one will be hidden soon. This way it can know
2632 // to ignore it when computing the desired screen orientation.
2633 if (prev != null) {
2634 if (prev.finishing) {
2635 if (DEBUG_TRANSITION) Log.v(TAG,
2636 "Prepare close transition: prev=" + prev);
2637 mWindowManager.prepareAppTransition(prev.task == next.task
2638 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2639 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2640 mWindowManager.setAppWillBeHidden(prev);
2641 mWindowManager.setAppVisibility(prev, false);
2642 } else {
2643 if (DEBUG_TRANSITION) Log.v(TAG,
2644 "Prepare open transition: prev=" + prev);
2645 mWindowManager.prepareAppTransition(prev.task == next.task
2646 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2647 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2648 }
2649 if (false) {
2650 mWindowManager.setAppWillBeHidden(prev);
2651 mWindowManager.setAppVisibility(prev, false);
2652 }
2653 } else if (mHistory.size() > 1) {
2654 if (DEBUG_TRANSITION) Log.v(TAG,
2655 "Prepare open transition: no previous");
2656 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2657 }
2658
2659 if (next.app != null && next.app.thread != null) {
2660 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2661
2662 // This activity is now becoming visible.
2663 mWindowManager.setAppVisibility(next, true);
2664
2665 HistoryRecord lastResumedActivity = mResumedActivity;
2666 ActivityState lastState = next.state;
2667
2668 updateCpuStats();
2669
2670 next.state = ActivityState.RESUMED;
2671 mResumedActivity = next;
2672 next.task.touchActiveTime();
2673 updateLRUListLocked(next.app, true);
2674 updateLRUListLocked(next);
2675
2676 // Have the window manager re-evaluate the orientation of
2677 // the screen based on the new activity order.
2678 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002679 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002680 next.mayFreezeScreenLocked(next.app) ? next : null);
2681 if (config != null) {
2682 next.frozenBeforeDestroy = true;
2683 }
2684 if (!updateConfigurationLocked(config, next)) {
2685 // The configuration update wasn't able to keep the existing
2686 // instance of the activity, and instead started a new one.
2687 // We should be all done, but let's just make sure our activity
2688 // is still at the top and schedule another run if something
2689 // weird happened.
2690 HistoryRecord nextNext = topRunningActivityLocked(null);
2691 if (DEBUG_SWITCH) Log.i(TAG,
2692 "Activity config changed during resume: " + next
2693 + ", new next: " + nextNext);
2694 if (nextNext != next) {
2695 // Do over!
2696 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2697 }
2698 mWindowManager.executeAppTransition();
2699 return true;
2700 }
2701
2702 try {
2703 // Deliver all pending results.
2704 ArrayList a = next.results;
2705 if (a != null) {
2706 final int N = a.size();
2707 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002708 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002709 TAG, "Delivering results to " + next
2710 + ": " + a);
2711 next.app.thread.scheduleSendResult(next, a);
2712 }
2713 }
2714
2715 if (next.newIntents != null) {
2716 next.app.thread.scheduleNewIntent(next.newIntents, next);
2717 }
2718
2719 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2720 System.identityHashCode(next),
2721 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002722
2723 next.app.thread.scheduleResumeActivity(next,
2724 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002725
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002726 pauseIfSleepingLocked();
2727
2728 } catch (Exception e) {
2729 // Whoops, need to restart this activity!
2730 next.state = lastState;
2731 mResumedActivity = lastResumedActivity;
2732 if (Config.LOGD) Log.d(TAG,
2733 "Restarting because process died: " + next);
2734 if (!next.hasBeenLaunched) {
2735 next.hasBeenLaunched = true;
2736 } else {
2737 if (SHOW_APP_STARTING_ICON) {
2738 mWindowManager.setAppStartingWindow(
2739 next, next.packageName, next.theme,
2740 next.nonLocalizedLabel,
2741 next.labelRes, next.icon, null, true);
2742 }
2743 }
2744 startSpecificActivityLocked(next, true, false);
2745 return true;
2746 }
2747
2748 // From this point on, if something goes wrong there is no way
2749 // to recover the activity.
2750 try {
2751 next.visible = true;
2752 completeResumeLocked(next);
2753 } catch (Exception e) {
2754 // If any exception gets thrown, toss away this
2755 // activity and try the next one.
2756 Log.w(TAG, "Exception thrown during resume of " + next, e);
2757 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2758 "resume-exception");
2759 return true;
2760 }
2761
2762 // Didn't need to use the icicle, and it is now out of date.
2763 next.icicle = null;
2764 next.haveState = false;
2765 next.stopped = false;
2766
2767 } else {
2768 // Whoops, need to restart this activity!
2769 if (!next.hasBeenLaunched) {
2770 next.hasBeenLaunched = true;
2771 } else {
2772 if (SHOW_APP_STARTING_ICON) {
2773 mWindowManager.setAppStartingWindow(
2774 next, next.packageName, next.theme,
2775 next.nonLocalizedLabel,
2776 next.labelRes, next.icon, null, true);
2777 }
2778 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2779 }
2780 startSpecificActivityLocked(next, true, true);
2781 }
2782
2783 return true;
2784 }
2785
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002786 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2787 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002788 final int NH = mHistory.size();
2789
2790 int addPos = -1;
2791
2792 if (!newTask) {
2793 // If starting in an existing task, find where that is...
2794 HistoryRecord next = null;
2795 boolean startIt = true;
2796 for (int i = NH-1; i >= 0; i--) {
2797 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2798 if (p.finishing) {
2799 continue;
2800 }
2801 if (p.task == r.task) {
2802 // Here it is! Now, if this is not yet visible to the
2803 // user, then just add it without starting; it will
2804 // get started when the user navigates back to it.
2805 addPos = i+1;
2806 if (!startIt) {
2807 mHistory.add(addPos, r);
2808 r.inHistory = true;
2809 r.task.numActivities++;
2810 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2811 r.info.screenOrientation, r.fullscreen);
2812 if (VALIDATE_TOKENS) {
2813 mWindowManager.validateAppTokens(mHistory);
2814 }
2815 return;
2816 }
2817 break;
2818 }
2819 if (p.fullscreen) {
2820 startIt = false;
2821 }
2822 next = p;
2823 }
2824 }
2825
2826 // Place a new activity at top of stack, so it is next to interact
2827 // with the user.
2828 if (addPos < 0) {
2829 addPos = mHistory.size();
2830 }
2831
2832 // If we are not placing the new activity frontmost, we do not want
2833 // to deliver the onUserLeaving callback to the actual frontmost
2834 // activity
2835 if (addPos < NH) {
2836 mUserLeaving = false;
2837 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2838 }
2839
2840 // Slot the activity into the history stack and proceed
2841 mHistory.add(addPos, r);
2842 r.inHistory = true;
2843 r.frontOfTask = newTask;
2844 r.task.numActivities++;
2845 if (NH > 0) {
2846 // We want to show the starting preview window if we are
2847 // switching to a new task, or the next activity's process is
2848 // not currently running.
2849 boolean showStartingIcon = newTask;
2850 ProcessRecord proc = r.app;
2851 if (proc == null) {
2852 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2853 }
2854 if (proc == null || proc.thread == null) {
2855 showStartingIcon = true;
2856 }
2857 if (DEBUG_TRANSITION) Log.v(TAG,
2858 "Prepare open transition: starting " + r);
2859 mWindowManager.prepareAppTransition(newTask
2860 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2861 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2862 mWindowManager.addAppToken(
2863 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2864 boolean doShow = true;
2865 if (newTask) {
2866 // Even though this activity is starting fresh, we still need
2867 // to reset it to make sure we apply affinities to move any
2868 // existing activities from other tasks in to it.
2869 // If the caller has requested that the target task be
2870 // reset, then do so.
2871 if ((r.intent.getFlags()
2872 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2873 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002874 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002875 }
2876 }
2877 if (SHOW_APP_STARTING_ICON && doShow) {
2878 // Figure out if we are transitioning from another activity that is
2879 // "has the same starting icon" as the next one. This allows the
2880 // window manager to keep the previous window it had previously
2881 // created, if it still had one.
2882 HistoryRecord prev = mResumedActivity;
2883 if (prev != null) {
2884 // We don't want to reuse the previous starting preview if:
2885 // (1) The current activity is in a different task.
2886 if (prev.task != r.task) prev = null;
2887 // (2) The current activity is already displayed.
2888 else if (prev.nowVisible) prev = null;
2889 }
2890 mWindowManager.setAppStartingWindow(
2891 r, r.packageName, r.theme, r.nonLocalizedLabel,
2892 r.labelRes, r.icon, prev, showStartingIcon);
2893 }
2894 } else {
2895 // If this is the first activity, don't do any fancy animations,
2896 // because there is nothing for it to animate on top of.
2897 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2898 r.info.screenOrientation, r.fullscreen);
2899 }
2900 if (VALIDATE_TOKENS) {
2901 mWindowManager.validateAppTokens(mHistory);
2902 }
2903
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002904 if (doResume) {
2905 resumeTopActivityLocked(null);
2906 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002907 }
2908
2909 /**
2910 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002911 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2912 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002913 * an instance of that activity in the stack and, if found, finish all
2914 * activities on top of it and return the instance.
2915 *
2916 * @param newR Description of the new activity being started.
2917 * @return Returns the old activity that should be continue to be used,
2918 * or null if none was found.
2919 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002920 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002921 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002922 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002923
2924 // First find the requested task.
2925 while (i > 0) {
2926 i--;
2927 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2928 if (r.task.taskId == taskId) {
2929 i++;
2930 break;
2931 }
2932 }
2933
2934 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002935 while (i > 0) {
2936 i--;
2937 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2938 if (r.finishing) {
2939 continue;
2940 }
2941 if (r.task.taskId != taskId) {
2942 return null;
2943 }
2944 if (r.realActivity.equals(newR.realActivity)) {
2945 // Here it is! Now finish everything in front...
2946 HistoryRecord ret = r;
2947 if (doClear) {
2948 while (i < (mHistory.size()-1)) {
2949 i++;
2950 r = (HistoryRecord)mHistory.get(i);
2951 if (r.finishing) {
2952 continue;
2953 }
2954 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2955 null, "clear")) {
2956 i--;
2957 }
2958 }
2959 }
2960
2961 // Finally, if this is a normal launch mode (that is, not
2962 // expecting onNewIntent()), then we will finish the current
2963 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002964 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
2965 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002966 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002967 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002968 if (index >= 0) {
2969 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2970 null, "clear");
2971 }
2972 return null;
2973 }
2974 }
2975
2976 return ret;
2977 }
2978 }
2979
2980 return null;
2981 }
2982
2983 /**
2984 * Find the activity in the history stack within the given task. Returns
2985 * the index within the history at which it's found, or < 0 if not found.
2986 */
2987 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2988 int i = mHistory.size();
2989 while (i > 0) {
2990 i--;
2991 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2992 if (candidate.task.taskId != task) {
2993 break;
2994 }
2995 if (candidate.realActivity.equals(r.realActivity)) {
2996 return i;
2997 }
2998 }
2999
3000 return -1;
3001 }
3002
3003 /**
3004 * Reorder the history stack so that the activity at the given index is
3005 * brought to the front.
3006 */
3007 private final HistoryRecord moveActivityToFrontLocked(int where) {
3008 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3009 int top = mHistory.size();
3010 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3011 mHistory.add(top, newTop);
3012 oldTop.frontOfTask = false;
3013 newTop.frontOfTask = true;
3014 return newTop;
3015 }
3016
3017 /**
3018 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3019 * method will be called at the proper time.
3020 */
3021 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3022 boolean sent = false;
3023 if (r.state == ActivityState.RESUMED
3024 && r.app != null && r.app.thread != null) {
3025 try {
3026 ArrayList<Intent> ar = new ArrayList<Intent>();
3027 ar.add(new Intent(intent));
3028 r.app.thread.scheduleNewIntent(ar, r);
3029 sent = true;
3030 } catch (Exception e) {
3031 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3032 }
3033 }
3034 if (!sent) {
3035 r.addNewIntentLocked(new Intent(intent));
3036 }
3037 }
3038
3039 private final void logStartActivity(int tag, HistoryRecord r,
3040 TaskRecord task) {
3041 EventLog.writeEvent(tag,
3042 System.identityHashCode(r), task.taskId,
3043 r.shortComponentName, r.intent.getAction(),
3044 r.intent.getType(), r.intent.getDataString(),
3045 r.intent.getFlags());
3046 }
3047
3048 private final int startActivityLocked(IApplicationThread caller,
3049 Intent intent, String resolvedType,
3050 Uri[] grantedUriPermissions,
3051 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3052 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003053 int callingPid, int callingUid, boolean onlyIfNeeded,
3054 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003055 Log.i(TAG, "Starting activity: " + intent);
3056
3057 HistoryRecord sourceRecord = null;
3058 HistoryRecord resultRecord = null;
3059 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003060 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003061 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003062 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3063 if (index >= 0) {
3064 sourceRecord = (HistoryRecord)mHistory.get(index);
3065 if (requestCode >= 0 && !sourceRecord.finishing) {
3066 resultRecord = sourceRecord;
3067 }
3068 }
3069 }
3070
3071 int launchFlags = intent.getFlags();
3072
3073 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3074 && sourceRecord != null) {
3075 // Transfer the result target from the source activity to the new
3076 // one being started, including any failures.
3077 if (requestCode >= 0) {
3078 return START_FORWARD_AND_REQUEST_CONFLICT;
3079 }
3080 resultRecord = sourceRecord.resultTo;
3081 resultWho = sourceRecord.resultWho;
3082 requestCode = sourceRecord.requestCode;
3083 sourceRecord.resultTo = null;
3084 if (resultRecord != null) {
3085 resultRecord.removeResultsLocked(
3086 sourceRecord, resultWho, requestCode);
3087 }
3088 }
3089
3090 int err = START_SUCCESS;
3091
3092 if (intent.getComponent() == null) {
3093 // We couldn't find a class that can handle the given Intent.
3094 // That's the end of that!
3095 err = START_INTENT_NOT_RESOLVED;
3096 }
3097
3098 if (err == START_SUCCESS && aInfo == null) {
3099 // We couldn't find the specific class specified in the Intent.
3100 // Also the end of the line.
3101 err = START_CLASS_NOT_FOUND;
3102 }
3103
3104 ProcessRecord callerApp = null;
3105 if (err == START_SUCCESS && caller != null) {
3106 callerApp = getRecordForAppLocked(caller);
3107 if (callerApp != null) {
3108 callingPid = callerApp.pid;
3109 callingUid = callerApp.info.uid;
3110 } else {
3111 Log.w(TAG, "Unable to find app for caller " + caller
3112 + " (pid=" + callingPid + ") when starting: "
3113 + intent.toString());
3114 err = START_PERMISSION_DENIED;
3115 }
3116 }
3117
3118 if (err != START_SUCCESS) {
3119 if (resultRecord != null) {
3120 sendActivityResultLocked(-1,
3121 resultRecord, resultWho, requestCode,
3122 Activity.RESULT_CANCELED, null);
3123 }
3124 return err;
3125 }
3126
3127 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3128 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3129 if (perm != PackageManager.PERMISSION_GRANTED) {
3130 if (resultRecord != null) {
3131 sendActivityResultLocked(-1,
3132 resultRecord, resultWho, requestCode,
3133 Activity.RESULT_CANCELED, null);
3134 }
3135 String msg = "Permission Denial: starting " + intent.toString()
3136 + " from " + callerApp + " (pid=" + callingPid
3137 + ", uid=" + callingUid + ")"
3138 + " requires " + aInfo.permission;
3139 Log.w(TAG, msg);
3140 throw new SecurityException(msg);
3141 }
3142
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003143 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003144 boolean abort = false;
3145 try {
3146 // The Intent we give to the watcher has the extra data
3147 // stripped off, since it can contain private information.
3148 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003149 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003150 aInfo.applicationInfo.packageName);
3151 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003152 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003153 }
3154
3155 if (abort) {
3156 if (resultRecord != null) {
3157 sendActivityResultLocked(-1,
3158 resultRecord, resultWho, requestCode,
3159 Activity.RESULT_CANCELED, null);
3160 }
3161 // We pretend to the caller that it was really started, but
3162 // they will just get a cancel result.
3163 return START_SUCCESS;
3164 }
3165 }
3166
3167 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3168 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003169 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003170
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003171 if (mResumedActivity == null
3172 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3173 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3174 PendingActivityLaunch pal = new PendingActivityLaunch();
3175 pal.r = r;
3176 pal.sourceRecord = sourceRecord;
3177 pal.grantedUriPermissions = grantedUriPermissions;
3178 pal.grantedMode = grantedMode;
3179 pal.onlyIfNeeded = onlyIfNeeded;
3180 mPendingActivityLaunches.add(pal);
3181 return START_SWITCHES_CANCELED;
3182 }
3183 }
3184
3185 if (mDidAppSwitch) {
3186 // This is the second allowed switch since we stopped switches,
3187 // so now just generally allow switches. Use case: user presses
3188 // home (switches disabled, switch to home, mDidAppSwitch now true);
3189 // user taps a home icon (coming from home so allowed, we hit here
3190 // and now allow anyone to switch again).
3191 mAppSwitchesAllowedTime = 0;
3192 } else {
3193 mDidAppSwitch = true;
3194 }
3195
3196 doPendingActivityLaunchesLocked(false);
3197
3198 return startActivityUncheckedLocked(r, sourceRecord,
3199 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3200 }
3201
3202 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3203 final int N = mPendingActivityLaunches.size();
3204 if (N <= 0) {
3205 return;
3206 }
3207 for (int i=0; i<N; i++) {
3208 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3209 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3210 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3211 doResume && i == (N-1));
3212 }
3213 mPendingActivityLaunches.clear();
3214 }
3215
3216 private final int startActivityUncheckedLocked(HistoryRecord r,
3217 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3218 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3219 final Intent intent = r.intent;
3220 final int callingUid = r.launchedFromUid;
3221
3222 int launchFlags = intent.getFlags();
3223
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003224 // We'll invoke onUserLeaving before onPause only if the launching
3225 // activity did not explicitly state that this is an automated launch.
3226 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3227 if (DEBUG_USER_LEAVING) Log.v(TAG,
3228 "startActivity() => mUserLeaving=" + mUserLeaving);
3229
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003230 // If the caller has asked not to resume at this point, we make note
3231 // of this in the record so that we can skip it when trying to find
3232 // the top running activity.
3233 if (!doResume) {
3234 r.delayedResume = true;
3235 }
3236
3237 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3238 != 0 ? r : null;
3239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003240 // If the onlyIfNeeded flag is set, then we can do this if the activity
3241 // being launched is the same as the one making the call... or, as
3242 // a special case, if we do not know the caller then we count the
3243 // current top activity as the caller.
3244 if (onlyIfNeeded) {
3245 HistoryRecord checkedCaller = sourceRecord;
3246 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003247 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003248 }
3249 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3250 // Caller is not the same as launcher, so always needed.
3251 onlyIfNeeded = false;
3252 }
3253 }
3254
3255 if (grantedUriPermissions != null && callingUid > 0) {
3256 for (int i=0; i<grantedUriPermissions.length; i++) {
3257 grantUriPermissionLocked(callingUid, r.packageName,
3258 grantedUriPermissions[i], grantedMode, r);
3259 }
3260 }
3261
3262 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3263 intent, r);
3264
3265 if (sourceRecord == null) {
3266 // This activity is not being started from another... in this
3267 // case we -always- start a new task.
3268 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3269 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3270 + intent);
3271 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3272 }
3273 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3274 // The original activity who is starting us is running as a single
3275 // instance... this new activity it is starting must go on its
3276 // own task.
3277 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3278 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3279 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3280 // The activity being started is a single instance... it always
3281 // gets launched into its own task.
3282 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3283 }
3284
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003285 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003286 // For whatever reason this activity is being launched into a new
3287 // task... yet the caller has requested a result back. Well, that
3288 // is pretty messed up, so instead immediately send back a cancel
3289 // and let the new task continue launched as normal without a
3290 // dependency on its originator.
3291 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3292 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003293 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003294 Activity.RESULT_CANCELED, null);
3295 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003296 }
3297
3298 boolean addingToTask = false;
3299 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3300 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3301 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3302 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3303 // If bring to front is requested, and no result is requested, and
3304 // we can find a task that was started with this same
3305 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003306 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003307 // See if there is a task to bring to the front. If this is
3308 // a SINGLE_INSTANCE activity, there can be one and only one
3309 // instance of it in the history, and it is always in its own
3310 // unique task, so we do a special search.
3311 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3312 ? findTaskLocked(intent, r.info)
3313 : findActivityLocked(intent, r.info);
3314 if (taskTop != null) {
3315 if (taskTop.task.intent == null) {
3316 // This task was started because of movement of
3317 // the activity based on affinity... now that we
3318 // are actually launching it, we can assign the
3319 // base intent.
3320 taskTop.task.setIntent(intent, r.info);
3321 }
3322 // If the target task is not in the front, then we need
3323 // to bring it to the front... except... well, with
3324 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3325 // to have the same behavior as if a new instance was
3326 // being started, which means not bringing it to the front
3327 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003328 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003329 if (curTop.task != taskTop.task) {
3330 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3331 boolean callerAtFront = sourceRecord == null
3332 || curTop.task == sourceRecord.task;
3333 if (callerAtFront) {
3334 // We really do want to push this one into the
3335 // user's face, right now.
3336 moveTaskToFrontLocked(taskTop.task);
3337 }
3338 }
3339 // If the caller has requested that the target task be
3340 // reset, then do so.
3341 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3342 taskTop = resetTaskIfNeededLocked(taskTop, r);
3343 }
3344 if (onlyIfNeeded) {
3345 // We don't need to start a new activity, and
3346 // the client said not to do anything if that
3347 // is the case, so this is it! And for paranoia, make
3348 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003349 if (doResume) {
3350 resumeTopActivityLocked(null);
3351 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003352 return START_RETURN_INTENT_TO_CALLER;
3353 }
3354 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3355 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3356 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3357 // In this situation we want to remove all activities
3358 // from the task up to the one being started. In most
3359 // cases this means we are resetting the task to its
3360 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003361 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003362 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003363 if (top != null) {
3364 if (top.frontOfTask) {
3365 // Activity aliases may mean we use different
3366 // intents for the top activity, so make sure
3367 // the task now has the identity of the new
3368 // intent.
3369 top.task.setIntent(r.intent, r.info);
3370 }
3371 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3372 deliverNewIntentLocked(top, r.intent);
3373 } else {
3374 // A special case: we need to
3375 // start the activity because it is not currently
3376 // running, and the caller has asked to clear the
3377 // current task to have this activity at the top.
3378 addingToTask = true;
3379 // Now pretend like this activity is being started
3380 // by the top of its task, so it is put in the
3381 // right place.
3382 sourceRecord = taskTop;
3383 }
3384 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3385 // In this case the top activity on the task is the
3386 // same as the one being launched, so we take that
3387 // as a request to bring the task to the foreground.
3388 // If the top activity in the task is the root
3389 // activity, deliver this new intent to it if it
3390 // desires.
3391 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3392 && taskTop.realActivity.equals(r.realActivity)) {
3393 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3394 if (taskTop.frontOfTask) {
3395 taskTop.task.setIntent(r.intent, r.info);
3396 }
3397 deliverNewIntentLocked(taskTop, r.intent);
3398 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3399 // In this case we are launching the root activity
3400 // of the task, but with a different intent. We
3401 // should start a new instance on top.
3402 addingToTask = true;
3403 sourceRecord = taskTop;
3404 }
3405 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3406 // In this case an activity is being launched in to an
3407 // existing task, without resetting that task. This
3408 // is typically the situation of launching an activity
3409 // from a notification or shortcut. We want to place
3410 // the new activity on top of the current task.
3411 addingToTask = true;
3412 sourceRecord = taskTop;
3413 } else if (!taskTop.task.rootWasReset) {
3414 // In this case we are launching in to an existing task
3415 // that has not yet been started from its front door.
3416 // The current task has been brought to the front.
3417 // Ideally, we'd probably like to place this new task
3418 // at the bottom of its stack, but that's a little hard
3419 // to do with the current organization of the code so
3420 // for now we'll just drop it.
3421 taskTop.task.setIntent(r.intent, r.info);
3422 }
3423 if (!addingToTask) {
3424 // We didn't do anything... but it was needed (a.k.a., client
3425 // don't use that intent!) And for paranoia, make
3426 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003427 if (doResume) {
3428 resumeTopActivityLocked(null);
3429 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003430 return START_TASK_TO_FRONT;
3431 }
3432 }
3433 }
3434 }
3435
3436 //String uri = r.intent.toURI();
3437 //Intent intent2 = new Intent(uri);
3438 //Log.i(TAG, "Given intent: " + r.intent);
3439 //Log.i(TAG, "URI is: " + uri);
3440 //Log.i(TAG, "To intent: " + intent2);
3441
3442 if (r.packageName != null) {
3443 // If the activity being launched is the same as the one currently
3444 // at the top, then we need to check if it should only be launched
3445 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003446 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3447 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003448 if (top.realActivity.equals(r.realActivity)) {
3449 if (top.app != null && top.app.thread != null) {
3450 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3451 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3452 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3453 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3454 // For paranoia, make sure we have correctly
3455 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003456 if (doResume) {
3457 resumeTopActivityLocked(null);
3458 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003459 if (onlyIfNeeded) {
3460 // We don't need to start a new activity, and
3461 // the client said not to do anything if that
3462 // is the case, so this is it!
3463 return START_RETURN_INTENT_TO_CALLER;
3464 }
3465 deliverNewIntentLocked(top, r.intent);
3466 return START_DELIVERED_TO_TOP;
3467 }
3468 }
3469 }
3470 }
3471
3472 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003473 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003474 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003475 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003476 Activity.RESULT_CANCELED, null);
3477 }
3478 return START_CLASS_NOT_FOUND;
3479 }
3480
3481 boolean newTask = false;
3482
3483 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003484 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003485 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3486 // todo: should do better management of integers.
3487 mCurTask++;
3488 if (mCurTask <= 0) {
3489 mCurTask = 1;
3490 }
3491 r.task = new TaskRecord(mCurTask, r.info, intent,
3492 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3493 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3494 + " in new task " + r.task);
3495 newTask = true;
3496 addRecentTask(r.task);
3497
3498 } else if (sourceRecord != null) {
3499 if (!addingToTask &&
3500 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3501 // In this case, we are adding the activity to an existing
3502 // task, but the caller has asked to clear that task if the
3503 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003504 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003505 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003506 if (top != null) {
3507 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3508 deliverNewIntentLocked(top, r.intent);
3509 // For paranoia, make sure we have correctly
3510 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003511 if (doResume) {
3512 resumeTopActivityLocked(null);
3513 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003514 return START_DELIVERED_TO_TOP;
3515 }
3516 } else if (!addingToTask &&
3517 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3518 // In this case, we are launching an activity in our own task
3519 // that may already be running somewhere in the history, and
3520 // we want to shuffle it to the front of the stack if so.
3521 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3522 if (where >= 0) {
3523 HistoryRecord top = moveActivityToFrontLocked(where);
3524 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3525 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003526 if (doResume) {
3527 resumeTopActivityLocked(null);
3528 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003529 return START_DELIVERED_TO_TOP;
3530 }
3531 }
3532 // An existing activity is starting this new activity, so we want
3533 // to keep the new one in the same task as the one that is starting
3534 // it.
3535 r.task = sourceRecord.task;
3536 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3537 + " in existing task " + r.task);
3538
3539 } else {
3540 // This not being started from an existing activity, and not part
3541 // of a new task... just put it in the top task, though these days
3542 // this case should never happen.
3543 final int N = mHistory.size();
3544 HistoryRecord prev =
3545 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3546 r.task = prev != null
3547 ? prev.task
3548 : new TaskRecord(mCurTask, r.info, intent,
3549 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3550 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3551 + " in new guessed " + r.task);
3552 }
3553 if (newTask) {
3554 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3555 }
3556 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003557 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003558 return START_SUCCESS;
3559 }
3560
3561 public final int startActivity(IApplicationThread caller,
3562 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3563 int grantedMode, IBinder resultTo,
3564 String resultWho, int requestCode, boolean onlyIfNeeded,
3565 boolean debug) {
3566 // Refuse possible leaked file descriptors
3567 if (intent != null && intent.hasFileDescriptors()) {
3568 throw new IllegalArgumentException("File descriptors passed in Intent");
3569 }
3570
The Android Open Source Project4df24232009-03-05 14:34:35 -08003571 final boolean componentSpecified = intent.getComponent() != null;
3572
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003573 // Don't modify the client's object!
3574 intent = new Intent(intent);
3575
3576 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003577 ActivityInfo aInfo;
3578 try {
3579 ResolveInfo rInfo =
3580 ActivityThread.getPackageManager().resolveIntent(
3581 intent, resolvedType,
3582 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003583 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003584 aInfo = rInfo != null ? rInfo.activityInfo : null;
3585 } catch (RemoteException e) {
3586 aInfo = null;
3587 }
3588
3589 if (aInfo != null) {
3590 // Store the found target back into the intent, because now that
3591 // we have it we never want to do this again. For example, if the
3592 // user navigates back to this point in the history, we should
3593 // always restart the exact same activity.
3594 intent.setComponent(new ComponentName(
3595 aInfo.applicationInfo.packageName, aInfo.name));
3596
3597 // Don't debug things in the system process
3598 if (debug) {
3599 if (!aInfo.processName.equals("system")) {
3600 setDebugApp(aInfo.processName, true, false);
3601 }
3602 }
3603 }
3604
3605 synchronized(this) {
3606 final long origId = Binder.clearCallingIdentity();
3607 int res = startActivityLocked(caller, intent, resolvedType,
3608 grantedUriPermissions, grantedMode, aInfo,
3609 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003610 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003611 Binder.restoreCallingIdentity(origId);
3612 return res;
3613 }
3614 }
3615
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003616 public int startActivityIntentSender(IApplicationThread caller,
3617 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003618 IBinder resultTo, String resultWho, int requestCode,
3619 int flagsMask, int flagsValues) {
3620 // Refuse possible leaked file descriptors
3621 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3622 throw new IllegalArgumentException("File descriptors passed in Intent");
3623 }
3624
3625 IIntentSender sender = intent.getTarget();
3626 if (!(sender instanceof PendingIntentRecord)) {
3627 throw new IllegalArgumentException("Bad PendingIntent object");
3628 }
3629
3630 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003631
3632 synchronized (this) {
3633 // If this is coming from the currently resumed activity, it is
3634 // effectively saying that app switches are allowed at this point.
3635 if (mResumedActivity != null
3636 && mResumedActivity.info.applicationInfo.uid ==
3637 Binder.getCallingUid()) {
3638 mAppSwitchesAllowedTime = 0;
3639 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003640 }
3641
3642 return pir.sendInner(0, fillInIntent, resolvedType,
3643 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3644 }
3645
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003646 public boolean startNextMatchingActivity(IBinder callingActivity,
3647 Intent intent) {
3648 // Refuse possible leaked file descriptors
3649 if (intent != null && intent.hasFileDescriptors() == true) {
3650 throw new IllegalArgumentException("File descriptors passed in Intent");
3651 }
3652
3653 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003654 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003655 if (index < 0) {
3656 return false;
3657 }
3658 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3659 if (r.app == null || r.app.thread == null) {
3660 // The caller is not running... d'oh!
3661 return false;
3662 }
3663 intent = new Intent(intent);
3664 // The caller is not allowed to change the data.
3665 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3666 // And we are resetting to find the next component...
3667 intent.setComponent(null);
3668
3669 ActivityInfo aInfo = null;
3670 try {
3671 List<ResolveInfo> resolves =
3672 ActivityThread.getPackageManager().queryIntentActivities(
3673 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003674 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003675
3676 // Look for the original activity in the list...
3677 final int N = resolves != null ? resolves.size() : 0;
3678 for (int i=0; i<N; i++) {
3679 ResolveInfo rInfo = resolves.get(i);
3680 if (rInfo.activityInfo.packageName.equals(r.packageName)
3681 && rInfo.activityInfo.name.equals(r.info.name)) {
3682 // We found the current one... the next matching is
3683 // after it.
3684 i++;
3685 if (i<N) {
3686 aInfo = resolves.get(i).activityInfo;
3687 }
3688 break;
3689 }
3690 }
3691 } catch (RemoteException e) {
3692 }
3693
3694 if (aInfo == null) {
3695 // Nobody who is next!
3696 return false;
3697 }
3698
3699 intent.setComponent(new ComponentName(
3700 aInfo.applicationInfo.packageName, aInfo.name));
3701 intent.setFlags(intent.getFlags()&~(
3702 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3703 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3704 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3705 Intent.FLAG_ACTIVITY_NEW_TASK));
3706
3707 // Okay now we need to start the new activity, replacing the
3708 // currently running activity. This is a little tricky because
3709 // we want to start the new one as if the current one is finished,
3710 // but not finish the current one first so that there is no flicker.
3711 // And thus...
3712 final boolean wasFinishing = r.finishing;
3713 r.finishing = true;
3714
3715 // Propagate reply information over to the new activity.
3716 final HistoryRecord resultTo = r.resultTo;
3717 final String resultWho = r.resultWho;
3718 final int requestCode = r.requestCode;
3719 r.resultTo = null;
3720 if (resultTo != null) {
3721 resultTo.removeResultsLocked(r, resultWho, requestCode);
3722 }
3723
3724 final long origId = Binder.clearCallingIdentity();
3725 // XXX we are not dealing with propagating grantedUriPermissions...
3726 // those are not yet exposed to user code, so there is no need.
3727 int res = startActivityLocked(r.app.thread, intent,
3728 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003729 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003730 Binder.restoreCallingIdentity(origId);
3731
3732 r.finishing = wasFinishing;
3733 if (res != START_SUCCESS) {
3734 return false;
3735 }
3736 return true;
3737 }
3738 }
3739
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003740 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003741 Intent intent, String resolvedType, IBinder resultTo,
3742 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003743
3744 // This is so super not safe, that only the system (or okay root)
3745 // can do it.
3746 final int callingUid = Binder.getCallingUid();
3747 if (callingUid != 0 && callingUid != Process.myUid()) {
3748 throw new SecurityException(
3749 "startActivityInPackage only available to the system");
3750 }
3751
The Android Open Source Project4df24232009-03-05 14:34:35 -08003752 final boolean componentSpecified = intent.getComponent() != null;
3753
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003754 // Don't modify the client's object!
3755 intent = new Intent(intent);
3756
3757 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003758 ActivityInfo aInfo;
3759 try {
3760 ResolveInfo rInfo =
3761 ActivityThread.getPackageManager().resolveIntent(
3762 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003763 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003764 aInfo = rInfo != null ? rInfo.activityInfo : null;
3765 } catch (RemoteException e) {
3766 aInfo = null;
3767 }
3768
3769 if (aInfo != null) {
3770 // Store the found target back into the intent, because now that
3771 // we have it we never want to do this again. For example, if the
3772 // user navigates back to this point in the history, we should
3773 // always restart the exact same activity.
3774 intent.setComponent(new ComponentName(
3775 aInfo.applicationInfo.packageName, aInfo.name));
3776 }
3777
3778 synchronized(this) {
3779 return startActivityLocked(null, intent, resolvedType,
3780 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003781 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003782 }
3783 }
3784
3785 private final void addRecentTask(TaskRecord task) {
3786 // Remove any existing entries that are the same kind of task.
3787 int N = mRecentTasks.size();
3788 for (int i=0; i<N; i++) {
3789 TaskRecord tr = mRecentTasks.get(i);
3790 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3791 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3792 mRecentTasks.remove(i);
3793 i--;
3794 N--;
3795 if (task.intent == null) {
3796 // If the new recent task we are adding is not fully
3797 // specified, then replace it with the existing recent task.
3798 task = tr;
3799 }
3800 }
3801 }
3802 if (N >= MAX_RECENT_TASKS) {
3803 mRecentTasks.remove(N-1);
3804 }
3805 mRecentTasks.add(0, task);
3806 }
3807
3808 public void setRequestedOrientation(IBinder token,
3809 int requestedOrientation) {
3810 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003811 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003812 if (index < 0) {
3813 return;
3814 }
3815 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3816 final long origId = Binder.clearCallingIdentity();
3817 mWindowManager.setAppOrientation(r, requestedOrientation);
3818 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003819 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003820 r.mayFreezeScreenLocked(r.app) ? r : null);
3821 if (config != null) {
3822 r.frozenBeforeDestroy = true;
3823 if (!updateConfigurationLocked(config, r)) {
3824 resumeTopActivityLocked(null);
3825 }
3826 }
3827 Binder.restoreCallingIdentity(origId);
3828 }
3829 }
3830
3831 public int getRequestedOrientation(IBinder token) {
3832 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003833 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003834 if (index < 0) {
3835 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3836 }
3837 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3838 return mWindowManager.getAppOrientation(r);
3839 }
3840 }
3841
3842 private final void stopActivityLocked(HistoryRecord r) {
3843 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3844 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3845 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3846 if (!r.finishing) {
3847 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3848 "no-history");
3849 }
3850 } else if (r.app != null && r.app.thread != null) {
3851 if (mFocusedActivity == r) {
3852 setFocusedActivityLocked(topRunningActivityLocked(null));
3853 }
3854 r.resumeKeyDispatchingLocked();
3855 try {
3856 r.stopped = false;
3857 r.state = ActivityState.STOPPING;
3858 if (DEBUG_VISBILITY) Log.v(
3859 TAG, "Stopping visible=" + r.visible + " for " + r);
3860 if (!r.visible) {
3861 mWindowManager.setAppVisibility(r, false);
3862 }
3863 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3864 } catch (Exception e) {
3865 // Maybe just ignore exceptions here... if the process
3866 // has crashed, our death notification will clean things
3867 // up.
3868 Log.w(TAG, "Exception thrown during pause", e);
3869 // Just in case, assume it to be stopped.
3870 r.stopped = true;
3871 r.state = ActivityState.STOPPED;
3872 if (r.configDestroy) {
3873 destroyActivityLocked(r, true);
3874 }
3875 }
3876 }
3877 }
3878
3879 /**
3880 * @return Returns true if the activity is being finished, false if for
3881 * some reason it is being left as-is.
3882 */
3883 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3884 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003885 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003886 TAG, "Finishing activity: token=" + token
3887 + ", result=" + resultCode + ", data=" + resultData);
3888
Dianne Hackborn75b03852009-06-12 15:43:26 -07003889 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003890 if (index < 0) {
3891 return false;
3892 }
3893 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3894
3895 // Is this the last activity left?
3896 boolean lastActivity = true;
3897 for (int i=mHistory.size()-1; i>=0; i--) {
3898 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3899 if (!p.finishing && p != r) {
3900 lastActivity = false;
3901 break;
3902 }
3903 }
3904
3905 // If this is the last activity, but it is the home activity, then
3906 // just don't finish it.
3907 if (lastActivity) {
3908 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3909 return false;
3910 }
3911 }
3912
3913 finishActivityLocked(r, index, resultCode, resultData, reason);
3914 return true;
3915 }
3916
3917 /**
3918 * @return Returns true if this activity has been removed from the history
3919 * list, or false if it is still in the list and will be removed later.
3920 */
3921 private final boolean finishActivityLocked(HistoryRecord r, int index,
3922 int resultCode, Intent resultData, String reason) {
3923 if (r.finishing) {
3924 Log.w(TAG, "Duplicate finish request for " + r);
3925 return false;
3926 }
3927
3928 r.finishing = true;
3929 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3930 System.identityHashCode(r),
3931 r.task.taskId, r.shortComponentName, reason);
3932 r.task.numActivities--;
3933 if (r.frontOfTask && index < (mHistory.size()-1)) {
3934 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3935 if (next.task == r.task) {
3936 next.frontOfTask = true;
3937 }
3938 }
3939
3940 r.pauseKeyDispatchingLocked();
3941 if (mFocusedActivity == r) {
3942 setFocusedActivityLocked(topRunningActivityLocked(null));
3943 }
3944
3945 // send the result
3946 HistoryRecord resultTo = r.resultTo;
3947 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003948 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3949 + " who=" + r.resultWho + " req=" + r.requestCode
3950 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003951 if (r.info.applicationInfo.uid > 0) {
3952 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3953 r.packageName, resultData, r);
3954 }
3955 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3956 resultData);
3957 r.resultTo = null;
3958 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003959 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003960
3961 // Make sure this HistoryRecord is not holding on to other resources,
3962 // because clients have remote IPC references to this object so we
3963 // can't assume that will go away and want to avoid circular IPC refs.
3964 r.results = null;
3965 r.pendingResults = null;
3966 r.newIntents = null;
3967 r.icicle = null;
3968
3969 if (mPendingThumbnails.size() > 0) {
3970 // There are clients waiting to receive thumbnails so, in case
3971 // this is an activity that someone is waiting for, add it
3972 // to the pending list so we can correctly update the clients.
3973 mCancelledThumbnails.add(r);
3974 }
3975
3976 if (mResumedActivity == r) {
3977 boolean endTask = index <= 0
3978 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3979 if (DEBUG_TRANSITION) Log.v(TAG,
3980 "Prepare close transition: finishing " + r);
3981 mWindowManager.prepareAppTransition(endTask
3982 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3983 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3984
3985 // Tell window manager to prepare for this one to be removed.
3986 mWindowManager.setAppVisibility(r, false);
3987
3988 if (mPausingActivity == null) {
3989 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3990 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3991 startPausingLocked(false, false);
3992 }
3993
3994 } else if (r.state != ActivityState.PAUSING) {
3995 // If the activity is PAUSING, we will complete the finish once
3996 // it is done pausing; else we can just directly finish it here.
3997 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3998 return finishCurrentActivityLocked(r, index,
3999 FINISH_AFTER_PAUSE) == null;
4000 } else {
4001 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4002 }
4003
4004 return false;
4005 }
4006
4007 private static final int FINISH_IMMEDIATELY = 0;
4008 private static final int FINISH_AFTER_PAUSE = 1;
4009 private static final int FINISH_AFTER_VISIBLE = 2;
4010
4011 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4012 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004013 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004014 if (index < 0) {
4015 return null;
4016 }
4017
4018 return finishCurrentActivityLocked(r, index, mode);
4019 }
4020
4021 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4022 int index, int mode) {
4023 // First things first: if this activity is currently visible,
4024 // and the resumed activity is not yet visible, then hold off on
4025 // finishing until the resumed one becomes visible.
4026 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4027 if (!mStoppingActivities.contains(r)) {
4028 mStoppingActivities.add(r);
4029 if (mStoppingActivities.size() > 3) {
4030 // If we already have a few activities waiting to stop,
4031 // then give up on things going idle and start clearing
4032 // them out.
4033 Message msg = Message.obtain();
4034 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4035 mHandler.sendMessage(msg);
4036 }
4037 }
4038 r.state = ActivityState.STOPPING;
4039 updateOomAdjLocked();
4040 return r;
4041 }
4042
4043 // make sure the record is cleaned out of other places.
4044 mStoppingActivities.remove(r);
4045 mWaitingVisibleActivities.remove(r);
4046 if (mResumedActivity == r) {
4047 mResumedActivity = null;
4048 }
4049 final ActivityState prevState = r.state;
4050 r.state = ActivityState.FINISHING;
4051
4052 if (mode == FINISH_IMMEDIATELY
4053 || prevState == ActivityState.STOPPED
4054 || prevState == ActivityState.INITIALIZING) {
4055 // If this activity is already stopped, we can just finish
4056 // it right now.
4057 return destroyActivityLocked(r, true) ? null : r;
4058 } else {
4059 // Need to go through the full pause cycle to get this
4060 // activity into the stopped state and then finish it.
4061 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4062 mFinishingActivities.add(r);
4063 resumeTopActivityLocked(null);
4064 }
4065 return r;
4066 }
4067
4068 /**
4069 * This is the internal entry point for handling Activity.finish().
4070 *
4071 * @param token The Binder token referencing the Activity we want to finish.
4072 * @param resultCode Result code, if any, from this Activity.
4073 * @param resultData Result data (Intent), if any, from this Activity.
4074 *
4075 * @result Returns true if the activity successfully finished, or false if it is still running.
4076 */
4077 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4078 // Refuse possible leaked file descriptors
4079 if (resultData != null && resultData.hasFileDescriptors() == true) {
4080 throw new IllegalArgumentException("File descriptors passed in Intent");
4081 }
4082
4083 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004084 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004085 // Find the first activity that is not finishing.
4086 HistoryRecord next = topRunningActivityLocked(token, 0);
4087 if (next != null) {
4088 // ask watcher if this is allowed
4089 boolean resumeOK = true;
4090 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004091 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004092 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004093 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004094 }
4095
4096 if (!resumeOK) {
4097 return false;
4098 }
4099 }
4100 }
4101 final long origId = Binder.clearCallingIdentity();
4102 boolean res = requestFinishActivityLocked(token, resultCode,
4103 resultData, "app-request");
4104 Binder.restoreCallingIdentity(origId);
4105 return res;
4106 }
4107 }
4108
4109 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4110 String resultWho, int requestCode, int resultCode, Intent data) {
4111
4112 if (callingUid > 0) {
4113 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4114 data, r);
4115 }
4116
The Android Open Source Project10592532009-03-18 17:39:46 -07004117 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4118 + " : who=" + resultWho + " req=" + requestCode
4119 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004120 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4121 try {
4122 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4123 list.add(new ResultInfo(resultWho, requestCode,
4124 resultCode, data));
4125 r.app.thread.scheduleSendResult(r, list);
4126 return;
4127 } catch (Exception e) {
4128 Log.w(TAG, "Exception thrown sending result to " + r, e);
4129 }
4130 }
4131
4132 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4133 }
4134
4135 public final void finishSubActivity(IBinder token, String resultWho,
4136 int requestCode) {
4137 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004138 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004139 if (index < 0) {
4140 return;
4141 }
4142 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4143
4144 final long origId = Binder.clearCallingIdentity();
4145
4146 int i;
4147 for (i=mHistory.size()-1; i>=0; i--) {
4148 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4149 if (r.resultTo == self && r.requestCode == requestCode) {
4150 if ((r.resultWho == null && resultWho == null) ||
4151 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4152 finishActivityLocked(r, i,
4153 Activity.RESULT_CANCELED, null, "request-sub");
4154 }
4155 }
4156 }
4157
4158 Binder.restoreCallingIdentity(origId);
4159 }
4160 }
4161
4162 /**
4163 * Perform clean-up of service connections in an activity record.
4164 */
4165 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4166 // Throw away any services that have been bound by this activity.
4167 if (r.connections != null) {
4168 Iterator<ConnectionRecord> it = r.connections.iterator();
4169 while (it.hasNext()) {
4170 ConnectionRecord c = it.next();
4171 removeConnectionLocked(c, null, r);
4172 }
4173 r.connections = null;
4174 }
4175 }
4176
4177 /**
4178 * Perform the common clean-up of an activity record. This is called both
4179 * as part of destroyActivityLocked() (when destroying the client-side
4180 * representation) and cleaning things up as a result of its hosting
4181 * processing going away, in which case there is no remaining client-side
4182 * state to destroy so only the cleanup here is needed.
4183 */
4184 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4185 if (mResumedActivity == r) {
4186 mResumedActivity = null;
4187 }
4188 if (mFocusedActivity == r) {
4189 mFocusedActivity = null;
4190 }
4191
4192 r.configDestroy = false;
4193 r.frozenBeforeDestroy = false;
4194
4195 // Make sure this record is no longer in the pending finishes list.
4196 // This could happen, for example, if we are trimming activities
4197 // down to the max limit while they are still waiting to finish.
4198 mFinishingActivities.remove(r);
4199 mWaitingVisibleActivities.remove(r);
4200
4201 // Remove any pending results.
4202 if (r.finishing && r.pendingResults != null) {
4203 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4204 PendingIntentRecord rec = apr.get();
4205 if (rec != null) {
4206 cancelIntentSenderLocked(rec, false);
4207 }
4208 }
4209 r.pendingResults = null;
4210 }
4211
4212 if (cleanServices) {
4213 cleanUpActivityServicesLocked(r);
4214 }
4215
4216 if (mPendingThumbnails.size() > 0) {
4217 // There are clients waiting to receive thumbnails so, in case
4218 // this is an activity that someone is waiting for, add it
4219 // to the pending list so we can correctly update the clients.
4220 mCancelledThumbnails.add(r);
4221 }
4222
4223 // Get rid of any pending idle timeouts.
4224 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4225 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4226 }
4227
4228 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4229 if (r.state != ActivityState.DESTROYED) {
4230 mHistory.remove(r);
4231 r.inHistory = false;
4232 r.state = ActivityState.DESTROYED;
4233 mWindowManager.removeAppToken(r);
4234 if (VALIDATE_TOKENS) {
4235 mWindowManager.validateAppTokens(mHistory);
4236 }
4237 cleanUpActivityServicesLocked(r);
4238 removeActivityUriPermissionsLocked(r);
4239 }
4240 }
4241
4242 /**
4243 * Destroy the current CLIENT SIDE instance of an activity. This may be
4244 * called both when actually finishing an activity, or when performing
4245 * a configuration switch where we destroy the current client-side object
4246 * but then create a new client-side object for this same HistoryRecord.
4247 */
4248 private final boolean destroyActivityLocked(HistoryRecord r,
4249 boolean removeFromApp) {
4250 if (DEBUG_SWITCH) Log.v(
4251 TAG, "Removing activity: token=" + r
4252 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4253 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4254 System.identityHashCode(r),
4255 r.task.taskId, r.shortComponentName);
4256
4257 boolean removedFromHistory = false;
4258
4259 cleanUpActivityLocked(r, false);
4260
4261 if (r.app != null) {
4262 if (removeFromApp) {
4263 int idx = r.app.activities.indexOf(r);
4264 if (idx >= 0) {
4265 r.app.activities.remove(idx);
4266 }
4267 if (r.persistent) {
4268 decPersistentCountLocked(r.app);
4269 }
4270 }
4271
4272 boolean skipDestroy = false;
4273
4274 try {
4275 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4276 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4277 r.configChangeFlags);
4278 } catch (Exception e) {
4279 // We can just ignore exceptions here... if the process
4280 // has crashed, our death notification will clean things
4281 // up.
4282 //Log.w(TAG, "Exception thrown during finish", e);
4283 if (r.finishing) {
4284 removeActivityFromHistoryLocked(r);
4285 removedFromHistory = true;
4286 skipDestroy = true;
4287 }
4288 }
4289
4290 r.app = null;
4291 r.nowVisible = false;
4292
4293 if (r.finishing && !skipDestroy) {
4294 r.state = ActivityState.DESTROYING;
4295 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4296 msg.obj = r;
4297 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4298 } else {
4299 r.state = ActivityState.DESTROYED;
4300 }
4301 } else {
4302 // remove this record from the history.
4303 if (r.finishing) {
4304 removeActivityFromHistoryLocked(r);
4305 removedFromHistory = true;
4306 } else {
4307 r.state = ActivityState.DESTROYED;
4308 }
4309 }
4310
4311 r.configChangeFlags = 0;
4312
4313 if (!mLRUActivities.remove(r)) {
4314 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4315 }
4316
4317 return removedFromHistory;
4318 }
4319
4320 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4321 ProcessRecord app)
4322 {
4323 int i = list.size();
4324 if (localLOGV) Log.v(
4325 TAG, "Removing app " + app + " from list " + list
4326 + " with " + i + " entries");
4327 while (i > 0) {
4328 i--;
4329 HistoryRecord r = (HistoryRecord)list.get(i);
4330 if (localLOGV) Log.v(
4331 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4332 if (r.app == app) {
4333 if (localLOGV) Log.v(TAG, "Removing this entry!");
4334 list.remove(i);
4335 }
4336 }
4337 }
4338
4339 /**
4340 * Main function for removing an existing process from the activity manager
4341 * as a result of that process going away. Clears out all connections
4342 * to the process.
4343 */
4344 private final void handleAppDiedLocked(ProcessRecord app,
4345 boolean restarting) {
4346 cleanUpApplicationRecordLocked(app, restarting, -1);
4347 if (!restarting) {
4348 mLRUProcesses.remove(app);
4349 }
4350
4351 // Just in case...
4352 if (mPausingActivity != null && mPausingActivity.app == app) {
4353 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4354 mPausingActivity = null;
4355 }
4356 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4357 mLastPausedActivity = null;
4358 }
4359
4360 // Remove this application's activities from active lists.
4361 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4362 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4363 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4364 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4365
4366 boolean atTop = true;
4367 boolean hasVisibleActivities = false;
4368
4369 // Clean out the history list.
4370 int i = mHistory.size();
4371 if (localLOGV) Log.v(
4372 TAG, "Removing app " + app + " from history with " + i + " entries");
4373 while (i > 0) {
4374 i--;
4375 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4376 if (localLOGV) Log.v(
4377 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4378 if (r.app == app) {
4379 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4380 if (localLOGV) Log.v(
4381 TAG, "Removing this entry! frozen=" + r.haveState
4382 + " finishing=" + r.finishing);
4383 mHistory.remove(i);
4384
4385 r.inHistory = false;
4386 mWindowManager.removeAppToken(r);
4387 if (VALIDATE_TOKENS) {
4388 mWindowManager.validateAppTokens(mHistory);
4389 }
4390 removeActivityUriPermissionsLocked(r);
4391
4392 } else {
4393 // We have the current state for this activity, so
4394 // it can be restarted later when needed.
4395 if (localLOGV) Log.v(
4396 TAG, "Keeping entry, setting app to null");
4397 if (r.visible) {
4398 hasVisibleActivities = true;
4399 }
4400 r.app = null;
4401 r.nowVisible = false;
4402 if (!r.haveState) {
4403 r.icicle = null;
4404 }
4405 }
4406
4407 cleanUpActivityLocked(r, true);
4408 r.state = ActivityState.STOPPED;
4409 }
4410 atTop = false;
4411 }
4412
4413 app.activities.clear();
4414
4415 if (app.instrumentationClass != null) {
4416 Log.w(TAG, "Crash of app " + app.processName
4417 + " running instrumentation " + app.instrumentationClass);
4418 Bundle info = new Bundle();
4419 info.putString("shortMsg", "Process crashed.");
4420 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4421 }
4422
4423 if (!restarting) {
4424 if (!resumeTopActivityLocked(null)) {
4425 // If there was nothing to resume, and we are not already
4426 // restarting this process, but there is a visible activity that
4427 // is hosted by the process... then make sure all visible
4428 // activities are running, taking care of restarting this
4429 // process.
4430 if (hasVisibleActivities) {
4431 ensureActivitiesVisibleLocked(null, 0);
4432 }
4433 }
4434 }
4435 }
4436
4437 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4438 IBinder threadBinder = thread.asBinder();
4439
4440 // Find the application record.
4441 int count = mLRUProcesses.size();
4442 int i;
4443 for (i=0; i<count; i++) {
4444 ProcessRecord rec = mLRUProcesses.get(i);
4445 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4446 return i;
4447 }
4448 }
4449 return -1;
4450 }
4451
4452 private final ProcessRecord getRecordForAppLocked(
4453 IApplicationThread thread) {
4454 if (thread == null) {
4455 return null;
4456 }
4457
4458 int appIndex = getLRURecordIndexForAppLocked(thread);
4459 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4460 }
4461
4462 private final void appDiedLocked(ProcessRecord app, int pid,
4463 IApplicationThread thread) {
4464
4465 mProcDeaths[0]++;
4466
4467 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4468 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4469 + ") has died.");
4470 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4471 if (localLOGV) Log.v(
4472 TAG, "Dying app: " + app + ", pid: " + pid
4473 + ", thread: " + thread.asBinder());
4474 boolean doLowMem = app.instrumentationClass == null;
4475 handleAppDiedLocked(app, false);
4476
4477 if (doLowMem) {
4478 // If there are no longer any background processes running,
4479 // and the app that died was not running instrumentation,
4480 // then tell everyone we are now low on memory.
4481 boolean haveBg = false;
4482 int count = mLRUProcesses.size();
4483 int i;
4484 for (i=0; i<count; i++) {
4485 ProcessRecord rec = mLRUProcesses.get(i);
4486 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4487 haveBg = true;
4488 break;
4489 }
4490 }
4491
4492 if (!haveBg) {
4493 Log.i(TAG, "Low Memory: No more background processes.");
4494 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004495 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004496 for (i=0; i<count; i++) {
4497 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004498 if (rec.thread != null &&
4499 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4500 // The low memory report is overriding any current
4501 // state for a GC request. Make sure to do
4502 // visible/foreground processes first.
4503 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4504 rec.lastRequestedGc = 0;
4505 } else {
4506 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004507 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004508 rec.reportLowMemory = true;
4509 rec.lastLowMemory = now;
4510 mProcessesToGc.remove(rec);
4511 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004512 }
4513 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004514 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004515 }
4516 }
4517 } else if (Config.LOGD) {
4518 Log.d(TAG, "Received spurious death notification for thread "
4519 + thread.asBinder());
4520 }
4521 }
4522
4523 final String readFile(String filename) {
4524 try {
4525 FileInputStream fs = new FileInputStream(filename);
4526 byte[] inp = new byte[8192];
4527 int size = fs.read(inp);
4528 fs.close();
4529 return new String(inp, 0, 0, size);
4530 } catch (java.io.IOException e) {
4531 }
4532 return "";
4533 }
4534
4535 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004536 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004537 if (app.notResponding || app.crashing) {
4538 return;
4539 }
4540
4541 // Log the ANR to the event log.
4542 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4543
4544 // If we are on a secure build and the application is not interesting to the user (it is
4545 // not visible or in the background), just kill it instead of displaying a dialog.
4546 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4547 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4548 Process.killProcess(app.pid);
4549 return;
4550 }
4551
4552 // DeviceMonitor.start();
4553
4554 String processInfo = null;
4555 if (MONITOR_CPU_USAGE) {
4556 updateCpuStatsNow();
4557 synchronized (mProcessStatsThread) {
4558 processInfo = mProcessStats.printCurrentState();
4559 }
4560 }
4561
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004562 StringBuilder info = mStringBuilder;
4563 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004564 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004565 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004566 if (reportedActivity != null && reportedActivity.app != null) {
4567 info.append(" (last in ");
4568 info.append(reportedActivity.app.processName);
4569 info.append(")");
4570 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004571 if (annotation != null) {
4572 info.append("\nAnnotation: ");
4573 info.append(annotation);
4574 }
4575 if (MONITOR_CPU_USAGE) {
4576 info.append("\nCPU usage:\n");
4577 info.append(processInfo);
4578 }
4579 Log.i(TAG, info.toString());
4580
4581 // The application is not responding. Dump as many thread traces as we can.
4582 boolean fileDump = prepareTraceFile(true);
4583 if (!fileDump) {
4584 // Dumping traces to the log, just dump the process that isn't responding so
4585 // we don't overflow the log
4586 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4587 } else {
4588 // Dumping traces to a file so dump all active processes we know about
4589 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004590 // First, these are the most important processes.
4591 final int[] imppids = new int[3];
4592 int i=0;
4593 imppids[0] = app.pid;
4594 i++;
4595 if (reportedActivity != null && reportedActivity.app != null
4596 && reportedActivity.app.thread != null
4597 && reportedActivity.app.pid != app.pid) {
4598 imppids[i] = reportedActivity.app.pid;
4599 i++;
4600 }
4601 imppids[i] = Process.myPid();
4602 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4603 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4604 synchronized (this) {
4605 try {
4606 wait(200);
4607 } catch (InterruptedException e) {
4608 }
4609 }
4610 }
4611 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004612 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004613 boolean done = false;
4614 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4615 if (imppids[j] == r.pid) {
4616 done = true;
4617 break;
4618 }
4619 }
4620 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004621 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004622 synchronized (this) {
4623 try {
4624 wait(200);
4625 } catch (InterruptedException e) {
4626 }
4627 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004628 }
4629 }
4630 }
4631 }
4632
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004633 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004634 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004635 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004636 app.pid, info.toString());
4637 if (res != 0) {
4638 if (res < 0) {
4639 // wait until the SIGQUIT has had a chance to process before killing the
4640 // process.
4641 try {
4642 wait(2000);
4643 } catch (InterruptedException e) {
4644 }
4645
4646 Process.killProcess(app.pid);
4647 return;
4648 }
4649 }
4650 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004651 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004652 }
4653 }
4654
4655 makeAppNotRespondingLocked(app,
4656 activity != null ? activity.shortComponentName : null,
4657 annotation != null ? "ANR " + annotation : "ANR",
4658 info.toString(), null);
4659 Message msg = Message.obtain();
4660 HashMap map = new HashMap();
4661 msg.what = SHOW_NOT_RESPONDING_MSG;
4662 msg.obj = map;
4663 map.put("app", app);
4664 if (activity != null) {
4665 map.put("activity", activity);
4666 }
4667
4668 mHandler.sendMessage(msg);
4669 return;
4670 }
4671
4672 /**
4673 * If a stack trace file has been configured, prepare the filesystem
4674 * by creating the directory if it doesn't exist and optionally
4675 * removing the old trace file.
4676 *
4677 * @param removeExisting If set, the existing trace file will be removed.
4678 * @return Returns true if the trace file preparations succeeded
4679 */
4680 public static boolean prepareTraceFile(boolean removeExisting) {
4681 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4682 boolean fileReady = false;
4683 if (!TextUtils.isEmpty(tracesPath)) {
4684 File f = new File(tracesPath);
4685 if (!f.exists()) {
4686 // Ensure the enclosing directory exists
4687 File dir = f.getParentFile();
4688 if (!dir.exists()) {
4689 fileReady = dir.mkdirs();
4690 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004691 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004692 } else if (dir.isDirectory()) {
4693 fileReady = true;
4694 }
4695 } else if (removeExisting) {
4696 // Remove the previous traces file, so we don't fill the disk.
4697 // The VM will recreate it
4698 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4699 fileReady = f.delete();
4700 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004701
4702 if (removeExisting) {
4703 try {
4704 f.createNewFile();
4705 FileUtils.setPermissions(f.getAbsolutePath(),
4706 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4707 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4708 fileReady = true;
4709 } catch (IOException e) {
4710 Log.w(TAG, "Unable to make ANR traces file", e);
4711 }
4712 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004713 }
4714
4715 return fileReady;
4716 }
4717
4718
4719 private final void decPersistentCountLocked(ProcessRecord app)
4720 {
4721 app.persistentActivities--;
4722 if (app.persistentActivities > 0) {
4723 // Still more of 'em...
4724 return;
4725 }
4726 if (app.persistent) {
4727 // Ah, but the application itself is persistent. Whatever!
4728 return;
4729 }
4730
4731 // App is no longer persistent... make sure it and the ones
4732 // following it in the LRU list have the correc oom_adj.
4733 updateOomAdjLocked();
4734 }
4735
4736 public void setPersistent(IBinder token, boolean isPersistent) {
4737 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4738 != PackageManager.PERMISSION_GRANTED) {
4739 String msg = "Permission Denial: setPersistent() from pid="
4740 + Binder.getCallingPid()
4741 + ", uid=" + Binder.getCallingUid()
4742 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4743 Log.w(TAG, msg);
4744 throw new SecurityException(msg);
4745 }
4746
4747 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004748 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004749 if (index < 0) {
4750 return;
4751 }
4752 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4753 ProcessRecord app = r.app;
4754
4755 if (localLOGV) Log.v(
4756 TAG, "Setting persistence " + isPersistent + ": " + r);
4757
4758 if (isPersistent) {
4759 if (r.persistent) {
4760 // Okay okay, I heard you already!
4761 if (localLOGV) Log.v(TAG, "Already persistent!");
4762 return;
4763 }
4764 r.persistent = true;
4765 app.persistentActivities++;
4766 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4767 if (app.persistentActivities > 1) {
4768 // We aren't the first...
4769 if (localLOGV) Log.v(TAG, "Not the first!");
4770 return;
4771 }
4772 if (app.persistent) {
4773 // This would be redundant.
4774 if (localLOGV) Log.v(TAG, "App is persistent!");
4775 return;
4776 }
4777
4778 // App is now persistent... make sure it and the ones
4779 // following it now have the correct oom_adj.
4780 final long origId = Binder.clearCallingIdentity();
4781 updateOomAdjLocked();
4782 Binder.restoreCallingIdentity(origId);
4783
4784 } else {
4785 if (!r.persistent) {
4786 // Okay okay, I heard you already!
4787 return;
4788 }
4789 r.persistent = false;
4790 final long origId = Binder.clearCallingIdentity();
4791 decPersistentCountLocked(app);
4792 Binder.restoreCallingIdentity(origId);
4793
4794 }
4795 }
4796 }
4797
4798 public boolean clearApplicationUserData(final String packageName,
4799 final IPackageDataObserver observer) {
4800 int uid = Binder.getCallingUid();
4801 int pid = Binder.getCallingPid();
4802 long callingId = Binder.clearCallingIdentity();
4803 try {
4804 IPackageManager pm = ActivityThread.getPackageManager();
4805 int pkgUid = -1;
4806 synchronized(this) {
4807 try {
4808 pkgUid = pm.getPackageUid(packageName);
4809 } catch (RemoteException e) {
4810 }
4811 if (pkgUid == -1) {
4812 Log.w(TAG, "Invalid packageName:" + packageName);
4813 return false;
4814 }
4815 if (uid == pkgUid || checkComponentPermission(
4816 android.Manifest.permission.CLEAR_APP_USER_DATA,
4817 pid, uid, -1)
4818 == PackageManager.PERMISSION_GRANTED) {
4819 restartPackageLocked(packageName, pkgUid);
4820 } else {
4821 throw new SecurityException(pid+" does not have permission:"+
4822 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4823 "for process:"+packageName);
4824 }
4825 }
4826
4827 try {
4828 //clear application user data
4829 pm.clearApplicationUserData(packageName, observer);
4830 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4831 Uri.fromParts("package", packageName, null));
4832 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4833 broadcastIntentLocked(null, null, intent,
4834 null, null, 0, null, null, null,
4835 false, false, MY_PID, Process.SYSTEM_UID);
4836 } catch (RemoteException e) {
4837 }
4838 } finally {
4839 Binder.restoreCallingIdentity(callingId);
4840 }
4841 return true;
4842 }
4843
4844 public void restartPackage(final String packageName) {
4845 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4846 != PackageManager.PERMISSION_GRANTED) {
4847 String msg = "Permission Denial: restartPackage() from pid="
4848 + Binder.getCallingPid()
4849 + ", uid=" + Binder.getCallingUid()
4850 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4851 Log.w(TAG, msg);
4852 throw new SecurityException(msg);
4853 }
4854
4855 long callingId = Binder.clearCallingIdentity();
4856 try {
4857 IPackageManager pm = ActivityThread.getPackageManager();
4858 int pkgUid = -1;
4859 synchronized(this) {
4860 try {
4861 pkgUid = pm.getPackageUid(packageName);
4862 } catch (RemoteException e) {
4863 }
4864 if (pkgUid == -1) {
4865 Log.w(TAG, "Invalid packageName: " + packageName);
4866 return;
4867 }
4868 restartPackageLocked(packageName, pkgUid);
4869 }
4870 } finally {
4871 Binder.restoreCallingIdentity(callingId);
4872 }
4873 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004874
4875 /*
4876 * The pkg name and uid have to be specified.
4877 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4878 */
4879 public void killApplicationWithUid(String pkg, int uid) {
4880 if (pkg == null) {
4881 return;
4882 }
4883 // Make sure the uid is valid.
4884 if (uid < 0) {
4885 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4886 return;
4887 }
4888 int callerUid = Binder.getCallingUid();
4889 // Only the system server can kill an application
4890 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004891 // Post an aysnc message to kill the application
4892 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4893 msg.arg1 = uid;
4894 msg.arg2 = 0;
4895 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004896 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004897 } else {
4898 throw new SecurityException(callerUid + " cannot kill pkg: " +
4899 pkg);
4900 }
4901 }
4902
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004903 public void closeSystemDialogs(String reason) {
4904 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4905 if (reason != null) {
4906 intent.putExtra("reason", reason);
4907 }
4908
4909 final int uid = Binder.getCallingUid();
4910 final long origId = Binder.clearCallingIdentity();
4911 synchronized (this) {
4912 int i = mWatchers.beginBroadcast();
4913 while (i > 0) {
4914 i--;
4915 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4916 if (w != null) {
4917 try {
4918 w.closingSystemDialogs(reason);
4919 } catch (RemoteException e) {
4920 }
4921 }
4922 }
4923 mWatchers.finishBroadcast();
4924
4925 broadcastIntentLocked(null, null, intent, null,
4926 null, 0, null, null, null, false, false, -1, uid);
4927 }
4928 Binder.restoreCallingIdentity(origId);
4929 }
4930
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004931 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004932 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004933 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
4934 for (int i=pids.length-1; i>=0; i--) {
4935 infos[i] = new Debug.MemoryInfo();
4936 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004937 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004938 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004939 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07004940
4941 public void killApplicationProcess(String processName, int uid) {
4942 if (processName == null) {
4943 return;
4944 }
4945
4946 int callerUid = Binder.getCallingUid();
4947 // Only the system server can kill an application
4948 if (callerUid == Process.SYSTEM_UID) {
4949 synchronized (this) {
4950 ProcessRecord app = getProcessRecordLocked(processName, uid);
4951 if (app != null) {
4952 try {
4953 app.thread.scheduleSuicide();
4954 } catch (RemoteException e) {
4955 // If the other end already died, then our work here is done.
4956 }
4957 } else {
4958 Log.w(TAG, "Process/uid not found attempting kill of "
4959 + processName + " / " + uid);
4960 }
4961 }
4962 } else {
4963 throw new SecurityException(callerUid + " cannot kill app process: " +
4964 processName);
4965 }
4966 }
4967
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004968 private void restartPackageLocked(final String packageName, int uid) {
4969 uninstallPackageLocked(packageName, uid, false);
4970 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4971 Uri.fromParts("package", packageName, null));
4972 intent.putExtra(Intent.EXTRA_UID, uid);
4973 broadcastIntentLocked(null, null, intent,
4974 null, null, 0, null, null, null,
4975 false, false, MY_PID, Process.SYSTEM_UID);
4976 }
4977
4978 private final void uninstallPackageLocked(String name, int uid,
4979 boolean callerWillRestart) {
4980 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4981
4982 int i, N;
4983
4984 final String procNamePrefix = name + ":";
4985 if (uid < 0) {
4986 try {
4987 uid = ActivityThread.getPackageManager().getPackageUid(name);
4988 } catch (RemoteException e) {
4989 }
4990 }
4991
4992 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4993 while (badApps.hasNext()) {
4994 SparseArray<Long> ba = badApps.next();
4995 if (ba.get(uid) != null) {
4996 badApps.remove();
4997 }
4998 }
4999
5000 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
5001
5002 // Remove all processes this package may have touched: all with the
5003 // same UID (except for the system or root user), and all whose name
5004 // matches the package name.
5005 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5006 final int NA = apps.size();
5007 for (int ia=0; ia<NA; ia++) {
5008 ProcessRecord app = apps.valueAt(ia);
5009 if (app.removed) {
5010 procs.add(app);
5011 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5012 || app.processName.equals(name)
5013 || app.processName.startsWith(procNamePrefix)) {
5014 app.removed = true;
5015 procs.add(app);
5016 }
5017 }
5018 }
5019
5020 N = procs.size();
5021 for (i=0; i<N; i++) {
5022 removeProcessLocked(procs.get(i), callerWillRestart);
5023 }
5024
5025 for (i=mHistory.size()-1; i>=0; i--) {
5026 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5027 if (r.packageName.equals(name)) {
5028 if (Config.LOGD) Log.d(
5029 TAG, " Force finishing activity "
5030 + r.intent.getComponent().flattenToShortString());
5031 if (r.app != null) {
5032 r.app.removed = true;
5033 }
5034 r.app = null;
5035 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5036 }
5037 }
5038
5039 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5040 for (ServiceRecord service : mServices.values()) {
5041 if (service.packageName.equals(name)) {
5042 if (service.app != null) {
5043 service.app.removed = true;
5044 }
5045 service.app = null;
5046 services.add(service);
5047 }
5048 }
5049
5050 N = services.size();
5051 for (i=0; i<N; i++) {
5052 bringDownServiceLocked(services.get(i), true);
5053 }
5054
5055 resumeTopActivityLocked(null);
5056 }
5057
5058 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5059 final String name = app.processName;
5060 final int uid = app.info.uid;
5061 if (Config.LOGD) Log.d(
5062 TAG, "Force removing process " + app + " (" + name
5063 + "/" + uid + ")");
5064
5065 mProcessNames.remove(name, uid);
5066 boolean needRestart = false;
5067 if (app.pid > 0 && app.pid != MY_PID) {
5068 int pid = app.pid;
5069 synchronized (mPidsSelfLocked) {
5070 mPidsSelfLocked.remove(pid);
5071 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5072 }
5073 handleAppDiedLocked(app, true);
5074 mLRUProcesses.remove(app);
5075 Process.killProcess(pid);
5076
5077 if (app.persistent) {
5078 if (!callerWillRestart) {
5079 addAppLocked(app.info);
5080 } else {
5081 needRestart = true;
5082 }
5083 }
5084 } else {
5085 mRemovedProcesses.add(app);
5086 }
5087
5088 return needRestart;
5089 }
5090
5091 private final void processStartTimedOutLocked(ProcessRecord app) {
5092 final int pid = app.pid;
5093 boolean gone = false;
5094 synchronized (mPidsSelfLocked) {
5095 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5096 if (knownApp != null && knownApp.thread == null) {
5097 mPidsSelfLocked.remove(pid);
5098 gone = true;
5099 }
5100 }
5101
5102 if (gone) {
5103 Log.w(TAG, "Process " + app + " failed to attach");
5104 mProcessNames.remove(app.processName, app.info.uid);
5105 Process.killProcess(pid);
5106 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5107 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5108 mPendingBroadcast = null;
5109 scheduleBroadcastsLocked();
5110 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005111 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5112 Log.w(TAG, "Unattached app died before backup, skipping");
5113 try {
5114 IBackupManager bm = IBackupManager.Stub.asInterface(
5115 ServiceManager.getService(Context.BACKUP_SERVICE));
5116 bm.agentDisconnected(app.info.packageName);
5117 } catch (RemoteException e) {
5118 // Can't happen; the backup manager is local
5119 }
5120 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005121 } else {
5122 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5123 }
5124 }
5125
5126 private final boolean attachApplicationLocked(IApplicationThread thread,
5127 int pid) {
5128
5129 // Find the application record that is being attached... either via
5130 // the pid if we are running in multiple processes, or just pull the
5131 // next app record if we are emulating process with anonymous threads.
5132 ProcessRecord app;
5133 if (pid != MY_PID && pid >= 0) {
5134 synchronized (mPidsSelfLocked) {
5135 app = mPidsSelfLocked.get(pid);
5136 }
5137 } else if (mStartingProcesses.size() > 0) {
5138 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005139 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005140 } else {
5141 app = null;
5142 }
5143
5144 if (app == null) {
5145 Log.w(TAG, "No pending application record for pid " + pid
5146 + " (IApplicationThread " + thread + "); dropping process");
5147 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5148 if (pid > 0 && pid != MY_PID) {
5149 Process.killProcess(pid);
5150 } else {
5151 try {
5152 thread.scheduleExit();
5153 } catch (Exception e) {
5154 // Ignore exceptions.
5155 }
5156 }
5157 return false;
5158 }
5159
5160 // If this application record is still attached to a previous
5161 // process, clean it up now.
5162 if (app.thread != null) {
5163 handleAppDiedLocked(app, true);
5164 }
5165
5166 // Tell the process all about itself.
5167
5168 if (localLOGV) Log.v(
5169 TAG, "Binding process pid " + pid + " to record " + app);
5170
5171 String processName = app.processName;
5172 try {
5173 thread.asBinder().linkToDeath(new AppDeathRecipient(
5174 app, pid, thread), 0);
5175 } catch (RemoteException e) {
5176 app.resetPackageList();
5177 startProcessLocked(app, "link fail", processName);
5178 return false;
5179 }
5180
5181 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5182
5183 app.thread = thread;
5184 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005185 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005186 app.forcingToForeground = null;
5187 app.foregroundServices = false;
5188 app.debugging = false;
5189
5190 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5191
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005192 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5193 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005194
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005195 if (!normalMode) {
5196 Log.i(TAG, "Launching preboot mode app: " + app);
5197 }
5198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005199 if (localLOGV) Log.v(
5200 TAG, "New app record " + app
5201 + " thread=" + thread.asBinder() + " pid=" + pid);
5202 try {
5203 int testMode = IApplicationThread.DEBUG_OFF;
5204 if (mDebugApp != null && mDebugApp.equals(processName)) {
5205 testMode = mWaitForDebugger
5206 ? IApplicationThread.DEBUG_WAIT
5207 : IApplicationThread.DEBUG_ON;
5208 app.debugging = true;
5209 if (mDebugTransient) {
5210 mDebugApp = mOrigDebugApp;
5211 mWaitForDebugger = mOrigWaitForDebugger;
5212 }
5213 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005214
Christopher Tate181fafa2009-05-14 11:12:14 -07005215 // If the app is being launched for restore or full backup, set it up specially
5216 boolean isRestrictedBackupMode = false;
5217 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5218 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5219 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5220 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005221
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005222 ensurePackageDexOpt(app.instrumentationInfo != null
5223 ? app.instrumentationInfo.packageName
5224 : app.info.packageName);
5225 if (app.instrumentationClass != null) {
5226 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005227 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07005228 thread.bindApplication(processName, app.instrumentationInfo != null
5229 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005230 app.instrumentationClass, app.instrumentationProfileFile,
5231 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005232 isRestrictedBackupMode || !normalMode,
5233 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005234 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005235 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005236 } catch (Exception e) {
5237 // todo: Yikes! What should we do? For now we will try to
5238 // start another process, but that could easily get us in
5239 // an infinite loop of restarting processes...
5240 Log.w(TAG, "Exception thrown during bind!", e);
5241
5242 app.resetPackageList();
5243 startProcessLocked(app, "bind fail", processName);
5244 return false;
5245 }
5246
5247 // Remove this record from the list of starting applications.
5248 mPersistentStartingProcesses.remove(app);
5249 mProcessesOnHold.remove(app);
5250
5251 boolean badApp = false;
5252 boolean didSomething = false;
5253
5254 // See if the top visible activity is waiting to run in this process...
5255 HistoryRecord hr = topRunningActivityLocked(null);
5256 if (hr != null) {
5257 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5258 && processName.equals(hr.processName)) {
5259 try {
5260 if (realStartActivityLocked(hr, app, true, true)) {
5261 didSomething = true;
5262 }
5263 } catch (Exception e) {
5264 Log.w(TAG, "Exception in new application when starting activity "
5265 + hr.intent.getComponent().flattenToShortString(), e);
5266 badApp = true;
5267 }
5268 } else {
5269 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5270 }
5271 }
5272
5273 // Find any services that should be running in this process...
5274 if (!badApp && mPendingServices.size() > 0) {
5275 ServiceRecord sr = null;
5276 try {
5277 for (int i=0; i<mPendingServices.size(); i++) {
5278 sr = mPendingServices.get(i);
5279 if (app.info.uid != sr.appInfo.uid
5280 || !processName.equals(sr.processName)) {
5281 continue;
5282 }
5283
5284 mPendingServices.remove(i);
5285 i--;
5286 realStartServiceLocked(sr, app);
5287 didSomething = true;
5288 }
5289 } catch (Exception e) {
5290 Log.w(TAG, "Exception in new application when starting service "
5291 + sr.shortName, e);
5292 badApp = true;
5293 }
5294 }
5295
5296 // Check if the next broadcast receiver is in this process...
5297 BroadcastRecord br = mPendingBroadcast;
5298 if (!badApp && br != null && br.curApp == app) {
5299 try {
5300 mPendingBroadcast = null;
5301 processCurBroadcastLocked(br, app);
5302 didSomething = true;
5303 } catch (Exception e) {
5304 Log.w(TAG, "Exception in new application when starting receiver "
5305 + br.curComponent.flattenToShortString(), e);
5306 badApp = true;
5307 logBroadcastReceiverDiscard(br);
5308 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5309 br.resultExtras, br.resultAbort, true);
5310 scheduleBroadcastsLocked();
5311 }
5312 }
5313
Christopher Tate181fafa2009-05-14 11:12:14 -07005314 // Check whether the next backup agent is in this process...
5315 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5316 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005317 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005318 try {
5319 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5320 } catch (Exception e) {
5321 Log.w(TAG, "Exception scheduling backup agent creation: ");
5322 e.printStackTrace();
5323 }
5324 }
5325
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005326 if (badApp) {
5327 // todo: Also need to kill application to deal with all
5328 // kinds of exceptions.
5329 handleAppDiedLocked(app, false);
5330 return false;
5331 }
5332
5333 if (!didSomething) {
5334 updateOomAdjLocked();
5335 }
5336
5337 return true;
5338 }
5339
5340 public final void attachApplication(IApplicationThread thread) {
5341 synchronized (this) {
5342 int callingPid = Binder.getCallingPid();
5343 final long origId = Binder.clearCallingIdentity();
5344 attachApplicationLocked(thread, callingPid);
5345 Binder.restoreCallingIdentity(origId);
5346 }
5347 }
5348
5349 public final void activityIdle(IBinder token) {
5350 final long origId = Binder.clearCallingIdentity();
5351 activityIdleInternal(token, false);
5352 Binder.restoreCallingIdentity(origId);
5353 }
5354
5355 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5356 boolean remove) {
5357 int N = mStoppingActivities.size();
5358 if (N <= 0) return null;
5359
5360 ArrayList<HistoryRecord> stops = null;
5361
5362 final boolean nowVisible = mResumedActivity != null
5363 && mResumedActivity.nowVisible
5364 && !mResumedActivity.waitingVisible;
5365 for (int i=0; i<N; i++) {
5366 HistoryRecord s = mStoppingActivities.get(i);
5367 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5368 + nowVisible + " waitingVisible=" + s.waitingVisible
5369 + " finishing=" + s.finishing);
5370 if (s.waitingVisible && nowVisible) {
5371 mWaitingVisibleActivities.remove(s);
5372 s.waitingVisible = false;
5373 if (s.finishing) {
5374 // If this activity is finishing, it is sitting on top of
5375 // everyone else but we now know it is no longer needed...
5376 // so get rid of it. Otherwise, we need to go through the
5377 // normal flow and hide it once we determine that it is
5378 // hidden by the activities in front of it.
5379 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5380 mWindowManager.setAppVisibility(s, false);
5381 }
5382 }
5383 if (!s.waitingVisible && remove) {
5384 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5385 if (stops == null) {
5386 stops = new ArrayList<HistoryRecord>();
5387 }
5388 stops.add(s);
5389 mStoppingActivities.remove(i);
5390 N--;
5391 i--;
5392 }
5393 }
5394
5395 return stops;
5396 }
5397
5398 void enableScreenAfterBoot() {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005399 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5400 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005401 mWindowManager.enableScreenAfterBoot();
5402 }
5403
5404 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5405 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5406
5407 ArrayList<HistoryRecord> stops = null;
5408 ArrayList<HistoryRecord> finishes = null;
5409 ArrayList<HistoryRecord> thumbnails = null;
5410 int NS = 0;
5411 int NF = 0;
5412 int NT = 0;
5413 IApplicationThread sendThumbnail = null;
5414 boolean booting = false;
5415 boolean enableScreen = false;
5416
5417 synchronized (this) {
5418 if (token != null) {
5419 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5420 }
5421
5422 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005423 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005424 if (index >= 0) {
5425 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5426
5427 // No longer need to keep the device awake.
5428 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5429 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5430 mLaunchingActivity.release();
5431 }
5432
5433 // We are now idle. If someone is waiting for a thumbnail from
5434 // us, we can now deliver.
5435 r.idle = true;
5436 scheduleAppGcsLocked();
5437 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5438 sendThumbnail = r.app.thread;
5439 r.thumbnailNeeded = false;
5440 }
5441
5442 // If this activity is fullscreen, set up to hide those under it.
5443
5444 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5445 ensureActivitiesVisibleLocked(null, 0);
5446
5447 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5448 if (!mBooted && !fromTimeout) {
5449 mBooted = true;
5450 enableScreen = true;
5451 }
5452 }
5453
5454 // Atomically retrieve all of the other things to do.
5455 stops = processStoppingActivitiesLocked(true);
5456 NS = stops != null ? stops.size() : 0;
5457 if ((NF=mFinishingActivities.size()) > 0) {
5458 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5459 mFinishingActivities.clear();
5460 }
5461 if ((NT=mCancelledThumbnails.size()) > 0) {
5462 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5463 mCancelledThumbnails.clear();
5464 }
5465
5466 booting = mBooting;
5467 mBooting = false;
5468 }
5469
5470 int i;
5471
5472 // Send thumbnail if requested.
5473 if (sendThumbnail != null) {
5474 try {
5475 sendThumbnail.requestThumbnail(token);
5476 } catch (Exception e) {
5477 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5478 sendPendingThumbnail(null, token, null, null, true);
5479 }
5480 }
5481
5482 // Stop any activities that are scheduled to do so but have been
5483 // waiting for the next one to start.
5484 for (i=0; i<NS; i++) {
5485 HistoryRecord r = (HistoryRecord)stops.get(i);
5486 synchronized (this) {
5487 if (r.finishing) {
5488 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5489 } else {
5490 stopActivityLocked(r);
5491 }
5492 }
5493 }
5494
5495 // Finish any activities that are scheduled to do so but have been
5496 // waiting for the next one to start.
5497 for (i=0; i<NF; i++) {
5498 HistoryRecord r = (HistoryRecord)finishes.get(i);
5499 synchronized (this) {
5500 destroyActivityLocked(r, true);
5501 }
5502 }
5503
5504 // Report back to any thumbnail receivers.
5505 for (i=0; i<NT; i++) {
5506 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5507 sendPendingThumbnail(r, null, null, null, true);
5508 }
5509
5510 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005511 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005512 }
5513
5514 trimApplications();
5515 //dump();
5516 //mWindowManager.dump();
5517
5518 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005519 enableScreenAfterBoot();
5520 }
5521 }
5522
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005523 final void finishBooting() {
5524 // Ensure that any processes we had put on hold are now started
5525 // up.
5526 final int NP = mProcessesOnHold.size();
5527 if (NP > 0) {
5528 ArrayList<ProcessRecord> procs =
5529 new ArrayList<ProcessRecord>(mProcessesOnHold);
5530 for (int ip=0; ip<NP; ip++) {
5531 this.startProcessLocked(procs.get(ip), "on-hold", null);
5532 }
5533 }
5534 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5535 // Tell anyone interested that we are done booting!
5536 synchronized (this) {
5537 broadcastIntentLocked(null, null,
5538 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5539 null, null, 0, null, null,
5540 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5541 false, false, MY_PID, Process.SYSTEM_UID);
5542 }
5543 }
5544 }
5545
5546 final void ensureBootCompleted() {
5547 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005548 boolean enableScreen;
5549 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005550 booting = mBooting;
5551 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005552 enableScreen = !mBooted;
5553 mBooted = true;
5554 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005555
5556 if (booting) {
5557 finishBooting();
5558 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005559
5560 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005561 enableScreenAfterBoot();
5562 }
5563 }
5564
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005565 public final void activityPaused(IBinder token, Bundle icicle) {
5566 // Refuse possible leaked file descriptors
5567 if (icicle != null && icicle.hasFileDescriptors()) {
5568 throw new IllegalArgumentException("File descriptors passed in Bundle");
5569 }
5570
5571 final long origId = Binder.clearCallingIdentity();
5572 activityPaused(token, icicle, false);
5573 Binder.restoreCallingIdentity(origId);
5574 }
5575
5576 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5577 if (DEBUG_PAUSE) Log.v(
5578 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5579 + ", timeout=" + timeout);
5580
5581 HistoryRecord r = null;
5582
5583 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005584 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005585 if (index >= 0) {
5586 r = (HistoryRecord)mHistory.get(index);
5587 if (!timeout) {
5588 r.icicle = icicle;
5589 r.haveState = true;
5590 }
5591 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5592 if (mPausingActivity == r) {
5593 r.state = ActivityState.PAUSED;
5594 completePauseLocked();
5595 } else {
5596 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5597 System.identityHashCode(r), r.shortComponentName,
5598 mPausingActivity != null
5599 ? mPausingActivity.shortComponentName : "(none)");
5600 }
5601 }
5602 }
5603 }
5604
5605 public final void activityStopped(IBinder token, Bitmap thumbnail,
5606 CharSequence description) {
5607 if (localLOGV) Log.v(
5608 TAG, "Activity stopped: token=" + token);
5609
5610 HistoryRecord r = null;
5611
5612 final long origId = Binder.clearCallingIdentity();
5613
5614 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005615 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005616 if (index >= 0) {
5617 r = (HistoryRecord)mHistory.get(index);
5618 r.thumbnail = thumbnail;
5619 r.description = description;
5620 r.stopped = true;
5621 r.state = ActivityState.STOPPED;
5622 if (!r.finishing) {
5623 if (r.configDestroy) {
5624 destroyActivityLocked(r, true);
5625 resumeTopActivityLocked(null);
5626 }
5627 }
5628 }
5629 }
5630
5631 if (r != null) {
5632 sendPendingThumbnail(r, null, null, null, false);
5633 }
5634
5635 trimApplications();
5636
5637 Binder.restoreCallingIdentity(origId);
5638 }
5639
5640 public final void activityDestroyed(IBinder token) {
5641 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5642 synchronized (this) {
5643 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5644
Dianne Hackborn75b03852009-06-12 15:43:26 -07005645 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005646 if (index >= 0) {
5647 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5648 if (r.state == ActivityState.DESTROYING) {
5649 final long origId = Binder.clearCallingIdentity();
5650 removeActivityFromHistoryLocked(r);
5651 Binder.restoreCallingIdentity(origId);
5652 }
5653 }
5654 }
5655 }
5656
5657 public String getCallingPackage(IBinder token) {
5658 synchronized (this) {
5659 HistoryRecord r = getCallingRecordLocked(token);
5660 return r != null && r.app != null ? r.app.processName : null;
5661 }
5662 }
5663
5664 public ComponentName getCallingActivity(IBinder token) {
5665 synchronized (this) {
5666 HistoryRecord r = getCallingRecordLocked(token);
5667 return r != null ? r.intent.getComponent() : null;
5668 }
5669 }
5670
5671 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005672 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005673 if (index >= 0) {
5674 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5675 if (r != null) {
5676 return r.resultTo;
5677 }
5678 }
5679 return null;
5680 }
5681
5682 public ComponentName getActivityClassForToken(IBinder token) {
5683 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005684 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005685 if (index >= 0) {
5686 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5687 return r.intent.getComponent();
5688 }
5689 return null;
5690 }
5691 }
5692
5693 public String getPackageForToken(IBinder token) {
5694 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005695 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005696 if (index >= 0) {
5697 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5698 return r.packageName;
5699 }
5700 return null;
5701 }
5702 }
5703
5704 public IIntentSender getIntentSender(int type,
5705 String packageName, IBinder token, String resultWho,
5706 int requestCode, Intent intent, String resolvedType, int flags) {
5707 // Refuse possible leaked file descriptors
5708 if (intent != null && intent.hasFileDescriptors() == true) {
5709 throw new IllegalArgumentException("File descriptors passed in Intent");
5710 }
5711
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005712 if (type == INTENT_SENDER_BROADCAST) {
5713 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5714 throw new IllegalArgumentException(
5715 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5716 }
5717 }
5718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005719 synchronized(this) {
5720 int callingUid = Binder.getCallingUid();
5721 try {
5722 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5723 Process.supportsProcesses()) {
5724 int uid = ActivityThread.getPackageManager()
5725 .getPackageUid(packageName);
5726 if (uid != Binder.getCallingUid()) {
5727 String msg = "Permission Denial: getIntentSender() from pid="
5728 + Binder.getCallingPid()
5729 + ", uid=" + Binder.getCallingUid()
5730 + ", (need uid=" + uid + ")"
5731 + " is not allowed to send as package " + packageName;
5732 Log.w(TAG, msg);
5733 throw new SecurityException(msg);
5734 }
5735 }
5736 } catch (RemoteException e) {
5737 throw new SecurityException(e);
5738 }
5739 HistoryRecord activity = null;
5740 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005741 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005742 if (index < 0) {
5743 return null;
5744 }
5745 activity = (HistoryRecord)mHistory.get(index);
5746 if (activity.finishing) {
5747 return null;
5748 }
5749 }
5750
5751 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5752 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5753 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5754 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5755 |PendingIntent.FLAG_UPDATE_CURRENT);
5756
5757 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5758 type, packageName, activity, resultWho,
5759 requestCode, intent, resolvedType, flags);
5760 WeakReference<PendingIntentRecord> ref;
5761 ref = mIntentSenderRecords.get(key);
5762 PendingIntentRecord rec = ref != null ? ref.get() : null;
5763 if (rec != null) {
5764 if (!cancelCurrent) {
5765 if (updateCurrent) {
5766 rec.key.requestIntent.replaceExtras(intent);
5767 }
5768 return rec;
5769 }
5770 rec.canceled = true;
5771 mIntentSenderRecords.remove(key);
5772 }
5773 if (noCreate) {
5774 return rec;
5775 }
5776 rec = new PendingIntentRecord(this, key, callingUid);
5777 mIntentSenderRecords.put(key, rec.ref);
5778 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5779 if (activity.pendingResults == null) {
5780 activity.pendingResults
5781 = new HashSet<WeakReference<PendingIntentRecord>>();
5782 }
5783 activity.pendingResults.add(rec.ref);
5784 }
5785 return rec;
5786 }
5787 }
5788
5789 public void cancelIntentSender(IIntentSender sender) {
5790 if (!(sender instanceof PendingIntentRecord)) {
5791 return;
5792 }
5793 synchronized(this) {
5794 PendingIntentRecord rec = (PendingIntentRecord)sender;
5795 try {
5796 int uid = ActivityThread.getPackageManager()
5797 .getPackageUid(rec.key.packageName);
5798 if (uid != Binder.getCallingUid()) {
5799 String msg = "Permission Denial: cancelIntentSender() from pid="
5800 + Binder.getCallingPid()
5801 + ", uid=" + Binder.getCallingUid()
5802 + " is not allowed to cancel packges "
5803 + rec.key.packageName;
5804 Log.w(TAG, msg);
5805 throw new SecurityException(msg);
5806 }
5807 } catch (RemoteException e) {
5808 throw new SecurityException(e);
5809 }
5810 cancelIntentSenderLocked(rec, true);
5811 }
5812 }
5813
5814 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5815 rec.canceled = true;
5816 mIntentSenderRecords.remove(rec.key);
5817 if (cleanActivity && rec.key.activity != null) {
5818 rec.key.activity.pendingResults.remove(rec.ref);
5819 }
5820 }
5821
5822 public String getPackageForIntentSender(IIntentSender pendingResult) {
5823 if (!(pendingResult instanceof PendingIntentRecord)) {
5824 return null;
5825 }
5826 synchronized(this) {
5827 try {
5828 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5829 return res.key.packageName;
5830 } catch (ClassCastException e) {
5831 }
5832 }
5833 return null;
5834 }
5835
5836 public void setProcessLimit(int max) {
5837 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5838 "setProcessLimit()");
5839 mProcessLimit = max;
5840 }
5841
5842 public int getProcessLimit() {
5843 return mProcessLimit;
5844 }
5845
5846 void foregroundTokenDied(ForegroundToken token) {
5847 synchronized (ActivityManagerService.this) {
5848 synchronized (mPidsSelfLocked) {
5849 ForegroundToken cur
5850 = mForegroundProcesses.get(token.pid);
5851 if (cur != token) {
5852 return;
5853 }
5854 mForegroundProcesses.remove(token.pid);
5855 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5856 if (pr == null) {
5857 return;
5858 }
5859 pr.forcingToForeground = null;
5860 pr.foregroundServices = false;
5861 }
5862 updateOomAdjLocked();
5863 }
5864 }
5865
5866 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5867 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5868 "setProcessForeground()");
5869 synchronized(this) {
5870 boolean changed = false;
5871
5872 synchronized (mPidsSelfLocked) {
5873 ProcessRecord pr = mPidsSelfLocked.get(pid);
5874 if (pr == null) {
5875 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5876 return;
5877 }
5878 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5879 if (oldToken != null) {
5880 oldToken.token.unlinkToDeath(oldToken, 0);
5881 mForegroundProcesses.remove(pid);
5882 pr.forcingToForeground = null;
5883 changed = true;
5884 }
5885 if (isForeground && token != null) {
5886 ForegroundToken newToken = new ForegroundToken() {
5887 public void binderDied() {
5888 foregroundTokenDied(this);
5889 }
5890 };
5891 newToken.pid = pid;
5892 newToken.token = token;
5893 try {
5894 token.linkToDeath(newToken, 0);
5895 mForegroundProcesses.put(pid, newToken);
5896 pr.forcingToForeground = token;
5897 changed = true;
5898 } catch (RemoteException e) {
5899 // If the process died while doing this, we will later
5900 // do the cleanup with the process death link.
5901 }
5902 }
5903 }
5904
5905 if (changed) {
5906 updateOomAdjLocked();
5907 }
5908 }
5909 }
5910
5911 // =========================================================
5912 // PERMISSIONS
5913 // =========================================================
5914
5915 static class PermissionController extends IPermissionController.Stub {
5916 ActivityManagerService mActivityManagerService;
5917 PermissionController(ActivityManagerService activityManagerService) {
5918 mActivityManagerService = activityManagerService;
5919 }
5920
5921 public boolean checkPermission(String permission, int pid, int uid) {
5922 return mActivityManagerService.checkPermission(permission, pid,
5923 uid) == PackageManager.PERMISSION_GRANTED;
5924 }
5925 }
5926
5927 /**
5928 * This can be called with or without the global lock held.
5929 */
5930 int checkComponentPermission(String permission, int pid, int uid,
5931 int reqUid) {
5932 // We might be performing an operation on behalf of an indirect binder
5933 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5934 // client identity accordingly before proceeding.
5935 Identity tlsIdentity = sCallerIdentity.get();
5936 if (tlsIdentity != null) {
5937 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5938 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5939 uid = tlsIdentity.uid;
5940 pid = tlsIdentity.pid;
5941 }
5942
5943 // Root, system server and our own process get to do everything.
5944 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5945 !Process.supportsProcesses()) {
5946 return PackageManager.PERMISSION_GRANTED;
5947 }
5948 // If the target requires a specific UID, always fail for others.
5949 if (reqUid >= 0 && uid != reqUid) {
5950 return PackageManager.PERMISSION_DENIED;
5951 }
5952 if (permission == null) {
5953 return PackageManager.PERMISSION_GRANTED;
5954 }
5955 try {
5956 return ActivityThread.getPackageManager()
5957 .checkUidPermission(permission, uid);
5958 } catch (RemoteException e) {
5959 // Should never happen, but if it does... deny!
5960 Log.e(TAG, "PackageManager is dead?!?", e);
5961 }
5962 return PackageManager.PERMISSION_DENIED;
5963 }
5964
5965 /**
5966 * As the only public entry point for permissions checking, this method
5967 * can enforce the semantic that requesting a check on a null global
5968 * permission is automatically denied. (Internally a null permission
5969 * string is used when calling {@link #checkComponentPermission} in cases
5970 * when only uid-based security is needed.)
5971 *
5972 * This can be called with or without the global lock held.
5973 */
5974 public int checkPermission(String permission, int pid, int uid) {
5975 if (permission == null) {
5976 return PackageManager.PERMISSION_DENIED;
5977 }
5978 return checkComponentPermission(permission, pid, uid, -1);
5979 }
5980
5981 /**
5982 * Binder IPC calls go through the public entry point.
5983 * This can be called with or without the global lock held.
5984 */
5985 int checkCallingPermission(String permission) {
5986 return checkPermission(permission,
5987 Binder.getCallingPid(),
5988 Binder.getCallingUid());
5989 }
5990
5991 /**
5992 * This can be called with or without the global lock held.
5993 */
5994 void enforceCallingPermission(String permission, String func) {
5995 if (checkCallingPermission(permission)
5996 == PackageManager.PERMISSION_GRANTED) {
5997 return;
5998 }
5999
6000 String msg = "Permission Denial: " + func + " from pid="
6001 + Binder.getCallingPid()
6002 + ", uid=" + Binder.getCallingUid()
6003 + " requires " + permission;
6004 Log.w(TAG, msg);
6005 throw new SecurityException(msg);
6006 }
6007
6008 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6009 ProviderInfo pi, int uid, int modeFlags) {
6010 try {
6011 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6012 if ((pi.readPermission != null) &&
6013 (pm.checkUidPermission(pi.readPermission, uid)
6014 != PackageManager.PERMISSION_GRANTED)) {
6015 return false;
6016 }
6017 }
6018 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6019 if ((pi.writePermission != null) &&
6020 (pm.checkUidPermission(pi.writePermission, uid)
6021 != PackageManager.PERMISSION_GRANTED)) {
6022 return false;
6023 }
6024 }
6025 return true;
6026 } catch (RemoteException e) {
6027 return false;
6028 }
6029 }
6030
6031 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6032 int modeFlags) {
6033 // Root gets to do everything.
6034 if (uid == 0 || !Process.supportsProcesses()) {
6035 return true;
6036 }
6037 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6038 if (perms == null) return false;
6039 UriPermission perm = perms.get(uri);
6040 if (perm == null) return false;
6041 return (modeFlags&perm.modeFlags) == modeFlags;
6042 }
6043
6044 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6045 // Another redirected-binder-call permissions check as in
6046 // {@link checkComponentPermission}.
6047 Identity tlsIdentity = sCallerIdentity.get();
6048 if (tlsIdentity != null) {
6049 uid = tlsIdentity.uid;
6050 pid = tlsIdentity.pid;
6051 }
6052
6053 // Our own process gets to do everything.
6054 if (pid == MY_PID) {
6055 return PackageManager.PERMISSION_GRANTED;
6056 }
6057 synchronized(this) {
6058 return checkUriPermissionLocked(uri, uid, modeFlags)
6059 ? PackageManager.PERMISSION_GRANTED
6060 : PackageManager.PERMISSION_DENIED;
6061 }
6062 }
6063
6064 private void grantUriPermissionLocked(int callingUid,
6065 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6066 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6067 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6068 if (modeFlags == 0) {
6069 return;
6070 }
6071
6072 final IPackageManager pm = ActivityThread.getPackageManager();
6073
6074 // If this is not a content: uri, we can't do anything with it.
6075 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6076 return;
6077 }
6078
6079 String name = uri.getAuthority();
6080 ProviderInfo pi = null;
6081 ContentProviderRecord cpr
6082 = (ContentProviderRecord)mProvidersByName.get(name);
6083 if (cpr != null) {
6084 pi = cpr.info;
6085 } else {
6086 try {
6087 pi = pm.resolveContentProvider(name,
6088 PackageManager.GET_URI_PERMISSION_PATTERNS);
6089 } catch (RemoteException ex) {
6090 }
6091 }
6092 if (pi == null) {
6093 Log.w(TAG, "No content provider found for: " + name);
6094 return;
6095 }
6096
6097 int targetUid;
6098 try {
6099 targetUid = pm.getPackageUid(targetPkg);
6100 if (targetUid < 0) {
6101 return;
6102 }
6103 } catch (RemoteException ex) {
6104 return;
6105 }
6106
6107 // First... does the target actually need this permission?
6108 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6109 // No need to grant the target this permission.
6110 return;
6111 }
6112
6113 // Second... maybe someone else has already granted the
6114 // permission?
6115 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6116 // No need to grant the target this permission.
6117 return;
6118 }
6119
6120 // Third... is the provider allowing granting of URI permissions?
6121 if (!pi.grantUriPermissions) {
6122 throw new SecurityException("Provider " + pi.packageName
6123 + "/" + pi.name
6124 + " does not allow granting of Uri permissions (uri "
6125 + uri + ")");
6126 }
6127 if (pi.uriPermissionPatterns != null) {
6128 final int N = pi.uriPermissionPatterns.length;
6129 boolean allowed = false;
6130 for (int i=0; i<N; i++) {
6131 if (pi.uriPermissionPatterns[i] != null
6132 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6133 allowed = true;
6134 break;
6135 }
6136 }
6137 if (!allowed) {
6138 throw new SecurityException("Provider " + pi.packageName
6139 + "/" + pi.name
6140 + " does not allow granting of permission to path of Uri "
6141 + uri);
6142 }
6143 }
6144
6145 // Fourth... does the caller itself have permission to access
6146 // this uri?
6147 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6148 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6149 throw new SecurityException("Uid " + callingUid
6150 + " does not have permission to uri " + uri);
6151 }
6152 }
6153
6154 // Okay! So here we are: the caller has the assumed permission
6155 // to the uri, and the target doesn't. Let's now give this to
6156 // the target.
6157
6158 HashMap<Uri, UriPermission> targetUris
6159 = mGrantedUriPermissions.get(targetUid);
6160 if (targetUris == null) {
6161 targetUris = new HashMap<Uri, UriPermission>();
6162 mGrantedUriPermissions.put(targetUid, targetUris);
6163 }
6164
6165 UriPermission perm = targetUris.get(uri);
6166 if (perm == null) {
6167 perm = new UriPermission(targetUid, uri);
6168 targetUris.put(uri, perm);
6169
6170 }
6171 perm.modeFlags |= modeFlags;
6172 if (activity == null) {
6173 perm.globalModeFlags |= modeFlags;
6174 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6175 perm.readActivities.add(activity);
6176 if (activity.readUriPermissions == null) {
6177 activity.readUriPermissions = new HashSet<UriPermission>();
6178 }
6179 activity.readUriPermissions.add(perm);
6180 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6181 perm.writeActivities.add(activity);
6182 if (activity.writeUriPermissions == null) {
6183 activity.writeUriPermissions = new HashSet<UriPermission>();
6184 }
6185 activity.writeUriPermissions.add(perm);
6186 }
6187 }
6188
6189 private void grantUriPermissionFromIntentLocked(int callingUid,
6190 String targetPkg, Intent intent, HistoryRecord activity) {
6191 if (intent == null) {
6192 return;
6193 }
6194 Uri data = intent.getData();
6195 if (data == null) {
6196 return;
6197 }
6198 grantUriPermissionLocked(callingUid, targetPkg, data,
6199 intent.getFlags(), activity);
6200 }
6201
6202 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6203 Uri uri, int modeFlags) {
6204 synchronized(this) {
6205 final ProcessRecord r = getRecordForAppLocked(caller);
6206 if (r == null) {
6207 throw new SecurityException("Unable to find app for caller "
6208 + caller
6209 + " when granting permission to uri " + uri);
6210 }
6211 if (targetPkg == null) {
6212 Log.w(TAG, "grantUriPermission: null target");
6213 return;
6214 }
6215 if (uri == null) {
6216 Log.w(TAG, "grantUriPermission: null uri");
6217 return;
6218 }
6219
6220 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6221 null);
6222 }
6223 }
6224
6225 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6226 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6227 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6228 HashMap<Uri, UriPermission> perms
6229 = mGrantedUriPermissions.get(perm.uid);
6230 if (perms != null) {
6231 perms.remove(perm.uri);
6232 if (perms.size() == 0) {
6233 mGrantedUriPermissions.remove(perm.uid);
6234 }
6235 }
6236 }
6237 }
6238
6239 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6240 if (activity.readUriPermissions != null) {
6241 for (UriPermission perm : activity.readUriPermissions) {
6242 perm.readActivities.remove(activity);
6243 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6244 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6245 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6246 removeUriPermissionIfNeededLocked(perm);
6247 }
6248 }
6249 }
6250 if (activity.writeUriPermissions != null) {
6251 for (UriPermission perm : activity.writeUriPermissions) {
6252 perm.writeActivities.remove(activity);
6253 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6254 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6255 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6256 removeUriPermissionIfNeededLocked(perm);
6257 }
6258 }
6259 }
6260 }
6261
6262 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6263 int modeFlags) {
6264 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6265 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6266 if (modeFlags == 0) {
6267 return;
6268 }
6269
6270 final IPackageManager pm = ActivityThread.getPackageManager();
6271
6272 final String authority = uri.getAuthority();
6273 ProviderInfo pi = null;
6274 ContentProviderRecord cpr
6275 = (ContentProviderRecord)mProvidersByName.get(authority);
6276 if (cpr != null) {
6277 pi = cpr.info;
6278 } else {
6279 try {
6280 pi = pm.resolveContentProvider(authority,
6281 PackageManager.GET_URI_PERMISSION_PATTERNS);
6282 } catch (RemoteException ex) {
6283 }
6284 }
6285 if (pi == null) {
6286 Log.w(TAG, "No content provider found for: " + authority);
6287 return;
6288 }
6289
6290 // Does the caller have this permission on the URI?
6291 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6292 // Right now, if you are not the original owner of the permission,
6293 // you are not allowed to revoke it.
6294 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6295 throw new SecurityException("Uid " + callingUid
6296 + " does not have permission to uri " + uri);
6297 //}
6298 }
6299
6300 // Go through all of the permissions and remove any that match.
6301 final List<String> SEGMENTS = uri.getPathSegments();
6302 if (SEGMENTS != null) {
6303 final int NS = SEGMENTS.size();
6304 int N = mGrantedUriPermissions.size();
6305 for (int i=0; i<N; i++) {
6306 HashMap<Uri, UriPermission> perms
6307 = mGrantedUriPermissions.valueAt(i);
6308 Iterator<UriPermission> it = perms.values().iterator();
6309 toploop:
6310 while (it.hasNext()) {
6311 UriPermission perm = it.next();
6312 Uri targetUri = perm.uri;
6313 if (!authority.equals(targetUri.getAuthority())) {
6314 continue;
6315 }
6316 List<String> targetSegments = targetUri.getPathSegments();
6317 if (targetSegments == null) {
6318 continue;
6319 }
6320 if (targetSegments.size() < NS) {
6321 continue;
6322 }
6323 for (int j=0; j<NS; j++) {
6324 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6325 continue toploop;
6326 }
6327 }
6328 perm.clearModes(modeFlags);
6329 if (perm.modeFlags == 0) {
6330 it.remove();
6331 }
6332 }
6333 if (perms.size() == 0) {
6334 mGrantedUriPermissions.remove(
6335 mGrantedUriPermissions.keyAt(i));
6336 N--;
6337 i--;
6338 }
6339 }
6340 }
6341 }
6342
6343 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6344 int modeFlags) {
6345 synchronized(this) {
6346 final ProcessRecord r = getRecordForAppLocked(caller);
6347 if (r == null) {
6348 throw new SecurityException("Unable to find app for caller "
6349 + caller
6350 + " when revoking permission to uri " + uri);
6351 }
6352 if (uri == null) {
6353 Log.w(TAG, "revokeUriPermission: null uri");
6354 return;
6355 }
6356
6357 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6358 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6359 if (modeFlags == 0) {
6360 return;
6361 }
6362
6363 final IPackageManager pm = ActivityThread.getPackageManager();
6364
6365 final String authority = uri.getAuthority();
6366 ProviderInfo pi = null;
6367 ContentProviderRecord cpr
6368 = (ContentProviderRecord)mProvidersByName.get(authority);
6369 if (cpr != null) {
6370 pi = cpr.info;
6371 } else {
6372 try {
6373 pi = pm.resolveContentProvider(authority,
6374 PackageManager.GET_URI_PERMISSION_PATTERNS);
6375 } catch (RemoteException ex) {
6376 }
6377 }
6378 if (pi == null) {
6379 Log.w(TAG, "No content provider found for: " + authority);
6380 return;
6381 }
6382
6383 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6384 }
6385 }
6386
6387 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6388 synchronized (this) {
6389 ProcessRecord app =
6390 who != null ? getRecordForAppLocked(who) : null;
6391 if (app == null) return;
6392
6393 Message msg = Message.obtain();
6394 msg.what = WAIT_FOR_DEBUGGER_MSG;
6395 msg.obj = app;
6396 msg.arg1 = waiting ? 1 : 0;
6397 mHandler.sendMessage(msg);
6398 }
6399 }
6400
6401 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6402 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006403 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006404 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006405 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006406 }
6407
6408 // =========================================================
6409 // TASK MANAGEMENT
6410 // =========================================================
6411
6412 public List getTasks(int maxNum, int flags,
6413 IThumbnailReceiver receiver) {
6414 ArrayList list = new ArrayList();
6415
6416 PendingThumbnailsRecord pending = null;
6417 IApplicationThread topThumbnail = null;
6418 HistoryRecord topRecord = null;
6419
6420 synchronized(this) {
6421 if (localLOGV) Log.v(
6422 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6423 + ", receiver=" + receiver);
6424
6425 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6426 != PackageManager.PERMISSION_GRANTED) {
6427 if (receiver != null) {
6428 // If the caller wants to wait for pending thumbnails,
6429 // it ain't gonna get them.
6430 try {
6431 receiver.finished();
6432 } catch (RemoteException ex) {
6433 }
6434 }
6435 String msg = "Permission Denial: getTasks() from pid="
6436 + Binder.getCallingPid()
6437 + ", uid=" + Binder.getCallingUid()
6438 + " requires " + android.Manifest.permission.GET_TASKS;
6439 Log.w(TAG, msg);
6440 throw new SecurityException(msg);
6441 }
6442
6443 int pos = mHistory.size()-1;
6444 HistoryRecord next =
6445 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6446 HistoryRecord top = null;
6447 CharSequence topDescription = null;
6448 TaskRecord curTask = null;
6449 int numActivities = 0;
6450 int numRunning = 0;
6451 while (pos >= 0 && maxNum > 0) {
6452 final HistoryRecord r = next;
6453 pos--;
6454 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6455
6456 // Initialize state for next task if needed.
6457 if (top == null ||
6458 (top.state == ActivityState.INITIALIZING
6459 && top.task == r.task)) {
6460 top = r;
6461 topDescription = r.description;
6462 curTask = r.task;
6463 numActivities = numRunning = 0;
6464 }
6465
6466 // Add 'r' into the current task.
6467 numActivities++;
6468 if (r.app != null && r.app.thread != null) {
6469 numRunning++;
6470 }
6471 if (topDescription == null) {
6472 topDescription = r.description;
6473 }
6474
6475 if (localLOGV) Log.v(
6476 TAG, r.intent.getComponent().flattenToShortString()
6477 + ": task=" + r.task);
6478
6479 // If the next one is a different task, generate a new
6480 // TaskInfo entry for what we have.
6481 if (next == null || next.task != curTask) {
6482 ActivityManager.RunningTaskInfo ci
6483 = new ActivityManager.RunningTaskInfo();
6484 ci.id = curTask.taskId;
6485 ci.baseActivity = r.intent.getComponent();
6486 ci.topActivity = top.intent.getComponent();
6487 ci.thumbnail = top.thumbnail;
6488 ci.description = topDescription;
6489 ci.numActivities = numActivities;
6490 ci.numRunning = numRunning;
6491 //System.out.println(
6492 // "#" + maxNum + ": " + " descr=" + ci.description);
6493 if (ci.thumbnail == null && receiver != null) {
6494 if (localLOGV) Log.v(
6495 TAG, "State=" + top.state + "Idle=" + top.idle
6496 + " app=" + top.app
6497 + " thr=" + (top.app != null ? top.app.thread : null));
6498 if (top.state == ActivityState.RESUMED
6499 || top.state == ActivityState.PAUSING) {
6500 if (top.idle && top.app != null
6501 && top.app.thread != null) {
6502 topRecord = top;
6503 topThumbnail = top.app.thread;
6504 } else {
6505 top.thumbnailNeeded = true;
6506 }
6507 }
6508 if (pending == null) {
6509 pending = new PendingThumbnailsRecord(receiver);
6510 }
6511 pending.pendingRecords.add(top);
6512 }
6513 list.add(ci);
6514 maxNum--;
6515 top = null;
6516 }
6517 }
6518
6519 if (pending != null) {
6520 mPendingThumbnails.add(pending);
6521 }
6522 }
6523
6524 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6525
6526 if (topThumbnail != null) {
6527 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6528 try {
6529 topThumbnail.requestThumbnail(topRecord);
6530 } catch (Exception e) {
6531 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6532 sendPendingThumbnail(null, topRecord, null, null, true);
6533 }
6534 }
6535
6536 if (pending == null && receiver != null) {
6537 // In this case all thumbnails were available and the client
6538 // is being asked to be told when the remaining ones come in...
6539 // which is unusually, since the top-most currently running
6540 // activity should never have a canned thumbnail! Oh well.
6541 try {
6542 receiver.finished();
6543 } catch (RemoteException ex) {
6544 }
6545 }
6546
6547 return list;
6548 }
6549
6550 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6551 int flags) {
6552 synchronized (this) {
6553 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6554 "getRecentTasks()");
6555
6556 final int N = mRecentTasks.size();
6557 ArrayList<ActivityManager.RecentTaskInfo> res
6558 = new ArrayList<ActivityManager.RecentTaskInfo>(
6559 maxNum < N ? maxNum : N);
6560 for (int i=0; i<N && maxNum > 0; i++) {
6561 TaskRecord tr = mRecentTasks.get(i);
6562 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6563 || (tr.intent == null)
6564 || ((tr.intent.getFlags()
6565 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6566 ActivityManager.RecentTaskInfo rti
6567 = new ActivityManager.RecentTaskInfo();
6568 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6569 rti.baseIntent = new Intent(
6570 tr.intent != null ? tr.intent : tr.affinityIntent);
6571 rti.origActivity = tr.origActivity;
6572 res.add(rti);
6573 maxNum--;
6574 }
6575 }
6576 return res;
6577 }
6578 }
6579
6580 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6581 int j;
6582 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6583 TaskRecord jt = startTask;
6584
6585 // First look backwards
6586 for (j=startIndex-1; j>=0; j--) {
6587 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6588 if (r.task != jt) {
6589 jt = r.task;
6590 if (affinity.equals(jt.affinity)) {
6591 return j;
6592 }
6593 }
6594 }
6595
6596 // Now look forwards
6597 final int N = mHistory.size();
6598 jt = startTask;
6599 for (j=startIndex+1; j<N; j++) {
6600 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6601 if (r.task != jt) {
6602 if (affinity.equals(jt.affinity)) {
6603 return j;
6604 }
6605 jt = r.task;
6606 }
6607 }
6608
6609 // Might it be at the top?
6610 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6611 return N-1;
6612 }
6613
6614 return -1;
6615 }
6616
6617 /**
6618 * Perform a reset of the given task, if needed as part of launching it.
6619 * Returns the new HistoryRecord at the top of the task.
6620 */
6621 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6622 HistoryRecord newActivity) {
6623 boolean forceReset = (newActivity.info.flags
6624 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6625 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6626 if ((newActivity.info.flags
6627 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6628 forceReset = true;
6629 }
6630 }
6631
6632 final TaskRecord task = taskTop.task;
6633
6634 // We are going to move through the history list so that we can look
6635 // at each activity 'target' with 'below' either the interesting
6636 // activity immediately below it in the stack or null.
6637 HistoryRecord target = null;
6638 int targetI = 0;
6639 int taskTopI = -1;
6640 int replyChainEnd = -1;
6641 int lastReparentPos = -1;
6642 for (int i=mHistory.size()-1; i>=-1; i--) {
6643 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6644
6645 if (below != null && below.finishing) {
6646 continue;
6647 }
6648 if (target == null) {
6649 target = below;
6650 targetI = i;
6651 // If we were in the middle of a reply chain before this
6652 // task, it doesn't appear like the root of the chain wants
6653 // anything interesting, so drop it.
6654 replyChainEnd = -1;
6655 continue;
6656 }
6657
6658 final int flags = target.info.flags;
6659
6660 final boolean finishOnTaskLaunch =
6661 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6662 final boolean allowTaskReparenting =
6663 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6664
6665 if (target.task == task) {
6666 // We are inside of the task being reset... we'll either
6667 // finish this activity, push it out for another task,
6668 // or leave it as-is. We only do this
6669 // for activities that are not the root of the task (since
6670 // if we finish the root, we may no longer have the task!).
6671 if (taskTopI < 0) {
6672 taskTopI = targetI;
6673 }
6674 if (below != null && below.task == task) {
6675 final boolean clearWhenTaskReset =
6676 (target.intent.getFlags()
6677 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006678 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006679 // If this activity is sending a reply to a previous
6680 // activity, we can't do anything with it now until
6681 // we reach the start of the reply chain.
6682 // XXX note that we are assuming the result is always
6683 // to the previous activity, which is almost always
6684 // the case but we really shouldn't count on.
6685 if (replyChainEnd < 0) {
6686 replyChainEnd = targetI;
6687 }
Ed Heyl73798232009-03-24 21:32:21 -07006688 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006689 && target.taskAffinity != null
6690 && !target.taskAffinity.equals(task.affinity)) {
6691 // If this activity has an affinity for another
6692 // task, then we need to move it out of here. We will
6693 // move it as far out of the way as possible, to the
6694 // bottom of the activity stack. This also keeps it
6695 // correctly ordered with any activities we previously
6696 // moved.
6697 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6698 if (target.taskAffinity != null
6699 && target.taskAffinity.equals(p.task.affinity)) {
6700 // If the activity currently at the bottom has the
6701 // same task affinity as the one we are moving,
6702 // then merge it into the same task.
6703 target.task = p.task;
6704 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6705 + " out to bottom task " + p.task);
6706 } else {
6707 mCurTask++;
6708 if (mCurTask <= 0) {
6709 mCurTask = 1;
6710 }
6711 target.task = new TaskRecord(mCurTask, target.info, null,
6712 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6713 target.task.affinityIntent = target.intent;
6714 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6715 + " out to new task " + target.task);
6716 }
6717 mWindowManager.setAppGroupId(target, task.taskId);
6718 if (replyChainEnd < 0) {
6719 replyChainEnd = targetI;
6720 }
6721 int dstPos = 0;
6722 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6723 p = (HistoryRecord)mHistory.get(srcPos);
6724 if (p.finishing) {
6725 continue;
6726 }
6727 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6728 + " out to target's task " + target.task);
6729 task.numActivities--;
6730 p.task = target.task;
6731 target.task.numActivities++;
6732 mHistory.remove(srcPos);
6733 mHistory.add(dstPos, p);
6734 mWindowManager.moveAppToken(dstPos, p);
6735 mWindowManager.setAppGroupId(p, p.task.taskId);
6736 dstPos++;
6737 if (VALIDATE_TOKENS) {
6738 mWindowManager.validateAppTokens(mHistory);
6739 }
6740 i++;
6741 }
6742 if (taskTop == p) {
6743 taskTop = below;
6744 }
6745 if (taskTopI == replyChainEnd) {
6746 taskTopI = -1;
6747 }
6748 replyChainEnd = -1;
6749 addRecentTask(target.task);
6750 } else if (forceReset || finishOnTaskLaunch
6751 || clearWhenTaskReset) {
6752 // If the activity should just be removed -- either
6753 // because it asks for it, or the task should be
6754 // cleared -- then finish it and anything that is
6755 // part of its reply chain.
6756 if (clearWhenTaskReset) {
6757 // In this case, we want to finish this activity
6758 // and everything above it, so be sneaky and pretend
6759 // like these are all in the reply chain.
6760 replyChainEnd = targetI+1;
6761 while (replyChainEnd < mHistory.size() &&
6762 ((HistoryRecord)mHistory.get(
6763 replyChainEnd)).task == task) {
6764 replyChainEnd++;
6765 }
6766 replyChainEnd--;
6767 } else if (replyChainEnd < 0) {
6768 replyChainEnd = targetI;
6769 }
6770 HistoryRecord p = null;
6771 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6772 p = (HistoryRecord)mHistory.get(srcPos);
6773 if (p.finishing) {
6774 continue;
6775 }
6776 if (finishActivityLocked(p, srcPos,
6777 Activity.RESULT_CANCELED, null, "reset")) {
6778 replyChainEnd--;
6779 srcPos--;
6780 }
6781 }
6782 if (taskTop == p) {
6783 taskTop = below;
6784 }
6785 if (taskTopI == replyChainEnd) {
6786 taskTopI = -1;
6787 }
6788 replyChainEnd = -1;
6789 } else {
6790 // If we were in the middle of a chain, well the
6791 // activity that started it all doesn't want anything
6792 // special, so leave it all as-is.
6793 replyChainEnd = -1;
6794 }
6795 } else {
6796 // Reached the bottom of the task -- any reply chain
6797 // should be left as-is.
6798 replyChainEnd = -1;
6799 }
6800
6801 } else if (target.resultTo != null) {
6802 // If this activity is sending a reply to a previous
6803 // activity, we can't do anything with it now until
6804 // we reach the start of the reply chain.
6805 // XXX note that we are assuming the result is always
6806 // to the previous activity, which is almost always
6807 // the case but we really shouldn't count on.
6808 if (replyChainEnd < 0) {
6809 replyChainEnd = targetI;
6810 }
6811
6812 } else if (taskTopI >= 0 && allowTaskReparenting
6813 && task.affinity != null
6814 && task.affinity.equals(target.taskAffinity)) {
6815 // We are inside of another task... if this activity has
6816 // an affinity for our task, then either remove it if we are
6817 // clearing or move it over to our task. Note that
6818 // we currently punt on the case where we are resetting a
6819 // task that is not at the top but who has activities above
6820 // with an affinity to it... this is really not a normal
6821 // case, and we will need to later pull that task to the front
6822 // and usually at that point we will do the reset and pick
6823 // up those remaining activities. (This only happens if
6824 // someone starts an activity in a new task from an activity
6825 // in a task that is not currently on top.)
6826 if (forceReset || finishOnTaskLaunch) {
6827 if (replyChainEnd < 0) {
6828 replyChainEnd = targetI;
6829 }
6830 HistoryRecord p = null;
6831 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6832 p = (HistoryRecord)mHistory.get(srcPos);
6833 if (p.finishing) {
6834 continue;
6835 }
6836 if (finishActivityLocked(p, srcPos,
6837 Activity.RESULT_CANCELED, null, "reset")) {
6838 taskTopI--;
6839 lastReparentPos--;
6840 replyChainEnd--;
6841 srcPos--;
6842 }
6843 }
6844 replyChainEnd = -1;
6845 } else {
6846 if (replyChainEnd < 0) {
6847 replyChainEnd = targetI;
6848 }
6849 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6850 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6851 if (p.finishing) {
6852 continue;
6853 }
6854 if (lastReparentPos < 0) {
6855 lastReparentPos = taskTopI;
6856 taskTop = p;
6857 } else {
6858 lastReparentPos--;
6859 }
6860 mHistory.remove(srcPos);
6861 p.task.numActivities--;
6862 p.task = task;
6863 mHistory.add(lastReparentPos, p);
6864 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6865 + " in to resetting task " + task);
6866 task.numActivities++;
6867 mWindowManager.moveAppToken(lastReparentPos, p);
6868 mWindowManager.setAppGroupId(p, p.task.taskId);
6869 if (VALIDATE_TOKENS) {
6870 mWindowManager.validateAppTokens(mHistory);
6871 }
6872 }
6873 replyChainEnd = -1;
6874
6875 // Now we've moved it in to place... but what if this is
6876 // a singleTop activity and we have put it on top of another
6877 // instance of the same activity? Then we drop the instance
6878 // below so it remains singleTop.
6879 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6880 for (int j=lastReparentPos-1; j>=0; j--) {
6881 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6882 if (p.finishing) {
6883 continue;
6884 }
6885 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6886 if (finishActivityLocked(p, j,
6887 Activity.RESULT_CANCELED, null, "replace")) {
6888 taskTopI--;
6889 lastReparentPos--;
6890 }
6891 }
6892 }
6893 }
6894 }
6895 }
6896
6897 target = below;
6898 targetI = i;
6899 }
6900
6901 return taskTop;
6902 }
6903
6904 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006905 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006906 */
6907 public void moveTaskToFront(int task) {
6908 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6909 "moveTaskToFront()");
6910
6911 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006912 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6913 Binder.getCallingUid(), "Task to front")) {
6914 return;
6915 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006916 final long origId = Binder.clearCallingIdentity();
6917 try {
6918 int N = mRecentTasks.size();
6919 for (int i=0; i<N; i++) {
6920 TaskRecord tr = mRecentTasks.get(i);
6921 if (tr.taskId == task) {
6922 moveTaskToFrontLocked(tr);
6923 return;
6924 }
6925 }
6926 for (int i=mHistory.size()-1; i>=0; i--) {
6927 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6928 if (hr.task.taskId == task) {
6929 moveTaskToFrontLocked(hr.task);
6930 return;
6931 }
6932 }
6933 } finally {
6934 Binder.restoreCallingIdentity(origId);
6935 }
6936 }
6937 }
6938
6939 private final void moveTaskToFrontLocked(TaskRecord tr) {
6940 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6941
6942 final int task = tr.taskId;
6943 int top = mHistory.size()-1;
6944
6945 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6946 // nothing to do!
6947 return;
6948 }
6949
6950 if (DEBUG_TRANSITION) Log.v(TAG,
6951 "Prepare to front transition: task=" + tr);
6952 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6953
6954 ArrayList moved = new ArrayList();
6955
6956 // Applying the affinities may have removed entries from the history,
6957 // so get the size again.
6958 top = mHistory.size()-1;
6959 int pos = top;
6960
6961 // Shift all activities with this task up to the top
6962 // of the stack, keeping them in the same internal order.
6963 while (pos >= 0) {
6964 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6965 if (localLOGV) Log.v(
6966 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6967 boolean first = true;
6968 if (r.task.taskId == task) {
6969 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6970 mHistory.remove(pos);
6971 mHistory.add(top, r);
6972 moved.add(0, r);
6973 top--;
6974 if (first) {
6975 addRecentTask(r.task);
6976 first = false;
6977 }
6978 }
6979 pos--;
6980 }
6981
6982 mWindowManager.moveAppTokensToTop(moved);
6983 if (VALIDATE_TOKENS) {
6984 mWindowManager.validateAppTokens(mHistory);
6985 }
6986
6987 finishTaskMove(task);
6988 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6989 }
6990
6991 private final void finishTaskMove(int task) {
6992 resumeTopActivityLocked(null);
6993 }
6994
6995 public void moveTaskToBack(int task) {
6996 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6997 "moveTaskToBack()");
6998
6999 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007000 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7001 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7002 Binder.getCallingUid(), "Task to back")) {
7003 return;
7004 }
7005 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007006 final long origId = Binder.clearCallingIdentity();
7007 moveTaskToBackLocked(task);
7008 Binder.restoreCallingIdentity(origId);
7009 }
7010 }
7011
7012 /**
7013 * Moves an activity, and all of the other activities within the same task, to the bottom
7014 * of the history stack. The activity's order within the task is unchanged.
7015 *
7016 * @param token A reference to the activity we wish to move
7017 * @param nonRoot If false then this only works if the activity is the root
7018 * of a task; if true it will work for any activity in a task.
7019 * @return Returns true if the move completed, false if not.
7020 */
7021 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7022 synchronized(this) {
7023 final long origId = Binder.clearCallingIdentity();
7024 int taskId = getTaskForActivityLocked(token, !nonRoot);
7025 if (taskId >= 0) {
7026 return moveTaskToBackLocked(taskId);
7027 }
7028 Binder.restoreCallingIdentity(origId);
7029 }
7030 return false;
7031 }
7032
7033 /**
7034 * Worker method for rearranging history stack. Implements the function of moving all
7035 * activities for a specific task (gathering them if disjoint) into a single group at the
7036 * bottom of the stack.
7037 *
7038 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7039 * to premeptively cancel the move.
7040 *
7041 * @param task The taskId to collect and move to the bottom.
7042 * @return Returns true if the move completed, false if not.
7043 */
7044 private final boolean moveTaskToBackLocked(int task) {
7045 Log.i(TAG, "moveTaskToBack: " + task);
7046
7047 // If we have a watcher, preflight the move before committing to it. First check
7048 // for *other* available tasks, but if none are available, then try again allowing the
7049 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007050 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007051 HistoryRecord next = topRunningActivityLocked(null, task);
7052 if (next == null) {
7053 next = topRunningActivityLocked(null, 0);
7054 }
7055 if (next != null) {
7056 // ask watcher if this is allowed
7057 boolean moveOK = true;
7058 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007059 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007060 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007061 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007062 }
7063 if (!moveOK) {
7064 return false;
7065 }
7066 }
7067 }
7068
7069 ArrayList moved = new ArrayList();
7070
7071 if (DEBUG_TRANSITION) Log.v(TAG,
7072 "Prepare to back transition: task=" + task);
7073 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
7074
7075 final int N = mHistory.size();
7076 int bottom = 0;
7077 int pos = 0;
7078
7079 // Shift all activities with this task down to the bottom
7080 // of the stack, keeping them in the same internal order.
7081 while (pos < N) {
7082 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7083 if (localLOGV) Log.v(
7084 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7085 if (r.task.taskId == task) {
7086 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7087 mHistory.remove(pos);
7088 mHistory.add(bottom, r);
7089 moved.add(r);
7090 bottom++;
7091 }
7092 pos++;
7093 }
7094
7095 mWindowManager.moveAppTokensToBottom(moved);
7096 if (VALIDATE_TOKENS) {
7097 mWindowManager.validateAppTokens(mHistory);
7098 }
7099
7100 finishTaskMove(task);
7101 return true;
7102 }
7103
7104 public void moveTaskBackwards(int task) {
7105 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7106 "moveTaskBackwards()");
7107
7108 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007109 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7110 Binder.getCallingUid(), "Task backwards")) {
7111 return;
7112 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007113 final long origId = Binder.clearCallingIdentity();
7114 moveTaskBackwardsLocked(task);
7115 Binder.restoreCallingIdentity(origId);
7116 }
7117 }
7118
7119 private final void moveTaskBackwardsLocked(int task) {
7120 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7121 }
7122
7123 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7124 synchronized(this) {
7125 return getTaskForActivityLocked(token, onlyRoot);
7126 }
7127 }
7128
7129 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7130 final int N = mHistory.size();
7131 TaskRecord lastTask = null;
7132 for (int i=0; i<N; i++) {
7133 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7134 if (r == token) {
7135 if (!onlyRoot || lastTask != r.task) {
7136 return r.task.taskId;
7137 }
7138 return -1;
7139 }
7140 lastTask = r.task;
7141 }
7142
7143 return -1;
7144 }
7145
7146 /**
7147 * Returns the top activity in any existing task matching the given
7148 * Intent. Returns null if no such task is found.
7149 */
7150 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7151 ComponentName cls = intent.getComponent();
7152 if (info.targetActivity != null) {
7153 cls = new ComponentName(info.packageName, info.targetActivity);
7154 }
7155
7156 TaskRecord cp = null;
7157
7158 final int N = mHistory.size();
7159 for (int i=(N-1); i>=0; i--) {
7160 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7161 if (!r.finishing && r.task != cp
7162 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7163 cp = r.task;
7164 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7165 // + "/aff=" + r.task.affinity + " to new cls="
7166 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7167 if (r.task.affinity != null) {
7168 if (r.task.affinity.equals(info.taskAffinity)) {
7169 //Log.i(TAG, "Found matching affinity!");
7170 return r;
7171 }
7172 } else if (r.task.intent != null
7173 && r.task.intent.getComponent().equals(cls)) {
7174 //Log.i(TAG, "Found matching class!");
7175 //dump();
7176 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7177 return r;
7178 } else if (r.task.affinityIntent != null
7179 && r.task.affinityIntent.getComponent().equals(cls)) {
7180 //Log.i(TAG, "Found matching class!");
7181 //dump();
7182 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7183 return r;
7184 }
7185 }
7186 }
7187
7188 return null;
7189 }
7190
7191 /**
7192 * Returns the first activity (starting from the top of the stack) that
7193 * is the same as the given activity. Returns null if no such activity
7194 * is found.
7195 */
7196 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7197 ComponentName cls = intent.getComponent();
7198 if (info.targetActivity != null) {
7199 cls = new ComponentName(info.packageName, info.targetActivity);
7200 }
7201
7202 final int N = mHistory.size();
7203 for (int i=(N-1); i>=0; i--) {
7204 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7205 if (!r.finishing) {
7206 if (r.intent.getComponent().equals(cls)) {
7207 //Log.i(TAG, "Found matching class!");
7208 //dump();
7209 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7210 return r;
7211 }
7212 }
7213 }
7214
7215 return null;
7216 }
7217
7218 public void finishOtherInstances(IBinder token, ComponentName className) {
7219 synchronized(this) {
7220 final long origId = Binder.clearCallingIdentity();
7221
7222 int N = mHistory.size();
7223 TaskRecord lastTask = null;
7224 for (int i=0; i<N; i++) {
7225 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7226 if (r.realActivity.equals(className)
7227 && r != token && lastTask != r.task) {
7228 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7229 null, "others")) {
7230 i--;
7231 N--;
7232 }
7233 }
7234 lastTask = r.task;
7235 }
7236
7237 Binder.restoreCallingIdentity(origId);
7238 }
7239 }
7240
7241 // =========================================================
7242 // THUMBNAILS
7243 // =========================================================
7244
7245 public void reportThumbnail(IBinder token,
7246 Bitmap thumbnail, CharSequence description) {
7247 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7248 final long origId = Binder.clearCallingIdentity();
7249 sendPendingThumbnail(null, token, thumbnail, description, true);
7250 Binder.restoreCallingIdentity(origId);
7251 }
7252
7253 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7254 Bitmap thumbnail, CharSequence description, boolean always) {
7255 TaskRecord task = null;
7256 ArrayList receivers = null;
7257
7258 //System.out.println("Send pending thumbnail: " + r);
7259
7260 synchronized(this) {
7261 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007262 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007263 if (index < 0) {
7264 return;
7265 }
7266 r = (HistoryRecord)mHistory.get(index);
7267 }
7268 if (thumbnail == null) {
7269 thumbnail = r.thumbnail;
7270 description = r.description;
7271 }
7272 if (thumbnail == null && !always) {
7273 // If there is no thumbnail, and this entry is not actually
7274 // going away, then abort for now and pick up the next
7275 // thumbnail we get.
7276 return;
7277 }
7278 task = r.task;
7279
7280 int N = mPendingThumbnails.size();
7281 int i=0;
7282 while (i<N) {
7283 PendingThumbnailsRecord pr =
7284 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7285 //System.out.println("Looking in " + pr.pendingRecords);
7286 if (pr.pendingRecords.remove(r)) {
7287 if (receivers == null) {
7288 receivers = new ArrayList();
7289 }
7290 receivers.add(pr);
7291 if (pr.pendingRecords.size() == 0) {
7292 pr.finished = true;
7293 mPendingThumbnails.remove(i);
7294 N--;
7295 continue;
7296 }
7297 }
7298 i++;
7299 }
7300 }
7301
7302 if (receivers != null) {
7303 final int N = receivers.size();
7304 for (int i=0; i<N; i++) {
7305 try {
7306 PendingThumbnailsRecord pr =
7307 (PendingThumbnailsRecord)receivers.get(i);
7308 pr.receiver.newThumbnail(
7309 task != null ? task.taskId : -1, thumbnail, description);
7310 if (pr.finished) {
7311 pr.receiver.finished();
7312 }
7313 } catch (Exception e) {
7314 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7315 }
7316 }
7317 }
7318 }
7319
7320 // =========================================================
7321 // CONTENT PROVIDERS
7322 // =========================================================
7323
7324 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7325 List providers = null;
7326 try {
7327 providers = ActivityThread.getPackageManager().
7328 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007329 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007330 } catch (RemoteException ex) {
7331 }
7332 if (providers != null) {
7333 final int N = providers.size();
7334 for (int i=0; i<N; i++) {
7335 ProviderInfo cpi =
7336 (ProviderInfo)providers.get(i);
7337 ContentProviderRecord cpr =
7338 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7339 if (cpr == null) {
7340 cpr = new ContentProviderRecord(cpi, app.info);
7341 mProvidersByClass.put(cpi.name, cpr);
7342 }
7343 app.pubProviders.put(cpi.name, cpr);
7344 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007345 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007346 }
7347 }
7348 return providers;
7349 }
7350
7351 private final String checkContentProviderPermissionLocked(
7352 ProviderInfo cpi, ProcessRecord r, int mode) {
7353 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7354 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7355 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7356 cpi.exported ? -1 : cpi.applicationInfo.uid)
7357 == PackageManager.PERMISSION_GRANTED
7358 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7359 return null;
7360 }
7361 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7362 cpi.exported ? -1 : cpi.applicationInfo.uid)
7363 == PackageManager.PERMISSION_GRANTED) {
7364 return null;
7365 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007366
7367 PathPermission[] pps = cpi.pathPermissions;
7368 if (pps != null) {
7369 int i = pps.length;
7370 while (i > 0) {
7371 i--;
7372 PathPermission pp = pps[i];
7373 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7374 cpi.exported ? -1 : cpi.applicationInfo.uid)
7375 == PackageManager.PERMISSION_GRANTED
7376 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7377 return null;
7378 }
7379 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7380 cpi.exported ? -1 : cpi.applicationInfo.uid)
7381 == PackageManager.PERMISSION_GRANTED) {
7382 return null;
7383 }
7384 }
7385 }
7386
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007387 String msg = "Permission Denial: opening provider " + cpi.name
7388 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7389 + ", uid=" + callingUid + ") requires "
7390 + cpi.readPermission + " or " + cpi.writePermission;
7391 Log.w(TAG, msg);
7392 return msg;
7393 }
7394
7395 private final ContentProviderHolder getContentProviderImpl(
7396 IApplicationThread caller, String name) {
7397 ContentProviderRecord cpr;
7398 ProviderInfo cpi = null;
7399
7400 synchronized(this) {
7401 ProcessRecord r = null;
7402 if (caller != null) {
7403 r = getRecordForAppLocked(caller);
7404 if (r == null) {
7405 throw new SecurityException(
7406 "Unable to find app for caller " + caller
7407 + " (pid=" + Binder.getCallingPid()
7408 + ") when getting content provider " + name);
7409 }
7410 }
7411
7412 // First check if this content provider has been published...
7413 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7414 if (cpr != null) {
7415 cpi = cpr.info;
7416 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7417 return new ContentProviderHolder(cpi,
7418 cpi.readPermission != null
7419 ? cpi.readPermission : cpi.writePermission);
7420 }
7421
7422 if (r != null && cpr.canRunHere(r)) {
7423 // This provider has been published or is in the process
7424 // of being published... but it is also allowed to run
7425 // in the caller's process, so don't make a connection
7426 // and just let the caller instantiate its own instance.
7427 if (cpr.provider != null) {
7428 // don't give caller the provider object, it needs
7429 // to make its own.
7430 cpr = new ContentProviderRecord(cpr);
7431 }
7432 return cpr;
7433 }
7434
7435 final long origId = Binder.clearCallingIdentity();
7436
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007437 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007438 // return it right away.
7439 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007440 if (DEBUG_PROVIDER) Log.v(TAG,
7441 "Adding provider requested by "
7442 + r.processName + " from process "
7443 + cpr.info.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007444 r.conProviders.add(cpr);
7445 cpr.clients.add(r);
7446 } else {
7447 cpr.externals++;
7448 }
7449
7450 if (cpr.app != null) {
7451 updateOomAdjLocked(cpr.app);
7452 }
7453
7454 Binder.restoreCallingIdentity(origId);
7455
7456 } else {
7457 try {
7458 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007459 resolveContentProvider(name,
7460 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007461 } catch (RemoteException ex) {
7462 }
7463 if (cpi == null) {
7464 return null;
7465 }
7466
7467 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7468 return new ContentProviderHolder(cpi,
7469 cpi.readPermission != null
7470 ? cpi.readPermission : cpi.writePermission);
7471 }
7472
7473 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7474 final boolean firstClass = cpr == null;
7475 if (firstClass) {
7476 try {
7477 ApplicationInfo ai =
7478 ActivityThread.getPackageManager().
7479 getApplicationInfo(
7480 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007481 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007482 if (ai == null) {
7483 Log.w(TAG, "No package info for content provider "
7484 + cpi.name);
7485 return null;
7486 }
7487 cpr = new ContentProviderRecord(cpi, ai);
7488 } catch (RemoteException ex) {
7489 // pm is in same process, this will never happen.
7490 }
7491 }
7492
7493 if (r != null && cpr.canRunHere(r)) {
7494 // If this is a multiprocess provider, then just return its
7495 // info and allow the caller to instantiate it. Only do
7496 // this if the provider is the same user as the caller's
7497 // process, or can run as root (so can be in any process).
7498 return cpr;
7499 }
7500
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007501 if (DEBUG_PROVIDER) {
7502 RuntimeException e = new RuntimeException("here");
7503 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7504 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007505 }
7506
7507 // This is single process, and our app is now connecting to it.
7508 // See if we are already in the process of launching this
7509 // provider.
7510 final int N = mLaunchingProviders.size();
7511 int i;
7512 for (i=0; i<N; i++) {
7513 if (mLaunchingProviders.get(i) == cpr) {
7514 break;
7515 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007516 }
7517
7518 // If the provider is not already being launched, then get it
7519 // started.
7520 if (i >= N) {
7521 final long origId = Binder.clearCallingIdentity();
7522 ProcessRecord proc = startProcessLocked(cpi.processName,
7523 cpr.appInfo, false, 0, "content provider",
7524 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007525 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007526 if (proc == null) {
7527 Log.w(TAG, "Unable to launch app "
7528 + cpi.applicationInfo.packageName + "/"
7529 + cpi.applicationInfo.uid + " for provider "
7530 + name + ": process is bad");
7531 return null;
7532 }
7533 cpr.launchingApp = proc;
7534 mLaunchingProviders.add(cpr);
7535 Binder.restoreCallingIdentity(origId);
7536 }
7537
7538 // Make sure the provider is published (the same provider class
7539 // may be published under multiple names).
7540 if (firstClass) {
7541 mProvidersByClass.put(cpi.name, cpr);
7542 }
7543 mProvidersByName.put(name, cpr);
7544
7545 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007546 if (DEBUG_PROVIDER) Log.v(TAG,
7547 "Adding provider requested by "
7548 + r.processName + " from process "
7549 + cpr.info.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007550 r.conProviders.add(cpr);
7551 cpr.clients.add(r);
7552 } else {
7553 cpr.externals++;
7554 }
7555 }
7556 }
7557
7558 // Wait for the provider to be published...
7559 synchronized (cpr) {
7560 while (cpr.provider == null) {
7561 if (cpr.launchingApp == null) {
7562 Log.w(TAG, "Unable to launch app "
7563 + cpi.applicationInfo.packageName + "/"
7564 + cpi.applicationInfo.uid + " for provider "
7565 + name + ": launching app became null");
7566 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7567 cpi.applicationInfo.packageName,
7568 cpi.applicationInfo.uid, name);
7569 return null;
7570 }
7571 try {
7572 cpr.wait();
7573 } catch (InterruptedException ex) {
7574 }
7575 }
7576 }
7577 return cpr;
7578 }
7579
7580 public final ContentProviderHolder getContentProvider(
7581 IApplicationThread caller, String name) {
7582 if (caller == null) {
7583 String msg = "null IApplicationThread when getting content provider "
7584 + name;
7585 Log.w(TAG, msg);
7586 throw new SecurityException(msg);
7587 }
7588
7589 return getContentProviderImpl(caller, name);
7590 }
7591
7592 private ContentProviderHolder getContentProviderExternal(String name) {
7593 return getContentProviderImpl(null, name);
7594 }
7595
7596 /**
7597 * Drop a content provider from a ProcessRecord's bookkeeping
7598 * @param cpr
7599 */
7600 public void removeContentProvider(IApplicationThread caller, String name) {
7601 synchronized (this) {
7602 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7603 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007604 // remove from mProvidersByClass
7605 if (DEBUG_PROVIDER) Log.v(TAG, name +
7606 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007607 return;
7608 }
7609 final ProcessRecord r = getRecordForAppLocked(caller);
7610 if (r == null) {
7611 throw new SecurityException(
7612 "Unable to find app for caller " + caller +
7613 " when removing content provider " + name);
7614 }
7615 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007616 ContentProviderRecord localCpr = (ContentProviderRecord)
7617 mProvidersByClass.get(cpr.info.name);
7618 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7619 + r.info.processName + " from process "
7620 + localCpr.appInfo.processName);
7621 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007622 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007623 Log.w(TAG, "removeContentProvider called on local provider: "
7624 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007625 return;
7626 } else {
7627 localCpr.clients.remove(r);
7628 r.conProviders.remove(localCpr);
7629 }
7630 updateOomAdjLocked();
7631 }
7632 }
7633
7634 private void removeContentProviderExternal(String name) {
7635 synchronized (this) {
7636 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7637 if(cpr == null) {
7638 //remove from mProvidersByClass
7639 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7640 return;
7641 }
7642
7643 //update content provider record entry info
7644 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7645 localCpr.externals--;
7646 if (localCpr.externals < 0) {
7647 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7648 }
7649 updateOomAdjLocked();
7650 }
7651 }
7652
7653 public final void publishContentProviders(IApplicationThread caller,
7654 List<ContentProviderHolder> providers) {
7655 if (providers == null) {
7656 return;
7657 }
7658
7659 synchronized(this) {
7660 final ProcessRecord r = getRecordForAppLocked(caller);
7661 if (r == null) {
7662 throw new SecurityException(
7663 "Unable to find app for caller " + caller
7664 + " (pid=" + Binder.getCallingPid()
7665 + ") when publishing content providers");
7666 }
7667
7668 final long origId = Binder.clearCallingIdentity();
7669
7670 final int N = providers.size();
7671 for (int i=0; i<N; i++) {
7672 ContentProviderHolder src = providers.get(i);
7673 if (src == null || src.info == null || src.provider == null) {
7674 continue;
7675 }
7676 ContentProviderRecord dst =
7677 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7678 if (dst != null) {
7679 mProvidersByClass.put(dst.info.name, dst);
7680 String names[] = dst.info.authority.split(";");
7681 for (int j = 0; j < names.length; j++) {
7682 mProvidersByName.put(names[j], dst);
7683 }
7684
7685 int NL = mLaunchingProviders.size();
7686 int j;
7687 for (j=0; j<NL; j++) {
7688 if (mLaunchingProviders.get(j) == dst) {
7689 mLaunchingProviders.remove(j);
7690 j--;
7691 NL--;
7692 }
7693 }
7694 synchronized (dst) {
7695 dst.provider = src.provider;
7696 dst.app = r;
7697 dst.notifyAll();
7698 }
7699 updateOomAdjLocked(r);
7700 }
7701 }
7702
7703 Binder.restoreCallingIdentity(origId);
7704 }
7705 }
7706
7707 public static final void installSystemProviders() {
7708 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7709 List providers = mSelf.generateApplicationProvidersLocked(app);
7710 mSystemThread.installSystemProviders(providers);
7711 }
7712
7713 // =========================================================
7714 // GLOBAL MANAGEMENT
7715 // =========================================================
7716
7717 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7718 ApplicationInfo info, String customProcess) {
7719 String proc = customProcess != null ? customProcess : info.processName;
7720 BatteryStatsImpl.Uid.Proc ps = null;
7721 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7722 synchronized (stats) {
7723 ps = stats.getProcessStatsLocked(info.uid, proc);
7724 }
7725 return new ProcessRecord(ps, thread, info, proc);
7726 }
7727
7728 final ProcessRecord addAppLocked(ApplicationInfo info) {
7729 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7730
7731 if (app == null) {
7732 app = newProcessRecordLocked(null, info, null);
7733 mProcessNames.put(info.processName, info.uid, app);
7734 updateLRUListLocked(app, true);
7735 }
7736
7737 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7738 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7739 app.persistent = true;
7740 app.maxAdj = CORE_SERVER_ADJ;
7741 }
7742 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7743 mPersistentStartingProcesses.add(app);
7744 startProcessLocked(app, "added application", app.processName);
7745 }
7746
7747 return app;
7748 }
7749
7750 public void unhandledBack() {
7751 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7752 "unhandledBack()");
7753
7754 synchronized(this) {
7755 int count = mHistory.size();
7756 if (Config.LOGD) Log.d(
7757 TAG, "Performing unhandledBack(): stack size = " + count);
7758 if (count > 1) {
7759 final long origId = Binder.clearCallingIdentity();
7760 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7761 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7762 Binder.restoreCallingIdentity(origId);
7763 }
7764 }
7765 }
7766
7767 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7768 String name = uri.getAuthority();
7769 ContentProviderHolder cph = getContentProviderExternal(name);
7770 ParcelFileDescriptor pfd = null;
7771 if (cph != null) {
7772 // We record the binder invoker's uid in thread-local storage before
7773 // going to the content provider to open the file. Later, in the code
7774 // that handles all permissions checks, we look for this uid and use
7775 // that rather than the Activity Manager's own uid. The effect is that
7776 // we do the check against the caller's permissions even though it looks
7777 // to the content provider like the Activity Manager itself is making
7778 // the request.
7779 sCallerIdentity.set(new Identity(
7780 Binder.getCallingPid(), Binder.getCallingUid()));
7781 try {
7782 pfd = cph.provider.openFile(uri, "r");
7783 } catch (FileNotFoundException e) {
7784 // do nothing; pfd will be returned null
7785 } finally {
7786 // Ensure that whatever happens, we clean up the identity state
7787 sCallerIdentity.remove();
7788 }
7789
7790 // We've got the fd now, so we're done with the provider.
7791 removeContentProviderExternal(name);
7792 } else {
7793 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7794 }
7795 return pfd;
7796 }
7797
7798 public void goingToSleep() {
7799 synchronized(this) {
7800 mSleeping = true;
7801 mWindowManager.setEventDispatching(false);
7802
7803 if (mResumedActivity != null) {
7804 pauseIfSleepingLocked();
7805 } else {
7806 Log.w(TAG, "goingToSleep with no resumed activity!");
7807 }
7808 }
7809 }
7810
Dianne Hackborn55280a92009-05-07 15:53:46 -07007811 public boolean shutdown(int timeout) {
7812 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7813 != PackageManager.PERMISSION_GRANTED) {
7814 throw new SecurityException("Requires permission "
7815 + android.Manifest.permission.SHUTDOWN);
7816 }
7817
7818 boolean timedout = false;
7819
7820 synchronized(this) {
7821 mShuttingDown = true;
7822 mWindowManager.setEventDispatching(false);
7823
7824 if (mResumedActivity != null) {
7825 pauseIfSleepingLocked();
7826 final long endTime = System.currentTimeMillis() + timeout;
7827 while (mResumedActivity != null || mPausingActivity != null) {
7828 long delay = endTime - System.currentTimeMillis();
7829 if (delay <= 0) {
7830 Log.w(TAG, "Activity manager shutdown timed out");
7831 timedout = true;
7832 break;
7833 }
7834 try {
7835 this.wait();
7836 } catch (InterruptedException e) {
7837 }
7838 }
7839 }
7840 }
7841
7842 mUsageStatsService.shutdown();
7843 mBatteryStatsService.shutdown();
7844
7845 return timedout;
7846 }
7847
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007848 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007849 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007850 if (!mGoingToSleep.isHeld()) {
7851 mGoingToSleep.acquire();
7852 if (mLaunchingActivity.isHeld()) {
7853 mLaunchingActivity.release();
7854 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7855 }
7856 }
7857
7858 // If we are not currently pausing an activity, get the current
7859 // one to pause. If we are pausing one, we will just let that stuff
7860 // run and release the wake lock when all done.
7861 if (mPausingActivity == null) {
7862 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7863 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7864 startPausingLocked(false, true);
7865 }
7866 }
7867 }
7868
7869 public void wakingUp() {
7870 synchronized(this) {
7871 if (mGoingToSleep.isHeld()) {
7872 mGoingToSleep.release();
7873 }
7874 mWindowManager.setEventDispatching(true);
7875 mSleeping = false;
7876 resumeTopActivityLocked(null);
7877 }
7878 }
7879
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007880 public void stopAppSwitches() {
7881 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7882 != PackageManager.PERMISSION_GRANTED) {
7883 throw new SecurityException("Requires permission "
7884 + android.Manifest.permission.STOP_APP_SWITCHES);
7885 }
7886
7887 synchronized(this) {
7888 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7889 + APP_SWITCH_DELAY_TIME;
7890 mDidAppSwitch = false;
7891 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7892 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7893 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7894 }
7895 }
7896
7897 public void resumeAppSwitches() {
7898 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7899 != PackageManager.PERMISSION_GRANTED) {
7900 throw new SecurityException("Requires permission "
7901 + android.Manifest.permission.STOP_APP_SWITCHES);
7902 }
7903
7904 synchronized(this) {
7905 // Note that we don't execute any pending app switches... we will
7906 // let those wait until either the timeout, or the next start
7907 // activity request.
7908 mAppSwitchesAllowedTime = 0;
7909 }
7910 }
7911
7912 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7913 String name) {
7914 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7915 return true;
7916 }
7917
7918 final int perm = checkComponentPermission(
7919 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7920 callingUid, -1);
7921 if (perm == PackageManager.PERMISSION_GRANTED) {
7922 return true;
7923 }
7924
7925 Log.w(TAG, name + " request from " + callingUid + " stopped");
7926 return false;
7927 }
7928
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007929 public void setDebugApp(String packageName, boolean waitForDebugger,
7930 boolean persistent) {
7931 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7932 "setDebugApp()");
7933
7934 // Note that this is not really thread safe if there are multiple
7935 // callers into it at the same time, but that's not a situation we
7936 // care about.
7937 if (persistent) {
7938 final ContentResolver resolver = mContext.getContentResolver();
7939 Settings.System.putString(
7940 resolver, Settings.System.DEBUG_APP,
7941 packageName);
7942 Settings.System.putInt(
7943 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7944 waitForDebugger ? 1 : 0);
7945 }
7946
7947 synchronized (this) {
7948 if (!persistent) {
7949 mOrigDebugApp = mDebugApp;
7950 mOrigWaitForDebugger = mWaitForDebugger;
7951 }
7952 mDebugApp = packageName;
7953 mWaitForDebugger = waitForDebugger;
7954 mDebugTransient = !persistent;
7955 if (packageName != null) {
7956 final long origId = Binder.clearCallingIdentity();
7957 uninstallPackageLocked(packageName, -1, false);
7958 Binder.restoreCallingIdentity(origId);
7959 }
7960 }
7961 }
7962
7963 public void setAlwaysFinish(boolean enabled) {
7964 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7965 "setAlwaysFinish()");
7966
7967 Settings.System.putInt(
7968 mContext.getContentResolver(),
7969 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7970
7971 synchronized (this) {
7972 mAlwaysFinishActivities = enabled;
7973 }
7974 }
7975
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007976 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007977 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007978 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007979 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007980 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007981 }
7982 }
7983
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007984 public void registerActivityWatcher(IActivityWatcher watcher) {
7985 mWatchers.register(watcher);
7986 }
7987
7988 public void unregisterActivityWatcher(IActivityWatcher watcher) {
7989 mWatchers.unregister(watcher);
7990 }
7991
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007992 public final void enterSafeMode() {
7993 synchronized(this) {
7994 // It only makes sense to do this before the system is ready
7995 // and started launching other packages.
7996 if (!mSystemReady) {
7997 try {
7998 ActivityThread.getPackageManager().enterSafeMode();
7999 } catch (RemoteException e) {
8000 }
8001
8002 View v = LayoutInflater.from(mContext).inflate(
8003 com.android.internal.R.layout.safe_mode, null);
8004 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8005 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8006 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8007 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8008 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8009 lp.format = v.getBackground().getOpacity();
8010 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8011 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8012 ((WindowManager)mContext.getSystemService(
8013 Context.WINDOW_SERVICE)).addView(v, lp);
8014 }
8015 }
8016 }
8017
8018 public void noteWakeupAlarm(IIntentSender sender) {
8019 if (!(sender instanceof PendingIntentRecord)) {
8020 return;
8021 }
8022 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8023 synchronized (stats) {
8024 if (mBatteryStatsService.isOnBattery()) {
8025 mBatteryStatsService.enforceCallingPermission();
8026 PendingIntentRecord rec = (PendingIntentRecord)sender;
8027 int MY_UID = Binder.getCallingUid();
8028 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8029 BatteryStatsImpl.Uid.Pkg pkg =
8030 stats.getPackageStatsLocked(uid, rec.key.packageName);
8031 pkg.incWakeupsLocked();
8032 }
8033 }
8034 }
8035
8036 public boolean killPidsForMemory(int[] pids) {
8037 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8038 throw new SecurityException("killPidsForMemory only available to the system");
8039 }
8040
8041 // XXX Note: don't acquire main activity lock here, because the window
8042 // manager calls in with its locks held.
8043
8044 boolean killed = false;
8045 synchronized (mPidsSelfLocked) {
8046 int[] types = new int[pids.length];
8047 int worstType = 0;
8048 for (int i=0; i<pids.length; i++) {
8049 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8050 if (proc != null) {
8051 int type = proc.setAdj;
8052 types[i] = type;
8053 if (type > worstType) {
8054 worstType = type;
8055 }
8056 }
8057 }
8058
8059 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8060 // then constrain it so we will kill all hidden procs.
8061 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8062 worstType = HIDDEN_APP_MIN_ADJ;
8063 }
8064 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8065 for (int i=0; i<pids.length; i++) {
8066 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8067 if (proc == null) {
8068 continue;
8069 }
8070 int adj = proc.setAdj;
8071 if (adj >= worstType) {
8072 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8073 + adj + ")");
8074 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
8075 proc.processName, adj);
8076 killed = true;
8077 Process.killProcess(pids[i]);
8078 }
8079 }
8080 }
8081 return killed;
8082 }
8083
8084 public void reportPss(IApplicationThread caller, int pss) {
8085 Watchdog.PssRequestor req;
8086 String name;
8087 ProcessRecord callerApp;
8088 synchronized (this) {
8089 if (caller == null) {
8090 return;
8091 }
8092 callerApp = getRecordForAppLocked(caller);
8093 if (callerApp == null) {
8094 return;
8095 }
8096 callerApp.lastPss = pss;
8097 req = callerApp;
8098 name = callerApp.processName;
8099 }
8100 Watchdog.getInstance().reportPss(req, name, pss);
8101 if (!callerApp.persistent) {
8102 removeRequestedPss(callerApp);
8103 }
8104 }
8105
8106 public void requestPss(Runnable completeCallback) {
8107 ArrayList<ProcessRecord> procs;
8108 synchronized (this) {
8109 mRequestPssCallback = completeCallback;
8110 mRequestPssList.clear();
8111 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8112 ProcessRecord proc = mLRUProcesses.get(i);
8113 if (!proc.persistent) {
8114 mRequestPssList.add(proc);
8115 }
8116 }
8117 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8118 }
8119
8120 int oldPri = Process.getThreadPriority(Process.myTid());
8121 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8122 for (int i=procs.size()-1; i>=0; i--) {
8123 ProcessRecord proc = procs.get(i);
8124 proc.lastPss = 0;
8125 proc.requestPss();
8126 }
8127 Process.setThreadPriority(oldPri);
8128 }
8129
8130 void removeRequestedPss(ProcessRecord proc) {
8131 Runnable callback = null;
8132 synchronized (this) {
8133 if (mRequestPssList.remove(proc)) {
8134 if (mRequestPssList.size() == 0) {
8135 callback = mRequestPssCallback;
8136 mRequestPssCallback = null;
8137 }
8138 }
8139 }
8140
8141 if (callback != null) {
8142 callback.run();
8143 }
8144 }
8145
8146 public void collectPss(Watchdog.PssStats stats) {
8147 stats.mEmptyPss = 0;
8148 stats.mEmptyCount = 0;
8149 stats.mBackgroundPss = 0;
8150 stats.mBackgroundCount = 0;
8151 stats.mServicePss = 0;
8152 stats.mServiceCount = 0;
8153 stats.mVisiblePss = 0;
8154 stats.mVisibleCount = 0;
8155 stats.mForegroundPss = 0;
8156 stats.mForegroundCount = 0;
8157 stats.mNoPssCount = 0;
8158 synchronized (this) {
8159 int i;
8160 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8161 ? mProcDeaths.length : stats.mProcDeaths.length;
8162 int aggr = 0;
8163 for (i=0; i<NPD; i++) {
8164 aggr += mProcDeaths[i];
8165 stats.mProcDeaths[i] = aggr;
8166 }
8167 while (i<stats.mProcDeaths.length) {
8168 stats.mProcDeaths[i] = 0;
8169 i++;
8170 }
8171
8172 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8173 ProcessRecord proc = mLRUProcesses.get(i);
8174 if (proc.persistent) {
8175 continue;
8176 }
8177 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8178 if (proc.lastPss == 0) {
8179 stats.mNoPssCount++;
8180 continue;
8181 }
8182 if (proc.setAdj == EMPTY_APP_ADJ) {
8183 stats.mEmptyPss += proc.lastPss;
8184 stats.mEmptyCount++;
8185 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8186 stats.mEmptyPss += proc.lastPss;
8187 stats.mEmptyCount++;
8188 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8189 stats.mBackgroundPss += proc.lastPss;
8190 stats.mBackgroundCount++;
8191 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8192 stats.mVisiblePss += proc.lastPss;
8193 stats.mVisibleCount++;
8194 } else {
8195 stats.mForegroundPss += proc.lastPss;
8196 stats.mForegroundCount++;
8197 }
8198 }
8199 }
8200 }
8201
8202 public final void startRunning(String pkg, String cls, String action,
8203 String data) {
8204 synchronized(this) {
8205 if (mStartRunning) {
8206 return;
8207 }
8208 mStartRunning = true;
8209 mTopComponent = pkg != null && cls != null
8210 ? new ComponentName(pkg, cls) : null;
8211 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8212 mTopData = data;
8213 if (!mSystemReady) {
8214 return;
8215 }
8216 }
8217
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008218 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008219 }
8220
8221 private void retrieveSettings() {
8222 final ContentResolver resolver = mContext.getContentResolver();
8223 String debugApp = Settings.System.getString(
8224 resolver, Settings.System.DEBUG_APP);
8225 boolean waitForDebugger = Settings.System.getInt(
8226 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8227 boolean alwaysFinishActivities = Settings.System.getInt(
8228 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8229
8230 Configuration configuration = new Configuration();
8231 Settings.System.getConfiguration(resolver, configuration);
8232
8233 synchronized (this) {
8234 mDebugApp = mOrigDebugApp = debugApp;
8235 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8236 mAlwaysFinishActivities = alwaysFinishActivities;
8237 // This happens before any activities are started, so we can
8238 // change mConfiguration in-place.
8239 mConfiguration.updateFrom(configuration);
8240 }
8241 }
8242
8243 public boolean testIsSystemReady() {
8244 // no need to synchronize(this) just to read & return the value
8245 return mSystemReady;
8246 }
8247
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008248 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008249 // In the simulator, startRunning will never have been called, which
8250 // normally sets a few crucial variables. Do it here instead.
8251 if (!Process.supportsProcesses()) {
8252 mStartRunning = true;
8253 mTopAction = Intent.ACTION_MAIN;
8254 }
8255
8256 synchronized(this) {
8257 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008258 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008259 return;
8260 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008261
8262 // Check to see if there are any update receivers to run.
8263 if (!mDidUpdate) {
8264 if (mWaitingUpdate) {
8265 return;
8266 }
8267 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8268 List<ResolveInfo> ris = null;
8269 try {
8270 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8271 intent, null, 0);
8272 } catch (RemoteException e) {
8273 }
8274 if (ris != null) {
8275 for (int i=ris.size()-1; i>=0; i--) {
8276 if ((ris.get(i).activityInfo.applicationInfo.flags
8277 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8278 ris.remove(i);
8279 }
8280 }
8281 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8282 for (int i=0; i<ris.size(); i++) {
8283 ActivityInfo ai = ris.get(i).activityInfo;
8284 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8285 IIntentReceiver finisher = null;
8286 if (i == 0) {
8287 finisher = new IIntentReceiver.Stub() {
8288 public void performReceive(Intent intent, int resultCode,
8289 String data, Bundle extras, boolean ordered)
8290 throws RemoteException {
8291 synchronized (ActivityManagerService.this) {
8292 mDidUpdate = true;
8293 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008294 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008295 }
8296 };
8297 }
8298 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8299 broadcastIntentLocked(null, null, intent, null, finisher,
8300 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8301 if (i == 0) {
8302 mWaitingUpdate = true;
8303 }
8304 }
8305 }
8306 if (mWaitingUpdate) {
8307 return;
8308 }
8309 mDidUpdate = true;
8310 }
8311
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008312 mSystemReady = true;
8313 if (!mStartRunning) {
8314 return;
8315 }
8316 }
8317
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008318 ArrayList<ProcessRecord> procsToKill = null;
8319 synchronized(mPidsSelfLocked) {
8320 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8321 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8322 if (!isAllowedWhileBooting(proc.info)){
8323 if (procsToKill == null) {
8324 procsToKill = new ArrayList<ProcessRecord>();
8325 }
8326 procsToKill.add(proc);
8327 }
8328 }
8329 }
8330
8331 if (procsToKill != null) {
8332 synchronized(this) {
8333 for (int i=procsToKill.size()-1; i>=0; i--) {
8334 ProcessRecord proc = procsToKill.get(i);
8335 Log.i(TAG, "Removing system update proc: " + proc);
8336 removeProcessLocked(proc, true);
8337 }
8338 }
8339 }
8340
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008341 Log.i(TAG, "System now ready");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008342 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8343 SystemClock.uptimeMillis());
8344
8345 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008346 // Make sure we have no pre-ready processes sitting around.
8347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008348 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8349 ResolveInfo ri = mContext.getPackageManager()
8350 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008351 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008352 CharSequence errorMsg = null;
8353 if (ri != null) {
8354 ActivityInfo ai = ri.activityInfo;
8355 ApplicationInfo app = ai.applicationInfo;
8356 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8357 mTopAction = Intent.ACTION_FACTORY_TEST;
8358 mTopData = null;
8359 mTopComponent = new ComponentName(app.packageName,
8360 ai.name);
8361 } else {
8362 errorMsg = mContext.getResources().getText(
8363 com.android.internal.R.string.factorytest_not_system);
8364 }
8365 } else {
8366 errorMsg = mContext.getResources().getText(
8367 com.android.internal.R.string.factorytest_no_action);
8368 }
8369 if (errorMsg != null) {
8370 mTopAction = null;
8371 mTopData = null;
8372 mTopComponent = null;
8373 Message msg = Message.obtain();
8374 msg.what = SHOW_FACTORY_ERROR_MSG;
8375 msg.getData().putCharSequence("msg", errorMsg);
8376 mHandler.sendMessage(msg);
8377 }
8378 }
8379 }
8380
8381 retrieveSettings();
8382
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008383 if (goingCallback != null) goingCallback.run();
8384
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008385 synchronized (this) {
8386 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8387 try {
8388 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008389 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008390 if (apps != null) {
8391 int N = apps.size();
8392 int i;
8393 for (i=0; i<N; i++) {
8394 ApplicationInfo info
8395 = (ApplicationInfo)apps.get(i);
8396 if (info != null &&
8397 !info.packageName.equals("android")) {
8398 addAppLocked(info);
8399 }
8400 }
8401 }
8402 } catch (RemoteException ex) {
8403 // pm is in same process, this will never happen.
8404 }
8405 }
8406
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008407 // Start up initial activity.
8408 mBooting = true;
8409
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008410 try {
8411 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8412 Message msg = Message.obtain();
8413 msg.what = SHOW_UID_ERROR_MSG;
8414 mHandler.sendMessage(msg);
8415 }
8416 } catch (RemoteException e) {
8417 }
8418
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008419 resumeTopActivityLocked(null);
8420 }
8421 }
8422
8423 boolean makeAppCrashingLocked(ProcessRecord app,
8424 String tag, String shortMsg, String longMsg, byte[] crashData) {
8425 app.crashing = true;
8426 app.crashingReport = generateProcessError(app,
8427 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8428 startAppProblemLocked(app);
8429 app.stopFreezingAllLocked();
8430 return handleAppCrashLocked(app);
8431 }
8432
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008433 private ComponentName getErrorReportReceiver(ProcessRecord app) {
8434 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008435
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008436 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008437 // look for receiver in the installer package
8438 String candidate = pm.getInstallerPackageName(app.info.packageName);
8439 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8440 if (result != null) {
8441 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008442 }
8443
Jacek Surazski82a73df2009-06-17 14:33:18 +02008444 // if the error app is on the system image, look for system apps
8445 // error receiver
8446 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8447 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8448 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8449 if (result != null) {
8450 return result;
8451 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008452 }
8453
Jacek Surazski82a73df2009-06-17 14:33:18 +02008454 // if there is a default receiver, try that
8455 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8456 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008457 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008458 // should not happen
8459 Log.e(TAG, "error talking to PackageManager", e);
8460 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008461 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008462 }
8463
8464 /**
8465 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8466 *
8467 * @param pm PackageManager isntance
8468 * @param errorPackage package which caused the error
8469 * @param receiverPackage candidate package to receive the error
8470 * @return activity component within receiverPackage which handles
8471 * ACTION_APP_ERROR, or null if not found
8472 */
8473 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8474 String receiverPackage) throws RemoteException {
8475 if (receiverPackage == null || receiverPackage.length() == 0) {
8476 return null;
8477 }
8478
8479 // break the loop if it's the error report receiver package that crashed
8480 if (receiverPackage.equals(errorPackage)) {
8481 return null;
8482 }
8483
8484 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8485 intent.setPackage(receiverPackage);
8486 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8487 if (info == null || info.activityInfo == null) {
8488 return null;
8489 }
8490 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008491 }
8492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008493 void makeAppNotRespondingLocked(ProcessRecord app,
8494 String tag, String shortMsg, String longMsg, byte[] crashData) {
8495 app.notResponding = true;
8496 app.notRespondingReport = generateProcessError(app,
8497 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8498 crashData);
8499 startAppProblemLocked(app);
8500 app.stopFreezingAllLocked();
8501 }
8502
8503 /**
8504 * Generate a process error record, suitable for attachment to a ProcessRecord.
8505 *
8506 * @param app The ProcessRecord in which the error occurred.
8507 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8508 * ActivityManager.AppErrorStateInfo
8509 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8510 * @param shortMsg Short message describing the crash.
8511 * @param longMsg Long message describing the crash.
8512 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8513 *
8514 * @return Returns a fully-formed AppErrorStateInfo record.
8515 */
8516 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8517 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8518 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8519
8520 report.condition = condition;
8521 report.processName = app.processName;
8522 report.pid = app.pid;
8523 report.uid = app.info.uid;
8524 report.tag = tag;
8525 report.shortMsg = shortMsg;
8526 report.longMsg = longMsg;
8527 report.crashData = crashData;
8528
8529 return report;
8530 }
8531
8532 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8533 boolean crashed) {
8534 synchronized (this) {
8535 app.crashing = false;
8536 app.crashingReport = null;
8537 app.notResponding = false;
8538 app.notRespondingReport = null;
8539 if (app.anrDialog == fromDialog) {
8540 app.anrDialog = null;
8541 }
8542 if (app.waitDialog == fromDialog) {
8543 app.waitDialog = null;
8544 }
8545 if (app.pid > 0 && app.pid != MY_PID) {
8546 if (crashed) {
8547 handleAppCrashLocked(app);
8548 }
8549 Log.i(ActivityManagerService.TAG, "Killing process "
8550 + app.processName
8551 + " (pid=" + app.pid + ") at user's request");
8552 Process.killProcess(app.pid);
8553 }
8554
8555 }
8556 }
8557
8558 boolean handleAppCrashLocked(ProcessRecord app) {
8559 long now = SystemClock.uptimeMillis();
8560
8561 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8562 app.info.uid);
8563 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8564 // This process loses!
8565 Log.w(TAG, "Process " + app.info.processName
8566 + " has crashed too many times: killing!");
8567 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8568 app.info.processName, app.info.uid);
8569 killServicesLocked(app, false);
8570 for (int i=mHistory.size()-1; i>=0; i--) {
8571 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8572 if (r.app == app) {
8573 if (Config.LOGD) Log.d(
8574 TAG, " Force finishing activity "
8575 + r.intent.getComponent().flattenToShortString());
8576 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8577 }
8578 }
8579 if (!app.persistent) {
8580 // We don't want to start this process again until the user
8581 // explicitly does so... but for persistent process, we really
8582 // need to keep it running. If a persistent process is actually
8583 // repeatedly crashing, then badness for everyone.
8584 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8585 app.info.processName);
8586 mBadProcesses.put(app.info.processName, app.info.uid, now);
8587 app.bad = true;
8588 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8589 app.removed = true;
8590 removeProcessLocked(app, false);
8591 return false;
8592 }
8593 }
8594
8595 // Bump up the crash count of any services currently running in the proc.
8596 if (app.services.size() != 0) {
8597 // Any services running in the application need to be placed
8598 // back in the pending list.
8599 Iterator it = app.services.iterator();
8600 while (it.hasNext()) {
8601 ServiceRecord sr = (ServiceRecord)it.next();
8602 sr.crashCount++;
8603 }
8604 }
8605
8606 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8607 return true;
8608 }
8609
8610 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008611 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008612 skipCurrentReceiverLocked(app);
8613 }
8614
8615 void skipCurrentReceiverLocked(ProcessRecord app) {
8616 boolean reschedule = false;
8617 BroadcastRecord r = app.curReceiver;
8618 if (r != null) {
8619 // The current broadcast is waiting for this app's receiver
8620 // to be finished. Looks like that's not going to happen, so
8621 // let the broadcast continue.
8622 logBroadcastReceiverDiscard(r);
8623 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8624 r.resultExtras, r.resultAbort, true);
8625 reschedule = true;
8626 }
8627 r = mPendingBroadcast;
8628 if (r != null && r.curApp == app) {
8629 if (DEBUG_BROADCAST) Log.v(TAG,
8630 "skip & discard pending app " + r);
8631 logBroadcastReceiverDiscard(r);
8632 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8633 r.resultExtras, r.resultAbort, true);
8634 reschedule = true;
8635 }
8636 if (reschedule) {
8637 scheduleBroadcastsLocked();
8638 }
8639 }
8640
8641 public int handleApplicationError(IBinder app, int flags,
8642 String tag, String shortMsg, String longMsg, byte[] crashData) {
8643 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008644 ProcessRecord r = null;
8645 synchronized (this) {
8646 if (app != null) {
8647 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8648 final int NA = apps.size();
8649 for (int ia=0; ia<NA; ia++) {
8650 ProcessRecord p = apps.valueAt(ia);
8651 if (p.thread != null && p.thread.asBinder() == app) {
8652 r = p;
8653 break;
8654 }
8655 }
8656 }
8657 }
8658
8659 if (r != null) {
8660 // The application has crashed. Send the SIGQUIT to the process so
8661 // that it can dump its state.
8662 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8663 //Log.i(TAG, "Current system threads:");
8664 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8665 }
8666
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008667 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008668 try {
8669 String name = r != null ? r.processName : null;
8670 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008671 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008672 shortMsg, longMsg, crashData)) {
8673 Log.w(TAG, "Force-killing crashed app " + name
8674 + " at watcher's request");
8675 Process.killProcess(pid);
8676 return 0;
8677 }
8678 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008679 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008680 }
8681 }
8682
8683 final long origId = Binder.clearCallingIdentity();
8684
8685 // If this process is running instrumentation, finish it.
8686 if (r != null && r.instrumentationClass != null) {
8687 Log.w(TAG, "Error in app " + r.processName
8688 + " running instrumentation " + r.instrumentationClass + ":");
8689 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8690 if (longMsg != null) Log.w(TAG, " " + longMsg);
8691 Bundle info = new Bundle();
8692 info.putString("shortMsg", shortMsg);
8693 info.putString("longMsg", longMsg);
8694 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8695 Binder.restoreCallingIdentity(origId);
8696 return 0;
8697 }
8698
8699 if (r != null) {
8700 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8701 return 0;
8702 }
8703 } else {
8704 Log.w(TAG, "Some application object " + app + " tag " + tag
8705 + " has crashed, but I don't know who it is.");
8706 Log.w(TAG, "ShortMsg:" + shortMsg);
8707 Log.w(TAG, "LongMsg:" + longMsg);
8708 Binder.restoreCallingIdentity(origId);
8709 return 0;
8710 }
8711
8712 Message msg = Message.obtain();
8713 msg.what = SHOW_ERROR_MSG;
8714 HashMap data = new HashMap();
8715 data.put("result", result);
8716 data.put("app", r);
8717 data.put("flags", flags);
8718 data.put("shortMsg", shortMsg);
8719 data.put("longMsg", longMsg);
8720 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8721 // For system processes, submit crash data to the server.
8722 data.put("crashData", crashData);
8723 }
8724 msg.obj = data;
8725 mHandler.sendMessage(msg);
8726
8727 Binder.restoreCallingIdentity(origId);
8728 }
8729
8730 int res = result.get();
8731
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008732 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008733 synchronized (this) {
8734 if (r != null) {
8735 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8736 SystemClock.uptimeMillis());
8737 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008738 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8739 appErrorIntent = createAppErrorIntentLocked(r);
8740 res = AppErrorDialog.FORCE_QUIT;
8741 }
8742 }
8743
8744 if (appErrorIntent != null) {
8745 try {
8746 mContext.startActivity(appErrorIntent);
8747 } catch (ActivityNotFoundException e) {
8748 Log.w(TAG, "bug report receiver dissappeared", e);
8749 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008750 }
8751
8752 return res;
8753 }
8754
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008755 Intent createAppErrorIntentLocked(ProcessRecord r) {
8756 ApplicationErrorReport report = createAppErrorReportLocked(r);
8757 if (report == null) {
8758 return null;
8759 }
8760 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8761 result.setComponent(r.errorReportReceiver);
8762 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8763 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8764 return result;
8765 }
8766
8767 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8768 if (r.errorReportReceiver == null) {
8769 return null;
8770 }
8771
8772 if (!r.crashing && !r.notResponding) {
8773 return null;
8774 }
8775
8776 try {
8777 ApplicationErrorReport report = new ApplicationErrorReport();
8778 report.packageName = r.info.packageName;
8779 report.installerPackageName = r.errorReportReceiver.getPackageName();
8780 report.processName = r.processName;
8781
8782 if (r.crashing) {
8783 report.type = ApplicationErrorReport.TYPE_CRASH;
8784 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8785
8786 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8787 r.crashingReport.crashData);
8788 DataInputStream dataStream = new DataInputStream(byteStream);
8789 CrashData crashData = new CrashData(dataStream);
8790 ThrowableData throwData = crashData.getThrowableData();
8791
8792 report.time = crashData.getTime();
8793 report.crashInfo.stackTrace = throwData.toString();
8794
Jacek Surazskif829a782009-06-11 22:47:02 +02008795 // Extract the source of the exception, useful for report
8796 // clustering. Also extract the "deepest" non-null exception
8797 // message.
8798 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008799 while (throwData.getCause() != null) {
8800 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008801 String msg = throwData.getMessage();
8802 if (msg != null && msg.length() > 0) {
8803 exceptionMessage = msg;
8804 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008805 }
8806 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008807 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008808 report.crashInfo.exceptionClassName = throwData.getType();
8809 report.crashInfo.throwFileName = trace.getFileName();
8810 report.crashInfo.throwClassName = trace.getClassName();
8811 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008812 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008813 } else if (r.notResponding) {
8814 report.type = ApplicationErrorReport.TYPE_ANR;
8815 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8816
8817 report.anrInfo.activity = r.notRespondingReport.tag;
8818 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8819 report.anrInfo.info = r.notRespondingReport.longMsg;
8820 }
8821
8822 return report;
8823 } catch (IOException e) {
8824 // we don't send it
8825 }
8826
8827 return null;
8828 }
8829
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008830 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8831 // assume our apps are happy - lazy create the list
8832 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8833
8834 synchronized (this) {
8835
8836 // iterate across all processes
8837 final int N = mLRUProcesses.size();
8838 for (int i = 0; i < N; i++) {
8839 ProcessRecord app = mLRUProcesses.get(i);
8840 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8841 // This one's in trouble, so we'll generate a report for it
8842 // crashes are higher priority (in case there's a crash *and* an anr)
8843 ActivityManager.ProcessErrorStateInfo report = null;
8844 if (app.crashing) {
8845 report = app.crashingReport;
8846 } else if (app.notResponding) {
8847 report = app.notRespondingReport;
8848 }
8849
8850 if (report != null) {
8851 if (errList == null) {
8852 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8853 }
8854 errList.add(report);
8855 } else {
8856 Log.w(TAG, "Missing app error report, app = " + app.processName +
8857 " crashing = " + app.crashing +
8858 " notResponding = " + app.notResponding);
8859 }
8860 }
8861 }
8862 }
8863
8864 return errList;
8865 }
8866
8867 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8868 // Lazy instantiation of list
8869 List<ActivityManager.RunningAppProcessInfo> runList = null;
8870 synchronized (this) {
8871 // Iterate across all processes
8872 final int N = mLRUProcesses.size();
8873 for (int i = 0; i < N; i++) {
8874 ProcessRecord app = mLRUProcesses.get(i);
8875 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8876 // Generate process state info for running application
8877 ActivityManager.RunningAppProcessInfo currApp =
8878 new ActivityManager.RunningAppProcessInfo(app.processName,
8879 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07008880 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008881 int adj = app.curAdj;
8882 if (adj >= CONTENT_PROVIDER_ADJ) {
8883 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8884 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8885 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008886 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8887 } else if (adj >= HOME_APP_ADJ) {
8888 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8889 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008890 } else if (adj >= SECONDARY_SERVER_ADJ) {
8891 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8892 } else if (adj >= VISIBLE_APP_ADJ) {
8893 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8894 } else {
8895 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8896 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07008897 currApp.importanceReasonCode = app.adjTypeCode;
8898 if (app.adjSource instanceof ProcessRecord) {
8899 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
8900 } else if (app.adjSource instanceof HistoryRecord) {
8901 HistoryRecord r = (HistoryRecord)app.adjSource;
8902 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
8903 }
8904 if (app.adjTarget instanceof ComponentName) {
8905 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
8906 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008907 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8908 // + " lru=" + currApp.lru);
8909 if (runList == null) {
8910 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8911 }
8912 runList.add(currApp);
8913 }
8914 }
8915 }
8916 return runList;
8917 }
8918
8919 @Override
8920 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8921 synchronized (this) {
8922 if (checkCallingPermission(android.Manifest.permission.DUMP)
8923 != PackageManager.PERMISSION_GRANTED) {
8924 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8925 + Binder.getCallingPid()
8926 + ", uid=" + Binder.getCallingUid()
8927 + " without permission "
8928 + android.Manifest.permission.DUMP);
8929 return;
8930 }
8931 if (args.length != 0 && "service".equals(args[0])) {
8932 dumpService(fd, pw, args);
8933 return;
8934 }
8935 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008936 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008937 pw.println(" ");
8938 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008939 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008940 if (mWaitingVisibleActivities.size() > 0) {
8941 pw.println(" ");
8942 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008943 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008944 }
8945 if (mStoppingActivities.size() > 0) {
8946 pw.println(" ");
8947 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008948 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008949 }
8950 if (mFinishingActivities.size() > 0) {
8951 pw.println(" ");
8952 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008953 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008954 }
8955
8956 pw.println(" ");
8957 pw.println(" mPausingActivity: " + mPausingActivity);
8958 pw.println(" mResumedActivity: " + mResumedActivity);
8959 pw.println(" mFocusedActivity: " + mFocusedActivity);
8960 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8961
8962 if (mRecentTasks.size() > 0) {
8963 pw.println(" ");
8964 pw.println("Recent tasks in Current Activity Manager State:");
8965
8966 final int N = mRecentTasks.size();
8967 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008968 TaskRecord tr = mRecentTasks.get(i);
8969 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8970 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008971 mRecentTasks.get(i).dump(pw, " ");
8972 }
8973 }
8974
8975 pw.println(" ");
8976 pw.println(" mCurTask: " + mCurTask);
8977
8978 pw.println(" ");
8979 pw.println("Processes in Current Activity Manager State:");
8980
8981 boolean needSep = false;
8982 int numPers = 0;
8983
8984 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8985 final int NA = procs.size();
8986 for (int ia=0; ia<NA; ia++) {
8987 if (!needSep) {
8988 pw.println(" All known processes:");
8989 needSep = true;
8990 }
8991 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008992 pw.print(r.persistent ? " *PERS*" : " *APP*");
8993 pw.print(" UID "); pw.print(procs.keyAt(ia));
8994 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008995 r.dump(pw, " ");
8996 if (r.persistent) {
8997 numPers++;
8998 }
8999 }
9000 }
9001
9002 if (mLRUProcesses.size() > 0) {
9003 if (needSep) pw.println(" ");
9004 needSep = true;
9005 pw.println(" Running processes (most recent first):");
9006 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009007 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009008 needSep = true;
9009 }
9010
9011 synchronized (mPidsSelfLocked) {
9012 if (mPidsSelfLocked.size() > 0) {
9013 if (needSep) pw.println(" ");
9014 needSep = true;
9015 pw.println(" PID mappings:");
9016 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009017 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9018 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009019 }
9020 }
9021 }
9022
9023 if (mForegroundProcesses.size() > 0) {
9024 if (needSep) pw.println(" ");
9025 needSep = true;
9026 pw.println(" Foreground Processes:");
9027 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009028 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9029 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009030 }
9031 }
9032
9033 if (mPersistentStartingProcesses.size() > 0) {
9034 if (needSep) pw.println(" ");
9035 needSep = true;
9036 pw.println(" Persisent processes that are starting:");
9037 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009038 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009039 }
9040
9041 if (mStartingProcesses.size() > 0) {
9042 if (needSep) pw.println(" ");
9043 needSep = true;
9044 pw.println(" Processes that are starting:");
9045 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009046 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009047 }
9048
9049 if (mRemovedProcesses.size() > 0) {
9050 if (needSep) pw.println(" ");
9051 needSep = true;
9052 pw.println(" Processes that are being removed:");
9053 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009054 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009055 }
9056
9057 if (mProcessesOnHold.size() > 0) {
9058 if (needSep) pw.println(" ");
9059 needSep = true;
9060 pw.println(" Processes that are on old until the system is ready:");
9061 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009062 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009063 }
9064
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009065 if (mProcessesToGc.size() > 0) {
9066 if (needSep) pw.println(" ");
9067 needSep = true;
9068 pw.println(" Processes that are waiting to GC:");
9069 long now = SystemClock.uptimeMillis();
9070 for (int i=0; i<mProcessesToGc.size(); i++) {
9071 ProcessRecord proc = mProcessesToGc.get(i);
9072 pw.print(" Process "); pw.println(proc);
9073 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9074 pw.print(", last gced=");
9075 pw.print(now-proc.lastRequestedGc);
9076 pw.print(" ms ago, last lowMwm=");
9077 pw.print(now-proc.lastLowMemory);
9078 pw.println(" ms ago");
9079
9080 }
9081 }
9082
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009083 if (mProcessCrashTimes.getMap().size() > 0) {
9084 if (needSep) pw.println(" ");
9085 needSep = true;
9086 pw.println(" Time since processes crashed:");
9087 long now = SystemClock.uptimeMillis();
9088 for (Map.Entry<String, SparseArray<Long>> procs
9089 : mProcessCrashTimes.getMap().entrySet()) {
9090 SparseArray<Long> uids = procs.getValue();
9091 final int N = uids.size();
9092 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009093 pw.print(" Process "); pw.print(procs.getKey());
9094 pw.print(" uid "); pw.print(uids.keyAt(i));
9095 pw.print(": last crashed ");
9096 pw.print((now-uids.valueAt(i)));
9097 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009098 }
9099 }
9100 }
9101
9102 if (mBadProcesses.getMap().size() > 0) {
9103 if (needSep) pw.println(" ");
9104 needSep = true;
9105 pw.println(" Bad processes:");
9106 for (Map.Entry<String, SparseArray<Long>> procs
9107 : mBadProcesses.getMap().entrySet()) {
9108 SparseArray<Long> uids = procs.getValue();
9109 final int N = uids.size();
9110 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009111 pw.print(" Bad process "); pw.print(procs.getKey());
9112 pw.print(" uid "); pw.print(uids.keyAt(i));
9113 pw.print(": crashed at time ");
9114 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009115 }
9116 }
9117 }
9118
9119 pw.println(" ");
9120 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009121 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009122 pw.println(" mConfiguration: " + mConfiguration);
9123 pw.println(" mStartRunning=" + mStartRunning
9124 + " mSystemReady=" + mSystemReady
9125 + " mBooting=" + mBooting
9126 + " mBooted=" + mBooted
9127 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009128 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009129 pw.println(" mGoingToSleep=" + mGoingToSleep);
9130 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9131 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9132 + " mDebugTransient=" + mDebugTransient
9133 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9134 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009135 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009136 }
9137 }
9138
9139 /**
9140 * There are three ways to call this:
9141 * - no service specified: dump all the services
9142 * - a flattened component name that matched an existing service was specified as the
9143 * first arg: dump that one service
9144 * - the first arg isn't the flattened component name of an existing service:
9145 * dump all services whose component contains the first arg as a substring
9146 */
9147 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9148 String[] newArgs;
9149 String componentNameString;
9150 ServiceRecord r;
9151 if (args.length == 1) {
9152 componentNameString = null;
9153 newArgs = EMPTY_STRING_ARRAY;
9154 r = null;
9155 } else {
9156 componentNameString = args[1];
9157 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9158 r = componentName != null ? mServices.get(componentName) : null;
9159 newArgs = new String[args.length - 2];
9160 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9161 }
9162
9163 if (r != null) {
9164 dumpService(fd, pw, r, newArgs);
9165 } else {
9166 for (ServiceRecord r1 : mServices.values()) {
9167 if (componentNameString == null
9168 || r1.name.flattenToString().contains(componentNameString)) {
9169 dumpService(fd, pw, r1, newArgs);
9170 }
9171 }
9172 }
9173 }
9174
9175 /**
9176 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9177 * there is a thread associated with the service.
9178 */
9179 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9180 pw.println(" Service " + r.name.flattenToString());
9181 if (r.app != null && r.app.thread != null) {
9182 try {
9183 // flush anything that is already in the PrintWriter since the thread is going
9184 // to write to the file descriptor directly
9185 pw.flush();
9186 r.app.thread.dumpService(fd, r, args);
9187 pw.print("\n");
9188 } catch (RemoteException e) {
9189 pw.println("got a RemoteException while dumping the service");
9190 }
9191 }
9192 }
9193
9194 void dumpBroadcasts(PrintWriter pw) {
9195 synchronized (this) {
9196 if (checkCallingPermission(android.Manifest.permission.DUMP)
9197 != PackageManager.PERMISSION_GRANTED) {
9198 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9199 + Binder.getCallingPid()
9200 + ", uid=" + Binder.getCallingUid()
9201 + " without permission "
9202 + android.Manifest.permission.DUMP);
9203 return;
9204 }
9205 pw.println("Broadcasts in Current Activity Manager State:");
9206
9207 if (mRegisteredReceivers.size() > 0) {
9208 pw.println(" ");
9209 pw.println(" Registered Receivers:");
9210 Iterator it = mRegisteredReceivers.values().iterator();
9211 while (it.hasNext()) {
9212 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009213 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009214 r.dump(pw, " ");
9215 }
9216 }
9217
9218 pw.println(" ");
9219 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009220 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009221
9222 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9223 || mPendingBroadcast != null) {
9224 if (mParallelBroadcasts.size() > 0) {
9225 pw.println(" ");
9226 pw.println(" Active broadcasts:");
9227 }
9228 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9229 pw.println(" Broadcast #" + i + ":");
9230 mParallelBroadcasts.get(i).dump(pw, " ");
9231 }
9232 if (mOrderedBroadcasts.size() > 0) {
9233 pw.println(" ");
9234 pw.println(" Active serialized broadcasts:");
9235 }
9236 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9237 pw.println(" Serialized Broadcast #" + i + ":");
9238 mOrderedBroadcasts.get(i).dump(pw, " ");
9239 }
9240 pw.println(" ");
9241 pw.println(" Pending broadcast:");
9242 if (mPendingBroadcast != null) {
9243 mPendingBroadcast.dump(pw, " ");
9244 } else {
9245 pw.println(" (null)");
9246 }
9247 }
9248
9249 pw.println(" ");
9250 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9251 if (mStickyBroadcasts != null) {
9252 pw.println(" ");
9253 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009254 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009255 for (Map.Entry<String, ArrayList<Intent>> ent
9256 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009257 pw.print(" * Sticky action "); pw.print(ent.getKey());
9258 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009259 ArrayList<Intent> intents = ent.getValue();
9260 final int N = intents.size();
9261 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009262 sb.setLength(0);
9263 sb.append(" Intent: ");
9264 intents.get(i).toShortString(sb, true, false);
9265 pw.println(sb.toString());
9266 Bundle bundle = intents.get(i).getExtras();
9267 if (bundle != null) {
9268 pw.print(" ");
9269 pw.println(bundle.toString());
9270 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009271 }
9272 }
9273 }
9274
9275 pw.println(" ");
9276 pw.println(" mHandler:");
9277 mHandler.dump(new PrintWriterPrinter(pw), " ");
9278 }
9279 }
9280
9281 void dumpServices(PrintWriter pw) {
9282 synchronized (this) {
9283 if (checkCallingPermission(android.Manifest.permission.DUMP)
9284 != PackageManager.PERMISSION_GRANTED) {
9285 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9286 + Binder.getCallingPid()
9287 + ", uid=" + Binder.getCallingUid()
9288 + " without permission "
9289 + android.Manifest.permission.DUMP);
9290 return;
9291 }
9292 pw.println("Services in Current Activity Manager State:");
9293
9294 boolean needSep = false;
9295
9296 if (mServices.size() > 0) {
9297 pw.println(" Active services:");
9298 Iterator<ServiceRecord> it = mServices.values().iterator();
9299 while (it.hasNext()) {
9300 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009301 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009302 r.dump(pw, " ");
9303 }
9304 needSep = true;
9305 }
9306
9307 if (mPendingServices.size() > 0) {
9308 if (needSep) pw.println(" ");
9309 pw.println(" Pending services:");
9310 for (int i=0; i<mPendingServices.size(); i++) {
9311 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009312 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009313 r.dump(pw, " ");
9314 }
9315 needSep = true;
9316 }
9317
9318 if (mRestartingServices.size() > 0) {
9319 if (needSep) pw.println(" ");
9320 pw.println(" Restarting services:");
9321 for (int i=0; i<mRestartingServices.size(); i++) {
9322 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009323 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009324 r.dump(pw, " ");
9325 }
9326 needSep = true;
9327 }
9328
9329 if (mStoppingServices.size() > 0) {
9330 if (needSep) pw.println(" ");
9331 pw.println(" Stopping services:");
9332 for (int i=0; i<mStoppingServices.size(); i++) {
9333 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009334 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009335 r.dump(pw, " ");
9336 }
9337 needSep = true;
9338 }
9339
9340 if (mServiceConnections.size() > 0) {
9341 if (needSep) pw.println(" ");
9342 pw.println(" Connection bindings to services:");
9343 Iterator<ConnectionRecord> it
9344 = mServiceConnections.values().iterator();
9345 while (it.hasNext()) {
9346 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009347 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009348 r.dump(pw, " ");
9349 }
9350 }
9351 }
9352 }
9353
9354 void dumpProviders(PrintWriter pw) {
9355 synchronized (this) {
9356 if (checkCallingPermission(android.Manifest.permission.DUMP)
9357 != PackageManager.PERMISSION_GRANTED) {
9358 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9359 + Binder.getCallingPid()
9360 + ", uid=" + Binder.getCallingUid()
9361 + " without permission "
9362 + android.Manifest.permission.DUMP);
9363 return;
9364 }
9365
9366 pw.println("Content Providers in Current Activity Manager State:");
9367
9368 boolean needSep = false;
9369
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009370 if (mProvidersByClass.size() > 0) {
9371 if (needSep) pw.println(" ");
9372 pw.println(" Published content providers (by class):");
9373 Iterator it = mProvidersByClass.entrySet().iterator();
9374 while (it.hasNext()) {
9375 Map.Entry e = (Map.Entry)it.next();
9376 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009377 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009378 r.dump(pw, " ");
9379 }
9380 needSep = true;
9381 }
9382
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009383 if (mProvidersByName.size() > 0) {
9384 pw.println(" ");
9385 pw.println(" Authority to provider mappings:");
9386 Iterator it = mProvidersByName.entrySet().iterator();
9387 while (it.hasNext()) {
9388 Map.Entry e = (Map.Entry)it.next();
9389 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9390 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9391 pw.println(r);
9392 }
9393 needSep = true;
9394 }
9395
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009396 if (mLaunchingProviders.size() > 0) {
9397 if (needSep) pw.println(" ");
9398 pw.println(" Launching content providers:");
9399 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009400 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9401 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009402 }
9403 needSep = true;
9404 }
9405
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009406 if (mGrantedUriPermissions.size() > 0) {
9407 pw.println();
9408 pw.println("Granted Uri Permissions:");
9409 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9410 int uid = mGrantedUriPermissions.keyAt(i);
9411 HashMap<Uri, UriPermission> perms
9412 = mGrantedUriPermissions.valueAt(i);
9413 pw.print(" * UID "); pw.print(uid);
9414 pw.println(" holds:");
9415 for (UriPermission perm : perms.values()) {
9416 pw.print(" "); pw.println(perm);
9417 perm.dump(pw, " ");
9418 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009419 }
9420 }
9421 }
9422 }
9423
9424 void dumpSenders(PrintWriter pw) {
9425 synchronized (this) {
9426 if (checkCallingPermission(android.Manifest.permission.DUMP)
9427 != PackageManager.PERMISSION_GRANTED) {
9428 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9429 + Binder.getCallingPid()
9430 + ", uid=" + Binder.getCallingUid()
9431 + " without permission "
9432 + android.Manifest.permission.DUMP);
9433 return;
9434 }
9435
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009436 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009437
9438 if (this.mIntentSenderRecords.size() > 0) {
9439 Iterator<WeakReference<PendingIntentRecord>> it
9440 = mIntentSenderRecords.values().iterator();
9441 while (it.hasNext()) {
9442 WeakReference<PendingIntentRecord> ref = it.next();
9443 PendingIntentRecord rec = ref != null ? ref.get(): null;
9444 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009445 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009446 rec.dump(pw, " ");
9447 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009448 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009449 }
9450 }
9451 }
9452 }
9453 }
9454
9455 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009456 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009457 TaskRecord lastTask = null;
9458 for (int i=list.size()-1; i>=0; i--) {
9459 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009460 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009461 if (lastTask != r.task) {
9462 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009463 pw.print(prefix);
9464 pw.print(full ? "* " : " ");
9465 pw.println(lastTask);
9466 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009467 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009468 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009469 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009470 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9471 pw.print(" #"); pw.print(i); pw.print(": ");
9472 pw.println(r);
9473 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009474 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009475 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009476 }
9477 }
9478
9479 private static final int dumpProcessList(PrintWriter pw, List list,
9480 String prefix, String normalLabel, String persistentLabel,
9481 boolean inclOomAdj) {
9482 int numPers = 0;
9483 for (int i=list.size()-1; i>=0; i--) {
9484 ProcessRecord r = (ProcessRecord)list.get(i);
9485 if (false) {
9486 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9487 + " #" + i + ":");
9488 r.dump(pw, prefix + " ");
9489 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009490 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009491 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009492 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9493 if (r.adjSource != null || r.adjTarget != null) {
9494 pw.println(prefix + " " + r.adjTarget
9495 + " used by " + r.adjSource);
9496 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009497 } else {
9498 pw.println(String.format("%s%s #%2d: %s",
9499 prefix, (r.persistent ? persistentLabel : normalLabel),
9500 i, r.toString()));
9501 }
9502 if (r.persistent) {
9503 numPers++;
9504 }
9505 }
9506 return numPers;
9507 }
9508
9509 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9510 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009511 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009512 long uptime = SystemClock.uptimeMillis();
9513 long realtime = SystemClock.elapsedRealtime();
9514
9515 if (isCheckinRequest) {
9516 // short checkin version
9517 pw.println(uptime + "," + realtime);
9518 pw.flush();
9519 } else {
9520 pw.println("Applications Memory Usage (kB):");
9521 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9522 }
9523 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9524 ProcessRecord r = (ProcessRecord)list.get(i);
9525 if (r.thread != null) {
9526 if (!isCheckinRequest) {
9527 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9528 pw.flush();
9529 }
9530 try {
9531 r.thread.asBinder().dump(fd, args);
9532 } catch (RemoteException e) {
9533 if (!isCheckinRequest) {
9534 pw.println("Got RemoteException!");
9535 pw.flush();
9536 }
9537 }
9538 }
9539 }
9540 }
9541
9542 /**
9543 * Searches array of arguments for the specified string
9544 * @param args array of argument strings
9545 * @param value value to search for
9546 * @return true if the value is contained in the array
9547 */
9548 private static boolean scanArgs(String[] args, String value) {
9549 if (args != null) {
9550 for (String arg : args) {
9551 if (value.equals(arg)) {
9552 return true;
9553 }
9554 }
9555 }
9556 return false;
9557 }
9558
Dianne Hackborn75b03852009-06-12 15:43:26 -07009559 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009560 int count = mHistory.size();
9561
9562 // convert the token to an entry in the history.
9563 HistoryRecord r = null;
9564 int index = -1;
9565 for (int i=count-1; i>=0; i--) {
9566 Object o = mHistory.get(i);
9567 if (o == token) {
9568 r = (HistoryRecord)o;
9569 index = i;
9570 break;
9571 }
9572 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009573
9574 return index;
9575 }
9576
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009577 private final void killServicesLocked(ProcessRecord app,
9578 boolean allowRestart) {
9579 // Report disconnected services.
9580 if (false) {
9581 // XXX we are letting the client link to the service for
9582 // death notifications.
9583 if (app.services.size() > 0) {
9584 Iterator it = app.services.iterator();
9585 while (it.hasNext()) {
9586 ServiceRecord r = (ServiceRecord)it.next();
9587 if (r.connections.size() > 0) {
9588 Iterator<ConnectionRecord> jt
9589 = r.connections.values().iterator();
9590 while (jt.hasNext()) {
9591 ConnectionRecord c = jt.next();
9592 if (c.binding.client != app) {
9593 try {
9594 //c.conn.connected(r.className, null);
9595 } catch (Exception e) {
9596 // todo: this should be asynchronous!
9597 Log.w(TAG, "Exception thrown disconnected servce "
9598 + r.shortName
9599 + " from app " + app.processName, e);
9600 }
9601 }
9602 }
9603 }
9604 }
9605 }
9606 }
9607
9608 // Clean up any connections this application has to other services.
9609 if (app.connections.size() > 0) {
9610 Iterator<ConnectionRecord> it = app.connections.iterator();
9611 while (it.hasNext()) {
9612 ConnectionRecord r = it.next();
9613 removeConnectionLocked(r, app, null);
9614 }
9615 }
9616 app.connections.clear();
9617
9618 if (app.services.size() != 0) {
9619 // Any services running in the application need to be placed
9620 // back in the pending list.
9621 Iterator it = app.services.iterator();
9622 while (it.hasNext()) {
9623 ServiceRecord sr = (ServiceRecord)it.next();
9624 synchronized (sr.stats.getBatteryStats()) {
9625 sr.stats.stopLaunchedLocked();
9626 }
9627 sr.app = null;
9628 sr.executeNesting = 0;
9629 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009630
9631 boolean hasClients = sr.bindings.size() > 0;
9632 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009633 Iterator<IntentBindRecord> bindings
9634 = sr.bindings.values().iterator();
9635 while (bindings.hasNext()) {
9636 IntentBindRecord b = bindings.next();
9637 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9638 + ": shouldUnbind=" + b.hasBound);
9639 b.binder = null;
9640 b.requested = b.received = b.hasBound = false;
9641 }
9642 }
9643
9644 if (sr.crashCount >= 2) {
9645 Log.w(TAG, "Service crashed " + sr.crashCount
9646 + " times, stopping: " + sr);
9647 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9648 sr.crashCount, sr.shortName, app.pid);
9649 bringDownServiceLocked(sr, true);
9650 } else if (!allowRestart) {
9651 bringDownServiceLocked(sr, true);
9652 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009653 boolean canceled = scheduleServiceRestartLocked(sr, true);
9654
9655 // Should the service remain running? Note that in the
9656 // extreme case of so many attempts to deliver a command
9657 // that it failed, that we also will stop it here.
9658 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9659 if (sr.pendingStarts.size() == 0) {
9660 sr.startRequested = false;
9661 if (!hasClients) {
9662 // Whoops, no reason to restart!
9663 bringDownServiceLocked(sr, true);
9664 }
9665 }
9666 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009667 }
9668 }
9669
9670 if (!allowRestart) {
9671 app.services.clear();
9672 }
9673 }
9674
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009675 // Make sure we have no more records on the stopping list.
9676 int i = mStoppingServices.size();
9677 while (i > 0) {
9678 i--;
9679 ServiceRecord sr = mStoppingServices.get(i);
9680 if (sr.app == app) {
9681 mStoppingServices.remove(i);
9682 }
9683 }
9684
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009685 app.executingServices.clear();
9686 }
9687
9688 private final void removeDyingProviderLocked(ProcessRecord proc,
9689 ContentProviderRecord cpr) {
9690 synchronized (cpr) {
9691 cpr.launchingApp = null;
9692 cpr.notifyAll();
9693 }
9694
9695 mProvidersByClass.remove(cpr.info.name);
9696 String names[] = cpr.info.authority.split(";");
9697 for (int j = 0; j < names.length; j++) {
9698 mProvidersByName.remove(names[j]);
9699 }
9700
9701 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9702 while (cit.hasNext()) {
9703 ProcessRecord capp = cit.next();
9704 if (!capp.persistent && capp.thread != null
9705 && capp.pid != 0
9706 && capp.pid != MY_PID) {
9707 Log.i(TAG, "Killing app " + capp.processName
9708 + " (pid " + capp.pid
9709 + ") because provider " + cpr.info.name
9710 + " is in dying process " + proc.processName);
9711 Process.killProcess(capp.pid);
9712 }
9713 }
9714
9715 mLaunchingProviders.remove(cpr);
9716 }
9717
9718 /**
9719 * Main code for cleaning up a process when it has gone away. This is
9720 * called both as a result of the process dying, or directly when stopping
9721 * a process when running in single process mode.
9722 */
9723 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9724 boolean restarting, int index) {
9725 if (index >= 0) {
9726 mLRUProcesses.remove(index);
9727 }
9728
9729 // Dismiss any open dialogs.
9730 if (app.crashDialog != null) {
9731 app.crashDialog.dismiss();
9732 app.crashDialog = null;
9733 }
9734 if (app.anrDialog != null) {
9735 app.anrDialog.dismiss();
9736 app.anrDialog = null;
9737 }
9738 if (app.waitDialog != null) {
9739 app.waitDialog.dismiss();
9740 app.waitDialog = null;
9741 }
9742
9743 app.crashing = false;
9744 app.notResponding = false;
9745
9746 app.resetPackageList();
9747 app.thread = null;
9748 app.forcingToForeground = null;
9749 app.foregroundServices = false;
9750
9751 killServicesLocked(app, true);
9752
9753 boolean restart = false;
9754
9755 int NL = mLaunchingProviders.size();
9756
9757 // Remove published content providers.
9758 if (!app.pubProviders.isEmpty()) {
9759 Iterator it = app.pubProviders.values().iterator();
9760 while (it.hasNext()) {
9761 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9762 cpr.provider = null;
9763 cpr.app = null;
9764
9765 // See if someone is waiting for this provider... in which
9766 // case we don't remove it, but just let it restart.
9767 int i = 0;
9768 if (!app.bad) {
9769 for (; i<NL; i++) {
9770 if (mLaunchingProviders.get(i) == cpr) {
9771 restart = true;
9772 break;
9773 }
9774 }
9775 } else {
9776 i = NL;
9777 }
9778
9779 if (i >= NL) {
9780 removeDyingProviderLocked(app, cpr);
9781 NL = mLaunchingProviders.size();
9782 }
9783 }
9784 app.pubProviders.clear();
9785 }
9786
9787 // Look through the content providers we are waiting to have launched,
9788 // and if any run in this process then either schedule a restart of
9789 // the process or kill the client waiting for it if this process has
9790 // gone bad.
9791 for (int i=0; i<NL; i++) {
9792 ContentProviderRecord cpr = (ContentProviderRecord)
9793 mLaunchingProviders.get(i);
9794 if (cpr.launchingApp == app) {
9795 if (!app.bad) {
9796 restart = true;
9797 } else {
9798 removeDyingProviderLocked(app, cpr);
9799 NL = mLaunchingProviders.size();
9800 }
9801 }
9802 }
9803
9804 // Unregister from connected content providers.
9805 if (!app.conProviders.isEmpty()) {
9806 Iterator it = app.conProviders.iterator();
9807 while (it.hasNext()) {
9808 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9809 cpr.clients.remove(app);
9810 }
9811 app.conProviders.clear();
9812 }
9813
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009814 // At this point there may be remaining entries in mLaunchingProviders
9815 // where we were the only one waiting, so they are no longer of use.
9816 // Look for these and clean up if found.
9817 // XXX Commented out for now. Trying to figure out a way to reproduce
9818 // the actual situation to identify what is actually going on.
9819 if (false) {
9820 for (int i=0; i<NL; i++) {
9821 ContentProviderRecord cpr = (ContentProviderRecord)
9822 mLaunchingProviders.get(i);
9823 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9824 synchronized (cpr) {
9825 cpr.launchingApp = null;
9826 cpr.notifyAll();
9827 }
9828 }
9829 }
9830 }
9831
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009832 skipCurrentReceiverLocked(app);
9833
9834 // Unregister any receivers.
9835 if (app.receivers.size() > 0) {
9836 Iterator<ReceiverList> it = app.receivers.iterator();
9837 while (it.hasNext()) {
9838 removeReceiverLocked(it.next());
9839 }
9840 app.receivers.clear();
9841 }
9842
Christopher Tate181fafa2009-05-14 11:12:14 -07009843 // If the app is undergoing backup, tell the backup manager about it
9844 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9845 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9846 try {
9847 IBackupManager bm = IBackupManager.Stub.asInterface(
9848 ServiceManager.getService(Context.BACKUP_SERVICE));
9849 bm.agentDisconnected(app.info.packageName);
9850 } catch (RemoteException e) {
9851 // can't happen; backup manager is local
9852 }
9853 }
9854
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009855 // If the caller is restarting this app, then leave it in its
9856 // current lists and let the caller take care of it.
9857 if (restarting) {
9858 return;
9859 }
9860
9861 if (!app.persistent) {
9862 if (DEBUG_PROCESSES) Log.v(TAG,
9863 "Removing non-persistent process during cleanup: " + app);
9864 mProcessNames.remove(app.processName, app.info.uid);
9865 } else if (!app.removed) {
9866 // This app is persistent, so we need to keep its record around.
9867 // If it is not already on the pending app list, add it there
9868 // and start a new process for it.
9869 app.thread = null;
9870 app.forcingToForeground = null;
9871 app.foregroundServices = false;
9872 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9873 mPersistentStartingProcesses.add(app);
9874 restart = true;
9875 }
9876 }
9877 mProcessesOnHold.remove(app);
9878
The Android Open Source Project4df24232009-03-05 14:34:35 -08009879 if (app == mHomeProcess) {
9880 mHomeProcess = null;
9881 }
9882
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009883 if (restart) {
9884 // We have components that still need to be running in the
9885 // process, so re-launch it.
9886 mProcessNames.put(app.processName, app.info.uid, app);
9887 startProcessLocked(app, "restart", app.processName);
9888 } else if (app.pid > 0 && app.pid != MY_PID) {
9889 // Goodbye!
9890 synchronized (mPidsSelfLocked) {
9891 mPidsSelfLocked.remove(app.pid);
9892 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9893 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009894 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009895 }
9896 }
9897
9898 // =========================================================
9899 // SERVICES
9900 // =========================================================
9901
9902 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9903 ActivityManager.RunningServiceInfo info =
9904 new ActivityManager.RunningServiceInfo();
9905 info.service = r.name;
9906 if (r.app != null) {
9907 info.pid = r.app.pid;
9908 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -07009909 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009910 info.process = r.processName;
9911 info.foreground = r.isForeground;
9912 info.activeSince = r.createTime;
9913 info.started = r.startRequested;
9914 info.clientCount = r.connections.size();
9915 info.crashCount = r.crashCount;
9916 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07009917 if (r.isForeground) {
9918 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
9919 }
9920 if (r.startRequested) {
9921 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
9922 }
9923 if (r.app != null && r.app.pid == Process.myPid()) {
9924 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
9925 }
9926 if (r.app != null && r.app.persistent) {
9927 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
9928 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009929 for (ConnectionRecord conn : r.connections.values()) {
9930 if (conn.clientLabel != 0) {
9931 info.clientPackage = conn.binding.client.info.packageName;
9932 info.clientLabel = conn.clientLabel;
9933 break;
9934 }
9935 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009936 return info;
9937 }
9938
9939 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9940 int flags) {
9941 synchronized (this) {
9942 ArrayList<ActivityManager.RunningServiceInfo> res
9943 = new ArrayList<ActivityManager.RunningServiceInfo>();
9944
9945 if (mServices.size() > 0) {
9946 Iterator<ServiceRecord> it = mServices.values().iterator();
9947 while (it.hasNext() && res.size() < maxNum) {
9948 res.add(makeRunningServiceInfoLocked(it.next()));
9949 }
9950 }
9951
9952 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9953 ServiceRecord r = mRestartingServices.get(i);
9954 ActivityManager.RunningServiceInfo info =
9955 makeRunningServiceInfoLocked(r);
9956 info.restarting = r.nextRestartTime;
9957 res.add(info);
9958 }
9959
9960 return res;
9961 }
9962 }
9963
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009964 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
9965 synchronized (this) {
9966 ServiceRecord r = mServices.get(name);
9967 if (r != null) {
9968 for (ConnectionRecord conn : r.connections.values()) {
9969 if (conn.clientIntent != null) {
9970 return conn.clientIntent;
9971 }
9972 }
9973 }
9974 }
9975 return null;
9976 }
9977
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009978 private final ServiceRecord findServiceLocked(ComponentName name,
9979 IBinder token) {
9980 ServiceRecord r = mServices.get(name);
9981 return r == token ? r : null;
9982 }
9983
9984 private final class ServiceLookupResult {
9985 final ServiceRecord record;
9986 final String permission;
9987
9988 ServiceLookupResult(ServiceRecord _record, String _permission) {
9989 record = _record;
9990 permission = _permission;
9991 }
9992 };
9993
9994 private ServiceLookupResult findServiceLocked(Intent service,
9995 String resolvedType) {
9996 ServiceRecord r = null;
9997 if (service.getComponent() != null) {
9998 r = mServices.get(service.getComponent());
9999 }
10000 if (r == null) {
10001 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10002 r = mServicesByIntent.get(filter);
10003 }
10004
10005 if (r == null) {
10006 try {
10007 ResolveInfo rInfo =
10008 ActivityThread.getPackageManager().resolveService(
10009 service, resolvedType, 0);
10010 ServiceInfo sInfo =
10011 rInfo != null ? rInfo.serviceInfo : null;
10012 if (sInfo == null) {
10013 return null;
10014 }
10015
10016 ComponentName name = new ComponentName(
10017 sInfo.applicationInfo.packageName, sInfo.name);
10018 r = mServices.get(name);
10019 } catch (RemoteException ex) {
10020 // pm is in same process, this will never happen.
10021 }
10022 }
10023 if (r != null) {
10024 int callingPid = Binder.getCallingPid();
10025 int callingUid = Binder.getCallingUid();
10026 if (checkComponentPermission(r.permission,
10027 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10028 != PackageManager.PERMISSION_GRANTED) {
10029 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10030 + " from pid=" + callingPid
10031 + ", uid=" + callingUid
10032 + " requires " + r.permission);
10033 return new ServiceLookupResult(null, r.permission);
10034 }
10035 return new ServiceLookupResult(r, null);
10036 }
10037 return null;
10038 }
10039
10040 private class ServiceRestarter implements Runnable {
10041 private ServiceRecord mService;
10042
10043 void setService(ServiceRecord service) {
10044 mService = service;
10045 }
10046
10047 public void run() {
10048 synchronized(ActivityManagerService.this) {
10049 performServiceRestartLocked(mService);
10050 }
10051 }
10052 }
10053
10054 private ServiceLookupResult retrieveServiceLocked(Intent service,
10055 String resolvedType, int callingPid, int callingUid) {
10056 ServiceRecord r = null;
10057 if (service.getComponent() != null) {
10058 r = mServices.get(service.getComponent());
10059 }
10060 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10061 r = mServicesByIntent.get(filter);
10062 if (r == null) {
10063 try {
10064 ResolveInfo rInfo =
10065 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010066 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010067 ServiceInfo sInfo =
10068 rInfo != null ? rInfo.serviceInfo : null;
10069 if (sInfo == null) {
10070 Log.w(TAG, "Unable to start service " + service +
10071 ": not found");
10072 return null;
10073 }
10074
10075 ComponentName name = new ComponentName(
10076 sInfo.applicationInfo.packageName, sInfo.name);
10077 r = mServices.get(name);
10078 if (r == null) {
10079 filter = new Intent.FilterComparison(service.cloneFilter());
10080 ServiceRestarter res = new ServiceRestarter();
10081 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10082 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10083 synchronized (stats) {
10084 ss = stats.getServiceStatsLocked(
10085 sInfo.applicationInfo.uid, sInfo.packageName,
10086 sInfo.name);
10087 }
10088 r = new ServiceRecord(ss, name, filter, sInfo, res);
10089 res.setService(r);
10090 mServices.put(name, r);
10091 mServicesByIntent.put(filter, r);
10092
10093 // Make sure this component isn't in the pending list.
10094 int N = mPendingServices.size();
10095 for (int i=0; i<N; i++) {
10096 ServiceRecord pr = mPendingServices.get(i);
10097 if (pr.name.equals(name)) {
10098 mPendingServices.remove(i);
10099 i--;
10100 N--;
10101 }
10102 }
10103 }
10104 } catch (RemoteException ex) {
10105 // pm is in same process, this will never happen.
10106 }
10107 }
10108 if (r != null) {
10109 if (checkComponentPermission(r.permission,
10110 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10111 != PackageManager.PERMISSION_GRANTED) {
10112 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10113 + " from pid=" + Binder.getCallingPid()
10114 + ", uid=" + Binder.getCallingUid()
10115 + " requires " + r.permission);
10116 return new ServiceLookupResult(null, r.permission);
10117 }
10118 return new ServiceLookupResult(r, null);
10119 }
10120 return null;
10121 }
10122
10123 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10124 long now = SystemClock.uptimeMillis();
10125 if (r.executeNesting == 0 && r.app != null) {
10126 if (r.app.executingServices.size() == 0) {
10127 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10128 msg.obj = r.app;
10129 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10130 }
10131 r.app.executingServices.add(r);
10132 }
10133 r.executeNesting++;
10134 r.executingStart = now;
10135 }
10136
10137 private final void sendServiceArgsLocked(ServiceRecord r,
10138 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010139 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010140 if (N == 0) {
10141 return;
10142 }
10143
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010144 int i = 0;
10145 while (i < N) {
10146 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010147 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010148 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010149 + r.name + " " + r.intent + " args=" + si.intent);
10150 if (si.intent == null && N > 0) {
10151 // If somehow we got a dummy start at the front, then
10152 // just drop it here.
10153 i++;
10154 continue;
10155 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010156 bumpServiceExecutingLocked(r);
10157 if (!oomAdjusted) {
10158 oomAdjusted = true;
10159 updateOomAdjLocked(r.app);
10160 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010161 int flags = 0;
10162 if (si.deliveryCount > 0) {
10163 flags |= Service.START_FLAG_RETRY;
10164 }
10165 if (si.doneExecutingCount > 0) {
10166 flags |= Service.START_FLAG_REDELIVERY;
10167 }
10168 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10169 si.deliveredTime = SystemClock.uptimeMillis();
10170 r.deliveredStarts.add(si);
10171 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010172 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010173 } catch (RemoteException e) {
10174 // Remote process gone... we'll let the normal cleanup take
10175 // care of this.
10176 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010177 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010178 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010179 break;
10180 }
10181 }
10182 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010183 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010184 } else {
10185 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010186 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010187 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010188 }
10189 }
10190 }
10191
10192 private final boolean requestServiceBindingLocked(ServiceRecord r,
10193 IntentBindRecord i, boolean rebind) {
10194 if (r.app == null || r.app.thread == null) {
10195 // If service is not currently running, can't yet bind.
10196 return false;
10197 }
10198 if ((!i.requested || rebind) && i.apps.size() > 0) {
10199 try {
10200 bumpServiceExecutingLocked(r);
10201 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10202 + ": shouldUnbind=" + i.hasBound);
10203 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10204 if (!rebind) {
10205 i.requested = true;
10206 }
10207 i.hasBound = true;
10208 i.doRebind = false;
10209 } catch (RemoteException e) {
10210 return false;
10211 }
10212 }
10213 return true;
10214 }
10215
10216 private final void requestServiceBindingsLocked(ServiceRecord r) {
10217 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10218 while (bindings.hasNext()) {
10219 IntentBindRecord i = bindings.next();
10220 if (!requestServiceBindingLocked(r, i, false)) {
10221 break;
10222 }
10223 }
10224 }
10225
10226 private final void realStartServiceLocked(ServiceRecord r,
10227 ProcessRecord app) throws RemoteException {
10228 if (app.thread == null) {
10229 throw new RemoteException();
10230 }
10231
10232 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010233 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010234
10235 app.services.add(r);
10236 bumpServiceExecutingLocked(r);
10237 updateLRUListLocked(app, true);
10238
10239 boolean created = false;
10240 try {
10241 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10242 + r.name + " " + r.intent);
10243 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
10244 System.identityHashCode(r), r.shortName,
10245 r.intent.getIntent().toString(), r.app.pid);
10246 synchronized (r.stats.getBatteryStats()) {
10247 r.stats.startLaunchedLocked();
10248 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010249 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010250 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010251 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010252 created = true;
10253 } finally {
10254 if (!created) {
10255 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010256 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010257 }
10258 }
10259
10260 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010261
10262 // If the service is in the started state, and there are no
10263 // pending arguments, then fake up one so its onStartCommand() will
10264 // be called.
10265 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10266 r.lastStartId++;
10267 if (r.lastStartId < 1) {
10268 r.lastStartId = 1;
10269 }
10270 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10271 }
10272
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010273 sendServiceArgsLocked(r, true);
10274 }
10275
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010276 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10277 boolean allowCancel) {
10278 boolean canceled = false;
10279
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010280 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010281 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010282 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010283
10284 // Any delivered but not yet finished starts should be put back
10285 // on the pending list.
10286 final int N = r.deliveredStarts.size();
10287 if (N > 0) {
10288 for (int i=N-1; i>=0; i--) {
10289 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10290 if (si.intent == null) {
10291 // We'll generate this again if needed.
10292 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10293 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10294 r.pendingStarts.add(0, si);
10295 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10296 dur *= 2;
10297 if (minDuration < dur) minDuration = dur;
10298 if (resetTime < dur) resetTime = dur;
10299 } else {
10300 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10301 + r.name);
10302 canceled = true;
10303 }
10304 }
10305 r.deliveredStarts.clear();
10306 }
10307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010308 r.totalRestartCount++;
10309 if (r.restartDelay == 0) {
10310 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010311 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010312 } else {
10313 // If it has been a "reasonably long time" since the service
10314 // was started, then reset our restart duration back to
10315 // the beginning, so we don't infinitely increase the duration
10316 // on a service that just occasionally gets killed (which is
10317 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010318 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010319 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010320 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010321 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010322 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010323 if (r.restartDelay < minDuration) {
10324 r.restartDelay = minDuration;
10325 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010326 }
10327 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010328
10329 r.nextRestartTime = now + r.restartDelay;
10330
10331 // Make sure that we don't end up restarting a bunch of services
10332 // all at the same time.
10333 boolean repeat;
10334 do {
10335 repeat = false;
10336 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10337 ServiceRecord r2 = mRestartingServices.get(i);
10338 if (r2 != r && r.nextRestartTime
10339 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10340 && r.nextRestartTime
10341 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10342 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10343 r.restartDelay = r.nextRestartTime - now;
10344 repeat = true;
10345 break;
10346 }
10347 }
10348 } while (repeat);
10349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010350 if (!mRestartingServices.contains(r)) {
10351 mRestartingServices.add(r);
10352 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010353
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010354 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010355
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010356 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010357 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010358 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10359 Log.w(TAG, "Scheduling restart of crashed service "
10360 + r.shortName + " in " + r.restartDelay + "ms");
10361 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10362 r.shortName, r.restartDelay);
10363
10364 Message msg = Message.obtain();
10365 msg.what = SERVICE_ERROR_MSG;
10366 msg.obj = r;
10367 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010368
10369 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010370 }
10371
10372 final void performServiceRestartLocked(ServiceRecord r) {
10373 if (!mRestartingServices.contains(r)) {
10374 return;
10375 }
10376 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10377 }
10378
10379 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10380 if (r.restartDelay == 0) {
10381 return false;
10382 }
10383 r.resetRestartCounter();
10384 mRestartingServices.remove(r);
10385 mHandler.removeCallbacks(r.restarter);
10386 return true;
10387 }
10388
10389 private final boolean bringUpServiceLocked(ServiceRecord r,
10390 int intentFlags, boolean whileRestarting) {
10391 //Log.i(TAG, "Bring up service:");
10392 //r.dump(" ");
10393
10394 if (r.app != null) {
10395 sendServiceArgsLocked(r, false);
10396 return true;
10397 }
10398
10399 if (!whileRestarting && r.restartDelay > 0) {
10400 // If waiting for a restart, then do nothing.
10401 return true;
10402 }
10403
10404 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10405 + " " + r.intent);
10406
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010407 // We are now bringing the service up, so no longer in the
10408 // restarting state.
10409 mRestartingServices.remove(r);
10410
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010411 final String appName = r.processName;
10412 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10413 if (app != null && app.thread != null) {
10414 try {
10415 realStartServiceLocked(r, app);
10416 return true;
10417 } catch (RemoteException e) {
10418 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10419 }
10420
10421 // If a dead object exception was thrown -- fall through to
10422 // restart the application.
10423 }
10424
10425 if (!mPendingServices.contains(r)) {
10426 // Not running -- get it started, and enqueue this service record
10427 // to be executed when the app comes up.
10428 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070010429 "service", r.name, false) == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010430 Log.w(TAG, "Unable to launch app "
10431 + r.appInfo.packageName + "/"
10432 + r.appInfo.uid + " for service "
10433 + r.intent.getIntent() + ": process is bad");
10434 bringDownServiceLocked(r, true);
10435 return false;
10436 }
10437 mPendingServices.add(r);
10438 }
10439 return true;
10440 }
10441
10442 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10443 //Log.i(TAG, "Bring down service:");
10444 //r.dump(" ");
10445
10446 // Does it still need to run?
10447 if (!force && r.startRequested) {
10448 return;
10449 }
10450 if (r.connections.size() > 0) {
10451 if (!force) {
10452 // XXX should probably keep a count of the number of auto-create
10453 // connections directly in the service.
10454 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10455 while (it.hasNext()) {
10456 ConnectionRecord cr = it.next();
10457 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10458 return;
10459 }
10460 }
10461 }
10462
10463 // Report to all of the connections that the service is no longer
10464 // available.
10465 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10466 while (it.hasNext()) {
10467 ConnectionRecord c = it.next();
10468 try {
10469 // todo: shouldn't be a synchronous call!
10470 c.conn.connected(r.name, null);
10471 } catch (Exception e) {
10472 Log.w(TAG, "Failure disconnecting service " + r.name +
10473 " to connection " + c.conn.asBinder() +
10474 " (in " + c.binding.client.processName + ")", e);
10475 }
10476 }
10477 }
10478
10479 // Tell the service that it has been unbound.
10480 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10481 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10482 while (it.hasNext()) {
10483 IntentBindRecord ibr = it.next();
10484 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10485 + ": hasBound=" + ibr.hasBound);
10486 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10487 try {
10488 bumpServiceExecutingLocked(r);
10489 updateOomAdjLocked(r.app);
10490 ibr.hasBound = false;
10491 r.app.thread.scheduleUnbindService(r,
10492 ibr.intent.getIntent());
10493 } catch (Exception e) {
10494 Log.w(TAG, "Exception when unbinding service "
10495 + r.shortName, e);
10496 serviceDoneExecutingLocked(r, true);
10497 }
10498 }
10499 }
10500 }
10501
10502 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10503 + " " + r.intent);
10504 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10505 System.identityHashCode(r), r.shortName,
10506 (r.app != null) ? r.app.pid : -1);
10507
10508 mServices.remove(r.name);
10509 mServicesByIntent.remove(r.intent);
10510 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10511 r.totalRestartCount = 0;
10512 unscheduleServiceRestartLocked(r);
10513
10514 // Also make sure it is not on the pending list.
10515 int N = mPendingServices.size();
10516 for (int i=0; i<N; i++) {
10517 if (mPendingServices.get(i) == r) {
10518 mPendingServices.remove(i);
10519 if (DEBUG_SERVICE) Log.v(
10520 TAG, "Removed pending service: " + r.shortName);
10521 i--;
10522 N--;
10523 }
10524 }
10525
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010526 r.cancelNotification();
10527 r.isForeground = false;
10528 r.foregroundId = 0;
10529 r.foregroundNoti = null;
10530
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010531 // Clear start entries.
10532 r.deliveredStarts.clear();
10533 r.pendingStarts.clear();
10534
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010535 if (r.app != null) {
10536 synchronized (r.stats.getBatteryStats()) {
10537 r.stats.stopLaunchedLocked();
10538 }
10539 r.app.services.remove(r);
10540 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010541 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010542 if (DEBUG_SERVICE) Log.v(TAG,
10543 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010544 bumpServiceExecutingLocked(r);
10545 mStoppingServices.add(r);
10546 updateOomAdjLocked(r.app);
10547 r.app.thread.scheduleStopService(r);
10548 } catch (Exception e) {
10549 Log.w(TAG, "Exception when stopping service "
10550 + r.shortName, e);
10551 serviceDoneExecutingLocked(r, true);
10552 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010553 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010554 } else {
10555 if (DEBUG_SERVICE) Log.v(
10556 TAG, "Removed service that has no process: " + r.shortName);
10557 }
10558 } else {
10559 if (DEBUG_SERVICE) Log.v(
10560 TAG, "Removed service that is not running: " + r.shortName);
10561 }
10562 }
10563
10564 ComponentName startServiceLocked(IApplicationThread caller,
10565 Intent service, String resolvedType,
10566 int callingPid, int callingUid) {
10567 synchronized(this) {
10568 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10569 + " type=" + resolvedType + " args=" + service.getExtras());
10570
10571 if (caller != null) {
10572 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10573 if (callerApp == null) {
10574 throw new SecurityException(
10575 "Unable to find app for caller " + caller
10576 + " (pid=" + Binder.getCallingPid()
10577 + ") when starting service " + service);
10578 }
10579 }
10580
10581 ServiceLookupResult res =
10582 retrieveServiceLocked(service, resolvedType,
10583 callingPid, callingUid);
10584 if (res == null) {
10585 return null;
10586 }
10587 if (res.record == null) {
10588 return new ComponentName("!", res.permission != null
10589 ? res.permission : "private to package");
10590 }
10591 ServiceRecord r = res.record;
10592 if (unscheduleServiceRestartLocked(r)) {
10593 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10594 + r.shortName);
10595 }
10596 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010597 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010598 r.lastStartId++;
10599 if (r.lastStartId < 1) {
10600 r.lastStartId = 1;
10601 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010602 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010603 r.lastActivity = SystemClock.uptimeMillis();
10604 synchronized (r.stats.getBatteryStats()) {
10605 r.stats.startRunningLocked();
10606 }
10607 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10608 return new ComponentName("!", "Service process is bad");
10609 }
10610 return r.name;
10611 }
10612 }
10613
10614 public ComponentName startService(IApplicationThread caller, Intent service,
10615 String resolvedType) {
10616 // Refuse possible leaked file descriptors
10617 if (service != null && service.hasFileDescriptors() == true) {
10618 throw new IllegalArgumentException("File descriptors passed in Intent");
10619 }
10620
10621 synchronized(this) {
10622 final int callingPid = Binder.getCallingPid();
10623 final int callingUid = Binder.getCallingUid();
10624 final long origId = Binder.clearCallingIdentity();
10625 ComponentName res = startServiceLocked(caller, service,
10626 resolvedType, callingPid, callingUid);
10627 Binder.restoreCallingIdentity(origId);
10628 return res;
10629 }
10630 }
10631
10632 ComponentName startServiceInPackage(int uid,
10633 Intent service, String resolvedType) {
10634 synchronized(this) {
10635 final long origId = Binder.clearCallingIdentity();
10636 ComponentName res = startServiceLocked(null, service,
10637 resolvedType, -1, uid);
10638 Binder.restoreCallingIdentity(origId);
10639 return res;
10640 }
10641 }
10642
10643 public int stopService(IApplicationThread caller, Intent service,
10644 String resolvedType) {
10645 // Refuse possible leaked file descriptors
10646 if (service != null && service.hasFileDescriptors() == true) {
10647 throw new IllegalArgumentException("File descriptors passed in Intent");
10648 }
10649
10650 synchronized(this) {
10651 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10652 + " type=" + resolvedType);
10653
10654 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10655 if (caller != null && callerApp == null) {
10656 throw new SecurityException(
10657 "Unable to find app for caller " + caller
10658 + " (pid=" + Binder.getCallingPid()
10659 + ") when stopping service " + service);
10660 }
10661
10662 // If this service is active, make sure it is stopped.
10663 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10664 if (r != null) {
10665 if (r.record != null) {
10666 synchronized (r.record.stats.getBatteryStats()) {
10667 r.record.stats.stopRunningLocked();
10668 }
10669 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010670 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010671 final long origId = Binder.clearCallingIdentity();
10672 bringDownServiceLocked(r.record, false);
10673 Binder.restoreCallingIdentity(origId);
10674 return 1;
10675 }
10676 return -1;
10677 }
10678 }
10679
10680 return 0;
10681 }
10682
10683 public IBinder peekService(Intent service, String resolvedType) {
10684 // Refuse possible leaked file descriptors
10685 if (service != null && service.hasFileDescriptors() == true) {
10686 throw new IllegalArgumentException("File descriptors passed in Intent");
10687 }
10688
10689 IBinder ret = null;
10690
10691 synchronized(this) {
10692 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10693
10694 if (r != null) {
10695 // r.record is null if findServiceLocked() failed the caller permission check
10696 if (r.record == null) {
10697 throw new SecurityException(
10698 "Permission Denial: Accessing service " + r.record.name
10699 + " from pid=" + Binder.getCallingPid()
10700 + ", uid=" + Binder.getCallingUid()
10701 + " requires " + r.permission);
10702 }
10703 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10704 if (ib != null) {
10705 ret = ib.binder;
10706 }
10707 }
10708 }
10709
10710 return ret;
10711 }
10712
10713 public boolean stopServiceToken(ComponentName className, IBinder token,
10714 int startId) {
10715 synchronized(this) {
10716 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10717 + " " + token + " startId=" + startId);
10718 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010719 if (r != null) {
10720 if (startId >= 0) {
10721 // Asked to only stop if done with all work. Note that
10722 // to avoid leaks, we will take this as dropping all
10723 // start items up to and including this one.
10724 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10725 if (si != null) {
10726 while (r.deliveredStarts.size() > 0) {
10727 if (r.deliveredStarts.remove(0) == si) {
10728 break;
10729 }
10730 }
10731 }
10732
10733 if (r.lastStartId != startId) {
10734 return false;
10735 }
10736
10737 if (r.deliveredStarts.size() > 0) {
10738 Log.w(TAG, "stopServiceToken startId " + startId
10739 + " is last, but have " + r.deliveredStarts.size()
10740 + " remaining args");
10741 }
10742 }
10743
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010744 synchronized (r.stats.getBatteryStats()) {
10745 r.stats.stopRunningLocked();
10746 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010747 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010748 }
10749 final long origId = Binder.clearCallingIdentity();
10750 bringDownServiceLocked(r, false);
10751 Binder.restoreCallingIdentity(origId);
10752 return true;
10753 }
10754 }
10755 return false;
10756 }
10757
10758 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010759 int id, Notification notification, boolean removeNotification) {
10760 final long origId = Binder.clearCallingIdentity();
10761 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010762 synchronized(this) {
10763 ServiceRecord r = findServiceLocked(className, token);
10764 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010765 if (id != 0) {
10766 if (notification == null) {
10767 throw new IllegalArgumentException("null notification");
10768 }
10769 if (r.foregroundId != id) {
10770 r.cancelNotification();
10771 r.foregroundId = id;
10772 }
10773 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10774 r.foregroundNoti = notification;
10775 r.isForeground = true;
10776 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010777 if (r.app != null) {
10778 updateServiceForegroundLocked(r.app, true);
10779 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010780 } else {
10781 if (r.isForeground) {
10782 r.isForeground = false;
10783 if (r.app != null) {
10784 updateServiceForegroundLocked(r.app, true);
10785 }
10786 }
10787 if (removeNotification) {
10788 r.cancelNotification();
10789 r.foregroundId = 0;
10790 r.foregroundNoti = null;
10791 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010792 }
10793 }
10794 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010795 } finally {
10796 Binder.restoreCallingIdentity(origId);
10797 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010798 }
10799
10800 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10801 boolean anyForeground = false;
10802 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10803 if (sr.isForeground) {
10804 anyForeground = true;
10805 break;
10806 }
10807 }
10808 if (anyForeground != proc.foregroundServices) {
10809 proc.foregroundServices = anyForeground;
10810 if (oomAdj) {
10811 updateOomAdjLocked();
10812 }
10813 }
10814 }
10815
10816 public int bindService(IApplicationThread caller, IBinder token,
10817 Intent service, String resolvedType,
10818 IServiceConnection connection, int flags) {
10819 // Refuse possible leaked file descriptors
10820 if (service != null && service.hasFileDescriptors() == true) {
10821 throw new IllegalArgumentException("File descriptors passed in Intent");
10822 }
10823
10824 synchronized(this) {
10825 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10826 + " type=" + resolvedType + " conn=" + connection.asBinder()
10827 + " flags=0x" + Integer.toHexString(flags));
10828 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10829 if (callerApp == null) {
10830 throw new SecurityException(
10831 "Unable to find app for caller " + caller
10832 + " (pid=" + Binder.getCallingPid()
10833 + ") when binding service " + service);
10834 }
10835
10836 HistoryRecord activity = null;
10837 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010838 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010839 if (aindex < 0) {
10840 Log.w(TAG, "Binding with unknown activity: " + token);
10841 return 0;
10842 }
10843 activity = (HistoryRecord)mHistory.get(aindex);
10844 }
10845
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010846 int clientLabel = 0;
10847 PendingIntent clientIntent = null;
10848
10849 if (callerApp.info.uid == Process.SYSTEM_UID) {
10850 // Hacky kind of thing -- allow system stuff to tell us
10851 // what they are, so we can report this elsewhere for
10852 // others to know why certain services are running.
10853 try {
10854 clientIntent = (PendingIntent)service.getParcelableExtra(
10855 Intent.EXTRA_CLIENT_INTENT);
10856 } catch (RuntimeException e) {
10857 }
10858 if (clientIntent != null) {
10859 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
10860 if (clientLabel != 0) {
10861 // There are no useful extras in the intent, trash them.
10862 // System code calling with this stuff just needs to know
10863 // this will happen.
10864 service = service.cloneFilter();
10865 }
10866 }
10867 }
10868
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010869 ServiceLookupResult res =
10870 retrieveServiceLocked(service, resolvedType,
10871 Binder.getCallingPid(), Binder.getCallingUid());
10872 if (res == null) {
10873 return 0;
10874 }
10875 if (res.record == null) {
10876 return -1;
10877 }
10878 ServiceRecord s = res.record;
10879
10880 final long origId = Binder.clearCallingIdentity();
10881
10882 if (unscheduleServiceRestartLocked(s)) {
10883 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10884 + s.shortName);
10885 }
10886
10887 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10888 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010889 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010890
10891 IBinder binder = connection.asBinder();
10892 s.connections.put(binder, c);
10893 b.connections.add(c);
10894 if (activity != null) {
10895 if (activity.connections == null) {
10896 activity.connections = new HashSet<ConnectionRecord>();
10897 }
10898 activity.connections.add(c);
10899 }
10900 b.client.connections.add(c);
10901 mServiceConnections.put(binder, c);
10902
10903 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10904 s.lastActivity = SystemClock.uptimeMillis();
10905 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10906 return 0;
10907 }
10908 }
10909
10910 if (s.app != null) {
10911 // This could have made the service more important.
10912 updateOomAdjLocked(s.app);
10913 }
10914
10915 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10916 + ": received=" + b.intent.received
10917 + " apps=" + b.intent.apps.size()
10918 + " doRebind=" + b.intent.doRebind);
10919
10920 if (s.app != null && b.intent.received) {
10921 // Service is already running, so we can immediately
10922 // publish the connection.
10923 try {
10924 c.conn.connected(s.name, b.intent.binder);
10925 } catch (Exception e) {
10926 Log.w(TAG, "Failure sending service " + s.shortName
10927 + " to connection " + c.conn.asBinder()
10928 + " (in " + c.binding.client.processName + ")", e);
10929 }
10930
10931 // If this is the first app connected back to this binding,
10932 // and the service had previously asked to be told when
10933 // rebound, then do so.
10934 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10935 requestServiceBindingLocked(s, b.intent, true);
10936 }
10937 } else if (!b.intent.requested) {
10938 requestServiceBindingLocked(s, b.intent, false);
10939 }
10940
10941 Binder.restoreCallingIdentity(origId);
10942 }
10943
10944 return 1;
10945 }
10946
10947 private void removeConnectionLocked(
10948 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10949 IBinder binder = c.conn.asBinder();
10950 AppBindRecord b = c.binding;
10951 ServiceRecord s = b.service;
10952 s.connections.remove(binder);
10953 b.connections.remove(c);
10954 if (c.activity != null && c.activity != skipAct) {
10955 if (c.activity.connections != null) {
10956 c.activity.connections.remove(c);
10957 }
10958 }
10959 if (b.client != skipApp) {
10960 b.client.connections.remove(c);
10961 }
10962 mServiceConnections.remove(binder);
10963
10964 if (b.connections.size() == 0) {
10965 b.intent.apps.remove(b.client);
10966 }
10967
10968 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10969 + ": shouldUnbind=" + b.intent.hasBound);
10970 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10971 && b.intent.hasBound) {
10972 try {
10973 bumpServiceExecutingLocked(s);
10974 updateOomAdjLocked(s.app);
10975 b.intent.hasBound = false;
10976 // Assume the client doesn't want to know about a rebind;
10977 // we will deal with that later if it asks for one.
10978 b.intent.doRebind = false;
10979 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10980 } catch (Exception e) {
10981 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10982 serviceDoneExecutingLocked(s, true);
10983 }
10984 }
10985
10986 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10987 bringDownServiceLocked(s, false);
10988 }
10989 }
10990
10991 public boolean unbindService(IServiceConnection connection) {
10992 synchronized (this) {
10993 IBinder binder = connection.asBinder();
10994 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10995 ConnectionRecord r = mServiceConnections.get(binder);
10996 if (r == null) {
10997 Log.w(TAG, "Unbind failed: could not find connection for "
10998 + connection.asBinder());
10999 return false;
11000 }
11001
11002 final long origId = Binder.clearCallingIdentity();
11003
11004 removeConnectionLocked(r, null, null);
11005
11006 if (r.binding.service.app != null) {
11007 // This could have made the service less important.
11008 updateOomAdjLocked(r.binding.service.app);
11009 }
11010
11011 Binder.restoreCallingIdentity(origId);
11012 }
11013
11014 return true;
11015 }
11016
11017 public void publishService(IBinder token, Intent intent, IBinder service) {
11018 // Refuse possible leaked file descriptors
11019 if (intent != null && intent.hasFileDescriptors() == true) {
11020 throw new IllegalArgumentException("File descriptors passed in Intent");
11021 }
11022
11023 synchronized(this) {
11024 if (!(token instanceof ServiceRecord)) {
11025 throw new IllegalArgumentException("Invalid service token");
11026 }
11027 ServiceRecord r = (ServiceRecord)token;
11028
11029 final long origId = Binder.clearCallingIdentity();
11030
11031 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11032 + " " + intent + ": " + service);
11033 if (r != null) {
11034 Intent.FilterComparison filter
11035 = new Intent.FilterComparison(intent);
11036 IntentBindRecord b = r.bindings.get(filter);
11037 if (b != null && !b.received) {
11038 b.binder = service;
11039 b.requested = true;
11040 b.received = true;
11041 if (r.connections.size() > 0) {
11042 Iterator<ConnectionRecord> it
11043 = r.connections.values().iterator();
11044 while (it.hasNext()) {
11045 ConnectionRecord c = it.next();
11046 if (!filter.equals(c.binding.intent.intent)) {
11047 if (DEBUG_SERVICE) Log.v(
11048 TAG, "Not publishing to: " + c);
11049 if (DEBUG_SERVICE) Log.v(
11050 TAG, "Bound intent: " + c.binding.intent.intent);
11051 if (DEBUG_SERVICE) Log.v(
11052 TAG, "Published intent: " + intent);
11053 continue;
11054 }
11055 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11056 try {
11057 c.conn.connected(r.name, service);
11058 } catch (Exception e) {
11059 Log.w(TAG, "Failure sending service " + r.name +
11060 " to connection " + c.conn.asBinder() +
11061 " (in " + c.binding.client.processName + ")", e);
11062 }
11063 }
11064 }
11065 }
11066
11067 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11068
11069 Binder.restoreCallingIdentity(origId);
11070 }
11071 }
11072 }
11073
11074 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11075 // Refuse possible leaked file descriptors
11076 if (intent != null && intent.hasFileDescriptors() == true) {
11077 throw new IllegalArgumentException("File descriptors passed in Intent");
11078 }
11079
11080 synchronized(this) {
11081 if (!(token instanceof ServiceRecord)) {
11082 throw new IllegalArgumentException("Invalid service token");
11083 }
11084 ServiceRecord r = (ServiceRecord)token;
11085
11086 final long origId = Binder.clearCallingIdentity();
11087
11088 if (r != null) {
11089 Intent.FilterComparison filter
11090 = new Intent.FilterComparison(intent);
11091 IntentBindRecord b = r.bindings.get(filter);
11092 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11093 + " at " + b + ": apps="
11094 + (b != null ? b.apps.size() : 0));
11095 if (b != null) {
11096 if (b.apps.size() > 0) {
11097 // Applications have already bound since the last
11098 // unbind, so just rebind right here.
11099 requestServiceBindingLocked(r, b, true);
11100 } else {
11101 // Note to tell the service the next time there is
11102 // a new client.
11103 b.doRebind = true;
11104 }
11105 }
11106
11107 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11108
11109 Binder.restoreCallingIdentity(origId);
11110 }
11111 }
11112 }
11113
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011114 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011115 synchronized(this) {
11116 if (!(token instanceof ServiceRecord)) {
11117 throw new IllegalArgumentException("Invalid service token");
11118 }
11119 ServiceRecord r = (ServiceRecord)token;
11120 boolean inStopping = mStoppingServices.contains(token);
11121 if (r != null) {
11122 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11123 + ": nesting=" + r.executeNesting
11124 + ", inStopping=" + inStopping);
11125 if (r != token) {
11126 Log.w(TAG, "Done executing service " + r.name
11127 + " with incorrect token: given " + token
11128 + ", expected " + r);
11129 return;
11130 }
11131
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011132 if (type == 1) {
11133 // This is a call from a service start... take care of
11134 // book-keeping.
11135 r.callStart = true;
11136 switch (res) {
11137 case Service.START_STICKY_COMPATIBILITY:
11138 case Service.START_STICKY: {
11139 // We are done with the associated start arguments.
11140 r.findDeliveredStart(startId, true);
11141 // Don't stop if killed.
11142 r.stopIfKilled = false;
11143 break;
11144 }
11145 case Service.START_NOT_STICKY: {
11146 // We are done with the associated start arguments.
11147 r.findDeliveredStart(startId, true);
11148 if (r.lastStartId == startId) {
11149 // There is no more work, and this service
11150 // doesn't want to hang around if killed.
11151 r.stopIfKilled = true;
11152 }
11153 break;
11154 }
11155 case Service.START_REDELIVER_INTENT: {
11156 // We'll keep this item until they explicitly
11157 // call stop for it, but keep track of the fact
11158 // that it was delivered.
11159 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11160 if (si != null) {
11161 si.deliveryCount = 0;
11162 si.doneExecutingCount++;
11163 // Don't stop if killed.
11164 r.stopIfKilled = true;
11165 }
11166 break;
11167 }
11168 default:
11169 throw new IllegalArgumentException(
11170 "Unknown service start result: " + res);
11171 }
11172 if (res == Service.START_STICKY_COMPATIBILITY) {
11173 r.callStart = false;
11174 }
11175 }
11176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011177 final long origId = Binder.clearCallingIdentity();
11178 serviceDoneExecutingLocked(r, inStopping);
11179 Binder.restoreCallingIdentity(origId);
11180 } else {
11181 Log.w(TAG, "Done executing unknown service " + r.name
11182 + " with token " + token);
11183 }
11184 }
11185 }
11186
11187 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11188 r.executeNesting--;
11189 if (r.executeNesting <= 0 && r.app != null) {
11190 r.app.executingServices.remove(r);
11191 if (r.app.executingServices.size() == 0) {
11192 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11193 }
11194 if (inStopping) {
11195 mStoppingServices.remove(r);
11196 }
11197 updateOomAdjLocked(r.app);
11198 }
11199 }
11200
11201 void serviceTimeout(ProcessRecord proc) {
11202 synchronized(this) {
11203 if (proc.executingServices.size() == 0 || proc.thread == null) {
11204 return;
11205 }
11206 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11207 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11208 ServiceRecord timeout = null;
11209 long nextTime = 0;
11210 while (it.hasNext()) {
11211 ServiceRecord sr = it.next();
11212 if (sr.executingStart < maxTime) {
11213 timeout = sr;
11214 break;
11215 }
11216 if (sr.executingStart > nextTime) {
11217 nextTime = sr.executingStart;
11218 }
11219 }
11220 if (timeout != null && mLRUProcesses.contains(proc)) {
11221 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011222 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011223 + timeout.name);
11224 } else {
11225 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11226 msg.obj = proc;
11227 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11228 }
11229 }
11230 }
11231
11232 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011233 // BACKUP AND RESTORE
11234 // =========================================================
11235
11236 // Cause the target app to be launched if necessary and its backup agent
11237 // instantiated. The backup agent will invoke backupAgentCreated() on the
11238 // activity manager to announce its creation.
11239 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11240 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11241 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11242
11243 synchronized(this) {
11244 // !!! TODO: currently no check here that we're already bound
11245 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11246 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11247 synchronized (stats) {
11248 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11249 }
11250
11251 BackupRecord r = new BackupRecord(ss, app, backupMode);
11252 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11253 // startProcessLocked() returns existing proc's record if it's already running
11254 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011255 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011256 if (proc == null) {
11257 Log.e(TAG, "Unable to start backup agent process " + r);
11258 return false;
11259 }
11260
11261 r.app = proc;
11262 mBackupTarget = r;
11263 mBackupAppName = app.packageName;
11264
Christopher Tate6fa95972009-06-05 18:43:55 -070011265 // Try not to kill the process during backup
11266 updateOomAdjLocked(proc);
11267
Christopher Tate181fafa2009-05-14 11:12:14 -070011268 // If the process is already attached, schedule the creation of the backup agent now.
11269 // If it is not yet live, this will be done when it attaches to the framework.
11270 if (proc.thread != null) {
11271 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11272 try {
11273 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11274 } catch (RemoteException e) {
11275 // !!! TODO: notify the backup manager that we crashed, or rely on
11276 // death notices, or...?
11277 }
11278 } else {
11279 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11280 }
11281 // Invariants: at this point, the target app process exists and the application
11282 // is either already running or in the process of coming up. mBackupTarget and
11283 // mBackupAppName describe the app, so that when it binds back to the AM we
11284 // know that it's scheduled for a backup-agent operation.
11285 }
11286
11287 return true;
11288 }
11289
11290 // A backup agent has just come up
11291 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11292 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11293 + " = " + agent);
11294
11295 synchronized(this) {
11296 if (!agentPackageName.equals(mBackupAppName)) {
11297 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11298 return;
11299 }
11300
Christopher Tate043dadc2009-06-02 16:11:00 -070011301 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011302 try {
11303 IBackupManager bm = IBackupManager.Stub.asInterface(
11304 ServiceManager.getService(Context.BACKUP_SERVICE));
11305 bm.agentConnected(agentPackageName, agent);
11306 } catch (RemoteException e) {
11307 // can't happen; the backup manager service is local
11308 } catch (Exception e) {
11309 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11310 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011311 } finally {
11312 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011313 }
11314 }
11315 }
11316
11317 // done with this agent
11318 public void unbindBackupAgent(ApplicationInfo appInfo) {
11319 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011320 if (appInfo == null) {
11321 Log.w(TAG, "unbind backup agent for null app");
11322 return;
11323 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011324
11325 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011326 if (mBackupAppName == null) {
11327 Log.w(TAG, "Unbinding backup agent with no active backup");
11328 return;
11329 }
11330
Christopher Tate181fafa2009-05-14 11:12:14 -070011331 if (!mBackupAppName.equals(appInfo.packageName)) {
11332 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11333 return;
11334 }
11335
Christopher Tate6fa95972009-06-05 18:43:55 -070011336 ProcessRecord proc = mBackupTarget.app;
11337 mBackupTarget = null;
11338 mBackupAppName = null;
11339
11340 // Not backing this app up any more; reset its OOM adjustment
11341 updateOomAdjLocked(proc);
11342
Christopher Tatec7b31e32009-06-10 15:49:30 -070011343 // If the app crashed during backup, 'thread' will be null here
11344 if (proc.thread != null) {
11345 try {
11346 proc.thread.scheduleDestroyBackupAgent(appInfo);
11347 } catch (Exception e) {
11348 Log.e(TAG, "Exception when unbinding backup agent:");
11349 e.printStackTrace();
11350 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011351 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011352 }
11353 }
11354 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011355 // BROADCASTS
11356 // =========================================================
11357
11358 private final List getStickies(String action, IntentFilter filter,
11359 List cur) {
11360 final ContentResolver resolver = mContext.getContentResolver();
11361 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11362 if (list == null) {
11363 return cur;
11364 }
11365 int N = list.size();
11366 for (int i=0; i<N; i++) {
11367 Intent intent = list.get(i);
11368 if (filter.match(resolver, intent, true, TAG) >= 0) {
11369 if (cur == null) {
11370 cur = new ArrayList<Intent>();
11371 }
11372 cur.add(intent);
11373 }
11374 }
11375 return cur;
11376 }
11377
11378 private final void scheduleBroadcastsLocked() {
11379 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11380 + mBroadcastsScheduled);
11381
11382 if (mBroadcastsScheduled) {
11383 return;
11384 }
11385 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11386 mBroadcastsScheduled = true;
11387 }
11388
11389 public Intent registerReceiver(IApplicationThread caller,
11390 IIntentReceiver receiver, IntentFilter filter, String permission) {
11391 synchronized(this) {
11392 ProcessRecord callerApp = null;
11393 if (caller != null) {
11394 callerApp = getRecordForAppLocked(caller);
11395 if (callerApp == null) {
11396 throw new SecurityException(
11397 "Unable to find app for caller " + caller
11398 + " (pid=" + Binder.getCallingPid()
11399 + ") when registering receiver " + receiver);
11400 }
11401 }
11402
11403 List allSticky = null;
11404
11405 // Look for any matching sticky broadcasts...
11406 Iterator actions = filter.actionsIterator();
11407 if (actions != null) {
11408 while (actions.hasNext()) {
11409 String action = (String)actions.next();
11410 allSticky = getStickies(action, filter, allSticky);
11411 }
11412 } else {
11413 allSticky = getStickies(null, filter, allSticky);
11414 }
11415
11416 // The first sticky in the list is returned directly back to
11417 // the client.
11418 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11419
11420 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11421 + ": " + sticky);
11422
11423 if (receiver == null) {
11424 return sticky;
11425 }
11426
11427 ReceiverList rl
11428 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11429 if (rl == null) {
11430 rl = new ReceiverList(this, callerApp,
11431 Binder.getCallingPid(),
11432 Binder.getCallingUid(), receiver);
11433 if (rl.app != null) {
11434 rl.app.receivers.add(rl);
11435 } else {
11436 try {
11437 receiver.asBinder().linkToDeath(rl, 0);
11438 } catch (RemoteException e) {
11439 return sticky;
11440 }
11441 rl.linkedToDeath = true;
11442 }
11443 mRegisteredReceivers.put(receiver.asBinder(), rl);
11444 }
11445 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11446 rl.add(bf);
11447 if (!bf.debugCheck()) {
11448 Log.w(TAG, "==> For Dynamic broadast");
11449 }
11450 mReceiverResolver.addFilter(bf);
11451
11452 // Enqueue broadcasts for all existing stickies that match
11453 // this filter.
11454 if (allSticky != null) {
11455 ArrayList receivers = new ArrayList();
11456 receivers.add(bf);
11457
11458 int N = allSticky.size();
11459 for (int i=0; i<N; i++) {
11460 Intent intent = (Intent)allSticky.get(i);
11461 BroadcastRecord r = new BroadcastRecord(intent, null,
11462 null, -1, -1, null, receivers, null, 0, null, null,
11463 false);
11464 if (mParallelBroadcasts.size() == 0) {
11465 scheduleBroadcastsLocked();
11466 }
11467 mParallelBroadcasts.add(r);
11468 }
11469 }
11470
11471 return sticky;
11472 }
11473 }
11474
11475 public void unregisterReceiver(IIntentReceiver receiver) {
11476 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11477
11478 boolean doNext = false;
11479
11480 synchronized(this) {
11481 ReceiverList rl
11482 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11483 if (rl != null) {
11484 if (rl.curBroadcast != null) {
11485 BroadcastRecord r = rl.curBroadcast;
11486 doNext = finishReceiverLocked(
11487 receiver.asBinder(), r.resultCode, r.resultData,
11488 r.resultExtras, r.resultAbort, true);
11489 }
11490
11491 if (rl.app != null) {
11492 rl.app.receivers.remove(rl);
11493 }
11494 removeReceiverLocked(rl);
11495 if (rl.linkedToDeath) {
11496 rl.linkedToDeath = false;
11497 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11498 }
11499 }
11500 }
11501
11502 if (!doNext) {
11503 return;
11504 }
11505
11506 final long origId = Binder.clearCallingIdentity();
11507 processNextBroadcast(false);
11508 trimApplications();
11509 Binder.restoreCallingIdentity(origId);
11510 }
11511
11512 void removeReceiverLocked(ReceiverList rl) {
11513 mRegisteredReceivers.remove(rl.receiver.asBinder());
11514 int N = rl.size();
11515 for (int i=0; i<N; i++) {
11516 mReceiverResolver.removeFilter(rl.get(i));
11517 }
11518 }
11519
11520 private final int broadcastIntentLocked(ProcessRecord callerApp,
11521 String callerPackage, Intent intent, String resolvedType,
11522 IIntentReceiver resultTo, int resultCode, String resultData,
11523 Bundle map, String requiredPermission,
11524 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11525 intent = new Intent(intent);
11526
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011527 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011528 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11529 + " ordered=" + ordered);
11530 if ((resultTo != null) && !ordered) {
11531 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11532 }
11533
11534 // Handle special intents: if this broadcast is from the package
11535 // manager about a package being removed, we need to remove all of
11536 // its activities from the history stack.
11537 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11538 intent.getAction());
11539 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11540 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11541 || uidRemoved) {
11542 if (checkComponentPermission(
11543 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11544 callingPid, callingUid, -1)
11545 == PackageManager.PERMISSION_GRANTED) {
11546 if (uidRemoved) {
11547 final Bundle intentExtras = intent.getExtras();
11548 final int uid = intentExtras != null
11549 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11550 if (uid >= 0) {
11551 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11552 synchronized (bs) {
11553 bs.removeUidStatsLocked(uid);
11554 }
11555 }
11556 } else {
11557 Uri data = intent.getData();
11558 String ssp;
11559 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11560 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11561 uninstallPackageLocked(ssp,
11562 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011563 AttributeCache ac = AttributeCache.instance();
11564 if (ac != null) {
11565 ac.removePackage(ssp);
11566 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011567 }
11568 }
11569 }
11570 } else {
11571 String msg = "Permission Denial: " + intent.getAction()
11572 + " broadcast from " + callerPackage + " (pid=" + callingPid
11573 + ", uid=" + callingUid + ")"
11574 + " requires "
11575 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11576 Log.w(TAG, msg);
11577 throw new SecurityException(msg);
11578 }
11579 }
11580
11581 /*
11582 * If this is the time zone changed action, queue up a message that will reset the timezone
11583 * of all currently running processes. This message will get queued up before the broadcast
11584 * happens.
11585 */
11586 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11587 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11588 }
11589
Dianne Hackborn854060af2009-07-09 18:14:31 -070011590 /*
11591 * Prevent non-system code (defined here to be non-persistent
11592 * processes) from sending protected broadcasts.
11593 */
11594 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11595 || callingUid == Process.SHELL_UID || callingUid == 0) {
11596 // Always okay.
11597 } else if (callerApp == null || !callerApp.persistent) {
11598 try {
11599 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11600 intent.getAction())) {
11601 String msg = "Permission Denial: not allowed to send broadcast "
11602 + intent.getAction() + " from pid="
11603 + callingPid + ", uid=" + callingUid;
11604 Log.w(TAG, msg);
11605 throw new SecurityException(msg);
11606 }
11607 } catch (RemoteException e) {
11608 Log.w(TAG, "Remote exception", e);
11609 return BROADCAST_SUCCESS;
11610 }
11611 }
11612
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011613 // Add to the sticky list if requested.
11614 if (sticky) {
11615 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11616 callingPid, callingUid)
11617 != PackageManager.PERMISSION_GRANTED) {
11618 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11619 + callingPid + ", uid=" + callingUid
11620 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11621 Log.w(TAG, msg);
11622 throw new SecurityException(msg);
11623 }
11624 if (requiredPermission != null) {
11625 Log.w(TAG, "Can't broadcast sticky intent " + intent
11626 + " and enforce permission " + requiredPermission);
11627 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11628 }
11629 if (intent.getComponent() != null) {
11630 throw new SecurityException(
11631 "Sticky broadcasts can't target a specific component");
11632 }
11633 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11634 if (list == null) {
11635 list = new ArrayList<Intent>();
11636 mStickyBroadcasts.put(intent.getAction(), list);
11637 }
11638 int N = list.size();
11639 int i;
11640 for (i=0; i<N; i++) {
11641 if (intent.filterEquals(list.get(i))) {
11642 // This sticky already exists, replace it.
11643 list.set(i, new Intent(intent));
11644 break;
11645 }
11646 }
11647 if (i >= N) {
11648 list.add(new Intent(intent));
11649 }
11650 }
11651
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011652 // Figure out who all will receive this broadcast.
11653 List receivers = null;
11654 List<BroadcastFilter> registeredReceivers = null;
11655 try {
11656 if (intent.getComponent() != null) {
11657 // Broadcast is going to one specific receiver class...
11658 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011659 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011660 if (ai != null) {
11661 receivers = new ArrayList();
11662 ResolveInfo ri = new ResolveInfo();
11663 ri.activityInfo = ai;
11664 receivers.add(ri);
11665 }
11666 } else {
11667 // Need to resolve the intent to interested receivers...
11668 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11669 == 0) {
11670 receivers =
11671 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011672 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011673 }
Mihai Preda074edef2009-05-18 17:13:31 +020011674 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011675 }
11676 } catch (RemoteException ex) {
11677 // pm is in same process, this will never happen.
11678 }
11679
11680 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11681 if (!ordered && NR > 0) {
11682 // If we are not serializing this broadcast, then send the
11683 // registered receivers separately so they don't wait for the
11684 // components to be launched.
11685 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11686 callerPackage, callingPid, callingUid, requiredPermission,
11687 registeredReceivers, resultTo, resultCode, resultData, map,
11688 ordered);
11689 if (DEBUG_BROADCAST) Log.v(
11690 TAG, "Enqueueing parallel broadcast " + r
11691 + ": prev had " + mParallelBroadcasts.size());
11692 mParallelBroadcasts.add(r);
11693 scheduleBroadcastsLocked();
11694 registeredReceivers = null;
11695 NR = 0;
11696 }
11697
11698 // Merge into one list.
11699 int ir = 0;
11700 if (receivers != null) {
11701 // A special case for PACKAGE_ADDED: do not allow the package
11702 // being added to see this broadcast. This prevents them from
11703 // using this as a back door to get run as soon as they are
11704 // installed. Maybe in the future we want to have a special install
11705 // broadcast or such for apps, but we'd like to deliberately make
11706 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011707 boolean skip = false;
11708 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011709 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011710 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11711 skip = true;
11712 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11713 skip = true;
11714 }
11715 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011716 ? intent.getData().getSchemeSpecificPart()
11717 : null;
11718 if (skipPackage != null && receivers != null) {
11719 int NT = receivers.size();
11720 for (int it=0; it<NT; it++) {
11721 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11722 if (curt.activityInfo.packageName.equals(skipPackage)) {
11723 receivers.remove(it);
11724 it--;
11725 NT--;
11726 }
11727 }
11728 }
11729
11730 int NT = receivers != null ? receivers.size() : 0;
11731 int it = 0;
11732 ResolveInfo curt = null;
11733 BroadcastFilter curr = null;
11734 while (it < NT && ir < NR) {
11735 if (curt == null) {
11736 curt = (ResolveInfo)receivers.get(it);
11737 }
11738 if (curr == null) {
11739 curr = registeredReceivers.get(ir);
11740 }
11741 if (curr.getPriority() >= curt.priority) {
11742 // Insert this broadcast record into the final list.
11743 receivers.add(it, curr);
11744 ir++;
11745 curr = null;
11746 it++;
11747 NT++;
11748 } else {
11749 // Skip to the next ResolveInfo in the final list.
11750 it++;
11751 curt = null;
11752 }
11753 }
11754 }
11755 while (ir < NR) {
11756 if (receivers == null) {
11757 receivers = new ArrayList();
11758 }
11759 receivers.add(registeredReceivers.get(ir));
11760 ir++;
11761 }
11762
11763 if ((receivers != null && receivers.size() > 0)
11764 || resultTo != null) {
11765 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11766 callerPackage, callingPid, callingUid, requiredPermission,
11767 receivers, resultTo, resultCode, resultData, map, ordered);
11768 if (DEBUG_BROADCAST) Log.v(
11769 TAG, "Enqueueing ordered broadcast " + r
11770 + ": prev had " + mOrderedBroadcasts.size());
11771 if (DEBUG_BROADCAST) {
11772 int seq = r.intent.getIntExtra("seq", -1);
11773 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11774 }
11775 mOrderedBroadcasts.add(r);
11776 scheduleBroadcastsLocked();
11777 }
11778
11779 return BROADCAST_SUCCESS;
11780 }
11781
11782 public final int broadcastIntent(IApplicationThread caller,
11783 Intent intent, String resolvedType, IIntentReceiver resultTo,
11784 int resultCode, String resultData, Bundle map,
11785 String requiredPermission, boolean serialized, boolean sticky) {
11786 // Refuse possible leaked file descriptors
11787 if (intent != null && intent.hasFileDescriptors() == true) {
11788 throw new IllegalArgumentException("File descriptors passed in Intent");
11789 }
11790
11791 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011792 int flags = intent.getFlags();
11793
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011794 if (!mSystemReady) {
11795 // if the caller really truly claims to know what they're doing, go
11796 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011797 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11798 intent = new Intent(intent);
11799 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11800 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11801 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11802 + " before boot completion");
11803 throw new IllegalStateException("Cannot broadcast before boot completed");
11804 }
11805 }
11806
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011807 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
11808 throw new IllegalArgumentException(
11809 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
11810 }
11811
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011812 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11813 final int callingPid = Binder.getCallingPid();
11814 final int callingUid = Binder.getCallingUid();
11815 final long origId = Binder.clearCallingIdentity();
11816 int res = broadcastIntentLocked(callerApp,
11817 callerApp != null ? callerApp.info.packageName : null,
11818 intent, resolvedType, resultTo,
11819 resultCode, resultData, map, requiredPermission, serialized,
11820 sticky, callingPid, callingUid);
11821 Binder.restoreCallingIdentity(origId);
11822 return res;
11823 }
11824 }
11825
11826 int broadcastIntentInPackage(String packageName, int uid,
11827 Intent intent, String resolvedType, IIntentReceiver resultTo,
11828 int resultCode, String resultData, Bundle map,
11829 String requiredPermission, boolean serialized, boolean sticky) {
11830 synchronized(this) {
11831 final long origId = Binder.clearCallingIdentity();
11832 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11833 resultTo, resultCode, resultData, map, requiredPermission,
11834 serialized, sticky, -1, uid);
11835 Binder.restoreCallingIdentity(origId);
11836 return res;
11837 }
11838 }
11839
11840 public final void unbroadcastIntent(IApplicationThread caller,
11841 Intent intent) {
11842 // Refuse possible leaked file descriptors
11843 if (intent != null && intent.hasFileDescriptors() == true) {
11844 throw new IllegalArgumentException("File descriptors passed in Intent");
11845 }
11846
11847 synchronized(this) {
11848 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11849 != PackageManager.PERMISSION_GRANTED) {
11850 String msg = "Permission Denial: unbroadcastIntent() from pid="
11851 + Binder.getCallingPid()
11852 + ", uid=" + Binder.getCallingUid()
11853 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11854 Log.w(TAG, msg);
11855 throw new SecurityException(msg);
11856 }
11857 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11858 if (list != null) {
11859 int N = list.size();
11860 int i;
11861 for (i=0; i<N; i++) {
11862 if (intent.filterEquals(list.get(i))) {
11863 list.remove(i);
11864 break;
11865 }
11866 }
11867 }
11868 }
11869 }
11870
11871 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11872 String resultData, Bundle resultExtras, boolean resultAbort,
11873 boolean explicit) {
11874 if (mOrderedBroadcasts.size() == 0) {
11875 if (explicit) {
11876 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11877 }
11878 return false;
11879 }
11880 BroadcastRecord r = mOrderedBroadcasts.get(0);
11881 if (r.receiver == null) {
11882 if (explicit) {
11883 Log.w(TAG, "finishReceiver called but none active");
11884 }
11885 return false;
11886 }
11887 if (r.receiver != receiver) {
11888 Log.w(TAG, "finishReceiver called but active receiver is different");
11889 return false;
11890 }
11891 int state = r.state;
11892 r.state = r.IDLE;
11893 if (state == r.IDLE) {
11894 if (explicit) {
11895 Log.w(TAG, "finishReceiver called but state is IDLE");
11896 }
11897 }
11898 r.receiver = null;
11899 r.intent.setComponent(null);
11900 if (r.curApp != null) {
11901 r.curApp.curReceiver = null;
11902 }
11903 if (r.curFilter != null) {
11904 r.curFilter.receiverList.curBroadcast = null;
11905 }
11906 r.curFilter = null;
11907 r.curApp = null;
11908 r.curComponent = null;
11909 r.curReceiver = null;
11910 mPendingBroadcast = null;
11911
11912 r.resultCode = resultCode;
11913 r.resultData = resultData;
11914 r.resultExtras = resultExtras;
11915 r.resultAbort = resultAbort;
11916
11917 // We will process the next receiver right now if this is finishing
11918 // an app receiver (which is always asynchronous) or after we have
11919 // come back from calling a receiver.
11920 return state == BroadcastRecord.APP_RECEIVE
11921 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11922 }
11923
11924 public void finishReceiver(IBinder who, int resultCode, String resultData,
11925 Bundle resultExtras, boolean resultAbort) {
11926 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11927
11928 // Refuse possible leaked file descriptors
11929 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11930 throw new IllegalArgumentException("File descriptors passed in Bundle");
11931 }
11932
11933 boolean doNext;
11934
11935 final long origId = Binder.clearCallingIdentity();
11936
11937 synchronized(this) {
11938 doNext = finishReceiverLocked(
11939 who, resultCode, resultData, resultExtras, resultAbort, true);
11940 }
11941
11942 if (doNext) {
11943 processNextBroadcast(false);
11944 }
11945 trimApplications();
11946
11947 Binder.restoreCallingIdentity(origId);
11948 }
11949
11950 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11951 if (r.nextReceiver > 0) {
11952 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11953 if (curReceiver instanceof BroadcastFilter) {
11954 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11955 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11956 System.identityHashCode(r),
11957 r.intent.getAction(),
11958 r.nextReceiver - 1,
11959 System.identityHashCode(bf));
11960 } else {
11961 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11962 System.identityHashCode(r),
11963 r.intent.getAction(),
11964 r.nextReceiver - 1,
11965 ((ResolveInfo)curReceiver).toString());
11966 }
11967 } else {
11968 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11969 + r);
11970 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11971 System.identityHashCode(r),
11972 r.intent.getAction(),
11973 r.nextReceiver,
11974 "NONE");
11975 }
11976 }
11977
11978 private final void broadcastTimeout() {
11979 synchronized (this) {
11980 if (mOrderedBroadcasts.size() == 0) {
11981 return;
11982 }
11983 long now = SystemClock.uptimeMillis();
11984 BroadcastRecord r = mOrderedBroadcasts.get(0);
11985 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11986 if (DEBUG_BROADCAST) Log.v(TAG,
11987 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11988 + (r.startTime + BROADCAST_TIMEOUT));
11989 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11990 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11991 return;
11992 }
11993
11994 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11995 r.startTime = now;
11996 r.anrCount++;
11997
11998 // Current receiver has passed its expiration date.
11999 if (r.nextReceiver <= 0) {
12000 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12001 return;
12002 }
12003
12004 ProcessRecord app = null;
12005
12006 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12007 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12008 logBroadcastReceiverDiscard(r);
12009 if (curReceiver instanceof BroadcastFilter) {
12010 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12011 if (bf.receiverList.pid != 0
12012 && bf.receiverList.pid != MY_PID) {
12013 synchronized (this.mPidsSelfLocked) {
12014 app = this.mPidsSelfLocked.get(
12015 bf.receiverList.pid);
12016 }
12017 }
12018 } else {
12019 app = r.curApp;
12020 }
12021
12022 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070012023 appNotRespondingLocked(app, null, null,
12024 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012025 }
12026
12027 if (mPendingBroadcast == r) {
12028 mPendingBroadcast = null;
12029 }
12030
12031 // Move on to the next receiver.
12032 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12033 r.resultExtras, r.resultAbort, true);
12034 scheduleBroadcastsLocked();
12035 }
12036 }
12037
12038 private final void processCurBroadcastLocked(BroadcastRecord r,
12039 ProcessRecord app) throws RemoteException {
12040 if (app.thread == null) {
12041 throw new RemoteException();
12042 }
12043 r.receiver = app.thread.asBinder();
12044 r.curApp = app;
12045 app.curReceiver = r;
12046 updateLRUListLocked(app, true);
12047
12048 // Tell the application to launch this receiver.
12049 r.intent.setComponent(r.curComponent);
12050
12051 boolean started = false;
12052 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012053 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012054 "Delivering to component " + r.curComponent
12055 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012056 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012057 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12058 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12059 started = true;
12060 } finally {
12061 if (!started) {
12062 r.receiver = null;
12063 r.curApp = null;
12064 app.curReceiver = null;
12065 }
12066 }
12067
12068 }
12069
12070 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
12071 Intent intent, int resultCode, String data,
12072 Bundle extras, boolean ordered) throws RemoteException {
12073 if (app != null && app.thread != null) {
12074 // If we have an app thread, do the call through that so it is
12075 // correctly ordered with other one-way calls.
12076 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
12077 data, extras, ordered);
12078 } else {
12079 receiver.performReceive(intent, resultCode, data, extras, ordered);
12080 }
12081 }
12082
12083 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12084 BroadcastFilter filter, boolean ordered) {
12085 boolean skip = false;
12086 if (filter.requiredPermission != null) {
12087 int perm = checkComponentPermission(filter.requiredPermission,
12088 r.callingPid, r.callingUid, -1);
12089 if (perm != PackageManager.PERMISSION_GRANTED) {
12090 Log.w(TAG, "Permission Denial: broadcasting "
12091 + r.intent.toString()
12092 + " from " + r.callerPackage + " (pid="
12093 + r.callingPid + ", uid=" + r.callingUid + ")"
12094 + " requires " + filter.requiredPermission
12095 + " due to registered receiver " + filter);
12096 skip = true;
12097 }
12098 }
12099 if (r.requiredPermission != null) {
12100 int perm = checkComponentPermission(r.requiredPermission,
12101 filter.receiverList.pid, filter.receiverList.uid, -1);
12102 if (perm != PackageManager.PERMISSION_GRANTED) {
12103 Log.w(TAG, "Permission Denial: receiving "
12104 + r.intent.toString()
12105 + " to " + filter.receiverList.app
12106 + " (pid=" + filter.receiverList.pid
12107 + ", uid=" + filter.receiverList.uid + ")"
12108 + " requires " + r.requiredPermission
12109 + " due to sender " + r.callerPackage
12110 + " (uid " + r.callingUid + ")");
12111 skip = true;
12112 }
12113 }
12114
12115 if (!skip) {
12116 // If this is not being sent as an ordered broadcast, then we
12117 // don't want to touch the fields that keep track of the current
12118 // state of ordered broadcasts.
12119 if (ordered) {
12120 r.receiver = filter.receiverList.receiver.asBinder();
12121 r.curFilter = filter;
12122 filter.receiverList.curBroadcast = r;
12123 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012124 if (filter.receiverList.app != null) {
12125 // Bump hosting application to no longer be in background
12126 // scheduling class. Note that we can't do that if there
12127 // isn't an app... but we can only be in that case for
12128 // things that directly call the IActivityManager API, which
12129 // are already core system stuff so don't matter for this.
12130 r.curApp = filter.receiverList.app;
12131 filter.receiverList.app.curReceiver = r;
12132 updateOomAdjLocked();
12133 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012134 }
12135 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012136 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012137 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012138 Log.i(TAG, "Delivering to " + filter.receiverList.app
12139 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012140 }
12141 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12142 new Intent(r.intent), r.resultCode,
12143 r.resultData, r.resultExtras, r.ordered);
12144 if (ordered) {
12145 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12146 }
12147 } catch (RemoteException e) {
12148 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12149 if (ordered) {
12150 r.receiver = null;
12151 r.curFilter = null;
12152 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012153 if (filter.receiverList.app != null) {
12154 filter.receiverList.app.curReceiver = null;
12155 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012156 }
12157 }
12158 }
12159 }
12160
12161 private final void processNextBroadcast(boolean fromMsg) {
12162 synchronized(this) {
12163 BroadcastRecord r;
12164
12165 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12166 + mParallelBroadcasts.size() + " broadcasts, "
12167 + mOrderedBroadcasts.size() + " serialized broadcasts");
12168
12169 updateCpuStats();
12170
12171 if (fromMsg) {
12172 mBroadcastsScheduled = false;
12173 }
12174
12175 // First, deliver any non-serialized broadcasts right away.
12176 while (mParallelBroadcasts.size() > 0) {
12177 r = mParallelBroadcasts.remove(0);
12178 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012179 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12180 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012181 for (int i=0; i<N; i++) {
12182 Object target = r.receivers.get(i);
12183 if (DEBUG_BROADCAST) Log.v(TAG,
12184 "Delivering non-serialized to registered "
12185 + target + ": " + r);
12186 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12187 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012188 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12189 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012190 }
12191
12192 // Now take care of the next serialized one...
12193
12194 // If we are waiting for a process to come up to handle the next
12195 // broadcast, then do nothing at this point. Just in case, we
12196 // check that the process we're waiting for still exists.
12197 if (mPendingBroadcast != null) {
12198 Log.i(TAG, "processNextBroadcast: waiting for "
12199 + mPendingBroadcast.curApp);
12200
12201 boolean isDead;
12202 synchronized (mPidsSelfLocked) {
12203 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12204 }
12205 if (!isDead) {
12206 // It's still alive, so keep waiting
12207 return;
12208 } else {
12209 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12210 + " died before responding to broadcast");
12211 mPendingBroadcast = null;
12212 }
12213 }
12214
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012215 boolean looped = false;
12216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012217 do {
12218 if (mOrderedBroadcasts.size() == 0) {
12219 // No more broadcasts pending, so all done!
12220 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012221 if (looped) {
12222 // If we had finished the last ordered broadcast, then
12223 // make sure all processes have correct oom and sched
12224 // adjustments.
12225 updateOomAdjLocked();
12226 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012227 return;
12228 }
12229 r = mOrderedBroadcasts.get(0);
12230 boolean forceReceive = false;
12231
12232 // Ensure that even if something goes awry with the timeout
12233 // detection, we catch "hung" broadcasts here, discard them,
12234 // and continue to make progress.
12235 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12236 long now = SystemClock.uptimeMillis();
12237 if (r.dispatchTime > 0) {
12238 if ((numReceivers > 0) &&
12239 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12240 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12241 + " now=" + now
12242 + " dispatchTime=" + r.dispatchTime
12243 + " startTime=" + r.startTime
12244 + " intent=" + r.intent
12245 + " numReceivers=" + numReceivers
12246 + " nextReceiver=" + r.nextReceiver
12247 + " state=" + r.state);
12248 broadcastTimeout(); // forcibly finish this broadcast
12249 forceReceive = true;
12250 r.state = BroadcastRecord.IDLE;
12251 }
12252 }
12253
12254 if (r.state != BroadcastRecord.IDLE) {
12255 if (DEBUG_BROADCAST) Log.d(TAG,
12256 "processNextBroadcast() called when not idle (state="
12257 + r.state + ")");
12258 return;
12259 }
12260
12261 if (r.receivers == null || r.nextReceiver >= numReceivers
12262 || r.resultAbort || forceReceive) {
12263 // No more receivers for this broadcast! Send the final
12264 // result if requested...
12265 if (r.resultTo != null) {
12266 try {
12267 if (DEBUG_BROADCAST) {
12268 int seq = r.intent.getIntExtra("seq", -1);
12269 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12270 + " seq=" + seq + " app=" + r.callerApp);
12271 }
12272 performReceive(r.callerApp, r.resultTo,
12273 new Intent(r.intent), r.resultCode,
12274 r.resultData, r.resultExtras, false);
12275 } catch (RemoteException e) {
12276 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12277 }
12278 }
12279
12280 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12281 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12282
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012283 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12284 + r);
12285
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012286 // ... and on to the next...
12287 mOrderedBroadcasts.remove(0);
12288 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012289 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012290 continue;
12291 }
12292 } while (r == null);
12293
12294 // Get the next receiver...
12295 int recIdx = r.nextReceiver++;
12296
12297 // Keep track of when this receiver started, and make sure there
12298 // is a timeout message pending to kill it if need be.
12299 r.startTime = SystemClock.uptimeMillis();
12300 if (recIdx == 0) {
12301 r.dispatchTime = r.startTime;
12302
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012303 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12304 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012305 if (DEBUG_BROADCAST) Log.v(TAG,
12306 "Submitting BROADCAST_TIMEOUT_MSG for "
12307 + (r.startTime + BROADCAST_TIMEOUT));
12308 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12309 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12310 }
12311
12312 Object nextReceiver = r.receivers.get(recIdx);
12313 if (nextReceiver instanceof BroadcastFilter) {
12314 // Simple case: this is a registered receiver who gets
12315 // a direct call.
12316 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12317 if (DEBUG_BROADCAST) Log.v(TAG,
12318 "Delivering serialized to registered "
12319 + filter + ": " + r);
12320 deliverToRegisteredReceiver(r, filter, r.ordered);
12321 if (r.receiver == null || !r.ordered) {
12322 // The receiver has already finished, so schedule to
12323 // process the next one.
12324 r.state = BroadcastRecord.IDLE;
12325 scheduleBroadcastsLocked();
12326 }
12327 return;
12328 }
12329
12330 // Hard case: need to instantiate the receiver, possibly
12331 // starting its application process to host it.
12332
12333 ResolveInfo info =
12334 (ResolveInfo)nextReceiver;
12335
12336 boolean skip = false;
12337 int perm = checkComponentPermission(info.activityInfo.permission,
12338 r.callingPid, r.callingUid,
12339 info.activityInfo.exported
12340 ? -1 : info.activityInfo.applicationInfo.uid);
12341 if (perm != PackageManager.PERMISSION_GRANTED) {
12342 Log.w(TAG, "Permission Denial: broadcasting "
12343 + r.intent.toString()
12344 + " from " + r.callerPackage + " (pid=" + r.callingPid
12345 + ", uid=" + r.callingUid + ")"
12346 + " requires " + info.activityInfo.permission
12347 + " due to receiver " + info.activityInfo.packageName
12348 + "/" + info.activityInfo.name);
12349 skip = true;
12350 }
12351 if (r.callingUid != Process.SYSTEM_UID &&
12352 r.requiredPermission != null) {
12353 try {
12354 perm = ActivityThread.getPackageManager().
12355 checkPermission(r.requiredPermission,
12356 info.activityInfo.applicationInfo.packageName);
12357 } catch (RemoteException e) {
12358 perm = PackageManager.PERMISSION_DENIED;
12359 }
12360 if (perm != PackageManager.PERMISSION_GRANTED) {
12361 Log.w(TAG, "Permission Denial: receiving "
12362 + r.intent + " to "
12363 + info.activityInfo.applicationInfo.packageName
12364 + " requires " + r.requiredPermission
12365 + " due to sender " + r.callerPackage
12366 + " (uid " + r.callingUid + ")");
12367 skip = true;
12368 }
12369 }
12370 if (r.curApp != null && r.curApp.crashing) {
12371 // If the target process is crashing, just skip it.
12372 skip = true;
12373 }
12374
12375 if (skip) {
12376 r.receiver = null;
12377 r.curFilter = null;
12378 r.state = BroadcastRecord.IDLE;
12379 scheduleBroadcastsLocked();
12380 return;
12381 }
12382
12383 r.state = BroadcastRecord.APP_RECEIVE;
12384 String targetProcess = info.activityInfo.processName;
12385 r.curComponent = new ComponentName(
12386 info.activityInfo.applicationInfo.packageName,
12387 info.activityInfo.name);
12388 r.curReceiver = info.activityInfo;
12389
12390 // Is this receiver's application already running?
12391 ProcessRecord app = getProcessRecordLocked(targetProcess,
12392 info.activityInfo.applicationInfo.uid);
12393 if (app != null && app.thread != null) {
12394 try {
12395 processCurBroadcastLocked(r, app);
12396 return;
12397 } catch (RemoteException e) {
12398 Log.w(TAG, "Exception when sending broadcast to "
12399 + r.curComponent, e);
12400 }
12401
12402 // If a dead object exception was thrown -- fall through to
12403 // restart the application.
12404 }
12405
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012406 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012407 if ((r.curApp=startProcessLocked(targetProcess,
12408 info.activityInfo.applicationInfo, true,
12409 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012410 "broadcast", r.curComponent,
12411 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12412 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012413 // Ah, this recipient is unavailable. Finish it if necessary,
12414 // and mark the broadcast record as ready for the next.
12415 Log.w(TAG, "Unable to launch app "
12416 + info.activityInfo.applicationInfo.packageName + "/"
12417 + info.activityInfo.applicationInfo.uid + " for broadcast "
12418 + r.intent + ": process is bad");
12419 logBroadcastReceiverDiscard(r);
12420 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12421 r.resultExtras, r.resultAbort, true);
12422 scheduleBroadcastsLocked();
12423 r.state = BroadcastRecord.IDLE;
12424 return;
12425 }
12426
12427 mPendingBroadcast = r;
12428 }
12429 }
12430
12431 // =========================================================
12432 // INSTRUMENTATION
12433 // =========================================================
12434
12435 public boolean startInstrumentation(ComponentName className,
12436 String profileFile, int flags, Bundle arguments,
12437 IInstrumentationWatcher watcher) {
12438 // Refuse possible leaked file descriptors
12439 if (arguments != null && arguments.hasFileDescriptors()) {
12440 throw new IllegalArgumentException("File descriptors passed in Bundle");
12441 }
12442
12443 synchronized(this) {
12444 InstrumentationInfo ii = null;
12445 ApplicationInfo ai = null;
12446 try {
12447 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012448 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012449 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012450 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012451 } catch (PackageManager.NameNotFoundException e) {
12452 }
12453 if (ii == null) {
12454 reportStartInstrumentationFailure(watcher, className,
12455 "Unable to find instrumentation info for: " + className);
12456 return false;
12457 }
12458 if (ai == null) {
12459 reportStartInstrumentationFailure(watcher, className,
12460 "Unable to find instrumentation target package: " + ii.targetPackage);
12461 return false;
12462 }
12463
12464 int match = mContext.getPackageManager().checkSignatures(
12465 ii.targetPackage, ii.packageName);
12466 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12467 String msg = "Permission Denial: starting instrumentation "
12468 + className + " from pid="
12469 + Binder.getCallingPid()
12470 + ", uid=" + Binder.getCallingPid()
12471 + " not allowed because package " + ii.packageName
12472 + " does not have a signature matching the target "
12473 + ii.targetPackage;
12474 reportStartInstrumentationFailure(watcher, className, msg);
12475 throw new SecurityException(msg);
12476 }
12477
12478 final long origId = Binder.clearCallingIdentity();
12479 uninstallPackageLocked(ii.targetPackage, -1, true);
12480 ProcessRecord app = addAppLocked(ai);
12481 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012482 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012483 app.instrumentationProfileFile = profileFile;
12484 app.instrumentationArguments = arguments;
12485 app.instrumentationWatcher = watcher;
12486 app.instrumentationResultClass = className;
12487 Binder.restoreCallingIdentity(origId);
12488 }
12489
12490 return true;
12491 }
12492
12493 /**
12494 * Report errors that occur while attempting to start Instrumentation. Always writes the
12495 * error to the logs, but if somebody is watching, send the report there too. This enables
12496 * the "am" command to report errors with more information.
12497 *
12498 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12499 * @param cn The component name of the instrumentation.
12500 * @param report The error report.
12501 */
12502 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12503 ComponentName cn, String report) {
12504 Log.w(TAG, report);
12505 try {
12506 if (watcher != null) {
12507 Bundle results = new Bundle();
12508 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12509 results.putString("Error", report);
12510 watcher.instrumentationStatus(cn, -1, results);
12511 }
12512 } catch (RemoteException e) {
12513 Log.w(TAG, e);
12514 }
12515 }
12516
12517 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12518 if (app.instrumentationWatcher != null) {
12519 try {
12520 // NOTE: IInstrumentationWatcher *must* be oneway here
12521 app.instrumentationWatcher.instrumentationFinished(
12522 app.instrumentationClass,
12523 resultCode,
12524 results);
12525 } catch (RemoteException e) {
12526 }
12527 }
12528 app.instrumentationWatcher = null;
12529 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012530 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012531 app.instrumentationProfileFile = null;
12532 app.instrumentationArguments = null;
12533
12534 uninstallPackageLocked(app.processName, -1, false);
12535 }
12536
12537 public void finishInstrumentation(IApplicationThread target,
12538 int resultCode, Bundle results) {
12539 // Refuse possible leaked file descriptors
12540 if (results != null && results.hasFileDescriptors()) {
12541 throw new IllegalArgumentException("File descriptors passed in Intent");
12542 }
12543
12544 synchronized(this) {
12545 ProcessRecord app = getRecordForAppLocked(target);
12546 if (app == null) {
12547 Log.w(TAG, "finishInstrumentation: no app for " + target);
12548 return;
12549 }
12550 final long origId = Binder.clearCallingIdentity();
12551 finishInstrumentationLocked(app, resultCode, results);
12552 Binder.restoreCallingIdentity(origId);
12553 }
12554 }
12555
12556 // =========================================================
12557 // CONFIGURATION
12558 // =========================================================
12559
12560 public ConfigurationInfo getDeviceConfigurationInfo() {
12561 ConfigurationInfo config = new ConfigurationInfo();
12562 synchronized (this) {
12563 config.reqTouchScreen = mConfiguration.touchscreen;
12564 config.reqKeyboardType = mConfiguration.keyboard;
12565 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012566 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12567 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012568 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12569 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012570 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12571 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012572 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12573 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012574 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012575 }
12576 return config;
12577 }
12578
12579 public Configuration getConfiguration() {
12580 Configuration ci;
12581 synchronized(this) {
12582 ci = new Configuration(mConfiguration);
12583 }
12584 return ci;
12585 }
12586
12587 public void updateConfiguration(Configuration values) {
12588 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12589 "updateConfiguration()");
12590
12591 synchronized(this) {
12592 if (values == null && mWindowManager != null) {
12593 // sentinel: fetch the current configuration from the window manager
12594 values = mWindowManager.computeNewConfiguration();
12595 }
12596
12597 final long origId = Binder.clearCallingIdentity();
12598 updateConfigurationLocked(values, null);
12599 Binder.restoreCallingIdentity(origId);
12600 }
12601 }
12602
12603 /**
12604 * Do either or both things: (1) change the current configuration, and (2)
12605 * make sure the given activity is running with the (now) current
12606 * configuration. Returns true if the activity has been left running, or
12607 * false if <var>starting</var> is being destroyed to match the new
12608 * configuration.
12609 */
12610 public boolean updateConfigurationLocked(Configuration values,
12611 HistoryRecord starting) {
12612 int changes = 0;
12613
12614 boolean kept = true;
12615
12616 if (values != null) {
12617 Configuration newConfig = new Configuration(mConfiguration);
12618 changes = newConfig.updateFrom(values);
12619 if (changes != 0) {
12620 if (DEBUG_SWITCH) {
12621 Log.i(TAG, "Updating configuration to: " + values);
12622 }
12623
12624 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12625
12626 if (values.locale != null) {
12627 saveLocaleLocked(values.locale,
12628 !values.locale.equals(mConfiguration.locale),
12629 values.userSetLocale);
12630 }
12631
12632 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012633 Log.i(TAG, "Config changed: " + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012634
12635 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12636 msg.obj = new Configuration(mConfiguration);
12637 mHandler.sendMessage(msg);
12638
12639 final int N = mLRUProcesses.size();
12640 for (int i=0; i<N; i++) {
12641 ProcessRecord app = mLRUProcesses.get(i);
12642 try {
12643 if (app.thread != null) {
12644 app.thread.scheduleConfigurationChanged(mConfiguration);
12645 }
12646 } catch (Exception e) {
12647 }
12648 }
12649 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12650 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12651 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012652
12653 AttributeCache ac = AttributeCache.instance();
12654 if (ac != null) {
12655 ac.updateConfiguration(mConfiguration);
12656 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012657 }
12658 }
12659
12660 if (changes != 0 && starting == null) {
12661 // If the configuration changed, and the caller is not already
12662 // in the process of starting an activity, then find the top
12663 // activity to check if its configuration needs to change.
12664 starting = topRunningActivityLocked(null);
12665 }
12666
12667 if (starting != null) {
12668 kept = ensureActivityConfigurationLocked(starting, changes);
12669 if (kept) {
12670 // If this didn't result in the starting activity being
12671 // destroyed, then we need to make sure at this point that all
12672 // other activities are made visible.
12673 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12674 + ", ensuring others are correct.");
12675 ensureActivitiesVisibleLocked(starting, changes);
12676 }
12677 }
12678
12679 return kept;
12680 }
12681
12682 private final boolean relaunchActivityLocked(HistoryRecord r,
12683 int changes, boolean andResume) {
12684 List<ResultInfo> results = null;
12685 List<Intent> newIntents = null;
12686 if (andResume) {
12687 results = r.results;
12688 newIntents = r.newIntents;
12689 }
12690 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12691 + " with results=" + results + " newIntents=" + newIntents
12692 + " andResume=" + andResume);
12693 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12694 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12695 r.task.taskId, r.shortComponentName);
12696
12697 r.startFreezingScreenLocked(r.app, 0);
12698
12699 try {
12700 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12701 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12702 changes, !andResume);
12703 // Note: don't need to call pauseIfSleepingLocked() here, because
12704 // the caller will only pass in 'andResume' if this activity is
12705 // currently resumed, which implies we aren't sleeping.
12706 } catch (RemoteException e) {
12707 return false;
12708 }
12709
12710 if (andResume) {
12711 r.results = null;
12712 r.newIntents = null;
12713 }
12714
12715 return true;
12716 }
12717
12718 /**
12719 * Make sure the given activity matches the current configuration. Returns
12720 * false if the activity had to be destroyed. Returns true if the
12721 * configuration is the same, or the activity will remain running as-is
12722 * for whatever reason. Ensures the HistoryRecord is updated with the
12723 * correct configuration and all other bookkeeping is handled.
12724 */
12725 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12726 int globalChanges) {
12727 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12728
12729 // Short circuit: if the two configurations are the exact same
12730 // object (the common case), then there is nothing to do.
12731 Configuration newConfig = mConfiguration;
12732 if (r.configuration == newConfig) {
12733 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12734 return true;
12735 }
12736
12737 // We don't worry about activities that are finishing.
12738 if (r.finishing) {
12739 if (DEBUG_SWITCH) Log.i(TAG,
12740 "Configuration doesn't matter in finishing " + r);
12741 r.stopFreezingScreenLocked(false);
12742 return true;
12743 }
12744
12745 // Okay we now are going to make this activity have the new config.
12746 // But then we need to figure out how it needs to deal with that.
12747 Configuration oldConfig = r.configuration;
12748 r.configuration = newConfig;
12749
12750 // If the activity isn't currently running, just leave the new
12751 // configuration and it will pick that up next time it starts.
12752 if (r.app == null || r.app.thread == null) {
12753 if (DEBUG_SWITCH) Log.i(TAG,
12754 "Configuration doesn't matter not running " + r);
12755 r.stopFreezingScreenLocked(false);
12756 return true;
12757 }
12758
12759 // If the activity isn't persistent, there is a chance we will
12760 // need to restart it.
12761 if (!r.persistent) {
12762
12763 // Figure out what has changed between the two configurations.
12764 int changes = oldConfig.diff(newConfig);
12765 if (DEBUG_SWITCH) {
12766 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12767 + Integer.toHexString(changes) + ", handles=0x"
12768 + Integer.toHexString(r.info.configChanges));
12769 }
12770 if ((changes&(~r.info.configChanges)) != 0) {
12771 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12772 r.configChangeFlags |= changes;
12773 r.startFreezingScreenLocked(r.app, globalChanges);
12774 if (r.app == null || r.app.thread == null) {
12775 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12776 destroyActivityLocked(r, true);
12777 } else if (r.state == ActivityState.PAUSING) {
12778 // A little annoying: we are waiting for this activity to
12779 // finish pausing. Let's not do anything now, but just
12780 // flag that it needs to be restarted when done pausing.
12781 r.configDestroy = true;
12782 return true;
12783 } else if (r.state == ActivityState.RESUMED) {
12784 // Try to optimize this case: the configuration is changing
12785 // and we need to restart the top, resumed activity.
12786 // Instead of doing the normal handshaking, just say
12787 // "restart!".
12788 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12789 relaunchActivityLocked(r, r.configChangeFlags, true);
12790 r.configChangeFlags = 0;
12791 } else {
12792 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12793 relaunchActivityLocked(r, r.configChangeFlags, false);
12794 r.configChangeFlags = 0;
12795 }
12796
12797 // All done... tell the caller we weren't able to keep this
12798 // activity around.
12799 return false;
12800 }
12801 }
12802
12803 // Default case: the activity can handle this new configuration, so
12804 // hand it over. Note that we don't need to give it the new
12805 // configuration, since we always send configuration changes to all
12806 // process when they happen so it can just use whatever configuration
12807 // it last got.
12808 if (r.app != null && r.app.thread != null) {
12809 try {
12810 r.app.thread.scheduleActivityConfigurationChanged(r);
12811 } catch (RemoteException e) {
12812 // If process died, whatever.
12813 }
12814 }
12815 r.stopFreezingScreenLocked(false);
12816
12817 return true;
12818 }
12819
12820 /**
12821 * Save the locale. You must be inside a synchronized (this) block.
12822 */
12823 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12824 if(isDiff) {
12825 SystemProperties.set("user.language", l.getLanguage());
12826 SystemProperties.set("user.region", l.getCountry());
12827 }
12828
12829 if(isPersist) {
12830 SystemProperties.set("persist.sys.language", l.getLanguage());
12831 SystemProperties.set("persist.sys.country", l.getCountry());
12832 SystemProperties.set("persist.sys.localevar", l.getVariant());
12833 }
12834 }
12835
12836 // =========================================================
12837 // LIFETIME MANAGEMENT
12838 // =========================================================
12839
12840 private final int computeOomAdjLocked(
12841 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12842 if (mAdjSeq == app.adjSeq) {
12843 // This adjustment has already been computed.
12844 return app.curAdj;
12845 }
12846
12847 if (app.thread == null) {
12848 app.adjSeq = mAdjSeq;
12849 return (app.curAdj=EMPTY_APP_ADJ);
12850 }
12851
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012852 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
12853 // The max adjustment doesn't allow this app to be anything
12854 // below foreground, so it is not worth doing work for it.
12855 app.adjType = "fixed";
12856 app.adjSeq = mAdjSeq;
12857 app.curRawAdj = app.maxAdj;
12858 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
12859 return (app.curAdj=app.maxAdj);
12860 }
12861
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070012862 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012863 app.adjSource = null;
12864 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012865
The Android Open Source Project4df24232009-03-05 14:34:35 -080012866 // Determine the importance of the process, starting with most
12867 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012868 int adj;
12869 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012870 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012871 // The last app on the list is the foreground app.
12872 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012873 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012874 } else if (app.instrumentationClass != null) {
12875 // Don't want to kill running instrumentation.
12876 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012877 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012878 } else if (app.persistentActivities > 0) {
12879 // Special persistent activities... shouldn't be used these days.
12880 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012881 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012882 } else if (app.curReceiver != null ||
12883 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12884 // An app that is currently receiving a broadcast also
12885 // counts as being in the foreground.
12886 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012887 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012888 } else if (app.executingServices.size() > 0) {
12889 // An app that is currently executing a service callback also
12890 // counts as being in the foreground.
12891 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012892 app.adjType = "exec-service";
12893 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012894 // The user is aware of this app, so make it visible.
12895 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012896 app.adjType = "foreground-service";
12897 } else if (app.forcingToForeground != null) {
12898 // The user is aware of this app, so make it visible.
12899 adj = VISIBLE_APP_ADJ;
12900 app.adjType = "force-foreground";
12901 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012902 } else if (app == mHomeProcess) {
12903 // This process is hosting what we currently consider to be the
12904 // home app, so we don't want to let it go into the background.
12905 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012906 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012907 } else if ((N=app.activities.size()) != 0) {
12908 // This app is in the background with paused activities.
12909 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012910 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012911 for (int j=0; j<N; j++) {
12912 if (((HistoryRecord)app.activities.get(j)).visible) {
12913 // This app has a visible activity!
12914 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012915 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012916 break;
12917 }
12918 }
12919 } else {
12920 // A very not-needed process.
12921 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012922 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012923 }
12924
The Android Open Source Project4df24232009-03-05 14:34:35 -080012925 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012926 // there are applications dependent on our services or providers, but
12927 // this gives us a baseline and makes sure we don't get into an
12928 // infinite recursion.
12929 app.adjSeq = mAdjSeq;
12930 app.curRawAdj = adj;
12931 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12932
Christopher Tate6fa95972009-06-05 18:43:55 -070012933 if (mBackupTarget != null && app == mBackupTarget.app) {
12934 // If possible we want to avoid killing apps while they're being backed up
12935 if (adj > BACKUP_APP_ADJ) {
12936 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12937 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012938 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070012939 }
12940 }
12941
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012942 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012943 final long now = SystemClock.uptimeMillis();
12944 // This process is more important if the top activity is
12945 // bound to the service.
12946 Iterator jt = app.services.iterator();
12947 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12948 ServiceRecord s = (ServiceRecord)jt.next();
12949 if (s.startRequested) {
12950 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12951 // This service has seen some activity within
12952 // recent memory, so we will keep its process ahead
12953 // of the background processes.
12954 if (adj > SECONDARY_SERVER_ADJ) {
12955 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012956 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012957 }
12958 }
12959 }
12960 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12961 Iterator<ConnectionRecord> kt
12962 = s.connections.values().iterator();
12963 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12964 // XXX should compute this based on the max of
12965 // all connected clients.
12966 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012967 if (cr.binding.client == app) {
12968 // Binding to ourself is not interesting.
12969 continue;
12970 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012971 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12972 ProcessRecord client = cr.binding.client;
12973 int myHiddenAdj = hiddenAdj;
12974 if (myHiddenAdj > client.hiddenAdj) {
12975 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12976 myHiddenAdj = client.hiddenAdj;
12977 } else {
12978 myHiddenAdj = VISIBLE_APP_ADJ;
12979 }
12980 }
12981 int clientAdj = computeOomAdjLocked(
12982 client, myHiddenAdj, TOP_APP);
12983 if (adj > clientAdj) {
12984 adj = clientAdj > VISIBLE_APP_ADJ
12985 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012986 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070012987 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
12988 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012989 app.adjSource = cr.binding.client;
12990 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012991 }
12992 }
12993 HistoryRecord a = cr.activity;
12994 //if (a != null) {
12995 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12996 //}
12997 if (a != null && adj > FOREGROUND_APP_ADJ &&
12998 (a.state == ActivityState.RESUMED
12999 || a.state == ActivityState.PAUSING)) {
13000 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013001 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013002 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13003 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013004 app.adjSource = a;
13005 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013006 }
13007 }
13008 }
13009 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013010
13011 // Finally, f this process has active services running in it, we
13012 // would like to avoid killing it unless it would prevent the current
13013 // application from running. By default we put the process in
13014 // with the rest of the background processes; as we scan through
13015 // its services we may bump it up from there.
13016 if (adj > hiddenAdj) {
13017 adj = hiddenAdj;
13018 app.adjType = "bg-services";
13019 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013020 }
13021
13022 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013023 Iterator jt = app.pubProviders.values().iterator();
13024 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13025 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13026 if (cpr.clients.size() != 0) {
13027 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13028 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13029 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013030 if (client == app) {
13031 // Being our own client is not interesting.
13032 continue;
13033 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013034 int myHiddenAdj = hiddenAdj;
13035 if (myHiddenAdj > client.hiddenAdj) {
13036 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13037 myHiddenAdj = client.hiddenAdj;
13038 } else {
13039 myHiddenAdj = FOREGROUND_APP_ADJ;
13040 }
13041 }
13042 int clientAdj = computeOomAdjLocked(
13043 client, myHiddenAdj, TOP_APP);
13044 if (adj > clientAdj) {
13045 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013046 ? clientAdj : FOREGROUND_APP_ADJ;
13047 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013048 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13049 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013050 app.adjSource = client;
13051 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013052 }
13053 }
13054 }
13055 // If the provider has external (non-framework) process
13056 // dependencies, ensure that its adjustment is at least
13057 // FOREGROUND_APP_ADJ.
13058 if (cpr.externals != 0) {
13059 if (adj > FOREGROUND_APP_ADJ) {
13060 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013061 app.adjType = "provider";
13062 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013063 }
13064 }
13065 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013066
13067 // Finally, if this process has published any content providers,
13068 // then its adjustment makes it at least as important as any of the
13069 // processes using those providers, and no less important than
13070 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
13071 if (adj > CONTENT_PROVIDER_ADJ) {
13072 adj = CONTENT_PROVIDER_ADJ;
13073 app.adjType = "pub-providers";
13074 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013075 }
13076
13077 app.curRawAdj = adj;
13078
13079 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13080 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13081 if (adj > app.maxAdj) {
13082 adj = app.maxAdj;
13083 }
13084
13085 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013086 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013087 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
13088 : Process.THREAD_GROUP_DEFAULT;
13089
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013090 return adj;
13091 }
13092
13093 /**
13094 * Ask a given process to GC right now.
13095 */
13096 final void performAppGcLocked(ProcessRecord app) {
13097 try {
13098 app.lastRequestedGc = SystemClock.uptimeMillis();
13099 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013100 if (app.reportLowMemory) {
13101 app.reportLowMemory = false;
13102 app.thread.scheduleLowMemory();
13103 } else {
13104 app.thread.processInBackground();
13105 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013106 }
13107 } catch (Exception e) {
13108 // whatever.
13109 }
13110 }
13111
13112 /**
13113 * Returns true if things are idle enough to perform GCs.
13114 */
13115 private final boolean canGcNow() {
13116 return mParallelBroadcasts.size() == 0
13117 && mOrderedBroadcasts.size() == 0
13118 && (mSleeping || (mResumedActivity != null &&
13119 mResumedActivity.idle));
13120 }
13121
13122 /**
13123 * Perform GCs on all processes that are waiting for it, but only
13124 * if things are idle.
13125 */
13126 final void performAppGcsLocked() {
13127 final int N = mProcessesToGc.size();
13128 if (N <= 0) {
13129 return;
13130 }
13131 if (canGcNow()) {
13132 while (mProcessesToGc.size() > 0) {
13133 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013134 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13135 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13136 <= SystemClock.uptimeMillis()) {
13137 // To avoid spamming the system, we will GC processes one
13138 // at a time, waiting a few seconds between each.
13139 performAppGcLocked(proc);
13140 scheduleAppGcsLocked();
13141 return;
13142 } else {
13143 // It hasn't been long enough since we last GCed this
13144 // process... put it in the list to wait for its time.
13145 addProcessToGcListLocked(proc);
13146 break;
13147 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013148 }
13149 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013150
13151 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013152 }
13153 }
13154
13155 /**
13156 * If all looks good, perform GCs on all processes waiting for them.
13157 */
13158 final void performAppGcsIfAppropriateLocked() {
13159 if (canGcNow()) {
13160 performAppGcsLocked();
13161 return;
13162 }
13163 // Still not idle, wait some more.
13164 scheduleAppGcsLocked();
13165 }
13166
13167 /**
13168 * Schedule the execution of all pending app GCs.
13169 */
13170 final void scheduleAppGcsLocked() {
13171 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013172
13173 if (mProcessesToGc.size() > 0) {
13174 // Schedule a GC for the time to the next process.
13175 ProcessRecord proc = mProcessesToGc.get(0);
13176 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13177
13178 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13179 long now = SystemClock.uptimeMillis();
13180 if (when < (now+GC_TIMEOUT)) {
13181 when = now + GC_TIMEOUT;
13182 }
13183 mHandler.sendMessageAtTime(msg, when);
13184 }
13185 }
13186
13187 /**
13188 * Add a process to the array of processes waiting to be GCed. Keeps the
13189 * list in sorted order by the last GC time. The process can't already be
13190 * on the list.
13191 */
13192 final void addProcessToGcListLocked(ProcessRecord proc) {
13193 boolean added = false;
13194 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13195 if (mProcessesToGc.get(i).lastRequestedGc <
13196 proc.lastRequestedGc) {
13197 added = true;
13198 mProcessesToGc.add(i+1, proc);
13199 break;
13200 }
13201 }
13202 if (!added) {
13203 mProcessesToGc.add(0, proc);
13204 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013205 }
13206
13207 /**
13208 * Set up to ask a process to GC itself. This will either do it
13209 * immediately, or put it on the list of processes to gc the next
13210 * time things are idle.
13211 */
13212 final void scheduleAppGcLocked(ProcessRecord app) {
13213 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013214 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013215 return;
13216 }
13217 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013218 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013219 scheduleAppGcsLocked();
13220 }
13221 }
13222
13223 private final boolean updateOomAdjLocked(
13224 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13225 app.hiddenAdj = hiddenAdj;
13226
13227 if (app.thread == null) {
13228 return true;
13229 }
13230
13231 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
13232
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013233 if (app.pid != 0 && app.pid != MY_PID) {
13234 if (app.curRawAdj != app.setRawAdj) {
13235 if (app.curRawAdj > FOREGROUND_APP_ADJ
13236 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13237 // If this app is transitioning from foreground to
13238 // non-foreground, have it do a gc.
13239 scheduleAppGcLocked(app);
13240 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13241 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13242 // Likewise do a gc when an app is moving in to the
13243 // background (such as a service stopping).
13244 scheduleAppGcLocked(app);
13245 }
13246 app.setRawAdj = app.curRawAdj;
13247 }
13248 if (adj != app.setAdj) {
13249 if (Process.setOomAdj(app.pid, adj)) {
13250 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13251 TAG, "Set app " + app.processName +
13252 " oom adj to " + adj);
13253 app.setAdj = adj;
13254 } else {
13255 return false;
13256 }
13257 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013258 if (app.setSchedGroup != app.curSchedGroup) {
13259 app.setSchedGroup = app.curSchedGroup;
13260 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13261 "Setting process group of " + app.processName
13262 + " to " + app.curSchedGroup);
13263 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013264 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013265 try {
13266 Process.setProcessGroup(app.pid, app.curSchedGroup);
13267 } catch (Exception e) {
13268 Log.w(TAG, "Failed setting process group of " + app.pid
13269 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013270 e.printStackTrace();
13271 } finally {
13272 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013273 }
13274 }
13275 if (false) {
13276 if (app.thread != null) {
13277 try {
13278 app.thread.setSchedulingGroup(app.curSchedGroup);
13279 } catch (RemoteException e) {
13280 }
13281 }
13282 }
13283 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013284 }
13285
13286 return true;
13287 }
13288
13289 private final HistoryRecord resumedAppLocked() {
13290 HistoryRecord resumedActivity = mResumedActivity;
13291 if (resumedActivity == null || resumedActivity.app == null) {
13292 resumedActivity = mPausingActivity;
13293 if (resumedActivity == null || resumedActivity.app == null) {
13294 resumedActivity = topRunningActivityLocked(null);
13295 }
13296 }
13297 return resumedActivity;
13298 }
13299
13300 private final boolean updateOomAdjLocked(ProcessRecord app) {
13301 final HistoryRecord TOP_ACT = resumedAppLocked();
13302 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13303 int curAdj = app.curAdj;
13304 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13305 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13306
13307 mAdjSeq++;
13308
13309 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13310 if (res) {
13311 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13312 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13313 if (nowHidden != wasHidden) {
13314 // Changed to/from hidden state, so apps after it in the LRU
13315 // list may also be changed.
13316 updateOomAdjLocked();
13317 }
13318 }
13319 return res;
13320 }
13321
13322 private final boolean updateOomAdjLocked() {
13323 boolean didOomAdj = true;
13324 final HistoryRecord TOP_ACT = resumedAppLocked();
13325 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13326
13327 if (false) {
13328 RuntimeException e = new RuntimeException();
13329 e.fillInStackTrace();
13330 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13331 }
13332
13333 mAdjSeq++;
13334
13335 // First try updating the OOM adjustment for each of the
13336 // application processes based on their current state.
13337 int i = mLRUProcesses.size();
13338 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13339 while (i > 0) {
13340 i--;
13341 ProcessRecord app = mLRUProcesses.get(i);
13342 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13343 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13344 && app.curAdj == curHiddenAdj) {
13345 curHiddenAdj++;
13346 }
13347 } else {
13348 didOomAdj = false;
13349 }
13350 }
13351
13352 // todo: for now pretend like OOM ADJ didn't work, because things
13353 // aren't behaving as expected on Linux -- it's not killing processes.
13354 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13355 }
13356
13357 private final void trimApplications() {
13358 synchronized (this) {
13359 int i;
13360
13361 // First remove any unused application processes whose package
13362 // has been removed.
13363 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13364 final ProcessRecord app = mRemovedProcesses.get(i);
13365 if (app.activities.size() == 0
13366 && app.curReceiver == null && app.services.size() == 0) {
13367 Log.i(
13368 TAG, "Exiting empty application process "
13369 + app.processName + " ("
13370 + (app.thread != null ? app.thread.asBinder() : null)
13371 + ")\n");
13372 if (app.pid > 0 && app.pid != MY_PID) {
13373 Process.killProcess(app.pid);
13374 } else {
13375 try {
13376 app.thread.scheduleExit();
13377 } catch (Exception e) {
13378 // Ignore exceptions.
13379 }
13380 }
13381 cleanUpApplicationRecordLocked(app, false, -1);
13382 mRemovedProcesses.remove(i);
13383
13384 if (app.persistent) {
13385 if (app.persistent) {
13386 addAppLocked(app.info);
13387 }
13388 }
13389 }
13390 }
13391
13392 // Now try updating the OOM adjustment for each of the
13393 // application processes based on their current state.
13394 // If the setOomAdj() API is not supported, then go with our
13395 // back-up plan...
13396 if (!updateOomAdjLocked()) {
13397
13398 // Count how many processes are running services.
13399 int numServiceProcs = 0;
13400 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13401 final ProcessRecord app = mLRUProcesses.get(i);
13402
13403 if (app.persistent || app.services.size() != 0
13404 || app.curReceiver != null
13405 || app.persistentActivities > 0) {
13406 // Don't count processes holding services against our
13407 // maximum process count.
13408 if (localLOGV) Log.v(
13409 TAG, "Not trimming app " + app + " with services: "
13410 + app.services);
13411 numServiceProcs++;
13412 }
13413 }
13414
13415 int curMaxProcs = mProcessLimit;
13416 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13417 if (mAlwaysFinishActivities) {
13418 curMaxProcs = 1;
13419 }
13420 curMaxProcs += numServiceProcs;
13421
13422 // Quit as many processes as we can to get down to the desired
13423 // process count. First remove any processes that no longer
13424 // have activites running in them.
13425 for ( i=0;
13426 i<mLRUProcesses.size()
13427 && mLRUProcesses.size() > curMaxProcs;
13428 i++) {
13429 final ProcessRecord app = mLRUProcesses.get(i);
13430 // Quit an application only if it is not currently
13431 // running any activities.
13432 if (!app.persistent && app.activities.size() == 0
13433 && app.curReceiver == null && app.services.size() == 0) {
13434 Log.i(
13435 TAG, "Exiting empty application process "
13436 + app.processName + " ("
13437 + (app.thread != null ? app.thread.asBinder() : null)
13438 + ")\n");
13439 if (app.pid > 0 && app.pid != MY_PID) {
13440 Process.killProcess(app.pid);
13441 } else {
13442 try {
13443 app.thread.scheduleExit();
13444 } catch (Exception e) {
13445 // Ignore exceptions.
13446 }
13447 }
13448 // todo: For now we assume the application is not buggy
13449 // or evil, and will quit as a result of our request.
13450 // Eventually we need to drive this off of the death
13451 // notification, and kill the process if it takes too long.
13452 cleanUpApplicationRecordLocked(app, false, i);
13453 i--;
13454 }
13455 }
13456
13457 // If we still have too many processes, now from the least
13458 // recently used process we start finishing activities.
13459 if (Config.LOGV) Log.v(
13460 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13461 " of " + curMaxProcs + " processes");
13462 for ( i=0;
13463 i<mLRUProcesses.size()
13464 && mLRUProcesses.size() > curMaxProcs;
13465 i++) {
13466 final ProcessRecord app = mLRUProcesses.get(i);
13467 // Quit the application only if we have a state saved for
13468 // all of its activities.
13469 boolean canQuit = !app.persistent && app.curReceiver == null
13470 && app.services.size() == 0
13471 && app.persistentActivities == 0;
13472 int NUMA = app.activities.size();
13473 int j;
13474 if (Config.LOGV) Log.v(
13475 TAG, "Looking to quit " + app.processName);
13476 for (j=0; j<NUMA && canQuit; j++) {
13477 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13478 if (Config.LOGV) Log.v(
13479 TAG, " " + r.intent.getComponent().flattenToShortString()
13480 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13481 canQuit = (r.haveState || !r.stateNotNeeded)
13482 && !r.visible && r.stopped;
13483 }
13484 if (canQuit) {
13485 // Finish all of the activities, and then the app itself.
13486 for (j=0; j<NUMA; j++) {
13487 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13488 if (!r.finishing) {
13489 destroyActivityLocked(r, false);
13490 }
13491 r.resultTo = null;
13492 }
13493 Log.i(TAG, "Exiting application process "
13494 + app.processName + " ("
13495 + (app.thread != null ? app.thread.asBinder() : null)
13496 + ")\n");
13497 if (app.pid > 0 && app.pid != MY_PID) {
13498 Process.killProcess(app.pid);
13499 } else {
13500 try {
13501 app.thread.scheduleExit();
13502 } catch (Exception e) {
13503 // Ignore exceptions.
13504 }
13505 }
13506 // todo: For now we assume the application is not buggy
13507 // or evil, and will quit as a result of our request.
13508 // Eventually we need to drive this off of the death
13509 // notification, and kill the process if it takes too long.
13510 cleanUpApplicationRecordLocked(app, false, i);
13511 i--;
13512 //dump();
13513 }
13514 }
13515
13516 }
13517
13518 int curMaxActivities = MAX_ACTIVITIES;
13519 if (mAlwaysFinishActivities) {
13520 curMaxActivities = 1;
13521 }
13522
13523 // Finally, if there are too many activities now running, try to
13524 // finish as many as we can to get back down to the limit.
13525 for ( i=0;
13526 i<mLRUActivities.size()
13527 && mLRUActivities.size() > curMaxActivities;
13528 i++) {
13529 final HistoryRecord r
13530 = (HistoryRecord)mLRUActivities.get(i);
13531
13532 // We can finish this one if we have its icicle saved and
13533 // it is not persistent.
13534 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13535 && r.stopped && !r.persistent && !r.finishing) {
13536 final int origSize = mLRUActivities.size();
13537 destroyActivityLocked(r, true);
13538
13539 // This will remove it from the LRU list, so keep
13540 // our index at the same value. Note that this check to
13541 // see if the size changes is just paranoia -- if
13542 // something unexpected happens, we don't want to end up
13543 // in an infinite loop.
13544 if (origSize > mLRUActivities.size()) {
13545 i--;
13546 }
13547 }
13548 }
13549 }
13550 }
13551
13552 /** This method sends the specified signal to each of the persistent apps */
13553 public void signalPersistentProcesses(int sig) throws RemoteException {
13554 if (sig != Process.SIGNAL_USR1) {
13555 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13556 }
13557
13558 synchronized (this) {
13559 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13560 != PackageManager.PERMISSION_GRANTED) {
13561 throw new SecurityException("Requires permission "
13562 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13563 }
13564
13565 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13566 ProcessRecord r = mLRUProcesses.get(i);
13567 if (r.thread != null && r.persistent) {
13568 Process.sendSignal(r.pid, sig);
13569 }
13570 }
13571 }
13572 }
13573
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013574 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013575 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013576
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013577 try {
13578 synchronized (this) {
13579 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13580 // its own permission.
13581 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13582 != PackageManager.PERMISSION_GRANTED) {
13583 throw new SecurityException("Requires permission "
13584 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013585 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013586
13587 if (start && fd == null) {
13588 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013589 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013590
13591 ProcessRecord proc = null;
13592 try {
13593 int pid = Integer.parseInt(process);
13594 synchronized (mPidsSelfLocked) {
13595 proc = mPidsSelfLocked.get(pid);
13596 }
13597 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013598 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013599
13600 if (proc == null) {
13601 HashMap<String, SparseArray<ProcessRecord>> all
13602 = mProcessNames.getMap();
13603 SparseArray<ProcessRecord> procs = all.get(process);
13604 if (procs != null && procs.size() > 0) {
13605 proc = procs.valueAt(0);
13606 }
13607 }
13608
13609 if (proc == null || proc.thread == null) {
13610 throw new IllegalArgumentException("Unknown process: " + process);
13611 }
13612
13613 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13614 if (isSecure) {
13615 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13616 throw new SecurityException("Process not debuggable: " + proc);
13617 }
13618 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013619
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013620 proc.thread.profilerControl(start, path, fd);
13621 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013622 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013623 }
13624 } catch (RemoteException e) {
13625 throw new IllegalStateException("Process disappeared");
13626 } finally {
13627 if (fd != null) {
13628 try {
13629 fd.close();
13630 } catch (IOException e) {
13631 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013632 }
13633 }
13634 }
13635
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013636 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13637 public void monitor() {
13638 synchronized (this) { }
13639 }
13640}