blob: 15972701e85fe46603dbb44f702ed5f15eb0c18e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
19import com.android.internal.os.BatteryStatsImpl;
Dianne Hackbornde7faf62009-06-30 13:27:30 -070020import com.android.server.AttributeCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import com.android.server.IntentResolver;
22import com.android.server.ProcessMap;
23import com.android.server.ProcessStats;
24import com.android.server.SystemServer;
25import com.android.server.Watchdog;
26import com.android.server.WindowManagerService;
27
28import android.app.Activity;
29import android.app.ActivityManager;
30import android.app.ActivityManagerNative;
31import android.app.ActivityThread;
32import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020033import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.app.Dialog;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070035import android.app.IActivityController;
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070036import android.app.IActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.app.IActivityWatcher;
38import android.app.IApplicationThread;
39import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.app.IServiceConnection;
41import android.app.IThumbnailReceiver;
42import android.app.Instrumentation;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070043import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.app.PendingIntent;
45import android.app.ResultInfo;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070046import android.app.Service;
Christopher Tate181fafa2009-05-14 11:12:14 -070047import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020048import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.content.ComponentName;
50import android.content.ContentResolver;
51import android.content.Context;
52import android.content.Intent;
53import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070054import android.content.IIntentReceiver;
55import android.content.IIntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.content.pm.ActivityInfo;
57import android.content.pm.ApplicationInfo;
58import android.content.pm.ConfigurationInfo;
59import android.content.pm.IPackageDataObserver;
60import android.content.pm.IPackageManager;
61import android.content.pm.InstrumentationInfo;
62import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070063import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import android.content.pm.ProviderInfo;
65import android.content.pm.ResolveInfo;
66import android.content.pm.ServiceInfo;
67import android.content.res.Configuration;
68import android.graphics.Bitmap;
69import android.net.Uri;
70import android.os.Binder;
71import android.os.Bundle;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070072import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.os.Environment;
74import android.os.FileUtils;
75import android.os.Handler;
76import android.os.IBinder;
77import android.os.IPermissionController;
78import android.os.Looper;
79import android.os.Message;
80import android.os.Parcel;
81import android.os.ParcelFileDescriptor;
82import android.os.PowerManager;
83import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070084import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.os.RemoteException;
86import android.os.ServiceManager;
87import android.os.SystemClock;
88import android.os.SystemProperties;
89import android.provider.Checkin;
90import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020091import android.server.data.CrashData;
92import android.server.data.StackTraceElementData;
93import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094import android.text.TextUtils;
95import android.util.Config;
96import android.util.EventLog;
97import android.util.Log;
98import android.util.PrintWriterPrinter;
99import android.util.SparseArray;
100import android.view.Gravity;
101import android.view.LayoutInflater;
102import android.view.View;
103import android.view.WindowManager;
104import android.view.WindowManagerPolicy;
105
106import dalvik.system.Zygote;
107
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200108import java.io.ByteArrayInputStream;
109import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110import java.io.File;
111import java.io.FileDescriptor;
112import java.io.FileInputStream;
113import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200114import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115import java.io.PrintWriter;
116import java.lang.IllegalStateException;
117import java.lang.ref.WeakReference;
118import java.util.ArrayList;
119import java.util.HashMap;
120import java.util.HashSet;
121import java.util.Iterator;
122import java.util.List;
123import java.util.Locale;
124import java.util.Map;
125
126public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
127 static final String TAG = "ActivityManager";
128 static final boolean DEBUG = false;
129 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
130 static final boolean DEBUG_SWITCH = localLOGV || false;
131 static final boolean DEBUG_TASKS = localLOGV || false;
132 static final boolean DEBUG_PAUSE = localLOGV || false;
133 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
134 static final boolean DEBUG_TRANSITION = localLOGV || false;
135 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700136 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 static final boolean DEBUG_SERVICE = localLOGV || false;
138 static final boolean DEBUG_VISBILITY = localLOGV || false;
139 static final boolean DEBUG_PROCESSES = localLOGV || false;
Dianne Hackborna1e989b2009-09-01 19:54:29 -0700140 static final boolean DEBUG_PROVIDER = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700142 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700143 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 static final boolean VALIDATE_TOKENS = false;
145 static final boolean SHOW_ACTIVITY_START_TIME = true;
146
147 // Control over CPU and battery monitoring.
148 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
149 static final boolean MONITOR_CPU_USAGE = true;
150 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
151 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
152 static final boolean MONITOR_THREAD_CPU_USAGE = false;
153
154 // Event log tags
155 static final int LOG_CONFIGURATION_CHANGED = 2719;
156 static final int LOG_CPU = 2721;
157 static final int LOG_AM_FINISH_ACTIVITY = 30001;
158 static final int LOG_TASK_TO_FRONT = 30002;
159 static final int LOG_AM_NEW_INTENT = 30003;
160 static final int LOG_AM_CREATE_TASK = 30004;
161 static final int LOG_AM_CREATE_ACTIVITY = 30005;
162 static final int LOG_AM_RESTART_ACTIVITY = 30006;
163 static final int LOG_AM_RESUME_ACTIVITY = 30007;
164 static final int LOG_ANR = 30008;
165 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
166 static final int LOG_AM_PROCESS_BOUND = 30010;
167 static final int LOG_AM_PROCESS_DIED = 30011;
168 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
169 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
170 static final int LOG_AM_PROCESS_START = 30014;
171 static final int LOG_AM_PROCESS_BAD = 30015;
172 static final int LOG_AM_PROCESS_GOOD = 30016;
173 static final int LOG_AM_LOW_MEMORY = 30017;
174 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
175 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
176 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
177 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
178 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
179 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
180 static final int LOG_AM_CREATE_SERVICE = 30030;
181 static final int LOG_AM_DESTROY_SERVICE = 30031;
182 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
183 static final int LOG_AM_DROP_PROCESS = 30033;
184 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
185 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
186 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
187
188 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
189 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
190
Dianne Hackborn1655be42009-05-08 14:29:01 -0700191 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700192 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700193
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 private static final String SYSTEM_SECURE = "ro.secure";
195
196 // This is the maximum number of application processes we would like
197 // to have running. Due to the asynchronous nature of things, we can
198 // temporarily go beyond this limit.
199 static final int MAX_PROCESSES = 2;
200
201 // Set to false to leave processes running indefinitely, relying on
202 // the kernel killing them as resources are required.
203 static final boolean ENFORCE_PROCESS_LIMIT = false;
204
205 // This is the maximum number of activities that we would like to have
206 // running at a given time.
207 static final int MAX_ACTIVITIES = 20;
208
209 // Maximum number of recent tasks that we can remember.
210 static final int MAX_RECENT_TASKS = 20;
211
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700212 // Amount of time after a call to stopAppSwitches() during which we will
213 // prevent further untrusted switches from happening.
214 static final long APP_SWITCH_DELAY_TIME = 5*1000;
215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 // How long until we reset a task when the user returns to it. Currently
217 // 30 minutes.
218 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
219
220 // Set to true to disable the icon that is shown while a new activity
221 // is being started.
222 static final boolean SHOW_APP_STARTING_ICON = true;
223
224 // How long we wait until giving up on the last activity to pause. This
225 // is short because it directly impacts the responsiveness of starting the
226 // next activity.
227 static final int PAUSE_TIMEOUT = 500;
228
229 /**
230 * How long we can hold the launch wake lock before giving up.
231 */
232 static final int LAUNCH_TIMEOUT = 10*1000;
233
234 // How long we wait for a launched process to attach to the activity manager
235 // before we decide it's never going to come up for real.
236 static final int PROC_START_TIMEOUT = 10*1000;
237
238 // How long we wait until giving up on the last activity telling us it
239 // is idle.
240 static final int IDLE_TIMEOUT = 10*1000;
241
242 // How long to wait after going idle before forcing apps to GC.
243 static final int GC_TIMEOUT = 5*1000;
244
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700245 // The minimum amount of time between successive GC requests for a process.
246 static final int GC_MIN_INTERVAL = 60*1000;
247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 // How long we wait until giving up on an activity telling us it has
249 // finished destroying itself.
250 static final int DESTROY_TIMEOUT = 10*1000;
251
252 // How long we allow a receiver to run before giving up on it.
253 static final int BROADCAST_TIMEOUT = 10*1000;
254
255 // How long we wait for a service to finish executing.
256 static final int SERVICE_TIMEOUT = 20*1000;
257
258 // How long a service needs to be running until restarting its process
259 // is no longer considered to be a relaunch of the service.
260 static final int SERVICE_RESTART_DURATION = 5*1000;
261
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700262 // How long a service needs to be running until it will start back at
263 // SERVICE_RESTART_DURATION after being killed.
264 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
265
266 // Multiplying factor to increase restart duration time by, for each time
267 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
268 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
269
270 // The minimum amount of time between restarting services that we allow.
271 // That is, when multiple services are restarting, we won't allow each
272 // to restart less than this amount of time from the last one.
273 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
274
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 // Maximum amount of time for there to be no activity on a service before
276 // we consider it non-essential and allow its process to go on the
277 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700278 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279
280 // How long we wait until we timeout on key dispatching.
281 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
282
283 // The minimum time we allow between crashes, for us to consider this
284 // application to be bad and stop and its services and reject broadcasts.
285 static final int MIN_CRASH_INTERVAL = 60*1000;
286
287 // How long we wait until we timeout on key dispatching during instrumentation.
288 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
289
290 // OOM adjustments for processes in various states:
291
292 // This is a process without anything currently running in it. Definitely
293 // the first to go! Value set in system/rootdir/init.rc on startup.
294 // This value is initalized in the constructor, careful when refering to
295 // this static variable externally.
296 static int EMPTY_APP_ADJ;
297
298 // This is a process with a content provider that does not have any clients
299 // attached to it. If it did have any clients, its adjustment would be the
300 // one for the highest-priority of those processes.
301 static int CONTENT_PROVIDER_ADJ;
302
303 // This is a process only hosting activities that are not visible,
304 // so it can be killed without any disruption. Value set in
305 // system/rootdir/init.rc on startup.
306 final int HIDDEN_APP_MAX_ADJ;
307 static int HIDDEN_APP_MIN_ADJ;
308
The Android Open Source Project4df24232009-03-05 14:34:35 -0800309 // This is a process holding the home application -- we want to try
310 // avoiding killing it, even if it would normally be in the background,
311 // because the user interacts with it so much.
312 final int HOME_APP_ADJ;
313
Christopher Tate6fa95972009-06-05 18:43:55 -0700314 // This is a process currently hosting a backup operation. Killing it
315 // is not entirely fatal but is generally a bad idea.
316 final int BACKUP_APP_ADJ;
317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 // This is a process holding a secondary server -- killing it will not
319 // have much of an impact as far as the user is concerned. Value set in
320 // system/rootdir/init.rc on startup.
321 final int SECONDARY_SERVER_ADJ;
322
323 // This is a process only hosting activities that are visible to the
324 // user, so we'd prefer they don't disappear. Value set in
325 // system/rootdir/init.rc on startup.
326 final int VISIBLE_APP_ADJ;
327
328 // This is the process running the current foreground app. We'd really
329 // rather not kill it! Value set in system/rootdir/init.rc on startup.
330 final int FOREGROUND_APP_ADJ;
331
332 // This is a process running a core server, such as telephony. Definitely
333 // don't want to kill it, but doing so is not completely fatal.
334 static final int CORE_SERVER_ADJ = -12;
335
336 // The system process runs at the default adjustment.
337 static final int SYSTEM_ADJ = -16;
338
339 // Memory pages are 4K.
340 static final int PAGE_SIZE = 4*1024;
341
Jacek Surazski82a73df2009-06-17 14:33:18 +0200342 // System property defining error report receiver for system apps
343 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
344
345 // System property defining default error report receiver
346 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 // Corresponding memory levels for above adjustments.
349 final int EMPTY_APP_MEM;
350 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800351 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700352 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 final int SECONDARY_SERVER_MEM;
354 final int VISIBLE_APP_MEM;
355 final int FOREGROUND_APP_MEM;
356
357 final int MY_PID;
358
359 static final String[] EMPTY_STRING_ARRAY = new String[0];
360
361 enum ActivityState {
362 INITIALIZING,
363 RESUMED,
364 PAUSING,
365 PAUSED,
366 STOPPING,
367 STOPPED,
368 FINISHING,
369 DESTROYING,
370 DESTROYED
371 }
372
373 /**
374 * The back history of all previous (and possibly still
375 * running) activities. It contains HistoryRecord objects.
376 */
377 final ArrayList mHistory = new ArrayList();
378
379 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700380 * Description of a request to start a new activity, which has been held
381 * due to app switches being disabled.
382 */
383 class PendingActivityLaunch {
384 HistoryRecord r;
385 HistoryRecord sourceRecord;
386 Uri[] grantedUriPermissions;
387 int grantedMode;
388 boolean onlyIfNeeded;
389 }
390
391 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
392 = new ArrayList<PendingActivityLaunch>();
393
394 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 * List of all active broadcasts that are to be executed immediately
396 * (without waiting for another broadcast to finish). Currently this only
397 * contains broadcasts to registered receivers, to avoid spinning up
398 * a bunch of processes to execute IntentReceiver components.
399 */
400 final ArrayList<BroadcastRecord> mParallelBroadcasts
401 = new ArrayList<BroadcastRecord>();
402
403 /**
404 * List of all active broadcasts that are to be executed one at a time.
405 * The object at the top of the list is the currently activity broadcasts;
406 * those after it are waiting for the top to finish..
407 */
408 final ArrayList<BroadcastRecord> mOrderedBroadcasts
409 = new ArrayList<BroadcastRecord>();
410
411 /**
412 * Set when we current have a BROADCAST_INTENT_MSG in flight.
413 */
414 boolean mBroadcastsScheduled = false;
415
416 /**
417 * Set to indicate whether to issue an onUserLeaving callback when a
418 * newly launched activity is being brought in front of us.
419 */
420 boolean mUserLeaving = false;
421
422 /**
423 * When we are in the process of pausing an activity, before starting the
424 * next one, this variable holds the activity that is currently being paused.
425 */
426 HistoryRecord mPausingActivity = null;
427
428 /**
429 * Current activity that is resumed, or null if there is none.
430 */
431 HistoryRecord mResumedActivity = null;
432
433 /**
434 * Activity we have told the window manager to have key focus.
435 */
436 HistoryRecord mFocusedActivity = null;
437
438 /**
439 * This is the last activity that we put into the paused state. This is
440 * used to determine if we need to do an activity transition while sleeping,
441 * when we normally hold the top activity paused.
442 */
443 HistoryRecord mLastPausedActivity = null;
444
445 /**
446 * List of activities that are waiting for a new activity
447 * to become visible before completing whatever operation they are
448 * supposed to do.
449 */
450 final ArrayList mWaitingVisibleActivities = new ArrayList();
451
452 /**
453 * List of activities that are ready to be stopped, but waiting
454 * for the next activity to settle down before doing so. It contains
455 * HistoryRecord objects.
456 */
457 final ArrayList<HistoryRecord> mStoppingActivities
458 = new ArrayList<HistoryRecord>();
459
460 /**
461 * List of intents that were used to start the most recent tasks.
462 */
463 final ArrayList<TaskRecord> mRecentTasks
464 = new ArrayList<TaskRecord>();
465
466 /**
467 * List of activities that are ready to be finished, but waiting
468 * for the previous activity to settle down before doing so. It contains
469 * HistoryRecord objects.
470 */
471 final ArrayList mFinishingActivities = new ArrayList();
472
473 /**
474 * All of the applications we currently have running organized by name.
475 * The keys are strings of the application package name (as
476 * returned by the package manager), and the keys are ApplicationRecord
477 * objects.
478 */
479 final ProcessMap<ProcessRecord> mProcessNames
480 = new ProcessMap<ProcessRecord>();
481
482 /**
483 * The last time that various processes have crashed.
484 */
485 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
486
487 /**
488 * Set of applications that we consider to be bad, and will reject
489 * incoming broadcasts from (which the user has no control over).
490 * Processes are added to this set when they have crashed twice within
491 * a minimum amount of time; they are removed from it when they are
492 * later restarted (hopefully due to some user action). The value is the
493 * time it was added to the list.
494 */
495 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
496
497 /**
498 * All of the processes we currently have running organized by pid.
499 * The keys are the pid running the application.
500 *
501 * <p>NOTE: This object is protected by its own lock, NOT the global
502 * activity manager lock!
503 */
504 final SparseArray<ProcessRecord> mPidsSelfLocked
505 = new SparseArray<ProcessRecord>();
506
507 /**
508 * All of the processes that have been forced to be foreground. The key
509 * is the pid of the caller who requested it (we hold a death
510 * link on it).
511 */
512 abstract class ForegroundToken implements IBinder.DeathRecipient {
513 int pid;
514 IBinder token;
515 }
516 final SparseArray<ForegroundToken> mForegroundProcesses
517 = new SparseArray<ForegroundToken>();
518
519 /**
520 * List of records for processes that someone had tried to start before the
521 * system was ready. We don't start them at that point, but ensure they
522 * are started by the time booting is complete.
523 */
524 final ArrayList<ProcessRecord> mProcessesOnHold
525 = new ArrayList<ProcessRecord>();
526
527 /**
528 * List of records for processes that we have started and are waiting
529 * for them to call back. This is really only needed when running in
530 * single processes mode, in which case we do not have a unique pid for
531 * each process.
532 */
533 final ArrayList<ProcessRecord> mStartingProcesses
534 = new ArrayList<ProcessRecord>();
535
536 /**
537 * List of persistent applications that are in the process
538 * of being started.
539 */
540 final ArrayList<ProcessRecord> mPersistentStartingProcesses
541 = new ArrayList<ProcessRecord>();
542
543 /**
544 * Processes that are being forcibly torn down.
545 */
546 final ArrayList<ProcessRecord> mRemovedProcesses
547 = new ArrayList<ProcessRecord>();
548
549 /**
550 * List of running applications, sorted by recent usage.
551 * The first entry in the list is the least recently used.
552 * It contains ApplicationRecord objects. This list does NOT include
553 * any persistent application records (since we never want to exit them).
554 */
555 final ArrayList<ProcessRecord> mLRUProcesses
556 = new ArrayList<ProcessRecord>();
557
558 /**
559 * List of processes that should gc as soon as things are idle.
560 */
561 final ArrayList<ProcessRecord> mProcessesToGc
562 = new ArrayList<ProcessRecord>();
563
564 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800565 * This is the process holding what we currently consider to be
566 * the "home" activity.
567 */
568 private ProcessRecord mHomeProcess;
569
570 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 * List of running activities, sorted by recent usage.
572 * The first entry in the list is the least recently used.
573 * It contains HistoryRecord objects.
574 */
575 private final ArrayList mLRUActivities = new ArrayList();
576
577 /**
578 * Set of PendingResultRecord objects that are currently active.
579 */
580 final HashSet mPendingResultRecords = new HashSet();
581
582 /**
583 * Set of IntentSenderRecord objects that are currently active.
584 */
585 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
586 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
587
588 /**
589 * Intent broadcast that we have tried to start, but are
590 * waiting for its application's process to be created. We only
591 * need one (instead of a list) because we always process broadcasts
592 * one at a time, so no others can be started while waiting for this
593 * one.
594 */
595 BroadcastRecord mPendingBroadcast = null;
596
597 /**
598 * Keeps track of all IIntentReceivers that have been registered for
599 * broadcasts. Hash keys are the receiver IBinder, hash value is
600 * a ReceiverList.
601 */
602 final HashMap mRegisteredReceivers = new HashMap();
603
604 /**
605 * Resolver for broadcast intents to registered receivers.
606 * Holds BroadcastFilter (subclass of IntentFilter).
607 */
608 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
609 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
610 @Override
611 protected boolean allowFilterResult(
612 BroadcastFilter filter, List<BroadcastFilter> dest) {
613 IBinder target = filter.receiverList.receiver.asBinder();
614 for (int i=dest.size()-1; i>=0; i--) {
615 if (dest.get(i).receiverList.receiver.asBinder() == target) {
616 return false;
617 }
618 }
619 return true;
620 }
621 };
622
623 /**
624 * State of all active sticky broadcasts. Keys are the action of the
625 * sticky Intent, values are an ArrayList of all broadcasted intents with
626 * that action (which should usually be one).
627 */
628 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
629 new HashMap<String, ArrayList<Intent>>();
630
631 /**
632 * All currently running services.
633 */
634 final HashMap<ComponentName, ServiceRecord> mServices =
635 new HashMap<ComponentName, ServiceRecord>();
636
637 /**
638 * All currently running services indexed by the Intent used to start them.
639 */
640 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
641 new HashMap<Intent.FilterComparison, ServiceRecord>();
642
643 /**
644 * All currently bound service connections. Keys are the IBinder of
645 * the client's IServiceConnection.
646 */
647 final HashMap<IBinder, ConnectionRecord> mServiceConnections
648 = new HashMap<IBinder, ConnectionRecord>();
649
650 /**
651 * List of services that we have been asked to start,
652 * but haven't yet been able to. It is used to hold start requests
653 * while waiting for their corresponding application thread to get
654 * going.
655 */
656 final ArrayList<ServiceRecord> mPendingServices
657 = new ArrayList<ServiceRecord>();
658
659 /**
660 * List of services that are scheduled to restart following a crash.
661 */
662 final ArrayList<ServiceRecord> mRestartingServices
663 = new ArrayList<ServiceRecord>();
664
665 /**
666 * List of services that are in the process of being stopped.
667 */
668 final ArrayList<ServiceRecord> mStoppingServices
669 = new ArrayList<ServiceRecord>();
670
671 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700672 * Backup/restore process management
673 */
674 String mBackupAppName = null;
675 BackupRecord mBackupTarget = null;
676
677 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 * List of PendingThumbnailsRecord objects of clients who are still
679 * waiting to receive all of the thumbnails for a task.
680 */
681 final ArrayList mPendingThumbnails = new ArrayList();
682
683 /**
684 * List of HistoryRecord objects that have been finished and must
685 * still report back to a pending thumbnail receiver.
686 */
687 final ArrayList mCancelledThumbnails = new ArrayList();
688
689 /**
690 * All of the currently running global content providers. Keys are a
691 * string containing the provider name and values are a
692 * ContentProviderRecord object containing the data about it. Note
693 * that a single provider may be published under multiple names, so
694 * there may be multiple entries here for a single one in mProvidersByClass.
695 */
696 final HashMap mProvidersByName = new HashMap();
697
698 /**
699 * All of the currently running global content providers. Keys are a
700 * string containing the provider's implementation class and values are a
701 * ContentProviderRecord object containing the data about it.
702 */
703 final HashMap mProvidersByClass = new HashMap();
704
705 /**
706 * List of content providers who have clients waiting for them. The
707 * application is currently being launched and the provider will be
708 * removed from this list once it is published.
709 */
710 final ArrayList mLaunchingProviders = new ArrayList();
711
712 /**
713 * Global set of specific Uri permissions that have been granted.
714 */
715 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
716 = new SparseArray<HashMap<Uri, UriPermission>>();
717
718 /**
719 * Thread-local storage used to carry caller permissions over through
720 * indirect content-provider access.
721 * @see #ActivityManagerService.openContentUri()
722 */
723 private class Identity {
724 public int pid;
725 public int uid;
726
727 Identity(int _pid, int _uid) {
728 pid = _pid;
729 uid = _uid;
730 }
731 }
732 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
733
734 /**
735 * All information we have collected about the runtime performance of
736 * any user id that can impact battery performance.
737 */
738 final BatteryStatsService mBatteryStatsService;
739
740 /**
741 * information about component usage
742 */
743 final UsageStatsService mUsageStatsService;
744
745 /**
746 * Current configuration information. HistoryRecord objects are given
747 * a reference to this object to indicate which configuration they are
748 * currently running in, so this object must be kept immutable.
749 */
750 Configuration mConfiguration = new Configuration();
751
752 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700753 * Hardware-reported OpenGLES version.
754 */
755 final int GL_ES_VERSION;
756
757 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 * List of initialization arguments to pass to all processes when binding applications to them.
759 * For example, references to the commonly used services.
760 */
761 HashMap<String, IBinder> mAppBindArgs;
762
763 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700764 * Temporary to avoid allocations. Protected by main lock.
765 */
766 final StringBuilder mStringBuilder = new StringBuilder(256);
767
768 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 * Used to control how we initialize the service.
770 */
771 boolean mStartRunning = false;
772 ComponentName mTopComponent;
773 String mTopAction;
774 String mTopData;
775 boolean mSystemReady = false;
776 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700777 boolean mWaitingUpdate = false;
778 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779
780 Context mContext;
781
782 int mFactoryTest;
783
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700784 boolean mCheckedForSetup;
785
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700787 * The time at which we will allow normal application switches again,
788 * after a call to {@link #stopAppSwitches()}.
789 */
790 long mAppSwitchesAllowedTime;
791
792 /**
793 * This is set to true after the first switch after mAppSwitchesAllowedTime
794 * is set; any switches after that will clear the time.
795 */
796 boolean mDidAppSwitch;
797
798 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 * Set while we are wanting to sleep, to prevent any
800 * activities from being started/resumed.
801 */
802 boolean mSleeping = false;
803
804 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700805 * Set if we are shutting down the system, similar to sleeping.
806 */
807 boolean mShuttingDown = false;
808
809 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 * Set when the system is going to sleep, until we have
811 * successfully paused the current activity and released our wake lock.
812 * At that point the system is allowed to actually sleep.
813 */
814 PowerManager.WakeLock mGoingToSleep;
815
816 /**
817 * We don't want to allow the device to go to sleep while in the process
818 * of launching an activity. This is primarily to allow alarm intent
819 * receivers to launch an activity and get that to run before the device
820 * goes back to sleep.
821 */
822 PowerManager.WakeLock mLaunchingActivity;
823
824 /**
825 * Task identifier that activities are currently being started
826 * in. Incremented each time a new task is created.
827 * todo: Replace this with a TokenSpace class that generates non-repeating
828 * integers that won't wrap.
829 */
830 int mCurTask = 1;
831
832 /**
833 * Current sequence id for oom_adj computation traversal.
834 */
835 int mAdjSeq = 0;
836
837 /**
838 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
839 * is set, indicating the user wants processes started in such a way
840 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
841 * running in each process (thus no pre-initialized process, etc).
842 */
843 boolean mSimpleProcessManagement = false;
844
845 /**
846 * System monitoring: number of processes that died since the last
847 * N procs were started.
848 */
849 int[] mProcDeaths = new int[20];
850
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700851 /**
852 * This is set if we had to do a delayed dexopt of an app before launching
853 * it, to increasing the ANR timeouts in that case.
854 */
855 boolean mDidDexOpt;
856
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 String mDebugApp = null;
858 boolean mWaitForDebugger = false;
859 boolean mDebugTransient = false;
860 String mOrigDebugApp = null;
861 boolean mOrigWaitForDebugger = false;
862 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700863 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700865 final RemoteCallbackList<IActivityWatcher> mWatchers
866 = new RemoteCallbackList<IActivityWatcher>();
867
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 /**
869 * Callback of last caller to {@link #requestPss}.
870 */
871 Runnable mRequestPssCallback;
872
873 /**
874 * Remaining processes for which we are waiting results from the last
875 * call to {@link #requestPss}.
876 */
877 final ArrayList<ProcessRecord> mRequestPssList
878 = new ArrayList<ProcessRecord>();
879
880 /**
881 * Runtime statistics collection thread. This object's lock is used to
882 * protect all related state.
883 */
884 final Thread mProcessStatsThread;
885
886 /**
887 * Used to collect process stats when showing not responding dialog.
888 * Protected by mProcessStatsThread.
889 */
890 final ProcessStats mProcessStats = new ProcessStats(
891 MONITOR_THREAD_CPU_USAGE);
892 long mLastCpuTime = 0;
893 long mLastWriteTime = 0;
894
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700895 long mInitialStartTime = 0;
896
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 /**
898 * Set to true after the system has finished booting.
899 */
900 boolean mBooted = false;
901
902 int mProcessLimit = 0;
903
904 WindowManagerService mWindowManager;
905
906 static ActivityManagerService mSelf;
907 static ActivityThread mSystemThread;
908
909 private final class AppDeathRecipient implements IBinder.DeathRecipient {
910 final ProcessRecord mApp;
911 final int mPid;
912 final IApplicationThread mAppThread;
913
914 AppDeathRecipient(ProcessRecord app, int pid,
915 IApplicationThread thread) {
916 if (localLOGV) Log.v(
917 TAG, "New death recipient " + this
918 + " for thread " + thread.asBinder());
919 mApp = app;
920 mPid = pid;
921 mAppThread = thread;
922 }
923
924 public void binderDied() {
925 if (localLOGV) Log.v(
926 TAG, "Death received in " + this
927 + " for thread " + mAppThread.asBinder());
928 removeRequestedPss(mApp);
929 synchronized(ActivityManagerService.this) {
930 appDiedLocked(mApp, mPid, mAppThread);
931 }
932 }
933 }
934
935 static final int SHOW_ERROR_MSG = 1;
936 static final int SHOW_NOT_RESPONDING_MSG = 2;
937 static final int SHOW_FACTORY_ERROR_MSG = 3;
938 static final int UPDATE_CONFIGURATION_MSG = 4;
939 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
940 static final int WAIT_FOR_DEBUGGER_MSG = 6;
941 static final int BROADCAST_INTENT_MSG = 7;
942 static final int BROADCAST_TIMEOUT_MSG = 8;
943 static final int PAUSE_TIMEOUT_MSG = 9;
944 static final int IDLE_TIMEOUT_MSG = 10;
945 static final int IDLE_NOW_MSG = 11;
946 static final int SERVICE_TIMEOUT_MSG = 12;
947 static final int UPDATE_TIME_ZONE = 13;
948 static final int SHOW_UID_ERROR_MSG = 14;
949 static final int IM_FEELING_LUCKY_MSG = 15;
950 static final int LAUNCH_TIMEOUT_MSG = 16;
951 static final int DESTROY_TIMEOUT_MSG = 17;
952 static final int SERVICE_ERROR_MSG = 18;
953 static final int RESUME_TOP_ACTIVITY_MSG = 19;
954 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700955 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700956 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957
958 AlertDialog mUidAlert;
959
960 final Handler mHandler = new Handler() {
961 //public Handler() {
962 // if (localLOGV) Log.v(TAG, "Handler started!");
963 //}
964
965 public void handleMessage(Message msg) {
966 switch (msg.what) {
967 case SHOW_ERROR_MSG: {
968 HashMap data = (HashMap) msg.obj;
969 byte[] crashData = (byte[])data.get("crashData");
970 if (crashData != null) {
971 // This needs to be *un*synchronized to avoid deadlock.
972 ContentResolver resolver = mContext.getContentResolver();
973 Checkin.reportCrash(resolver, crashData);
974 }
975 synchronized (ActivityManagerService.this) {
976 ProcessRecord proc = (ProcessRecord)data.get("app");
977 if (proc != null && proc.crashDialog != null) {
978 Log.e(TAG, "App already has crash dialog: " + proc);
979 return;
980 }
981 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700982 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 Dialog d = new AppErrorDialog(
984 mContext, res, proc,
985 (Integer)data.get("flags"),
986 (String)data.get("shortMsg"),
987 (String)data.get("longMsg"));
988 d.show();
989 proc.crashDialog = d;
990 } else {
991 // The device is asleep, so just pretend that the user
992 // saw a crash dialog and hit "force quit".
993 res.set(0);
994 }
995 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700996
997 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 } break;
999 case SHOW_NOT_RESPONDING_MSG: {
1000 synchronized (ActivityManagerService.this) {
1001 HashMap data = (HashMap) msg.obj;
1002 ProcessRecord proc = (ProcessRecord)data.get("app");
1003 if (proc != null && proc.anrDialog != null) {
1004 Log.e(TAG, "App already has anr dialog: " + proc);
1005 return;
1006 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001007
1008 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1009 null, null, 0, null, null, null,
1010 false, false, MY_PID, Process.SYSTEM_UID);
1011
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1013 mContext, proc, (HistoryRecord)data.get("activity"));
1014 d.show();
1015 proc.anrDialog = d;
1016 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001017
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001018 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 } break;
1020 case SHOW_FACTORY_ERROR_MSG: {
1021 Dialog d = new FactoryErrorDialog(
1022 mContext, msg.getData().getCharSequence("msg"));
1023 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001024 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 } break;
1026 case UPDATE_CONFIGURATION_MSG: {
1027 final ContentResolver resolver = mContext.getContentResolver();
1028 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1029 } break;
1030 case GC_BACKGROUND_PROCESSES_MSG: {
1031 synchronized (ActivityManagerService.this) {
1032 performAppGcsIfAppropriateLocked();
1033 }
1034 } break;
1035 case WAIT_FOR_DEBUGGER_MSG: {
1036 synchronized (ActivityManagerService.this) {
1037 ProcessRecord app = (ProcessRecord)msg.obj;
1038 if (msg.arg1 != 0) {
1039 if (!app.waitedForDebugger) {
1040 Dialog d = new AppWaitingForDebuggerDialog(
1041 ActivityManagerService.this,
1042 mContext, app);
1043 app.waitDialog = d;
1044 app.waitedForDebugger = true;
1045 d.show();
1046 }
1047 } else {
1048 if (app.waitDialog != null) {
1049 app.waitDialog.dismiss();
1050 app.waitDialog = null;
1051 }
1052 }
1053 }
1054 } break;
1055 case BROADCAST_INTENT_MSG: {
1056 if (DEBUG_BROADCAST) Log.v(
1057 TAG, "Received BROADCAST_INTENT_MSG");
1058 processNextBroadcast(true);
1059 } break;
1060 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001061 if (mDidDexOpt) {
1062 mDidDexOpt = false;
1063 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1064 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1065 return;
1066 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 broadcastTimeout();
1068 } break;
1069 case PAUSE_TIMEOUT_MSG: {
1070 IBinder token = (IBinder)msg.obj;
1071 // We don't at this point know if the activity is fullscreen,
1072 // so we need to be conservative and assume it isn't.
1073 Log.w(TAG, "Activity pause timeout for " + token);
1074 activityPaused(token, null, true);
1075 } break;
1076 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001077 if (mDidDexOpt) {
1078 mDidDexOpt = false;
1079 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1080 nmsg.obj = msg.obj;
1081 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1082 return;
1083 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001084 // We don't at this point know if the activity is fullscreen,
1085 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001086 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 Log.w(TAG, "Activity idle timeout for " + token);
1088 activityIdleInternal(token, true);
1089 } break;
1090 case DESTROY_TIMEOUT_MSG: {
1091 IBinder token = (IBinder)msg.obj;
1092 // We don't at this point know if the activity is fullscreen,
1093 // so we need to be conservative and assume it isn't.
1094 Log.w(TAG, "Activity destroy timeout for " + token);
1095 activityDestroyed(token);
1096 } break;
1097 case IDLE_NOW_MSG: {
1098 IBinder token = (IBinder)msg.obj;
1099 activityIdle(token);
1100 } break;
1101 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001102 if (mDidDexOpt) {
1103 mDidDexOpt = false;
1104 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1105 nmsg.obj = msg.obj;
1106 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1107 return;
1108 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 serviceTimeout((ProcessRecord)msg.obj);
1110 } break;
1111 case UPDATE_TIME_ZONE: {
1112 synchronized (ActivityManagerService.this) {
1113 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1114 ProcessRecord r = mLRUProcesses.get(i);
1115 if (r.thread != null) {
1116 try {
1117 r.thread.updateTimeZone();
1118 } catch (RemoteException ex) {
1119 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1120 }
1121 }
1122 }
1123 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001124 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 case SHOW_UID_ERROR_MSG: {
1126 // XXX This is a temporary dialog, no need to localize.
1127 AlertDialog d = new BaseErrorDialog(mContext);
1128 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1129 d.setCancelable(false);
1130 d.setTitle("System UIDs Inconsistent");
1131 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1132 d.setButton("I'm Feeling Lucky",
1133 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1134 mUidAlert = d;
1135 d.show();
1136 } break;
1137 case IM_FEELING_LUCKY_MSG: {
1138 if (mUidAlert != null) {
1139 mUidAlert.dismiss();
1140 mUidAlert = null;
1141 }
1142 } break;
1143 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001144 if (mDidDexOpt) {
1145 mDidDexOpt = false;
1146 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1147 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1148 return;
1149 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 synchronized (ActivityManagerService.this) {
1151 if (mLaunchingActivity.isHeld()) {
1152 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1153 mLaunchingActivity.release();
1154 }
1155 }
1156 } break;
1157 case SERVICE_ERROR_MSG: {
1158 ServiceRecord srv = (ServiceRecord)msg.obj;
1159 // This needs to be *un*synchronized to avoid deadlock.
1160 Checkin.logEvent(mContext.getContentResolver(),
1161 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1162 srv.name.toShortString());
1163 } break;
1164 case RESUME_TOP_ACTIVITY_MSG: {
1165 synchronized (ActivityManagerService.this) {
1166 resumeTopActivityLocked(null);
1167 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001168 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001170 if (mDidDexOpt) {
1171 mDidDexOpt = false;
1172 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1173 nmsg.obj = msg.obj;
1174 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1175 return;
1176 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177 ProcessRecord app = (ProcessRecord)msg.obj;
1178 synchronized (ActivityManagerService.this) {
1179 processStartTimedOutLocked(app);
1180 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001181 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001182 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1183 synchronized (ActivityManagerService.this) {
1184 doPendingActivityLaunchesLocked(true);
1185 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001186 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001187 case KILL_APPLICATION_MSG: {
1188 synchronized (ActivityManagerService.this) {
1189 int uid = msg.arg1;
1190 boolean restart = (msg.arg2 == 1);
1191 String pkg = (String) msg.obj;
1192 uninstallPackageLocked(pkg, uid, restart);
1193 }
1194 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195 }
1196 }
1197 };
1198
1199 public static void setSystemProcess() {
1200 try {
1201 ActivityManagerService m = mSelf;
1202
1203 ServiceManager.addService("activity", m);
1204 ServiceManager.addService("meminfo", new MemBinder(m));
1205 if (MONITOR_CPU_USAGE) {
1206 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1207 }
1208 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1209 ServiceManager.addService("activity.services", new ServicesBinder(m));
1210 ServiceManager.addService("activity.senders", new SendersBinder(m));
1211 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1212 ServiceManager.addService("permission", new PermissionController(m));
1213
1214 ApplicationInfo info =
1215 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001216 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217 synchronized (mSelf) {
1218 ProcessRecord app = mSelf.newProcessRecordLocked(
1219 mSystemThread.getApplicationThread(), info,
1220 info.processName);
1221 app.persistent = true;
1222 app.pid = Process.myPid();
1223 app.maxAdj = SYSTEM_ADJ;
1224 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1225 synchronized (mSelf.mPidsSelfLocked) {
1226 mSelf.mPidsSelfLocked.put(app.pid, app);
1227 }
1228 mSelf.updateLRUListLocked(app, true);
1229 }
1230 } catch (PackageManager.NameNotFoundException e) {
1231 throw new RuntimeException(
1232 "Unable to find android system package", e);
1233 }
1234 }
1235
1236 public void setWindowManager(WindowManagerService wm) {
1237 mWindowManager = wm;
1238 }
1239
1240 public static final Context main(int factoryTest) {
1241 AThread thr = new AThread();
1242 thr.start();
1243
1244 synchronized (thr) {
1245 while (thr.mService == null) {
1246 try {
1247 thr.wait();
1248 } catch (InterruptedException e) {
1249 }
1250 }
1251 }
1252
1253 ActivityManagerService m = thr.mService;
1254 mSelf = m;
1255 ActivityThread at = ActivityThread.systemMain();
1256 mSystemThread = at;
1257 Context context = at.getSystemContext();
1258 m.mContext = context;
1259 m.mFactoryTest = factoryTest;
1260 PowerManager pm =
1261 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1262 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1263 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1264 m.mLaunchingActivity.setReferenceCounted(false);
1265
1266 m.mBatteryStatsService.publish(context);
1267 m.mUsageStatsService.publish(context);
1268
1269 synchronized (thr) {
1270 thr.mReady = true;
1271 thr.notifyAll();
1272 }
1273
1274 m.startRunning(null, null, null, null);
1275
1276 return context;
1277 }
1278
1279 public static ActivityManagerService self() {
1280 return mSelf;
1281 }
1282
1283 static class AThread extends Thread {
1284 ActivityManagerService mService;
1285 boolean mReady = false;
1286
1287 public AThread() {
1288 super("ActivityManager");
1289 }
1290
1291 public void run() {
1292 Looper.prepare();
1293
1294 android.os.Process.setThreadPriority(
1295 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1296
1297 ActivityManagerService m = new ActivityManagerService();
1298
1299 synchronized (this) {
1300 mService = m;
1301 notifyAll();
1302 }
1303
1304 synchronized (this) {
1305 while (!mReady) {
1306 try {
1307 wait();
1308 } catch (InterruptedException e) {
1309 }
1310 }
1311 }
1312
1313 Looper.loop();
1314 }
1315 }
1316
1317 static class BroadcastsBinder extends Binder {
1318 ActivityManagerService mActivityManagerService;
1319 BroadcastsBinder(ActivityManagerService activityManagerService) {
1320 mActivityManagerService = activityManagerService;
1321 }
1322
1323 @Override
1324 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1325 mActivityManagerService.dumpBroadcasts(pw);
1326 }
1327 }
1328
1329 static class ServicesBinder extends Binder {
1330 ActivityManagerService mActivityManagerService;
1331 ServicesBinder(ActivityManagerService activityManagerService) {
1332 mActivityManagerService = activityManagerService;
1333 }
1334
1335 @Override
1336 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1337 mActivityManagerService.dumpServices(pw);
1338 }
1339 }
1340
1341 static class SendersBinder extends Binder {
1342 ActivityManagerService mActivityManagerService;
1343 SendersBinder(ActivityManagerService activityManagerService) {
1344 mActivityManagerService = activityManagerService;
1345 }
1346
1347 @Override
1348 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1349 mActivityManagerService.dumpSenders(pw);
1350 }
1351 }
1352
1353 static class ProvidersBinder extends Binder {
1354 ActivityManagerService mActivityManagerService;
1355 ProvidersBinder(ActivityManagerService activityManagerService) {
1356 mActivityManagerService = activityManagerService;
1357 }
1358
1359 @Override
1360 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1361 mActivityManagerService.dumpProviders(pw);
1362 }
1363 }
1364
1365 static class MemBinder extends Binder {
1366 ActivityManagerService mActivityManagerService;
1367 MemBinder(ActivityManagerService activityManagerService) {
1368 mActivityManagerService = activityManagerService;
1369 }
1370
1371 @Override
1372 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1373 ActivityManagerService service = mActivityManagerService;
1374 ArrayList<ProcessRecord> procs;
1375 synchronized (mActivityManagerService) {
1376 if (args != null && args.length > 0
1377 && args[0].charAt(0) != '-') {
1378 procs = new ArrayList<ProcessRecord>();
1379 int pid = -1;
1380 try {
1381 pid = Integer.parseInt(args[0]);
1382 } catch (NumberFormatException e) {
1383
1384 }
1385 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1386 ProcessRecord proc = service.mLRUProcesses.get(i);
1387 if (proc.pid == pid) {
1388 procs.add(proc);
1389 } else if (proc.processName.equals(args[0])) {
1390 procs.add(proc);
1391 }
1392 }
1393 if (procs.size() <= 0) {
1394 pw.println("No process found for: " + args[0]);
1395 return;
1396 }
1397 } else {
1398 procs = service.mLRUProcesses;
1399 }
1400 }
1401 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1402 }
1403 }
1404
1405 static class CpuBinder extends Binder {
1406 ActivityManagerService mActivityManagerService;
1407 CpuBinder(ActivityManagerService activityManagerService) {
1408 mActivityManagerService = activityManagerService;
1409 }
1410
1411 @Override
1412 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1413 synchronized (mActivityManagerService.mProcessStatsThread) {
1414 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1415 }
1416 }
1417 }
1418
1419 private ActivityManagerService() {
1420 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1421 if (v != null && Integer.getInteger(v) != 0) {
1422 mSimpleProcessManagement = true;
1423 }
1424 v = System.getenv("ANDROID_DEBUG_APP");
1425 if (v != null) {
1426 mSimpleProcessManagement = true;
1427 }
1428
1429 MY_PID = Process.myPid();
1430
1431 File dataDir = Environment.getDataDirectory();
1432 File systemDir = new File(dataDir, "system");
1433 systemDir.mkdirs();
1434 mBatteryStatsService = new BatteryStatsService(new File(
1435 systemDir, "batterystats.bin").toString());
1436 mBatteryStatsService.getActiveStatistics().readLocked();
1437 mBatteryStatsService.getActiveStatistics().writeLocked();
1438
1439 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001440 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001441
Jack Palevichb90d28c2009-07-22 15:35:24 -07001442 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1443 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001445 mConfiguration.makeDefault();
1446 mProcessStats.init();
1447
1448 // Add ourself to the Watchdog monitors.
1449 Watchdog.getInstance().addMonitor(this);
1450
1451 // These values are set in system/rootdir/init.rc on startup.
1452 FOREGROUND_APP_ADJ =
1453 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1454 VISIBLE_APP_ADJ =
1455 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1456 SECONDARY_SERVER_ADJ =
1457 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001458 BACKUP_APP_ADJ =
1459 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001460 HOME_APP_ADJ =
1461 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001462 HIDDEN_APP_MIN_ADJ =
1463 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1464 CONTENT_PROVIDER_ADJ =
1465 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1466 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1467 EMPTY_APP_ADJ =
1468 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1469 FOREGROUND_APP_MEM =
1470 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1471 VISIBLE_APP_MEM =
1472 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1473 SECONDARY_SERVER_MEM =
1474 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001475 BACKUP_APP_MEM =
1476 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001477 HOME_APP_MEM =
1478 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001479 HIDDEN_APP_MEM =
1480 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1481 EMPTY_APP_MEM =
1482 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1483
1484 mProcessStatsThread = new Thread("ProcessStats") {
1485 public void run() {
1486 while (true) {
1487 try {
1488 try {
1489 synchronized(this) {
1490 final long now = SystemClock.uptimeMillis();
1491 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1492 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1493 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1494 // + ", write delay=" + nextWriteDelay);
1495 if (nextWriteDelay < nextCpuDelay) {
1496 nextCpuDelay = nextWriteDelay;
1497 }
1498 if (nextCpuDelay > 0) {
1499 this.wait(nextCpuDelay);
1500 }
1501 }
1502 } catch (InterruptedException e) {
1503 }
1504
1505 updateCpuStatsNow();
1506 } catch (Exception e) {
1507 Log.e(TAG, "Unexpected exception collecting process stats", e);
1508 }
1509 }
1510 }
1511 };
1512 mProcessStatsThread.start();
1513 }
1514
1515 @Override
1516 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1517 throws RemoteException {
1518 try {
1519 return super.onTransact(code, data, reply, flags);
1520 } catch (RuntimeException e) {
1521 // The activity manager only throws security exceptions, so let's
1522 // log all others.
1523 if (!(e instanceof SecurityException)) {
1524 Log.e(TAG, "Activity Manager Crash", e);
1525 }
1526 throw e;
1527 }
1528 }
1529
1530 void updateCpuStats() {
1531 synchronized (mProcessStatsThread) {
1532 final long now = SystemClock.uptimeMillis();
1533 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1534 mProcessStatsThread.notify();
1535 }
1536 }
1537 }
1538
1539 void updateCpuStatsNow() {
1540 synchronized (mProcessStatsThread) {
1541 final long now = SystemClock.uptimeMillis();
1542 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001544 if (MONITOR_CPU_USAGE &&
1545 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1546 mLastCpuTime = now;
1547 haveNewCpuStats = true;
1548 mProcessStats.update();
1549 //Log.i(TAG, mProcessStats.printCurrentState());
1550 //Log.i(TAG, "Total CPU usage: "
1551 // + mProcessStats.getTotalCpuPercent() + "%");
1552
1553 // Log the cpu usage if the property is set.
1554 if ("true".equals(SystemProperties.get("events.cpu"))) {
1555 int user = mProcessStats.getLastUserTime();
1556 int system = mProcessStats.getLastSystemTime();
1557 int iowait = mProcessStats.getLastIoWaitTime();
1558 int irq = mProcessStats.getLastIrqTime();
1559 int softIrq = mProcessStats.getLastSoftIrqTime();
1560 int idle = mProcessStats.getLastIdleTime();
1561
1562 int total = user + system + iowait + irq + softIrq + idle;
1563 if (total == 0) total = 1;
1564
1565 EventLog.writeEvent(LOG_CPU,
1566 ((user+system+iowait+irq+softIrq) * 100) / total,
1567 (user * 100) / total,
1568 (system * 100) / total,
1569 (iowait * 100) / total,
1570 (irq * 100) / total,
1571 (softIrq * 100) / total);
1572 }
1573 }
1574
Amith Yamasani819f9282009-06-24 23:18:15 -07001575 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001576 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001577 synchronized(mPidsSelfLocked) {
1578 if (haveNewCpuStats) {
1579 if (mBatteryStatsService.isOnBattery()) {
1580 final int N = mProcessStats.countWorkingStats();
1581 for (int i=0; i<N; i++) {
1582 ProcessStats.Stats st
1583 = mProcessStats.getWorkingStats(i);
1584 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1585 if (pr != null) {
1586 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1587 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001588 } else {
1589 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001590 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001591 if (ps != null) {
1592 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1593 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001594 }
1595 }
1596 }
1597 }
1598 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001599
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001600 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1601 mLastWriteTime = now;
1602 mBatteryStatsService.getActiveStatistics().writeLocked();
1603 }
1604 }
1605 }
1606 }
1607
1608 /**
1609 * Initialize the application bind args. These are passed to each
1610 * process when the bindApplication() IPC is sent to the process. They're
1611 * lazily setup to make sure the services are running when they're asked for.
1612 */
1613 private HashMap<String, IBinder> getCommonServicesLocked() {
1614 if (mAppBindArgs == null) {
1615 mAppBindArgs = new HashMap<String, IBinder>();
1616
1617 // Setup the application init args
1618 mAppBindArgs.put("package", ServiceManager.getService("package"));
1619 mAppBindArgs.put("window", ServiceManager.getService("window"));
1620 mAppBindArgs.put(Context.ALARM_SERVICE,
1621 ServiceManager.getService(Context.ALARM_SERVICE));
1622 }
1623 return mAppBindArgs;
1624 }
1625
1626 private final void setFocusedActivityLocked(HistoryRecord r) {
1627 if (mFocusedActivity != r) {
1628 mFocusedActivity = r;
1629 mWindowManager.setFocusedApp(r, true);
1630 }
1631 }
1632
1633 private final void updateLRUListLocked(ProcessRecord app,
1634 boolean oomAdj) {
1635 // put it on the LRU to keep track of when it should be exited.
1636 int lrui = mLRUProcesses.indexOf(app);
1637 if (lrui >= 0) mLRUProcesses.remove(lrui);
1638 mLRUProcesses.add(app);
1639 //Log.i(TAG, "Putting proc to front: " + app.processName);
1640 if (oomAdj) {
1641 updateOomAdjLocked();
1642 }
1643 }
1644
1645 private final boolean updateLRUListLocked(HistoryRecord r) {
1646 final boolean hadit = mLRUActivities.remove(r);
1647 mLRUActivities.add(r);
1648 return hadit;
1649 }
1650
1651 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1652 int i = mHistory.size()-1;
1653 while (i >= 0) {
1654 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1655 if (!r.finishing && r != notTop) {
1656 return r;
1657 }
1658 i--;
1659 }
1660 return null;
1661 }
1662
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001663 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1664 int i = mHistory.size()-1;
1665 while (i >= 0) {
1666 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1667 if (!r.finishing && !r.delayedResume && r != notTop) {
1668 return r;
1669 }
1670 i--;
1671 }
1672 return null;
1673 }
1674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001675 /**
1676 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001677 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001678 *
1679 * @param token If non-null, any history records matching this token will be skipped.
1680 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1681 *
1682 * @return Returns the HistoryRecord of the next activity on the stack.
1683 */
1684 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1685 int i = mHistory.size()-1;
1686 while (i >= 0) {
1687 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1688 // Note: the taskId check depends on real taskId fields being non-zero
1689 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1690 return r;
1691 }
1692 i--;
1693 }
1694 return null;
1695 }
1696
1697 private final ProcessRecord getProcessRecordLocked(
1698 String processName, int uid) {
1699 if (uid == Process.SYSTEM_UID) {
1700 // The system gets to run in any process. If there are multiple
1701 // processes with the same uid, just pick the first (this
1702 // should never happen).
1703 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1704 processName);
1705 return procs != null ? procs.valueAt(0) : null;
1706 }
1707 ProcessRecord proc = mProcessNames.get(processName, uid);
1708 return proc;
1709 }
1710
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001711 private void ensurePackageDexOpt(String packageName) {
1712 IPackageManager pm = ActivityThread.getPackageManager();
1713 try {
1714 if (pm.performDexOpt(packageName)) {
1715 mDidDexOpt = true;
1716 }
1717 } catch (RemoteException e) {
1718 }
1719 }
1720
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001721 private boolean isNextTransitionForward() {
1722 int transit = mWindowManager.getPendingAppTransition();
1723 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1724 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1725 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1726 }
1727
1728 private final boolean realStartActivityLocked(HistoryRecord r,
1729 ProcessRecord app, boolean andResume, boolean checkConfig)
1730 throws RemoteException {
1731
1732 r.startFreezingScreenLocked(app, 0);
1733 mWindowManager.setAppVisibility(r, true);
1734
1735 // Have the window manager re-evaluate the orientation of
1736 // the screen based on the new activity order. Note that
1737 // as a result of this, it can call back into the activity
1738 // manager with a new orientation. We don't care about that,
1739 // because the activity is not currently running so we are
1740 // just restarting it anyway.
1741 if (checkConfig) {
1742 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001743 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001744 r.mayFreezeScreenLocked(app) ? r : null);
1745 updateConfigurationLocked(config, r);
1746 }
1747
1748 r.app = app;
1749
1750 if (localLOGV) Log.v(TAG, "Launching: " + r);
1751
1752 int idx = app.activities.indexOf(r);
1753 if (idx < 0) {
1754 app.activities.add(r);
1755 }
1756 updateLRUListLocked(app, true);
1757
1758 try {
1759 if (app.thread == null) {
1760 throw new RemoteException();
1761 }
1762 List<ResultInfo> results = null;
1763 List<Intent> newIntents = null;
1764 if (andResume) {
1765 results = r.results;
1766 newIntents = r.newIntents;
1767 }
1768 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1769 + " icicle=" + r.icicle
1770 + " with results=" + results + " newIntents=" + newIntents
1771 + " andResume=" + andResume);
1772 if (andResume) {
1773 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1774 System.identityHashCode(r),
1775 r.task.taskId, r.shortComponentName);
1776 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001777 if (r.isHomeActivity) {
1778 mHomeProcess = app;
1779 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001780 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001781 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001782 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001783 r.info, r.icicle, results, newIntents, !andResume,
1784 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001785 } catch (RemoteException e) {
1786 if (r.launchFailed) {
1787 // This is the second time we failed -- finish activity
1788 // and give up.
1789 Log.e(TAG, "Second failure launching "
1790 + r.intent.getComponent().flattenToShortString()
1791 + ", giving up", e);
1792 appDiedLocked(app, app.pid, app.thread);
1793 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1794 "2nd-crash");
1795 return false;
1796 }
1797
1798 // This is the first time we failed -- restart process and
1799 // retry.
1800 app.activities.remove(r);
1801 throw e;
1802 }
1803
1804 r.launchFailed = false;
1805 if (updateLRUListLocked(r)) {
1806 Log.w(TAG, "Activity " + r
1807 + " being launched, but already in LRU list");
1808 }
1809
1810 if (andResume) {
1811 // As part of the process of launching, ActivityThread also performs
1812 // a resume.
1813 r.state = ActivityState.RESUMED;
1814 r.icicle = null;
1815 r.haveState = false;
1816 r.stopped = false;
1817 mResumedActivity = r;
1818 r.task.touchActiveTime();
1819 completeResumeLocked(r);
1820 pauseIfSleepingLocked();
1821 } else {
1822 // This activity is not starting in the resumed state... which
1823 // should look like we asked it to pause+stop (but remain visible),
1824 // and it has done so and reported back the current icicle and
1825 // other state.
1826 r.state = ActivityState.STOPPED;
1827 r.stopped = true;
1828 }
1829
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001830 // Launch the new version setup screen if needed. We do this -after-
1831 // launching the initial activity (that is, home), so that it can have
1832 // a chance to initialize itself while in the background, making the
1833 // switch back to it faster and look better.
1834 startSetupActivityLocked();
1835
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001836 return true;
1837 }
1838
1839 private final void startSpecificActivityLocked(HistoryRecord r,
1840 boolean andResume, boolean checkConfig) {
1841 // Is this activity's application already running?
1842 ProcessRecord app = getProcessRecordLocked(r.processName,
1843 r.info.applicationInfo.uid);
1844
1845 if (r.startTime == 0) {
1846 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001847 if (mInitialStartTime == 0) {
1848 mInitialStartTime = r.startTime;
1849 }
1850 } else if (mInitialStartTime == 0) {
1851 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001852 }
1853
1854 if (app != null && app.thread != null) {
1855 try {
1856 realStartActivityLocked(r, app, andResume, checkConfig);
1857 return;
1858 } catch (RemoteException e) {
1859 Log.w(TAG, "Exception when starting activity "
1860 + r.intent.getComponent().flattenToShortString(), e);
1861 }
1862
1863 // If a dead object exception was thrown -- fall through to
1864 // restart the application.
1865 }
1866
1867 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001868 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001869 }
1870
1871 private final ProcessRecord startProcessLocked(String processName,
1872 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001873 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001874 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1875 // We don't have to do anything more if:
1876 // (1) There is an existing application record; and
1877 // (2) The caller doesn't think it is dead, OR there is no thread
1878 // object attached to it so we know it couldn't have crashed; and
1879 // (3) There is a pid assigned to it, so it is either starting or
1880 // already running.
1881 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1882 + " app=" + app + " knownToBeDead=" + knownToBeDead
1883 + " thread=" + (app != null ? app.thread : null)
1884 + " pid=" + (app != null ? app.pid : -1));
1885 if (app != null &&
1886 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1887 return app;
1888 }
1889
1890 String hostingNameStr = hostingName != null
1891 ? hostingName.flattenToShortString() : null;
1892
1893 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1894 // If we are in the background, then check to see if this process
1895 // is bad. If so, we will just silently fail.
1896 if (mBadProcesses.get(info.processName, info.uid) != null) {
1897 return null;
1898 }
1899 } else {
1900 // When the user is explicitly starting a process, then clear its
1901 // crash count so that we won't make it bad until they see at
1902 // least one crash dialog again, and make the process good again
1903 // if it had been bad.
1904 mProcessCrashTimes.remove(info.processName, info.uid);
1905 if (mBadProcesses.get(info.processName, info.uid) != null) {
1906 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1907 info.processName);
1908 mBadProcesses.remove(info.processName, info.uid);
1909 if (app != null) {
1910 app.bad = false;
1911 }
1912 }
1913 }
1914
1915 if (app == null) {
1916 app = newProcessRecordLocked(null, info, processName);
1917 mProcessNames.put(processName, info.uid, app);
1918 } else {
1919 // If this is a new package in the process, add the package to the list
1920 app.addPackage(info.packageName);
1921 }
1922
1923 // If the system is not ready yet, then hold off on starting this
1924 // process until it is.
1925 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001926 && !isAllowedWhileBooting(info)
1927 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001928 if (!mProcessesOnHold.contains(app)) {
1929 mProcessesOnHold.add(app);
1930 }
1931 return app;
1932 }
1933
1934 startProcessLocked(app, hostingType, hostingNameStr);
1935 return (app.pid != 0) ? app : null;
1936 }
1937
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001938 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1939 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1940 }
1941
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001942 private final void startProcessLocked(ProcessRecord app,
1943 String hostingType, String hostingNameStr) {
1944 if (app.pid > 0 && app.pid != MY_PID) {
1945 synchronized (mPidsSelfLocked) {
1946 mPidsSelfLocked.remove(app.pid);
1947 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1948 }
1949 app.pid = 0;
1950 }
1951
1952 mProcessesOnHold.remove(app);
1953
1954 updateCpuStats();
1955
1956 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1957 mProcDeaths[0] = 0;
1958
1959 try {
1960 int uid = app.info.uid;
1961 int[] gids = null;
1962 try {
1963 gids = mContext.getPackageManager().getPackageGids(
1964 app.info.packageName);
1965 } catch (PackageManager.NameNotFoundException e) {
1966 Log.w(TAG, "Unable to retrieve gids", e);
1967 }
1968 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1969 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1970 && mTopComponent != null
1971 && app.processName.equals(mTopComponent.getPackageName())) {
1972 uid = 0;
1973 }
1974 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1975 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1976 uid = 0;
1977 }
1978 }
1979 int debugFlags = 0;
1980 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1981 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1982 }
1983 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1984 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1985 }
1986 if ("1".equals(SystemProperties.get("debug.assert"))) {
1987 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1988 }
1989 int pid = Process.start("android.app.ActivityThread",
1990 mSimpleProcessManagement ? app.processName : null, uid, uid,
1991 gids, debugFlags, null);
1992 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1993 synchronized (bs) {
1994 if (bs.isOnBattery()) {
1995 app.batteryStats.incStartsLocked();
1996 }
1997 }
1998
1999 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
2000 app.processName, hostingType,
2001 hostingNameStr != null ? hostingNameStr : "");
2002
2003 if (app.persistent) {
2004 Watchdog.getInstance().processStarted(app, app.processName, pid);
2005 }
2006
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07002007 StringBuilder buf = mStringBuilder;
2008 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002009 buf.append("Start proc ");
2010 buf.append(app.processName);
2011 buf.append(" for ");
2012 buf.append(hostingType);
2013 if (hostingNameStr != null) {
2014 buf.append(" ");
2015 buf.append(hostingNameStr);
2016 }
2017 buf.append(": pid=");
2018 buf.append(pid);
2019 buf.append(" uid=");
2020 buf.append(uid);
2021 buf.append(" gids={");
2022 if (gids != null) {
2023 for (int gi=0; gi<gids.length; gi++) {
2024 if (gi != 0) buf.append(", ");
2025 buf.append(gids[gi]);
2026
2027 }
2028 }
2029 buf.append("}");
2030 Log.i(TAG, buf.toString());
2031 if (pid == 0 || pid == MY_PID) {
2032 // Processes are being emulated with threads.
2033 app.pid = MY_PID;
2034 app.removed = false;
2035 mStartingProcesses.add(app);
2036 } else if (pid > 0) {
2037 app.pid = pid;
2038 app.removed = false;
2039 synchronized (mPidsSelfLocked) {
2040 this.mPidsSelfLocked.put(pid, app);
2041 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2042 msg.obj = app;
2043 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2044 }
2045 } else {
2046 app.pid = 0;
2047 RuntimeException e = new RuntimeException(
2048 "Failure starting process " + app.processName
2049 + ": returned pid=" + pid);
2050 Log.e(TAG, e.getMessage(), e);
2051 }
2052 } catch (RuntimeException e) {
2053 // XXX do better error recovery.
2054 app.pid = 0;
2055 Log.e(TAG, "Failure starting process " + app.processName, e);
2056 }
2057 }
2058
2059 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2060 if (mPausingActivity != null) {
2061 RuntimeException e = new RuntimeException();
2062 Log.e(TAG, "Trying to pause when pause is already pending for "
2063 + mPausingActivity, e);
2064 }
2065 HistoryRecord prev = mResumedActivity;
2066 if (prev == null) {
2067 RuntimeException e = new RuntimeException();
2068 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2069 resumeTopActivityLocked(null);
2070 return;
2071 }
2072 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2073 mResumedActivity = null;
2074 mPausingActivity = prev;
2075 mLastPausedActivity = prev;
2076 prev.state = ActivityState.PAUSING;
2077 prev.task.touchActiveTime();
2078
2079 updateCpuStats();
2080
2081 if (prev.app != null && prev.app.thread != null) {
2082 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2083 try {
2084 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2085 System.identityHashCode(prev),
2086 prev.shortComponentName);
2087 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2088 prev.configChangeFlags);
2089 updateUsageStats(prev, false);
2090 } catch (Exception e) {
2091 // Ignore exception, if process died other code will cleanup.
2092 Log.w(TAG, "Exception thrown during pause", e);
2093 mPausingActivity = null;
2094 mLastPausedActivity = null;
2095 }
2096 } else {
2097 mPausingActivity = null;
2098 mLastPausedActivity = null;
2099 }
2100
2101 // If we are not going to sleep, we want to ensure the device is
2102 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002103 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002104 mLaunchingActivity.acquire();
2105 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2106 // To be safe, don't allow the wake lock to be held for too long.
2107 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2108 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2109 }
2110 }
2111
2112
2113 if (mPausingActivity != null) {
2114 // Have the window manager pause its key dispatching until the new
2115 // activity has started. If we're pausing the activity just because
2116 // the screen is being turned off and the UI is sleeping, don't interrupt
2117 // key dispatch; the same activity will pick it up again on wakeup.
2118 if (!uiSleeping) {
2119 prev.pauseKeyDispatchingLocked();
2120 } else {
2121 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2122 }
2123
2124 // Schedule a pause timeout in case the app doesn't respond.
2125 // We don't give it much time because this directly impacts the
2126 // responsiveness seen by the user.
2127 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2128 msg.obj = prev;
2129 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2130 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2131 } else {
2132 // This activity failed to schedule the
2133 // pause, so just treat it as being paused now.
2134 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2135 resumeTopActivityLocked(null);
2136 }
2137 }
2138
2139 private final void completePauseLocked() {
2140 HistoryRecord prev = mPausingActivity;
2141 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2142
2143 if (prev != null) {
2144 if (prev.finishing) {
2145 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2146 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2147 } else if (prev.app != null) {
2148 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2149 if (prev.waitingVisible) {
2150 prev.waitingVisible = false;
2151 mWaitingVisibleActivities.remove(prev);
2152 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2153 TAG, "Complete pause, no longer waiting: " + prev);
2154 }
2155 if (prev.configDestroy) {
2156 // The previous is being paused because the configuration
2157 // is changing, which means it is actually stopping...
2158 // To juggle the fact that we are also starting a new
2159 // instance right now, we need to first completely stop
2160 // the current instance before starting the new one.
2161 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2162 destroyActivityLocked(prev, true);
2163 } else {
2164 mStoppingActivities.add(prev);
2165 if (mStoppingActivities.size() > 3) {
2166 // If we already have a few activities waiting to stop,
2167 // then give up on things going idle and start clearing
2168 // them out.
2169 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2170 Message msg = Message.obtain();
2171 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2172 mHandler.sendMessage(msg);
2173 }
2174 }
2175 } else {
2176 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2177 prev = null;
2178 }
2179 mPausingActivity = null;
2180 }
2181
Dianne Hackborn55280a92009-05-07 15:53:46 -07002182 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002183 resumeTopActivityLocked(prev);
2184 } else {
2185 if (mGoingToSleep.isHeld()) {
2186 mGoingToSleep.release();
2187 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002188 if (mShuttingDown) {
2189 notifyAll();
2190 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002191 }
2192
2193 if (prev != null) {
2194 prev.resumeKeyDispatchingLocked();
2195 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002196
2197 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2198 long diff = 0;
2199 synchronized (mProcessStatsThread) {
2200 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2201 }
2202 if (diff > 0) {
2203 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2204 synchronized (bsi) {
2205 BatteryStatsImpl.Uid.Proc ps =
2206 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2207 prev.info.packageName);
2208 if (ps != null) {
2209 ps.addForegroundTimeLocked(diff);
2210 }
2211 }
2212 }
2213 }
2214 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002215 }
2216
2217 /**
2218 * Once we know that we have asked an application to put an activity in
2219 * the resumed state (either by launching it or explicitly telling it),
2220 * this function updates the rest of our state to match that fact.
2221 */
2222 private final void completeResumeLocked(HistoryRecord next) {
2223 next.idle = false;
2224 next.results = null;
2225 next.newIntents = null;
2226
2227 // schedule an idle timeout in case the app doesn't do it for us.
2228 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2229 msg.obj = next;
2230 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2231
2232 if (false) {
2233 // The activity was never told to pause, so just keep
2234 // things going as-is. To maintain our own state,
2235 // we need to emulate it coming back and saying it is
2236 // idle.
2237 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2238 msg.obj = next;
2239 mHandler.sendMessage(msg);
2240 }
2241
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002242 reportResumedActivity(next);
2243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002244 next.thumbnail = null;
2245 setFocusedActivityLocked(next);
2246 next.resumeKeyDispatchingLocked();
2247 ensureActivitiesVisibleLocked(null, 0);
2248 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002249
2250 // Mark the point when the activity is resuming
2251 // TODO: To be more accurate, the mark should be before the onCreate,
2252 // not after the onResume. But for subsequent starts, onResume is fine.
2253 if (next.app != null) {
2254 synchronized (mProcessStatsThread) {
2255 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2256 }
2257 } else {
2258 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2259 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002260 }
2261
2262 /**
2263 * Make sure that all activities that need to be visible (that is, they
2264 * currently can be seen by the user) actually are.
2265 */
2266 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2267 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2268 if (DEBUG_VISBILITY) Log.v(
2269 TAG, "ensureActivitiesVisible behind " + top
2270 + " configChanges=0x" + Integer.toHexString(configChanges));
2271
2272 // If the top activity is not fullscreen, then we need to
2273 // make sure any activities under it are now visible.
2274 final int count = mHistory.size();
2275 int i = count-1;
2276 while (mHistory.get(i) != top) {
2277 i--;
2278 }
2279 HistoryRecord r;
2280 boolean behindFullscreen = false;
2281 for (; i>=0; i--) {
2282 r = (HistoryRecord)mHistory.get(i);
2283 if (DEBUG_VISBILITY) Log.v(
2284 TAG, "Make visible? " + r + " finishing=" + r.finishing
2285 + " state=" + r.state);
2286 if (r.finishing) {
2287 continue;
2288 }
2289
2290 final boolean doThisProcess = onlyThisProcess == null
2291 || onlyThisProcess.equals(r.processName);
2292
2293 // First: if this is not the current activity being started, make
2294 // sure it matches the current configuration.
2295 if (r != starting && doThisProcess) {
2296 ensureActivityConfigurationLocked(r, 0);
2297 }
2298
2299 if (r.app == null || r.app.thread == null) {
2300 if (onlyThisProcess == null
2301 || onlyThisProcess.equals(r.processName)) {
2302 // This activity needs to be visible, but isn't even
2303 // running... get it started, but don't resume it
2304 // at this point.
2305 if (DEBUG_VISBILITY) Log.v(
2306 TAG, "Start and freeze screen for " + r);
2307 if (r != starting) {
2308 r.startFreezingScreenLocked(r.app, configChanges);
2309 }
2310 if (!r.visible) {
2311 if (DEBUG_VISBILITY) Log.v(
2312 TAG, "Starting and making visible: " + r);
2313 mWindowManager.setAppVisibility(r, true);
2314 }
2315 if (r != starting) {
2316 startSpecificActivityLocked(r, false, false);
2317 }
2318 }
2319
2320 } else if (r.visible) {
2321 // If this activity is already visible, then there is nothing
2322 // else to do here.
2323 if (DEBUG_VISBILITY) Log.v(
2324 TAG, "Skipping: already visible at " + r);
2325 r.stopFreezingScreenLocked(false);
2326
2327 } else if (onlyThisProcess == null) {
2328 // This activity is not currently visible, but is running.
2329 // Tell it to become visible.
2330 r.visible = true;
2331 if (r.state != ActivityState.RESUMED && r != starting) {
2332 // If this activity is paused, tell it
2333 // to now show its window.
2334 if (DEBUG_VISBILITY) Log.v(
2335 TAG, "Making visible and scheduling visibility: " + r);
2336 try {
2337 mWindowManager.setAppVisibility(r, true);
2338 r.app.thread.scheduleWindowVisibility(r, true);
2339 r.stopFreezingScreenLocked(false);
2340 } catch (Exception e) {
2341 // Just skip on any failure; we'll make it
2342 // visible when it next restarts.
2343 Log.w(TAG, "Exception thrown making visibile: "
2344 + r.intent.getComponent(), e);
2345 }
2346 }
2347 }
2348
2349 // Aggregate current change flags.
2350 configChanges |= r.configChangeFlags;
2351
2352 if (r.fullscreen) {
2353 // At this point, nothing else needs to be shown
2354 if (DEBUG_VISBILITY) Log.v(
2355 TAG, "Stopping: fullscreen at " + r);
2356 behindFullscreen = true;
2357 i--;
2358 break;
2359 }
2360 }
2361
2362 // Now for any activities that aren't visible to the user, make
2363 // sure they no longer are keeping the screen frozen.
2364 while (i >= 0) {
2365 r = (HistoryRecord)mHistory.get(i);
2366 if (DEBUG_VISBILITY) Log.v(
2367 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2368 + " state=" + r.state
2369 + " behindFullscreen=" + behindFullscreen);
2370 if (!r.finishing) {
2371 if (behindFullscreen) {
2372 if (r.visible) {
2373 if (DEBUG_VISBILITY) Log.v(
2374 TAG, "Making invisible: " + r);
2375 r.visible = false;
2376 try {
2377 mWindowManager.setAppVisibility(r, false);
2378 if ((r.state == ActivityState.STOPPING
2379 || r.state == ActivityState.STOPPED)
2380 && r.app != null && r.app.thread != null) {
2381 if (DEBUG_VISBILITY) Log.v(
2382 TAG, "Scheduling invisibility: " + r);
2383 r.app.thread.scheduleWindowVisibility(r, false);
2384 }
2385 } catch (Exception e) {
2386 // Just skip on any failure; we'll make it
2387 // visible when it next restarts.
2388 Log.w(TAG, "Exception thrown making hidden: "
2389 + r.intent.getComponent(), e);
2390 }
2391 } else {
2392 if (DEBUG_VISBILITY) Log.v(
2393 TAG, "Already invisible: " + r);
2394 }
2395 } else if (r.fullscreen) {
2396 if (DEBUG_VISBILITY) Log.v(
2397 TAG, "Now behindFullscreen: " + r);
2398 behindFullscreen = true;
2399 }
2400 }
2401 i--;
2402 }
2403 }
2404
2405 /**
2406 * Version of ensureActivitiesVisible that can easily be called anywhere.
2407 */
2408 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2409 int configChanges) {
2410 HistoryRecord r = topRunningActivityLocked(null);
2411 if (r != null) {
2412 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2413 }
2414 }
2415
2416 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2417 if (resumed) {
2418 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2419 } else {
2420 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2421 }
2422 }
2423
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002424 private boolean startHomeActivityLocked() {
2425 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2426 && mTopAction == null) {
2427 // We are running in factory test mode, but unable to find
2428 // the factory test app, so just sit around displaying the
2429 // error message and don't try to start anything.
2430 return false;
2431 }
2432 Intent intent = new Intent(
2433 mTopAction,
2434 mTopData != null ? Uri.parse(mTopData) : null);
2435 intent.setComponent(mTopComponent);
2436 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2437 intent.addCategory(Intent.CATEGORY_HOME);
2438 }
2439 ActivityInfo aInfo =
2440 intent.resolveActivityInfo(mContext.getPackageManager(),
2441 STOCK_PM_FLAGS);
2442 if (aInfo != null) {
2443 intent.setComponent(new ComponentName(
2444 aInfo.applicationInfo.packageName, aInfo.name));
2445 // Don't do this if the home app is currently being
2446 // instrumented.
2447 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2448 aInfo.applicationInfo.uid);
2449 if (app == null || app.instrumentationClass == null) {
2450 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2451 startActivityLocked(null, intent, null, null, 0, aInfo,
2452 null, null, 0, 0, 0, false, false);
2453 }
2454 }
2455
2456
2457 return true;
2458 }
2459
2460 /**
2461 * Starts the "new version setup screen" if appropriate.
2462 */
2463 private void startSetupActivityLocked() {
2464 // Only do this once per boot.
2465 if (mCheckedForSetup) {
2466 return;
2467 }
2468
2469 // We will show this screen if the current one is a different
2470 // version than the last one shown, and we are not running in
2471 // low-level factory test mode.
2472 final ContentResolver resolver = mContext.getContentResolver();
2473 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2474 Settings.Secure.getInt(resolver,
2475 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2476 mCheckedForSetup = true;
2477
2478 // See if we should be showing the platform update setup UI.
2479 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2480 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2481 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2482
2483 // We don't allow third party apps to replace this.
2484 ResolveInfo ri = null;
2485 for (int i=0; ris != null && i<ris.size(); i++) {
2486 if ((ris.get(i).activityInfo.applicationInfo.flags
2487 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2488 ri = ris.get(i);
2489 break;
2490 }
2491 }
2492
2493 if (ri != null) {
2494 String vers = ri.activityInfo.metaData != null
2495 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2496 : null;
2497 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2498 vers = ri.activityInfo.applicationInfo.metaData.getString(
2499 Intent.METADATA_SETUP_VERSION);
2500 }
2501 String lastVers = Settings.Secure.getString(
2502 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2503 if (vers != null && !vers.equals(lastVers)) {
2504 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2505 intent.setComponent(new ComponentName(
2506 ri.activityInfo.packageName, ri.activityInfo.name));
2507 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2508 null, null, 0, 0, 0, false, false);
2509 }
2510 }
2511 }
2512 }
2513
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002514 private void reportResumedActivity(HistoryRecord r) {
2515 //Log.i(TAG, "**** REPORT RESUME: " + r);
2516
2517 final int identHash = System.identityHashCode(r);
2518 updateUsageStats(r, true);
2519
2520 int i = mWatchers.beginBroadcast();
2521 while (i > 0) {
2522 i--;
2523 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2524 if (w != null) {
2525 try {
2526 w.activityResuming(identHash);
2527 } catch (RemoteException e) {
2528 }
2529 }
2530 }
2531 mWatchers.finishBroadcast();
2532 }
2533
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002534 /**
2535 * Ensure that the top activity in the stack is resumed.
2536 *
2537 * @param prev The previously resumed activity, for when in the process
2538 * of pausing; can be null to call from elsewhere.
2539 *
2540 * @return Returns true if something is being resumed, or false if
2541 * nothing happened.
2542 */
2543 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2544 // Find the first activity that is not finishing.
2545 HistoryRecord next = topRunningActivityLocked(null);
2546
2547 // Remember how we'll process this pause/resume situation, and ensure
2548 // that the state is reset however we wind up proceeding.
2549 final boolean userLeaving = mUserLeaving;
2550 mUserLeaving = false;
2551
2552 if (next == null) {
2553 // There are no more activities! Let's just start up the
2554 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002555 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002556 }
2557
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002558 next.delayedResume = false;
2559
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002560 // If the top activity is the resumed one, nothing to do.
2561 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2562 // Make sure we have executed any pending transitions, since there
2563 // should be nothing left to do at this point.
2564 mWindowManager.executeAppTransition();
2565 return false;
2566 }
2567
2568 // If we are sleeping, and there is no resumed activity, and the top
2569 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002570 if ((mSleeping || mShuttingDown)
2571 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002572 // Make sure we have executed any pending transitions, since there
2573 // should be nothing left to do at this point.
2574 mWindowManager.executeAppTransition();
2575 return false;
2576 }
2577
2578 // The activity may be waiting for stop, but that is no longer
2579 // appropriate for it.
2580 mStoppingActivities.remove(next);
2581 mWaitingVisibleActivities.remove(next);
2582
2583 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2584
2585 // If we are currently pausing an activity, then don't do anything
2586 // until that is done.
2587 if (mPausingActivity != null) {
2588 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2589 return false;
2590 }
2591
2592 // We need to start pausing the current activity so the top one
2593 // can be resumed...
2594 if (mResumedActivity != null) {
2595 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2596 startPausingLocked(userLeaving, false);
2597 return true;
2598 }
2599
2600 if (prev != null && prev != next) {
2601 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2602 prev.waitingVisible = true;
2603 mWaitingVisibleActivities.add(prev);
2604 if (DEBUG_SWITCH) Log.v(
2605 TAG, "Resuming top, waiting visible to hide: " + prev);
2606 } else {
2607 // The next activity is already visible, so hide the previous
2608 // activity's windows right now so we can show the new one ASAP.
2609 // We only do this if the previous is finishing, which should mean
2610 // it is on top of the one being resumed so hiding it quickly
2611 // is good. Otherwise, we want to do the normal route of allowing
2612 // the resumed activity to be shown so we can decide if the
2613 // previous should actually be hidden depending on whether the
2614 // new one is found to be full-screen or not.
2615 if (prev.finishing) {
2616 mWindowManager.setAppVisibility(prev, false);
2617 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2618 + prev + ", waitingVisible="
2619 + (prev != null ? prev.waitingVisible : null)
2620 + ", nowVisible=" + next.nowVisible);
2621 } else {
2622 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2623 + prev + ", waitingVisible="
2624 + (prev != null ? prev.waitingVisible : null)
2625 + ", nowVisible=" + next.nowVisible);
2626 }
2627 }
2628 }
2629
2630 // We are starting up the next activity, so tell the window manager
2631 // that the previous one will be hidden soon. This way it can know
2632 // to ignore it when computing the desired screen orientation.
2633 if (prev != null) {
2634 if (prev.finishing) {
2635 if (DEBUG_TRANSITION) Log.v(TAG,
2636 "Prepare close transition: prev=" + prev);
2637 mWindowManager.prepareAppTransition(prev.task == next.task
2638 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2639 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2640 mWindowManager.setAppWillBeHidden(prev);
2641 mWindowManager.setAppVisibility(prev, false);
2642 } else {
2643 if (DEBUG_TRANSITION) Log.v(TAG,
2644 "Prepare open transition: prev=" + prev);
2645 mWindowManager.prepareAppTransition(prev.task == next.task
2646 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2647 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2648 }
2649 if (false) {
2650 mWindowManager.setAppWillBeHidden(prev);
2651 mWindowManager.setAppVisibility(prev, false);
2652 }
2653 } else if (mHistory.size() > 1) {
2654 if (DEBUG_TRANSITION) Log.v(TAG,
2655 "Prepare open transition: no previous");
2656 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2657 }
2658
2659 if (next.app != null && next.app.thread != null) {
2660 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2661
2662 // This activity is now becoming visible.
2663 mWindowManager.setAppVisibility(next, true);
2664
2665 HistoryRecord lastResumedActivity = mResumedActivity;
2666 ActivityState lastState = next.state;
2667
2668 updateCpuStats();
2669
2670 next.state = ActivityState.RESUMED;
2671 mResumedActivity = next;
2672 next.task.touchActiveTime();
2673 updateLRUListLocked(next.app, true);
2674 updateLRUListLocked(next);
2675
2676 // Have the window manager re-evaluate the orientation of
2677 // the screen based on the new activity order.
2678 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002679 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002680 next.mayFreezeScreenLocked(next.app) ? next : null);
2681 if (config != null) {
2682 next.frozenBeforeDestroy = true;
2683 }
2684 if (!updateConfigurationLocked(config, next)) {
2685 // The configuration update wasn't able to keep the existing
2686 // instance of the activity, and instead started a new one.
2687 // We should be all done, but let's just make sure our activity
2688 // is still at the top and schedule another run if something
2689 // weird happened.
2690 HistoryRecord nextNext = topRunningActivityLocked(null);
2691 if (DEBUG_SWITCH) Log.i(TAG,
2692 "Activity config changed during resume: " + next
2693 + ", new next: " + nextNext);
2694 if (nextNext != next) {
2695 // Do over!
2696 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2697 }
2698 mWindowManager.executeAppTransition();
2699 return true;
2700 }
2701
2702 try {
2703 // Deliver all pending results.
2704 ArrayList a = next.results;
2705 if (a != null) {
2706 final int N = a.size();
2707 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002708 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002709 TAG, "Delivering results to " + next
2710 + ": " + a);
2711 next.app.thread.scheduleSendResult(next, a);
2712 }
2713 }
2714
2715 if (next.newIntents != null) {
2716 next.app.thread.scheduleNewIntent(next.newIntents, next);
2717 }
2718
2719 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2720 System.identityHashCode(next),
2721 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002722
2723 next.app.thread.scheduleResumeActivity(next,
2724 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002725
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002726 pauseIfSleepingLocked();
2727
2728 } catch (Exception e) {
2729 // Whoops, need to restart this activity!
2730 next.state = lastState;
2731 mResumedActivity = lastResumedActivity;
2732 if (Config.LOGD) Log.d(TAG,
2733 "Restarting because process died: " + next);
2734 if (!next.hasBeenLaunched) {
2735 next.hasBeenLaunched = true;
2736 } else {
2737 if (SHOW_APP_STARTING_ICON) {
2738 mWindowManager.setAppStartingWindow(
2739 next, next.packageName, next.theme,
2740 next.nonLocalizedLabel,
2741 next.labelRes, next.icon, null, true);
2742 }
2743 }
2744 startSpecificActivityLocked(next, true, false);
2745 return true;
2746 }
2747
2748 // From this point on, if something goes wrong there is no way
2749 // to recover the activity.
2750 try {
2751 next.visible = true;
2752 completeResumeLocked(next);
2753 } catch (Exception e) {
2754 // If any exception gets thrown, toss away this
2755 // activity and try the next one.
2756 Log.w(TAG, "Exception thrown during resume of " + next, e);
2757 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2758 "resume-exception");
2759 return true;
2760 }
2761
2762 // Didn't need to use the icicle, and it is now out of date.
2763 next.icicle = null;
2764 next.haveState = false;
2765 next.stopped = false;
2766
2767 } else {
2768 // Whoops, need to restart this activity!
2769 if (!next.hasBeenLaunched) {
2770 next.hasBeenLaunched = true;
2771 } else {
2772 if (SHOW_APP_STARTING_ICON) {
2773 mWindowManager.setAppStartingWindow(
2774 next, next.packageName, next.theme,
2775 next.nonLocalizedLabel,
2776 next.labelRes, next.icon, null, true);
2777 }
2778 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2779 }
2780 startSpecificActivityLocked(next, true, true);
2781 }
2782
2783 return true;
2784 }
2785
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002786 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2787 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002788 final int NH = mHistory.size();
2789
2790 int addPos = -1;
2791
2792 if (!newTask) {
2793 // If starting in an existing task, find where that is...
2794 HistoryRecord next = null;
2795 boolean startIt = true;
2796 for (int i = NH-1; i >= 0; i--) {
2797 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2798 if (p.finishing) {
2799 continue;
2800 }
2801 if (p.task == r.task) {
2802 // Here it is! Now, if this is not yet visible to the
2803 // user, then just add it without starting; it will
2804 // get started when the user navigates back to it.
2805 addPos = i+1;
2806 if (!startIt) {
2807 mHistory.add(addPos, r);
2808 r.inHistory = true;
2809 r.task.numActivities++;
2810 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2811 r.info.screenOrientation, r.fullscreen);
2812 if (VALIDATE_TOKENS) {
2813 mWindowManager.validateAppTokens(mHistory);
2814 }
2815 return;
2816 }
2817 break;
2818 }
2819 if (p.fullscreen) {
2820 startIt = false;
2821 }
2822 next = p;
2823 }
2824 }
2825
2826 // Place a new activity at top of stack, so it is next to interact
2827 // with the user.
2828 if (addPos < 0) {
2829 addPos = mHistory.size();
2830 }
2831
2832 // If we are not placing the new activity frontmost, we do not want
2833 // to deliver the onUserLeaving callback to the actual frontmost
2834 // activity
2835 if (addPos < NH) {
2836 mUserLeaving = false;
2837 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2838 }
2839
2840 // Slot the activity into the history stack and proceed
2841 mHistory.add(addPos, r);
2842 r.inHistory = true;
2843 r.frontOfTask = newTask;
2844 r.task.numActivities++;
2845 if (NH > 0) {
2846 // We want to show the starting preview window if we are
2847 // switching to a new task, or the next activity's process is
2848 // not currently running.
2849 boolean showStartingIcon = newTask;
2850 ProcessRecord proc = r.app;
2851 if (proc == null) {
2852 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2853 }
2854 if (proc == null || proc.thread == null) {
2855 showStartingIcon = true;
2856 }
2857 if (DEBUG_TRANSITION) Log.v(TAG,
2858 "Prepare open transition: starting " + r);
2859 mWindowManager.prepareAppTransition(newTask
2860 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2861 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2862 mWindowManager.addAppToken(
2863 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2864 boolean doShow = true;
2865 if (newTask) {
2866 // Even though this activity is starting fresh, we still need
2867 // to reset it to make sure we apply affinities to move any
2868 // existing activities from other tasks in to it.
2869 // If the caller has requested that the target task be
2870 // reset, then do so.
2871 if ((r.intent.getFlags()
2872 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2873 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002874 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002875 }
2876 }
2877 if (SHOW_APP_STARTING_ICON && doShow) {
2878 // Figure out if we are transitioning from another activity that is
2879 // "has the same starting icon" as the next one. This allows the
2880 // window manager to keep the previous window it had previously
2881 // created, if it still had one.
2882 HistoryRecord prev = mResumedActivity;
2883 if (prev != null) {
2884 // We don't want to reuse the previous starting preview if:
2885 // (1) The current activity is in a different task.
2886 if (prev.task != r.task) prev = null;
2887 // (2) The current activity is already displayed.
2888 else if (prev.nowVisible) prev = null;
2889 }
2890 mWindowManager.setAppStartingWindow(
2891 r, r.packageName, r.theme, r.nonLocalizedLabel,
2892 r.labelRes, r.icon, prev, showStartingIcon);
2893 }
2894 } else {
2895 // If this is the first activity, don't do any fancy animations,
2896 // because there is nothing for it to animate on top of.
2897 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2898 r.info.screenOrientation, r.fullscreen);
2899 }
2900 if (VALIDATE_TOKENS) {
2901 mWindowManager.validateAppTokens(mHistory);
2902 }
2903
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002904 if (doResume) {
2905 resumeTopActivityLocked(null);
2906 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002907 }
2908
2909 /**
2910 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002911 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2912 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002913 * an instance of that activity in the stack and, if found, finish all
2914 * activities on top of it and return the instance.
2915 *
2916 * @param newR Description of the new activity being started.
2917 * @return Returns the old activity that should be continue to be used,
2918 * or null if none was found.
2919 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002920 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002921 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002922 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002923
2924 // First find the requested task.
2925 while (i > 0) {
2926 i--;
2927 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2928 if (r.task.taskId == taskId) {
2929 i++;
2930 break;
2931 }
2932 }
2933
2934 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002935 while (i > 0) {
2936 i--;
2937 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2938 if (r.finishing) {
2939 continue;
2940 }
2941 if (r.task.taskId != taskId) {
2942 return null;
2943 }
2944 if (r.realActivity.equals(newR.realActivity)) {
2945 // Here it is! Now finish everything in front...
2946 HistoryRecord ret = r;
2947 if (doClear) {
2948 while (i < (mHistory.size()-1)) {
2949 i++;
2950 r = (HistoryRecord)mHistory.get(i);
2951 if (r.finishing) {
2952 continue;
2953 }
2954 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2955 null, "clear")) {
2956 i--;
2957 }
2958 }
2959 }
2960
2961 // Finally, if this is a normal launch mode (that is, not
2962 // expecting onNewIntent()), then we will finish the current
2963 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002964 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
2965 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002966 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002967 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002968 if (index >= 0) {
2969 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2970 null, "clear");
2971 }
2972 return null;
2973 }
2974 }
2975
2976 return ret;
2977 }
2978 }
2979
2980 return null;
2981 }
2982
2983 /**
2984 * Find the activity in the history stack within the given task. Returns
2985 * the index within the history at which it's found, or < 0 if not found.
2986 */
2987 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2988 int i = mHistory.size();
2989 while (i > 0) {
2990 i--;
2991 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2992 if (candidate.task.taskId != task) {
2993 break;
2994 }
2995 if (candidate.realActivity.equals(r.realActivity)) {
2996 return i;
2997 }
2998 }
2999
3000 return -1;
3001 }
3002
3003 /**
3004 * Reorder the history stack so that the activity at the given index is
3005 * brought to the front.
3006 */
3007 private final HistoryRecord moveActivityToFrontLocked(int where) {
3008 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3009 int top = mHistory.size();
3010 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3011 mHistory.add(top, newTop);
3012 oldTop.frontOfTask = false;
3013 newTop.frontOfTask = true;
3014 return newTop;
3015 }
3016
3017 /**
3018 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3019 * method will be called at the proper time.
3020 */
3021 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3022 boolean sent = false;
3023 if (r.state == ActivityState.RESUMED
3024 && r.app != null && r.app.thread != null) {
3025 try {
3026 ArrayList<Intent> ar = new ArrayList<Intent>();
3027 ar.add(new Intent(intent));
3028 r.app.thread.scheduleNewIntent(ar, r);
3029 sent = true;
3030 } catch (Exception e) {
3031 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3032 }
3033 }
3034 if (!sent) {
3035 r.addNewIntentLocked(new Intent(intent));
3036 }
3037 }
3038
3039 private final void logStartActivity(int tag, HistoryRecord r,
3040 TaskRecord task) {
3041 EventLog.writeEvent(tag,
3042 System.identityHashCode(r), task.taskId,
3043 r.shortComponentName, r.intent.getAction(),
3044 r.intent.getType(), r.intent.getDataString(),
3045 r.intent.getFlags());
3046 }
3047
3048 private final int startActivityLocked(IApplicationThread caller,
3049 Intent intent, String resolvedType,
3050 Uri[] grantedUriPermissions,
3051 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3052 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003053 int callingPid, int callingUid, boolean onlyIfNeeded,
3054 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003055 Log.i(TAG, "Starting activity: " + intent);
3056
3057 HistoryRecord sourceRecord = null;
3058 HistoryRecord resultRecord = null;
3059 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003060 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003061 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003062 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3063 if (index >= 0) {
3064 sourceRecord = (HistoryRecord)mHistory.get(index);
3065 if (requestCode >= 0 && !sourceRecord.finishing) {
3066 resultRecord = sourceRecord;
3067 }
3068 }
3069 }
3070
3071 int launchFlags = intent.getFlags();
3072
3073 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3074 && sourceRecord != null) {
3075 // Transfer the result target from the source activity to the new
3076 // one being started, including any failures.
3077 if (requestCode >= 0) {
3078 return START_FORWARD_AND_REQUEST_CONFLICT;
3079 }
3080 resultRecord = sourceRecord.resultTo;
3081 resultWho = sourceRecord.resultWho;
3082 requestCode = sourceRecord.requestCode;
3083 sourceRecord.resultTo = null;
3084 if (resultRecord != null) {
3085 resultRecord.removeResultsLocked(
3086 sourceRecord, resultWho, requestCode);
3087 }
3088 }
3089
3090 int err = START_SUCCESS;
3091
3092 if (intent.getComponent() == null) {
3093 // We couldn't find a class that can handle the given Intent.
3094 // That's the end of that!
3095 err = START_INTENT_NOT_RESOLVED;
3096 }
3097
3098 if (err == START_SUCCESS && aInfo == null) {
3099 // We couldn't find the specific class specified in the Intent.
3100 // Also the end of the line.
3101 err = START_CLASS_NOT_FOUND;
3102 }
3103
3104 ProcessRecord callerApp = null;
3105 if (err == START_SUCCESS && caller != null) {
3106 callerApp = getRecordForAppLocked(caller);
3107 if (callerApp != null) {
3108 callingPid = callerApp.pid;
3109 callingUid = callerApp.info.uid;
3110 } else {
3111 Log.w(TAG, "Unable to find app for caller " + caller
3112 + " (pid=" + callingPid + ") when starting: "
3113 + intent.toString());
3114 err = START_PERMISSION_DENIED;
3115 }
3116 }
3117
3118 if (err != START_SUCCESS) {
3119 if (resultRecord != null) {
3120 sendActivityResultLocked(-1,
3121 resultRecord, resultWho, requestCode,
3122 Activity.RESULT_CANCELED, null);
3123 }
3124 return err;
3125 }
3126
3127 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3128 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3129 if (perm != PackageManager.PERMISSION_GRANTED) {
3130 if (resultRecord != null) {
3131 sendActivityResultLocked(-1,
3132 resultRecord, resultWho, requestCode,
3133 Activity.RESULT_CANCELED, null);
3134 }
3135 String msg = "Permission Denial: starting " + intent.toString()
3136 + " from " + callerApp + " (pid=" + callingPid
3137 + ", uid=" + callingUid + ")"
3138 + " requires " + aInfo.permission;
3139 Log.w(TAG, msg);
3140 throw new SecurityException(msg);
3141 }
3142
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003143 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003144 boolean abort = false;
3145 try {
3146 // The Intent we give to the watcher has the extra data
3147 // stripped off, since it can contain private information.
3148 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003149 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003150 aInfo.applicationInfo.packageName);
3151 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003152 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003153 }
3154
3155 if (abort) {
3156 if (resultRecord != null) {
3157 sendActivityResultLocked(-1,
3158 resultRecord, resultWho, requestCode,
3159 Activity.RESULT_CANCELED, null);
3160 }
3161 // We pretend to the caller that it was really started, but
3162 // they will just get a cancel result.
3163 return START_SUCCESS;
3164 }
3165 }
3166
3167 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3168 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003169 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003170
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003171 if (mResumedActivity == null
3172 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3173 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3174 PendingActivityLaunch pal = new PendingActivityLaunch();
3175 pal.r = r;
3176 pal.sourceRecord = sourceRecord;
3177 pal.grantedUriPermissions = grantedUriPermissions;
3178 pal.grantedMode = grantedMode;
3179 pal.onlyIfNeeded = onlyIfNeeded;
3180 mPendingActivityLaunches.add(pal);
3181 return START_SWITCHES_CANCELED;
3182 }
3183 }
3184
3185 if (mDidAppSwitch) {
3186 // This is the second allowed switch since we stopped switches,
3187 // so now just generally allow switches. Use case: user presses
3188 // home (switches disabled, switch to home, mDidAppSwitch now true);
3189 // user taps a home icon (coming from home so allowed, we hit here
3190 // and now allow anyone to switch again).
3191 mAppSwitchesAllowedTime = 0;
3192 } else {
3193 mDidAppSwitch = true;
3194 }
3195
3196 doPendingActivityLaunchesLocked(false);
3197
3198 return startActivityUncheckedLocked(r, sourceRecord,
3199 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3200 }
3201
3202 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3203 final int N = mPendingActivityLaunches.size();
3204 if (N <= 0) {
3205 return;
3206 }
3207 for (int i=0; i<N; i++) {
3208 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3209 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3210 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3211 doResume && i == (N-1));
3212 }
3213 mPendingActivityLaunches.clear();
3214 }
3215
3216 private final int startActivityUncheckedLocked(HistoryRecord r,
3217 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3218 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3219 final Intent intent = r.intent;
3220 final int callingUid = r.launchedFromUid;
3221
3222 int launchFlags = intent.getFlags();
3223
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003224 // We'll invoke onUserLeaving before onPause only if the launching
3225 // activity did not explicitly state that this is an automated launch.
3226 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3227 if (DEBUG_USER_LEAVING) Log.v(TAG,
3228 "startActivity() => mUserLeaving=" + mUserLeaving);
3229
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003230 // If the caller has asked not to resume at this point, we make note
3231 // of this in the record so that we can skip it when trying to find
3232 // the top running activity.
3233 if (!doResume) {
3234 r.delayedResume = true;
3235 }
3236
3237 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3238 != 0 ? r : null;
3239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003240 // If the onlyIfNeeded flag is set, then we can do this if the activity
3241 // being launched is the same as the one making the call... or, as
3242 // a special case, if we do not know the caller then we count the
3243 // current top activity as the caller.
3244 if (onlyIfNeeded) {
3245 HistoryRecord checkedCaller = sourceRecord;
3246 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003247 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003248 }
3249 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3250 // Caller is not the same as launcher, so always needed.
3251 onlyIfNeeded = false;
3252 }
3253 }
3254
3255 if (grantedUriPermissions != null && callingUid > 0) {
3256 for (int i=0; i<grantedUriPermissions.length; i++) {
3257 grantUriPermissionLocked(callingUid, r.packageName,
3258 grantedUriPermissions[i], grantedMode, r);
3259 }
3260 }
3261
3262 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3263 intent, r);
3264
3265 if (sourceRecord == null) {
3266 // This activity is not being started from another... in this
3267 // case we -always- start a new task.
3268 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3269 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3270 + intent);
3271 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3272 }
3273 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3274 // The original activity who is starting us is running as a single
3275 // instance... this new activity it is starting must go on its
3276 // own task.
3277 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3278 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3279 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3280 // The activity being started is a single instance... it always
3281 // gets launched into its own task.
3282 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3283 }
3284
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003285 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003286 // For whatever reason this activity is being launched into a new
3287 // task... yet the caller has requested a result back. Well, that
3288 // is pretty messed up, so instead immediately send back a cancel
3289 // and let the new task continue launched as normal without a
3290 // dependency on its originator.
3291 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3292 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003293 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003294 Activity.RESULT_CANCELED, null);
3295 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003296 }
3297
3298 boolean addingToTask = false;
3299 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3300 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3301 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3302 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3303 // If bring to front is requested, and no result is requested, and
3304 // we can find a task that was started with this same
3305 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003306 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003307 // See if there is a task to bring to the front. If this is
3308 // a SINGLE_INSTANCE activity, there can be one and only one
3309 // instance of it in the history, and it is always in its own
3310 // unique task, so we do a special search.
3311 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3312 ? findTaskLocked(intent, r.info)
3313 : findActivityLocked(intent, r.info);
3314 if (taskTop != null) {
3315 if (taskTop.task.intent == null) {
3316 // This task was started because of movement of
3317 // the activity based on affinity... now that we
3318 // are actually launching it, we can assign the
3319 // base intent.
3320 taskTop.task.setIntent(intent, r.info);
3321 }
3322 // If the target task is not in the front, then we need
3323 // to bring it to the front... except... well, with
3324 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3325 // to have the same behavior as if a new instance was
3326 // being started, which means not bringing it to the front
3327 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003328 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003329 if (curTop.task != taskTop.task) {
3330 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3331 boolean callerAtFront = sourceRecord == null
3332 || curTop.task == sourceRecord.task;
3333 if (callerAtFront) {
3334 // We really do want to push this one into the
3335 // user's face, right now.
3336 moveTaskToFrontLocked(taskTop.task);
3337 }
3338 }
3339 // If the caller has requested that the target task be
3340 // reset, then do so.
3341 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3342 taskTop = resetTaskIfNeededLocked(taskTop, r);
3343 }
3344 if (onlyIfNeeded) {
3345 // We don't need to start a new activity, and
3346 // the client said not to do anything if that
3347 // is the case, so this is it! And for paranoia, make
3348 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003349 if (doResume) {
3350 resumeTopActivityLocked(null);
3351 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003352 return START_RETURN_INTENT_TO_CALLER;
3353 }
3354 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3355 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3356 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3357 // In this situation we want to remove all activities
3358 // from the task up to the one being started. In most
3359 // cases this means we are resetting the task to its
3360 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003361 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003362 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003363 if (top != null) {
3364 if (top.frontOfTask) {
3365 // Activity aliases may mean we use different
3366 // intents for the top activity, so make sure
3367 // the task now has the identity of the new
3368 // intent.
3369 top.task.setIntent(r.intent, r.info);
3370 }
3371 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3372 deliverNewIntentLocked(top, r.intent);
3373 } else {
3374 // A special case: we need to
3375 // start the activity because it is not currently
3376 // running, and the caller has asked to clear the
3377 // current task to have this activity at the top.
3378 addingToTask = true;
3379 // Now pretend like this activity is being started
3380 // by the top of its task, so it is put in the
3381 // right place.
3382 sourceRecord = taskTop;
3383 }
3384 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3385 // In this case the top activity on the task is the
3386 // same as the one being launched, so we take that
3387 // as a request to bring the task to the foreground.
3388 // If the top activity in the task is the root
3389 // activity, deliver this new intent to it if it
3390 // desires.
3391 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3392 && taskTop.realActivity.equals(r.realActivity)) {
3393 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3394 if (taskTop.frontOfTask) {
3395 taskTop.task.setIntent(r.intent, r.info);
3396 }
3397 deliverNewIntentLocked(taskTop, r.intent);
3398 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3399 // In this case we are launching the root activity
3400 // of the task, but with a different intent. We
3401 // should start a new instance on top.
3402 addingToTask = true;
3403 sourceRecord = taskTop;
3404 }
3405 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3406 // In this case an activity is being launched in to an
3407 // existing task, without resetting that task. This
3408 // is typically the situation of launching an activity
3409 // from a notification or shortcut. We want to place
3410 // the new activity on top of the current task.
3411 addingToTask = true;
3412 sourceRecord = taskTop;
3413 } else if (!taskTop.task.rootWasReset) {
3414 // In this case we are launching in to an existing task
3415 // that has not yet been started from its front door.
3416 // The current task has been brought to the front.
3417 // Ideally, we'd probably like to place this new task
3418 // at the bottom of its stack, but that's a little hard
3419 // to do with the current organization of the code so
3420 // for now we'll just drop it.
3421 taskTop.task.setIntent(r.intent, r.info);
3422 }
3423 if (!addingToTask) {
3424 // We didn't do anything... but it was needed (a.k.a., client
3425 // don't use that intent!) And for paranoia, make
3426 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003427 if (doResume) {
3428 resumeTopActivityLocked(null);
3429 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003430 return START_TASK_TO_FRONT;
3431 }
3432 }
3433 }
3434 }
3435
3436 //String uri = r.intent.toURI();
3437 //Intent intent2 = new Intent(uri);
3438 //Log.i(TAG, "Given intent: " + r.intent);
3439 //Log.i(TAG, "URI is: " + uri);
3440 //Log.i(TAG, "To intent: " + intent2);
3441
3442 if (r.packageName != null) {
3443 // If the activity being launched is the same as the one currently
3444 // at the top, then we need to check if it should only be launched
3445 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003446 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3447 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003448 if (top.realActivity.equals(r.realActivity)) {
3449 if (top.app != null && top.app.thread != null) {
3450 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3451 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3452 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3453 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3454 // For paranoia, make sure we have correctly
3455 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003456 if (doResume) {
3457 resumeTopActivityLocked(null);
3458 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003459 if (onlyIfNeeded) {
3460 // We don't need to start a new activity, and
3461 // the client said not to do anything if that
3462 // is the case, so this is it!
3463 return START_RETURN_INTENT_TO_CALLER;
3464 }
3465 deliverNewIntentLocked(top, r.intent);
3466 return START_DELIVERED_TO_TOP;
3467 }
3468 }
3469 }
3470 }
3471
3472 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003473 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003474 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003475 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003476 Activity.RESULT_CANCELED, null);
3477 }
3478 return START_CLASS_NOT_FOUND;
3479 }
3480
3481 boolean newTask = false;
3482
3483 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003484 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003485 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3486 // todo: should do better management of integers.
3487 mCurTask++;
3488 if (mCurTask <= 0) {
3489 mCurTask = 1;
3490 }
3491 r.task = new TaskRecord(mCurTask, r.info, intent,
3492 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3493 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3494 + " in new task " + r.task);
3495 newTask = true;
3496 addRecentTask(r.task);
3497
3498 } else if (sourceRecord != null) {
3499 if (!addingToTask &&
3500 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3501 // In this case, we are adding the activity to an existing
3502 // task, but the caller has asked to clear that task if the
3503 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003504 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003505 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003506 if (top != null) {
3507 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3508 deliverNewIntentLocked(top, r.intent);
3509 // For paranoia, make sure we have correctly
3510 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003511 if (doResume) {
3512 resumeTopActivityLocked(null);
3513 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003514 return START_DELIVERED_TO_TOP;
3515 }
3516 } else if (!addingToTask &&
3517 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3518 // In this case, we are launching an activity in our own task
3519 // that may already be running somewhere in the history, and
3520 // we want to shuffle it to the front of the stack if so.
3521 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3522 if (where >= 0) {
3523 HistoryRecord top = moveActivityToFrontLocked(where);
3524 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3525 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003526 if (doResume) {
3527 resumeTopActivityLocked(null);
3528 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003529 return START_DELIVERED_TO_TOP;
3530 }
3531 }
3532 // An existing activity is starting this new activity, so we want
3533 // to keep the new one in the same task as the one that is starting
3534 // it.
3535 r.task = sourceRecord.task;
3536 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3537 + " in existing task " + r.task);
3538
3539 } else {
3540 // This not being started from an existing activity, and not part
3541 // of a new task... just put it in the top task, though these days
3542 // this case should never happen.
3543 final int N = mHistory.size();
3544 HistoryRecord prev =
3545 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3546 r.task = prev != null
3547 ? prev.task
3548 : new TaskRecord(mCurTask, r.info, intent,
3549 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3550 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3551 + " in new guessed " + r.task);
3552 }
3553 if (newTask) {
3554 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3555 }
3556 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003557 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003558 return START_SUCCESS;
3559 }
3560
3561 public final int startActivity(IApplicationThread caller,
3562 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3563 int grantedMode, IBinder resultTo,
3564 String resultWho, int requestCode, boolean onlyIfNeeded,
3565 boolean debug) {
3566 // Refuse possible leaked file descriptors
3567 if (intent != null && intent.hasFileDescriptors()) {
3568 throw new IllegalArgumentException("File descriptors passed in Intent");
3569 }
3570
The Android Open Source Project4df24232009-03-05 14:34:35 -08003571 final boolean componentSpecified = intent.getComponent() != null;
3572
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003573 // Don't modify the client's object!
3574 intent = new Intent(intent);
3575
3576 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003577 ActivityInfo aInfo;
3578 try {
3579 ResolveInfo rInfo =
3580 ActivityThread.getPackageManager().resolveIntent(
3581 intent, resolvedType,
3582 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003583 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003584 aInfo = rInfo != null ? rInfo.activityInfo : null;
3585 } catch (RemoteException e) {
3586 aInfo = null;
3587 }
3588
3589 if (aInfo != null) {
3590 // Store the found target back into the intent, because now that
3591 // we have it we never want to do this again. For example, if the
3592 // user navigates back to this point in the history, we should
3593 // always restart the exact same activity.
3594 intent.setComponent(new ComponentName(
3595 aInfo.applicationInfo.packageName, aInfo.name));
3596
3597 // Don't debug things in the system process
3598 if (debug) {
3599 if (!aInfo.processName.equals("system")) {
3600 setDebugApp(aInfo.processName, true, false);
3601 }
3602 }
3603 }
3604
3605 synchronized(this) {
3606 final long origId = Binder.clearCallingIdentity();
3607 int res = startActivityLocked(caller, intent, resolvedType,
3608 grantedUriPermissions, grantedMode, aInfo,
3609 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003610 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003611 Binder.restoreCallingIdentity(origId);
3612 return res;
3613 }
3614 }
3615
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003616 public int startActivityPendingIntent(IApplicationThread caller,
3617 PendingIntent intent, Intent fillInIntent, String resolvedType,
3618 IBinder resultTo, String resultWho, int requestCode,
3619 int flagsMask, int flagsValues) {
3620 // Refuse possible leaked file descriptors
3621 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3622 throw new IllegalArgumentException("File descriptors passed in Intent");
3623 }
3624
3625 IIntentSender sender = intent.getTarget();
3626 if (!(sender instanceof PendingIntentRecord)) {
3627 throw new IllegalArgumentException("Bad PendingIntent object");
3628 }
3629
3630 PendingIntentRecord pir = (PendingIntentRecord)sender;
3631 if (pir.key.type != IActivityManager.INTENT_SENDER_ACTIVITY) {
3632 return START_NOT_ACTIVITY;
3633 }
3634
3635 return pir.sendInner(0, fillInIntent, resolvedType,
3636 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3637 }
3638
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003639 public boolean startNextMatchingActivity(IBinder callingActivity,
3640 Intent intent) {
3641 // Refuse possible leaked file descriptors
3642 if (intent != null && intent.hasFileDescriptors() == true) {
3643 throw new IllegalArgumentException("File descriptors passed in Intent");
3644 }
3645
3646 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003647 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003648 if (index < 0) {
3649 return false;
3650 }
3651 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3652 if (r.app == null || r.app.thread == null) {
3653 // The caller is not running... d'oh!
3654 return false;
3655 }
3656 intent = new Intent(intent);
3657 // The caller is not allowed to change the data.
3658 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3659 // And we are resetting to find the next component...
3660 intent.setComponent(null);
3661
3662 ActivityInfo aInfo = null;
3663 try {
3664 List<ResolveInfo> resolves =
3665 ActivityThread.getPackageManager().queryIntentActivities(
3666 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003667 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003668
3669 // Look for the original activity in the list...
3670 final int N = resolves != null ? resolves.size() : 0;
3671 for (int i=0; i<N; i++) {
3672 ResolveInfo rInfo = resolves.get(i);
3673 if (rInfo.activityInfo.packageName.equals(r.packageName)
3674 && rInfo.activityInfo.name.equals(r.info.name)) {
3675 // We found the current one... the next matching is
3676 // after it.
3677 i++;
3678 if (i<N) {
3679 aInfo = resolves.get(i).activityInfo;
3680 }
3681 break;
3682 }
3683 }
3684 } catch (RemoteException e) {
3685 }
3686
3687 if (aInfo == null) {
3688 // Nobody who is next!
3689 return false;
3690 }
3691
3692 intent.setComponent(new ComponentName(
3693 aInfo.applicationInfo.packageName, aInfo.name));
3694 intent.setFlags(intent.getFlags()&~(
3695 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3696 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3697 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3698 Intent.FLAG_ACTIVITY_NEW_TASK));
3699
3700 // Okay now we need to start the new activity, replacing the
3701 // currently running activity. This is a little tricky because
3702 // we want to start the new one as if the current one is finished,
3703 // but not finish the current one first so that there is no flicker.
3704 // And thus...
3705 final boolean wasFinishing = r.finishing;
3706 r.finishing = true;
3707
3708 // Propagate reply information over to the new activity.
3709 final HistoryRecord resultTo = r.resultTo;
3710 final String resultWho = r.resultWho;
3711 final int requestCode = r.requestCode;
3712 r.resultTo = null;
3713 if (resultTo != null) {
3714 resultTo.removeResultsLocked(r, resultWho, requestCode);
3715 }
3716
3717 final long origId = Binder.clearCallingIdentity();
3718 // XXX we are not dealing with propagating grantedUriPermissions...
3719 // those are not yet exposed to user code, so there is no need.
3720 int res = startActivityLocked(r.app.thread, intent,
3721 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003722 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003723 Binder.restoreCallingIdentity(origId);
3724
3725 r.finishing = wasFinishing;
3726 if (res != START_SUCCESS) {
3727 return false;
3728 }
3729 return true;
3730 }
3731 }
3732
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003733 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003734 Intent intent, String resolvedType, IBinder resultTo,
3735 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003736
3737 // This is so super not safe, that only the system (or okay root)
3738 // can do it.
3739 final int callingUid = Binder.getCallingUid();
3740 if (callingUid != 0 && callingUid != Process.myUid()) {
3741 throw new SecurityException(
3742 "startActivityInPackage only available to the system");
3743 }
3744
The Android Open Source Project4df24232009-03-05 14:34:35 -08003745 final boolean componentSpecified = intent.getComponent() != null;
3746
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003747 // Don't modify the client's object!
3748 intent = new Intent(intent);
3749
3750 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003751 ActivityInfo aInfo;
3752 try {
3753 ResolveInfo rInfo =
3754 ActivityThread.getPackageManager().resolveIntent(
3755 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003756 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003757 aInfo = rInfo != null ? rInfo.activityInfo : null;
3758 } catch (RemoteException e) {
3759 aInfo = null;
3760 }
3761
3762 if (aInfo != null) {
3763 // Store the found target back into the intent, because now that
3764 // we have it we never want to do this again. For example, if the
3765 // user navigates back to this point in the history, we should
3766 // always restart the exact same activity.
3767 intent.setComponent(new ComponentName(
3768 aInfo.applicationInfo.packageName, aInfo.name));
3769 }
3770
3771 synchronized(this) {
3772 return startActivityLocked(null, intent, resolvedType,
3773 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003774 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003775 }
3776 }
3777
3778 private final void addRecentTask(TaskRecord task) {
3779 // Remove any existing entries that are the same kind of task.
3780 int N = mRecentTasks.size();
3781 for (int i=0; i<N; i++) {
3782 TaskRecord tr = mRecentTasks.get(i);
3783 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3784 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3785 mRecentTasks.remove(i);
3786 i--;
3787 N--;
3788 if (task.intent == null) {
3789 // If the new recent task we are adding is not fully
3790 // specified, then replace it with the existing recent task.
3791 task = tr;
3792 }
3793 }
3794 }
3795 if (N >= MAX_RECENT_TASKS) {
3796 mRecentTasks.remove(N-1);
3797 }
3798 mRecentTasks.add(0, task);
3799 }
3800
3801 public void setRequestedOrientation(IBinder token,
3802 int requestedOrientation) {
3803 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003804 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003805 if (index < 0) {
3806 return;
3807 }
3808 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3809 final long origId = Binder.clearCallingIdentity();
3810 mWindowManager.setAppOrientation(r, requestedOrientation);
3811 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003812 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003813 r.mayFreezeScreenLocked(r.app) ? r : null);
3814 if (config != null) {
3815 r.frozenBeforeDestroy = true;
3816 if (!updateConfigurationLocked(config, r)) {
3817 resumeTopActivityLocked(null);
3818 }
3819 }
3820 Binder.restoreCallingIdentity(origId);
3821 }
3822 }
3823
3824 public int getRequestedOrientation(IBinder token) {
3825 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003826 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003827 if (index < 0) {
3828 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3829 }
3830 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3831 return mWindowManager.getAppOrientation(r);
3832 }
3833 }
3834
3835 private final void stopActivityLocked(HistoryRecord r) {
3836 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3837 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3838 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3839 if (!r.finishing) {
3840 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3841 "no-history");
3842 }
3843 } else if (r.app != null && r.app.thread != null) {
3844 if (mFocusedActivity == r) {
3845 setFocusedActivityLocked(topRunningActivityLocked(null));
3846 }
3847 r.resumeKeyDispatchingLocked();
3848 try {
3849 r.stopped = false;
3850 r.state = ActivityState.STOPPING;
3851 if (DEBUG_VISBILITY) Log.v(
3852 TAG, "Stopping visible=" + r.visible + " for " + r);
3853 if (!r.visible) {
3854 mWindowManager.setAppVisibility(r, false);
3855 }
3856 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3857 } catch (Exception e) {
3858 // Maybe just ignore exceptions here... if the process
3859 // has crashed, our death notification will clean things
3860 // up.
3861 Log.w(TAG, "Exception thrown during pause", e);
3862 // Just in case, assume it to be stopped.
3863 r.stopped = true;
3864 r.state = ActivityState.STOPPED;
3865 if (r.configDestroy) {
3866 destroyActivityLocked(r, true);
3867 }
3868 }
3869 }
3870 }
3871
3872 /**
3873 * @return Returns true if the activity is being finished, false if for
3874 * some reason it is being left as-is.
3875 */
3876 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3877 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003878 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003879 TAG, "Finishing activity: token=" + token
3880 + ", result=" + resultCode + ", data=" + resultData);
3881
Dianne Hackborn75b03852009-06-12 15:43:26 -07003882 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003883 if (index < 0) {
3884 return false;
3885 }
3886 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3887
3888 // Is this the last activity left?
3889 boolean lastActivity = true;
3890 for (int i=mHistory.size()-1; i>=0; i--) {
3891 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3892 if (!p.finishing && p != r) {
3893 lastActivity = false;
3894 break;
3895 }
3896 }
3897
3898 // If this is the last activity, but it is the home activity, then
3899 // just don't finish it.
3900 if (lastActivity) {
3901 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3902 return false;
3903 }
3904 }
3905
3906 finishActivityLocked(r, index, resultCode, resultData, reason);
3907 return true;
3908 }
3909
3910 /**
3911 * @return Returns true if this activity has been removed from the history
3912 * list, or false if it is still in the list and will be removed later.
3913 */
3914 private final boolean finishActivityLocked(HistoryRecord r, int index,
3915 int resultCode, Intent resultData, String reason) {
3916 if (r.finishing) {
3917 Log.w(TAG, "Duplicate finish request for " + r);
3918 return false;
3919 }
3920
3921 r.finishing = true;
3922 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3923 System.identityHashCode(r),
3924 r.task.taskId, r.shortComponentName, reason);
3925 r.task.numActivities--;
3926 if (r.frontOfTask && index < (mHistory.size()-1)) {
3927 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3928 if (next.task == r.task) {
3929 next.frontOfTask = true;
3930 }
3931 }
3932
3933 r.pauseKeyDispatchingLocked();
3934 if (mFocusedActivity == r) {
3935 setFocusedActivityLocked(topRunningActivityLocked(null));
3936 }
3937
3938 // send the result
3939 HistoryRecord resultTo = r.resultTo;
3940 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003941 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3942 + " who=" + r.resultWho + " req=" + r.requestCode
3943 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003944 if (r.info.applicationInfo.uid > 0) {
3945 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3946 r.packageName, resultData, r);
3947 }
3948 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3949 resultData);
3950 r.resultTo = null;
3951 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003952 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003953
3954 // Make sure this HistoryRecord is not holding on to other resources,
3955 // because clients have remote IPC references to this object so we
3956 // can't assume that will go away and want to avoid circular IPC refs.
3957 r.results = null;
3958 r.pendingResults = null;
3959 r.newIntents = null;
3960 r.icicle = null;
3961
3962 if (mPendingThumbnails.size() > 0) {
3963 // There are clients waiting to receive thumbnails so, in case
3964 // this is an activity that someone is waiting for, add it
3965 // to the pending list so we can correctly update the clients.
3966 mCancelledThumbnails.add(r);
3967 }
3968
3969 if (mResumedActivity == r) {
3970 boolean endTask = index <= 0
3971 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3972 if (DEBUG_TRANSITION) Log.v(TAG,
3973 "Prepare close transition: finishing " + r);
3974 mWindowManager.prepareAppTransition(endTask
3975 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3976 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3977
3978 // Tell window manager to prepare for this one to be removed.
3979 mWindowManager.setAppVisibility(r, false);
3980
3981 if (mPausingActivity == null) {
3982 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3983 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3984 startPausingLocked(false, false);
3985 }
3986
3987 } else if (r.state != ActivityState.PAUSING) {
3988 // If the activity is PAUSING, we will complete the finish once
3989 // it is done pausing; else we can just directly finish it here.
3990 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3991 return finishCurrentActivityLocked(r, index,
3992 FINISH_AFTER_PAUSE) == null;
3993 } else {
3994 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3995 }
3996
3997 return false;
3998 }
3999
4000 private static final int FINISH_IMMEDIATELY = 0;
4001 private static final int FINISH_AFTER_PAUSE = 1;
4002 private static final int FINISH_AFTER_VISIBLE = 2;
4003
4004 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4005 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004006 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004007 if (index < 0) {
4008 return null;
4009 }
4010
4011 return finishCurrentActivityLocked(r, index, mode);
4012 }
4013
4014 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4015 int index, int mode) {
4016 // First things first: if this activity is currently visible,
4017 // and the resumed activity is not yet visible, then hold off on
4018 // finishing until the resumed one becomes visible.
4019 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4020 if (!mStoppingActivities.contains(r)) {
4021 mStoppingActivities.add(r);
4022 if (mStoppingActivities.size() > 3) {
4023 // If we already have a few activities waiting to stop,
4024 // then give up on things going idle and start clearing
4025 // them out.
4026 Message msg = Message.obtain();
4027 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4028 mHandler.sendMessage(msg);
4029 }
4030 }
4031 r.state = ActivityState.STOPPING;
4032 updateOomAdjLocked();
4033 return r;
4034 }
4035
4036 // make sure the record is cleaned out of other places.
4037 mStoppingActivities.remove(r);
4038 mWaitingVisibleActivities.remove(r);
4039 if (mResumedActivity == r) {
4040 mResumedActivity = null;
4041 }
4042 final ActivityState prevState = r.state;
4043 r.state = ActivityState.FINISHING;
4044
4045 if (mode == FINISH_IMMEDIATELY
4046 || prevState == ActivityState.STOPPED
4047 || prevState == ActivityState.INITIALIZING) {
4048 // If this activity is already stopped, we can just finish
4049 // it right now.
4050 return destroyActivityLocked(r, true) ? null : r;
4051 } else {
4052 // Need to go through the full pause cycle to get this
4053 // activity into the stopped state and then finish it.
4054 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4055 mFinishingActivities.add(r);
4056 resumeTopActivityLocked(null);
4057 }
4058 return r;
4059 }
4060
4061 /**
4062 * This is the internal entry point for handling Activity.finish().
4063 *
4064 * @param token The Binder token referencing the Activity we want to finish.
4065 * @param resultCode Result code, if any, from this Activity.
4066 * @param resultData Result data (Intent), if any, from this Activity.
4067 *
4068 * @result Returns true if the activity successfully finished, or false if it is still running.
4069 */
4070 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4071 // Refuse possible leaked file descriptors
4072 if (resultData != null && resultData.hasFileDescriptors() == true) {
4073 throw new IllegalArgumentException("File descriptors passed in Intent");
4074 }
4075
4076 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004077 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004078 // Find the first activity that is not finishing.
4079 HistoryRecord next = topRunningActivityLocked(token, 0);
4080 if (next != null) {
4081 // ask watcher if this is allowed
4082 boolean resumeOK = true;
4083 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004084 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004085 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004086 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004087 }
4088
4089 if (!resumeOK) {
4090 return false;
4091 }
4092 }
4093 }
4094 final long origId = Binder.clearCallingIdentity();
4095 boolean res = requestFinishActivityLocked(token, resultCode,
4096 resultData, "app-request");
4097 Binder.restoreCallingIdentity(origId);
4098 return res;
4099 }
4100 }
4101
4102 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4103 String resultWho, int requestCode, int resultCode, Intent data) {
4104
4105 if (callingUid > 0) {
4106 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4107 data, r);
4108 }
4109
The Android Open Source Project10592532009-03-18 17:39:46 -07004110 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4111 + " : who=" + resultWho + " req=" + requestCode
4112 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004113 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4114 try {
4115 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4116 list.add(new ResultInfo(resultWho, requestCode,
4117 resultCode, data));
4118 r.app.thread.scheduleSendResult(r, list);
4119 return;
4120 } catch (Exception e) {
4121 Log.w(TAG, "Exception thrown sending result to " + r, e);
4122 }
4123 }
4124
4125 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4126 }
4127
4128 public final void finishSubActivity(IBinder token, String resultWho,
4129 int requestCode) {
4130 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004131 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004132 if (index < 0) {
4133 return;
4134 }
4135 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4136
4137 final long origId = Binder.clearCallingIdentity();
4138
4139 int i;
4140 for (i=mHistory.size()-1; i>=0; i--) {
4141 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4142 if (r.resultTo == self && r.requestCode == requestCode) {
4143 if ((r.resultWho == null && resultWho == null) ||
4144 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4145 finishActivityLocked(r, i,
4146 Activity.RESULT_CANCELED, null, "request-sub");
4147 }
4148 }
4149 }
4150
4151 Binder.restoreCallingIdentity(origId);
4152 }
4153 }
4154
4155 /**
4156 * Perform clean-up of service connections in an activity record.
4157 */
4158 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4159 // Throw away any services that have been bound by this activity.
4160 if (r.connections != null) {
4161 Iterator<ConnectionRecord> it = r.connections.iterator();
4162 while (it.hasNext()) {
4163 ConnectionRecord c = it.next();
4164 removeConnectionLocked(c, null, r);
4165 }
4166 r.connections = null;
4167 }
4168 }
4169
4170 /**
4171 * Perform the common clean-up of an activity record. This is called both
4172 * as part of destroyActivityLocked() (when destroying the client-side
4173 * representation) and cleaning things up as a result of its hosting
4174 * processing going away, in which case there is no remaining client-side
4175 * state to destroy so only the cleanup here is needed.
4176 */
4177 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4178 if (mResumedActivity == r) {
4179 mResumedActivity = null;
4180 }
4181 if (mFocusedActivity == r) {
4182 mFocusedActivity = null;
4183 }
4184
4185 r.configDestroy = false;
4186 r.frozenBeforeDestroy = false;
4187
4188 // Make sure this record is no longer in the pending finishes list.
4189 // This could happen, for example, if we are trimming activities
4190 // down to the max limit while they are still waiting to finish.
4191 mFinishingActivities.remove(r);
4192 mWaitingVisibleActivities.remove(r);
4193
4194 // Remove any pending results.
4195 if (r.finishing && r.pendingResults != null) {
4196 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4197 PendingIntentRecord rec = apr.get();
4198 if (rec != null) {
4199 cancelIntentSenderLocked(rec, false);
4200 }
4201 }
4202 r.pendingResults = null;
4203 }
4204
4205 if (cleanServices) {
4206 cleanUpActivityServicesLocked(r);
4207 }
4208
4209 if (mPendingThumbnails.size() > 0) {
4210 // There are clients waiting to receive thumbnails so, in case
4211 // this is an activity that someone is waiting for, add it
4212 // to the pending list so we can correctly update the clients.
4213 mCancelledThumbnails.add(r);
4214 }
4215
4216 // Get rid of any pending idle timeouts.
4217 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4218 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4219 }
4220
4221 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4222 if (r.state != ActivityState.DESTROYED) {
4223 mHistory.remove(r);
4224 r.inHistory = false;
4225 r.state = ActivityState.DESTROYED;
4226 mWindowManager.removeAppToken(r);
4227 if (VALIDATE_TOKENS) {
4228 mWindowManager.validateAppTokens(mHistory);
4229 }
4230 cleanUpActivityServicesLocked(r);
4231 removeActivityUriPermissionsLocked(r);
4232 }
4233 }
4234
4235 /**
4236 * Destroy the current CLIENT SIDE instance of an activity. This may be
4237 * called both when actually finishing an activity, or when performing
4238 * a configuration switch where we destroy the current client-side object
4239 * but then create a new client-side object for this same HistoryRecord.
4240 */
4241 private final boolean destroyActivityLocked(HistoryRecord r,
4242 boolean removeFromApp) {
4243 if (DEBUG_SWITCH) Log.v(
4244 TAG, "Removing activity: token=" + r
4245 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4246 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4247 System.identityHashCode(r),
4248 r.task.taskId, r.shortComponentName);
4249
4250 boolean removedFromHistory = false;
4251
4252 cleanUpActivityLocked(r, false);
4253
4254 if (r.app != null) {
4255 if (removeFromApp) {
4256 int idx = r.app.activities.indexOf(r);
4257 if (idx >= 0) {
4258 r.app.activities.remove(idx);
4259 }
4260 if (r.persistent) {
4261 decPersistentCountLocked(r.app);
4262 }
4263 }
4264
4265 boolean skipDestroy = false;
4266
4267 try {
4268 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4269 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4270 r.configChangeFlags);
4271 } catch (Exception e) {
4272 // We can just ignore exceptions here... if the process
4273 // has crashed, our death notification will clean things
4274 // up.
4275 //Log.w(TAG, "Exception thrown during finish", e);
4276 if (r.finishing) {
4277 removeActivityFromHistoryLocked(r);
4278 removedFromHistory = true;
4279 skipDestroy = true;
4280 }
4281 }
4282
4283 r.app = null;
4284 r.nowVisible = false;
4285
4286 if (r.finishing && !skipDestroy) {
4287 r.state = ActivityState.DESTROYING;
4288 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4289 msg.obj = r;
4290 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4291 } else {
4292 r.state = ActivityState.DESTROYED;
4293 }
4294 } else {
4295 // remove this record from the history.
4296 if (r.finishing) {
4297 removeActivityFromHistoryLocked(r);
4298 removedFromHistory = true;
4299 } else {
4300 r.state = ActivityState.DESTROYED;
4301 }
4302 }
4303
4304 r.configChangeFlags = 0;
4305
4306 if (!mLRUActivities.remove(r)) {
4307 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4308 }
4309
4310 return removedFromHistory;
4311 }
4312
4313 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4314 ProcessRecord app)
4315 {
4316 int i = list.size();
4317 if (localLOGV) Log.v(
4318 TAG, "Removing app " + app + " from list " + list
4319 + " with " + i + " entries");
4320 while (i > 0) {
4321 i--;
4322 HistoryRecord r = (HistoryRecord)list.get(i);
4323 if (localLOGV) Log.v(
4324 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4325 if (r.app == app) {
4326 if (localLOGV) Log.v(TAG, "Removing this entry!");
4327 list.remove(i);
4328 }
4329 }
4330 }
4331
4332 /**
4333 * Main function for removing an existing process from the activity manager
4334 * as a result of that process going away. Clears out all connections
4335 * to the process.
4336 */
4337 private final void handleAppDiedLocked(ProcessRecord app,
4338 boolean restarting) {
4339 cleanUpApplicationRecordLocked(app, restarting, -1);
4340 if (!restarting) {
4341 mLRUProcesses.remove(app);
4342 }
4343
4344 // Just in case...
4345 if (mPausingActivity != null && mPausingActivity.app == app) {
4346 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4347 mPausingActivity = null;
4348 }
4349 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4350 mLastPausedActivity = null;
4351 }
4352
4353 // Remove this application's activities from active lists.
4354 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4355 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4356 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4357 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4358
4359 boolean atTop = true;
4360 boolean hasVisibleActivities = false;
4361
4362 // Clean out the history list.
4363 int i = mHistory.size();
4364 if (localLOGV) Log.v(
4365 TAG, "Removing app " + app + " from history with " + i + " entries");
4366 while (i > 0) {
4367 i--;
4368 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4369 if (localLOGV) Log.v(
4370 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4371 if (r.app == app) {
4372 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4373 if (localLOGV) Log.v(
4374 TAG, "Removing this entry! frozen=" + r.haveState
4375 + " finishing=" + r.finishing);
4376 mHistory.remove(i);
4377
4378 r.inHistory = false;
4379 mWindowManager.removeAppToken(r);
4380 if (VALIDATE_TOKENS) {
4381 mWindowManager.validateAppTokens(mHistory);
4382 }
4383 removeActivityUriPermissionsLocked(r);
4384
4385 } else {
4386 // We have the current state for this activity, so
4387 // it can be restarted later when needed.
4388 if (localLOGV) Log.v(
4389 TAG, "Keeping entry, setting app to null");
4390 if (r.visible) {
4391 hasVisibleActivities = true;
4392 }
4393 r.app = null;
4394 r.nowVisible = false;
4395 if (!r.haveState) {
4396 r.icicle = null;
4397 }
4398 }
4399
4400 cleanUpActivityLocked(r, true);
4401 r.state = ActivityState.STOPPED;
4402 }
4403 atTop = false;
4404 }
4405
4406 app.activities.clear();
4407
4408 if (app.instrumentationClass != null) {
4409 Log.w(TAG, "Crash of app " + app.processName
4410 + " running instrumentation " + app.instrumentationClass);
4411 Bundle info = new Bundle();
4412 info.putString("shortMsg", "Process crashed.");
4413 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4414 }
4415
4416 if (!restarting) {
4417 if (!resumeTopActivityLocked(null)) {
4418 // If there was nothing to resume, and we are not already
4419 // restarting this process, but there is a visible activity that
4420 // is hosted by the process... then make sure all visible
4421 // activities are running, taking care of restarting this
4422 // process.
4423 if (hasVisibleActivities) {
4424 ensureActivitiesVisibleLocked(null, 0);
4425 }
4426 }
4427 }
4428 }
4429
4430 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4431 IBinder threadBinder = thread.asBinder();
4432
4433 // Find the application record.
4434 int count = mLRUProcesses.size();
4435 int i;
4436 for (i=0; i<count; i++) {
4437 ProcessRecord rec = mLRUProcesses.get(i);
4438 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4439 return i;
4440 }
4441 }
4442 return -1;
4443 }
4444
4445 private final ProcessRecord getRecordForAppLocked(
4446 IApplicationThread thread) {
4447 if (thread == null) {
4448 return null;
4449 }
4450
4451 int appIndex = getLRURecordIndexForAppLocked(thread);
4452 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4453 }
4454
4455 private final void appDiedLocked(ProcessRecord app, int pid,
4456 IApplicationThread thread) {
4457
4458 mProcDeaths[0]++;
4459
4460 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4461 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4462 + ") has died.");
4463 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4464 if (localLOGV) Log.v(
4465 TAG, "Dying app: " + app + ", pid: " + pid
4466 + ", thread: " + thread.asBinder());
4467 boolean doLowMem = app.instrumentationClass == null;
4468 handleAppDiedLocked(app, false);
4469
4470 if (doLowMem) {
4471 // If there are no longer any background processes running,
4472 // and the app that died was not running instrumentation,
4473 // then tell everyone we are now low on memory.
4474 boolean haveBg = false;
4475 int count = mLRUProcesses.size();
4476 int i;
4477 for (i=0; i<count; i++) {
4478 ProcessRecord rec = mLRUProcesses.get(i);
4479 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4480 haveBg = true;
4481 break;
4482 }
4483 }
4484
4485 if (!haveBg) {
4486 Log.i(TAG, "Low Memory: No more background processes.");
4487 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004488 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004489 for (i=0; i<count; i++) {
4490 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004491 if (rec.thread != null &&
4492 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4493 // The low memory report is overriding any current
4494 // state for a GC request. Make sure to do
4495 // visible/foreground processes first.
4496 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4497 rec.lastRequestedGc = 0;
4498 } else {
4499 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004500 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004501 rec.reportLowMemory = true;
4502 rec.lastLowMemory = now;
4503 mProcessesToGc.remove(rec);
4504 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004505 }
4506 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004507 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004508 }
4509 }
4510 } else if (Config.LOGD) {
4511 Log.d(TAG, "Received spurious death notification for thread "
4512 + thread.asBinder());
4513 }
4514 }
4515
4516 final String readFile(String filename) {
4517 try {
4518 FileInputStream fs = new FileInputStream(filename);
4519 byte[] inp = new byte[8192];
4520 int size = fs.read(inp);
4521 fs.close();
4522 return new String(inp, 0, 0, size);
4523 } catch (java.io.IOException e) {
4524 }
4525 return "";
4526 }
4527
4528 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004529 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004530 if (app.notResponding || app.crashing) {
4531 return;
4532 }
4533
4534 // Log the ANR to the event log.
4535 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4536
4537 // If we are on a secure build and the application is not interesting to the user (it is
4538 // not visible or in the background), just kill it instead of displaying a dialog.
4539 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4540 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4541 Process.killProcess(app.pid);
4542 return;
4543 }
4544
4545 // DeviceMonitor.start();
4546
4547 String processInfo = null;
4548 if (MONITOR_CPU_USAGE) {
4549 updateCpuStatsNow();
4550 synchronized (mProcessStatsThread) {
4551 processInfo = mProcessStats.printCurrentState();
4552 }
4553 }
4554
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004555 StringBuilder info = mStringBuilder;
4556 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004557 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004558 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004559 if (reportedActivity != null && reportedActivity.app != null) {
4560 info.append(" (last in ");
4561 info.append(reportedActivity.app.processName);
4562 info.append(")");
4563 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004564 if (annotation != null) {
4565 info.append("\nAnnotation: ");
4566 info.append(annotation);
4567 }
4568 if (MONITOR_CPU_USAGE) {
4569 info.append("\nCPU usage:\n");
4570 info.append(processInfo);
4571 }
4572 Log.i(TAG, info.toString());
4573
4574 // The application is not responding. Dump as many thread traces as we can.
4575 boolean fileDump = prepareTraceFile(true);
4576 if (!fileDump) {
4577 // Dumping traces to the log, just dump the process that isn't responding so
4578 // we don't overflow the log
4579 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4580 } else {
4581 // Dumping traces to a file so dump all active processes we know about
4582 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004583 // First, these are the most important processes.
4584 final int[] imppids = new int[3];
4585 int i=0;
4586 imppids[0] = app.pid;
4587 i++;
4588 if (reportedActivity != null && reportedActivity.app != null
4589 && reportedActivity.app.thread != null
4590 && reportedActivity.app.pid != app.pid) {
4591 imppids[i] = reportedActivity.app.pid;
4592 i++;
4593 }
4594 imppids[i] = Process.myPid();
4595 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4596 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4597 synchronized (this) {
4598 try {
4599 wait(200);
4600 } catch (InterruptedException e) {
4601 }
4602 }
4603 }
4604 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004605 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004606 boolean done = false;
4607 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4608 if (imppids[j] == r.pid) {
4609 done = true;
4610 break;
4611 }
4612 }
4613 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004614 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004615 synchronized (this) {
4616 try {
4617 wait(200);
4618 } catch (InterruptedException e) {
4619 }
4620 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004621 }
4622 }
4623 }
4624 }
4625
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004626 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004627 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004628 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004629 app.pid, info.toString());
4630 if (res != 0) {
4631 if (res < 0) {
4632 // wait until the SIGQUIT has had a chance to process before killing the
4633 // process.
4634 try {
4635 wait(2000);
4636 } catch (InterruptedException e) {
4637 }
4638
4639 Process.killProcess(app.pid);
4640 return;
4641 }
4642 }
4643 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004644 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004645 }
4646 }
4647
4648 makeAppNotRespondingLocked(app,
4649 activity != null ? activity.shortComponentName : null,
4650 annotation != null ? "ANR " + annotation : "ANR",
4651 info.toString(), null);
4652 Message msg = Message.obtain();
4653 HashMap map = new HashMap();
4654 msg.what = SHOW_NOT_RESPONDING_MSG;
4655 msg.obj = map;
4656 map.put("app", app);
4657 if (activity != null) {
4658 map.put("activity", activity);
4659 }
4660
4661 mHandler.sendMessage(msg);
4662 return;
4663 }
4664
4665 /**
4666 * If a stack trace file has been configured, prepare the filesystem
4667 * by creating the directory if it doesn't exist and optionally
4668 * removing the old trace file.
4669 *
4670 * @param removeExisting If set, the existing trace file will be removed.
4671 * @return Returns true if the trace file preparations succeeded
4672 */
4673 public static boolean prepareTraceFile(boolean removeExisting) {
4674 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4675 boolean fileReady = false;
4676 if (!TextUtils.isEmpty(tracesPath)) {
4677 File f = new File(tracesPath);
4678 if (!f.exists()) {
4679 // Ensure the enclosing directory exists
4680 File dir = f.getParentFile();
4681 if (!dir.exists()) {
4682 fileReady = dir.mkdirs();
4683 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004684 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004685 } else if (dir.isDirectory()) {
4686 fileReady = true;
4687 }
4688 } else if (removeExisting) {
4689 // Remove the previous traces file, so we don't fill the disk.
4690 // The VM will recreate it
4691 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4692 fileReady = f.delete();
4693 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004694
4695 if (removeExisting) {
4696 try {
4697 f.createNewFile();
4698 FileUtils.setPermissions(f.getAbsolutePath(),
4699 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4700 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4701 fileReady = true;
4702 } catch (IOException e) {
4703 Log.w(TAG, "Unable to make ANR traces file", e);
4704 }
4705 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004706 }
4707
4708 return fileReady;
4709 }
4710
4711
4712 private final void decPersistentCountLocked(ProcessRecord app)
4713 {
4714 app.persistentActivities--;
4715 if (app.persistentActivities > 0) {
4716 // Still more of 'em...
4717 return;
4718 }
4719 if (app.persistent) {
4720 // Ah, but the application itself is persistent. Whatever!
4721 return;
4722 }
4723
4724 // App is no longer persistent... make sure it and the ones
4725 // following it in the LRU list have the correc oom_adj.
4726 updateOomAdjLocked();
4727 }
4728
4729 public void setPersistent(IBinder token, boolean isPersistent) {
4730 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4731 != PackageManager.PERMISSION_GRANTED) {
4732 String msg = "Permission Denial: setPersistent() from pid="
4733 + Binder.getCallingPid()
4734 + ", uid=" + Binder.getCallingUid()
4735 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4736 Log.w(TAG, msg);
4737 throw new SecurityException(msg);
4738 }
4739
4740 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004741 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004742 if (index < 0) {
4743 return;
4744 }
4745 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4746 ProcessRecord app = r.app;
4747
4748 if (localLOGV) Log.v(
4749 TAG, "Setting persistence " + isPersistent + ": " + r);
4750
4751 if (isPersistent) {
4752 if (r.persistent) {
4753 // Okay okay, I heard you already!
4754 if (localLOGV) Log.v(TAG, "Already persistent!");
4755 return;
4756 }
4757 r.persistent = true;
4758 app.persistentActivities++;
4759 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4760 if (app.persistentActivities > 1) {
4761 // We aren't the first...
4762 if (localLOGV) Log.v(TAG, "Not the first!");
4763 return;
4764 }
4765 if (app.persistent) {
4766 // This would be redundant.
4767 if (localLOGV) Log.v(TAG, "App is persistent!");
4768 return;
4769 }
4770
4771 // App is now persistent... make sure it and the ones
4772 // following it now have the correct oom_adj.
4773 final long origId = Binder.clearCallingIdentity();
4774 updateOomAdjLocked();
4775 Binder.restoreCallingIdentity(origId);
4776
4777 } else {
4778 if (!r.persistent) {
4779 // Okay okay, I heard you already!
4780 return;
4781 }
4782 r.persistent = false;
4783 final long origId = Binder.clearCallingIdentity();
4784 decPersistentCountLocked(app);
4785 Binder.restoreCallingIdentity(origId);
4786
4787 }
4788 }
4789 }
4790
4791 public boolean clearApplicationUserData(final String packageName,
4792 final IPackageDataObserver observer) {
4793 int uid = Binder.getCallingUid();
4794 int pid = Binder.getCallingPid();
4795 long callingId = Binder.clearCallingIdentity();
4796 try {
4797 IPackageManager pm = ActivityThread.getPackageManager();
4798 int pkgUid = -1;
4799 synchronized(this) {
4800 try {
4801 pkgUid = pm.getPackageUid(packageName);
4802 } catch (RemoteException e) {
4803 }
4804 if (pkgUid == -1) {
4805 Log.w(TAG, "Invalid packageName:" + packageName);
4806 return false;
4807 }
4808 if (uid == pkgUid || checkComponentPermission(
4809 android.Manifest.permission.CLEAR_APP_USER_DATA,
4810 pid, uid, -1)
4811 == PackageManager.PERMISSION_GRANTED) {
4812 restartPackageLocked(packageName, pkgUid);
4813 } else {
4814 throw new SecurityException(pid+" does not have permission:"+
4815 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4816 "for process:"+packageName);
4817 }
4818 }
4819
4820 try {
4821 //clear application user data
4822 pm.clearApplicationUserData(packageName, observer);
4823 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4824 Uri.fromParts("package", packageName, null));
4825 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4826 broadcastIntentLocked(null, null, intent,
4827 null, null, 0, null, null, null,
4828 false, false, MY_PID, Process.SYSTEM_UID);
4829 } catch (RemoteException e) {
4830 }
4831 } finally {
4832 Binder.restoreCallingIdentity(callingId);
4833 }
4834 return true;
4835 }
4836
4837 public void restartPackage(final String packageName) {
4838 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4839 != PackageManager.PERMISSION_GRANTED) {
4840 String msg = "Permission Denial: restartPackage() from pid="
4841 + Binder.getCallingPid()
4842 + ", uid=" + Binder.getCallingUid()
4843 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4844 Log.w(TAG, msg);
4845 throw new SecurityException(msg);
4846 }
4847
4848 long callingId = Binder.clearCallingIdentity();
4849 try {
4850 IPackageManager pm = ActivityThread.getPackageManager();
4851 int pkgUid = -1;
4852 synchronized(this) {
4853 try {
4854 pkgUid = pm.getPackageUid(packageName);
4855 } catch (RemoteException e) {
4856 }
4857 if (pkgUid == -1) {
4858 Log.w(TAG, "Invalid packageName: " + packageName);
4859 return;
4860 }
4861 restartPackageLocked(packageName, pkgUid);
4862 }
4863 } finally {
4864 Binder.restoreCallingIdentity(callingId);
4865 }
4866 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004867
4868 /*
4869 * The pkg name and uid have to be specified.
4870 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4871 */
4872 public void killApplicationWithUid(String pkg, int uid) {
4873 if (pkg == null) {
4874 return;
4875 }
4876 // Make sure the uid is valid.
4877 if (uid < 0) {
4878 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4879 return;
4880 }
4881 int callerUid = Binder.getCallingUid();
4882 // Only the system server can kill an application
4883 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004884 // Post an aysnc message to kill the application
4885 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4886 msg.arg1 = uid;
4887 msg.arg2 = 0;
4888 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004889 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004890 } else {
4891 throw new SecurityException(callerUid + " cannot kill pkg: " +
4892 pkg);
4893 }
4894 }
4895
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004896 public void closeSystemDialogs(String reason) {
4897 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4898 if (reason != null) {
4899 intent.putExtra("reason", reason);
4900 }
4901
4902 final int uid = Binder.getCallingUid();
4903 final long origId = Binder.clearCallingIdentity();
4904 synchronized (this) {
4905 int i = mWatchers.beginBroadcast();
4906 while (i > 0) {
4907 i--;
4908 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4909 if (w != null) {
4910 try {
4911 w.closingSystemDialogs(reason);
4912 } catch (RemoteException e) {
4913 }
4914 }
4915 }
4916 mWatchers.finishBroadcast();
4917
4918 broadcastIntentLocked(null, null, intent, null,
4919 null, 0, null, null, null, false, false, -1, uid);
4920 }
4921 Binder.restoreCallingIdentity(origId);
4922 }
4923
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004924 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004925 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004926 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
4927 for (int i=pids.length-1; i>=0; i--) {
4928 infos[i] = new Debug.MemoryInfo();
4929 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004930 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004931 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004932 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07004933
4934 public void killApplicationProcess(String processName, int uid) {
4935 if (processName == null) {
4936 return;
4937 }
4938
4939 int callerUid = Binder.getCallingUid();
4940 // Only the system server can kill an application
4941 if (callerUid == Process.SYSTEM_UID) {
4942 synchronized (this) {
4943 ProcessRecord app = getProcessRecordLocked(processName, uid);
4944 if (app != null) {
4945 try {
4946 app.thread.scheduleSuicide();
4947 } catch (RemoteException e) {
4948 // If the other end already died, then our work here is done.
4949 }
4950 } else {
4951 Log.w(TAG, "Process/uid not found attempting kill of "
4952 + processName + " / " + uid);
4953 }
4954 }
4955 } else {
4956 throw new SecurityException(callerUid + " cannot kill app process: " +
4957 processName);
4958 }
4959 }
4960
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004961 private void restartPackageLocked(final String packageName, int uid) {
4962 uninstallPackageLocked(packageName, uid, false);
4963 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4964 Uri.fromParts("package", packageName, null));
4965 intent.putExtra(Intent.EXTRA_UID, uid);
4966 broadcastIntentLocked(null, null, intent,
4967 null, null, 0, null, null, null,
4968 false, false, MY_PID, Process.SYSTEM_UID);
4969 }
4970
4971 private final void uninstallPackageLocked(String name, int uid,
4972 boolean callerWillRestart) {
4973 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4974
4975 int i, N;
4976
4977 final String procNamePrefix = name + ":";
4978 if (uid < 0) {
4979 try {
4980 uid = ActivityThread.getPackageManager().getPackageUid(name);
4981 } catch (RemoteException e) {
4982 }
4983 }
4984
4985 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4986 while (badApps.hasNext()) {
4987 SparseArray<Long> ba = badApps.next();
4988 if (ba.get(uid) != null) {
4989 badApps.remove();
4990 }
4991 }
4992
4993 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4994
4995 // Remove all processes this package may have touched: all with the
4996 // same UID (except for the system or root user), and all whose name
4997 // matches the package name.
4998 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4999 final int NA = apps.size();
5000 for (int ia=0; ia<NA; ia++) {
5001 ProcessRecord app = apps.valueAt(ia);
5002 if (app.removed) {
5003 procs.add(app);
5004 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5005 || app.processName.equals(name)
5006 || app.processName.startsWith(procNamePrefix)) {
5007 app.removed = true;
5008 procs.add(app);
5009 }
5010 }
5011 }
5012
5013 N = procs.size();
5014 for (i=0; i<N; i++) {
5015 removeProcessLocked(procs.get(i), callerWillRestart);
5016 }
5017
5018 for (i=mHistory.size()-1; i>=0; i--) {
5019 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5020 if (r.packageName.equals(name)) {
5021 if (Config.LOGD) Log.d(
5022 TAG, " Force finishing activity "
5023 + r.intent.getComponent().flattenToShortString());
5024 if (r.app != null) {
5025 r.app.removed = true;
5026 }
5027 r.app = null;
5028 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5029 }
5030 }
5031
5032 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5033 for (ServiceRecord service : mServices.values()) {
5034 if (service.packageName.equals(name)) {
5035 if (service.app != null) {
5036 service.app.removed = true;
5037 }
5038 service.app = null;
5039 services.add(service);
5040 }
5041 }
5042
5043 N = services.size();
5044 for (i=0; i<N; i++) {
5045 bringDownServiceLocked(services.get(i), true);
5046 }
5047
5048 resumeTopActivityLocked(null);
5049 }
5050
5051 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5052 final String name = app.processName;
5053 final int uid = app.info.uid;
5054 if (Config.LOGD) Log.d(
5055 TAG, "Force removing process " + app + " (" + name
5056 + "/" + uid + ")");
5057
5058 mProcessNames.remove(name, uid);
5059 boolean needRestart = false;
5060 if (app.pid > 0 && app.pid != MY_PID) {
5061 int pid = app.pid;
5062 synchronized (mPidsSelfLocked) {
5063 mPidsSelfLocked.remove(pid);
5064 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5065 }
5066 handleAppDiedLocked(app, true);
5067 mLRUProcesses.remove(app);
5068 Process.killProcess(pid);
5069
5070 if (app.persistent) {
5071 if (!callerWillRestart) {
5072 addAppLocked(app.info);
5073 } else {
5074 needRestart = true;
5075 }
5076 }
5077 } else {
5078 mRemovedProcesses.add(app);
5079 }
5080
5081 return needRestart;
5082 }
5083
5084 private final void processStartTimedOutLocked(ProcessRecord app) {
5085 final int pid = app.pid;
5086 boolean gone = false;
5087 synchronized (mPidsSelfLocked) {
5088 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5089 if (knownApp != null && knownApp.thread == null) {
5090 mPidsSelfLocked.remove(pid);
5091 gone = true;
5092 }
5093 }
5094
5095 if (gone) {
5096 Log.w(TAG, "Process " + app + " failed to attach");
5097 mProcessNames.remove(app.processName, app.info.uid);
5098 Process.killProcess(pid);
5099 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5100 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5101 mPendingBroadcast = null;
5102 scheduleBroadcastsLocked();
5103 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005104 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5105 Log.w(TAG, "Unattached app died before backup, skipping");
5106 try {
5107 IBackupManager bm = IBackupManager.Stub.asInterface(
5108 ServiceManager.getService(Context.BACKUP_SERVICE));
5109 bm.agentDisconnected(app.info.packageName);
5110 } catch (RemoteException e) {
5111 // Can't happen; the backup manager is local
5112 }
5113 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005114 } else {
5115 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5116 }
5117 }
5118
5119 private final boolean attachApplicationLocked(IApplicationThread thread,
5120 int pid) {
5121
5122 // Find the application record that is being attached... either via
5123 // the pid if we are running in multiple processes, or just pull the
5124 // next app record if we are emulating process with anonymous threads.
5125 ProcessRecord app;
5126 if (pid != MY_PID && pid >= 0) {
5127 synchronized (mPidsSelfLocked) {
5128 app = mPidsSelfLocked.get(pid);
5129 }
5130 } else if (mStartingProcesses.size() > 0) {
5131 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005132 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005133 } else {
5134 app = null;
5135 }
5136
5137 if (app == null) {
5138 Log.w(TAG, "No pending application record for pid " + pid
5139 + " (IApplicationThread " + thread + "); dropping process");
5140 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5141 if (pid > 0 && pid != MY_PID) {
5142 Process.killProcess(pid);
5143 } else {
5144 try {
5145 thread.scheduleExit();
5146 } catch (Exception e) {
5147 // Ignore exceptions.
5148 }
5149 }
5150 return false;
5151 }
5152
5153 // If this application record is still attached to a previous
5154 // process, clean it up now.
5155 if (app.thread != null) {
5156 handleAppDiedLocked(app, true);
5157 }
5158
5159 // Tell the process all about itself.
5160
5161 if (localLOGV) Log.v(
5162 TAG, "Binding process pid " + pid + " to record " + app);
5163
5164 String processName = app.processName;
5165 try {
5166 thread.asBinder().linkToDeath(new AppDeathRecipient(
5167 app, pid, thread), 0);
5168 } catch (RemoteException e) {
5169 app.resetPackageList();
5170 startProcessLocked(app, "link fail", processName);
5171 return false;
5172 }
5173
5174 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5175
5176 app.thread = thread;
5177 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005178 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005179 app.forcingToForeground = null;
5180 app.foregroundServices = false;
5181 app.debugging = false;
5182
5183 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5184
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005185 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5186 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005187
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005188 if (!normalMode) {
5189 Log.i(TAG, "Launching preboot mode app: " + app);
5190 }
5191
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005192 if (localLOGV) Log.v(
5193 TAG, "New app record " + app
5194 + " thread=" + thread.asBinder() + " pid=" + pid);
5195 try {
5196 int testMode = IApplicationThread.DEBUG_OFF;
5197 if (mDebugApp != null && mDebugApp.equals(processName)) {
5198 testMode = mWaitForDebugger
5199 ? IApplicationThread.DEBUG_WAIT
5200 : IApplicationThread.DEBUG_ON;
5201 app.debugging = true;
5202 if (mDebugTransient) {
5203 mDebugApp = mOrigDebugApp;
5204 mWaitForDebugger = mOrigWaitForDebugger;
5205 }
5206 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005207
Christopher Tate181fafa2009-05-14 11:12:14 -07005208 // If the app is being launched for restore or full backup, set it up specially
5209 boolean isRestrictedBackupMode = false;
5210 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5211 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5212 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5213 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005214
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005215 ensurePackageDexOpt(app.instrumentationInfo != null
5216 ? app.instrumentationInfo.packageName
5217 : app.info.packageName);
5218 if (app.instrumentationClass != null) {
5219 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005220 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07005221 thread.bindApplication(processName, app.instrumentationInfo != null
5222 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005223 app.instrumentationClass, app.instrumentationProfileFile,
5224 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005225 isRestrictedBackupMode || !normalMode,
5226 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005227 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005228 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005229 } catch (Exception e) {
5230 // todo: Yikes! What should we do? For now we will try to
5231 // start another process, but that could easily get us in
5232 // an infinite loop of restarting processes...
5233 Log.w(TAG, "Exception thrown during bind!", e);
5234
5235 app.resetPackageList();
5236 startProcessLocked(app, "bind fail", processName);
5237 return false;
5238 }
5239
5240 // Remove this record from the list of starting applications.
5241 mPersistentStartingProcesses.remove(app);
5242 mProcessesOnHold.remove(app);
5243
5244 boolean badApp = false;
5245 boolean didSomething = false;
5246
5247 // See if the top visible activity is waiting to run in this process...
5248 HistoryRecord hr = topRunningActivityLocked(null);
5249 if (hr != null) {
5250 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5251 && processName.equals(hr.processName)) {
5252 try {
5253 if (realStartActivityLocked(hr, app, true, true)) {
5254 didSomething = true;
5255 }
5256 } catch (Exception e) {
5257 Log.w(TAG, "Exception in new application when starting activity "
5258 + hr.intent.getComponent().flattenToShortString(), e);
5259 badApp = true;
5260 }
5261 } else {
5262 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5263 }
5264 }
5265
5266 // Find any services that should be running in this process...
5267 if (!badApp && mPendingServices.size() > 0) {
5268 ServiceRecord sr = null;
5269 try {
5270 for (int i=0; i<mPendingServices.size(); i++) {
5271 sr = mPendingServices.get(i);
5272 if (app.info.uid != sr.appInfo.uid
5273 || !processName.equals(sr.processName)) {
5274 continue;
5275 }
5276
5277 mPendingServices.remove(i);
5278 i--;
5279 realStartServiceLocked(sr, app);
5280 didSomething = true;
5281 }
5282 } catch (Exception e) {
5283 Log.w(TAG, "Exception in new application when starting service "
5284 + sr.shortName, e);
5285 badApp = true;
5286 }
5287 }
5288
5289 // Check if the next broadcast receiver is in this process...
5290 BroadcastRecord br = mPendingBroadcast;
5291 if (!badApp && br != null && br.curApp == app) {
5292 try {
5293 mPendingBroadcast = null;
5294 processCurBroadcastLocked(br, app);
5295 didSomething = true;
5296 } catch (Exception e) {
5297 Log.w(TAG, "Exception in new application when starting receiver "
5298 + br.curComponent.flattenToShortString(), e);
5299 badApp = true;
5300 logBroadcastReceiverDiscard(br);
5301 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5302 br.resultExtras, br.resultAbort, true);
5303 scheduleBroadcastsLocked();
5304 }
5305 }
5306
Christopher Tate181fafa2009-05-14 11:12:14 -07005307 // Check whether the next backup agent is in this process...
5308 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5309 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005310 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005311 try {
5312 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5313 } catch (Exception e) {
5314 Log.w(TAG, "Exception scheduling backup agent creation: ");
5315 e.printStackTrace();
5316 }
5317 }
5318
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005319 if (badApp) {
5320 // todo: Also need to kill application to deal with all
5321 // kinds of exceptions.
5322 handleAppDiedLocked(app, false);
5323 return false;
5324 }
5325
5326 if (!didSomething) {
5327 updateOomAdjLocked();
5328 }
5329
5330 return true;
5331 }
5332
5333 public final void attachApplication(IApplicationThread thread) {
5334 synchronized (this) {
5335 int callingPid = Binder.getCallingPid();
5336 final long origId = Binder.clearCallingIdentity();
5337 attachApplicationLocked(thread, callingPid);
5338 Binder.restoreCallingIdentity(origId);
5339 }
5340 }
5341
5342 public final void activityIdle(IBinder token) {
5343 final long origId = Binder.clearCallingIdentity();
5344 activityIdleInternal(token, false);
5345 Binder.restoreCallingIdentity(origId);
5346 }
5347
5348 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5349 boolean remove) {
5350 int N = mStoppingActivities.size();
5351 if (N <= 0) return null;
5352
5353 ArrayList<HistoryRecord> stops = null;
5354
5355 final boolean nowVisible = mResumedActivity != null
5356 && mResumedActivity.nowVisible
5357 && !mResumedActivity.waitingVisible;
5358 for (int i=0; i<N; i++) {
5359 HistoryRecord s = mStoppingActivities.get(i);
5360 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5361 + nowVisible + " waitingVisible=" + s.waitingVisible
5362 + " finishing=" + s.finishing);
5363 if (s.waitingVisible && nowVisible) {
5364 mWaitingVisibleActivities.remove(s);
5365 s.waitingVisible = false;
5366 if (s.finishing) {
5367 // If this activity is finishing, it is sitting on top of
5368 // everyone else but we now know it is no longer needed...
5369 // so get rid of it. Otherwise, we need to go through the
5370 // normal flow and hide it once we determine that it is
5371 // hidden by the activities in front of it.
5372 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5373 mWindowManager.setAppVisibility(s, false);
5374 }
5375 }
5376 if (!s.waitingVisible && remove) {
5377 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5378 if (stops == null) {
5379 stops = new ArrayList<HistoryRecord>();
5380 }
5381 stops.add(s);
5382 mStoppingActivities.remove(i);
5383 N--;
5384 i--;
5385 }
5386 }
5387
5388 return stops;
5389 }
5390
5391 void enableScreenAfterBoot() {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005392 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5393 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005394 mWindowManager.enableScreenAfterBoot();
5395 }
5396
5397 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5398 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5399
5400 ArrayList<HistoryRecord> stops = null;
5401 ArrayList<HistoryRecord> finishes = null;
5402 ArrayList<HistoryRecord> thumbnails = null;
5403 int NS = 0;
5404 int NF = 0;
5405 int NT = 0;
5406 IApplicationThread sendThumbnail = null;
5407 boolean booting = false;
5408 boolean enableScreen = false;
5409
5410 synchronized (this) {
5411 if (token != null) {
5412 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5413 }
5414
5415 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005416 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005417 if (index >= 0) {
5418 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5419
5420 // No longer need to keep the device awake.
5421 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5422 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5423 mLaunchingActivity.release();
5424 }
5425
5426 // We are now idle. If someone is waiting for a thumbnail from
5427 // us, we can now deliver.
5428 r.idle = true;
5429 scheduleAppGcsLocked();
5430 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5431 sendThumbnail = r.app.thread;
5432 r.thumbnailNeeded = false;
5433 }
5434
5435 // If this activity is fullscreen, set up to hide those under it.
5436
5437 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5438 ensureActivitiesVisibleLocked(null, 0);
5439
5440 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5441 if (!mBooted && !fromTimeout) {
5442 mBooted = true;
5443 enableScreen = true;
5444 }
5445 }
5446
5447 // Atomically retrieve all of the other things to do.
5448 stops = processStoppingActivitiesLocked(true);
5449 NS = stops != null ? stops.size() : 0;
5450 if ((NF=mFinishingActivities.size()) > 0) {
5451 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5452 mFinishingActivities.clear();
5453 }
5454 if ((NT=mCancelledThumbnails.size()) > 0) {
5455 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5456 mCancelledThumbnails.clear();
5457 }
5458
5459 booting = mBooting;
5460 mBooting = false;
5461 }
5462
5463 int i;
5464
5465 // Send thumbnail if requested.
5466 if (sendThumbnail != null) {
5467 try {
5468 sendThumbnail.requestThumbnail(token);
5469 } catch (Exception e) {
5470 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5471 sendPendingThumbnail(null, token, null, null, true);
5472 }
5473 }
5474
5475 // Stop any activities that are scheduled to do so but have been
5476 // waiting for the next one to start.
5477 for (i=0; i<NS; i++) {
5478 HistoryRecord r = (HistoryRecord)stops.get(i);
5479 synchronized (this) {
5480 if (r.finishing) {
5481 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5482 } else {
5483 stopActivityLocked(r);
5484 }
5485 }
5486 }
5487
5488 // Finish any activities that are scheduled to do so but have been
5489 // waiting for the next one to start.
5490 for (i=0; i<NF; i++) {
5491 HistoryRecord r = (HistoryRecord)finishes.get(i);
5492 synchronized (this) {
5493 destroyActivityLocked(r, true);
5494 }
5495 }
5496
5497 // Report back to any thumbnail receivers.
5498 for (i=0; i<NT; i++) {
5499 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5500 sendPendingThumbnail(r, null, null, null, true);
5501 }
5502
5503 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005504 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005505 }
5506
5507 trimApplications();
5508 //dump();
5509 //mWindowManager.dump();
5510
5511 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005512 enableScreenAfterBoot();
5513 }
5514 }
5515
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005516 final void finishBooting() {
5517 // Ensure that any processes we had put on hold are now started
5518 // up.
5519 final int NP = mProcessesOnHold.size();
5520 if (NP > 0) {
5521 ArrayList<ProcessRecord> procs =
5522 new ArrayList<ProcessRecord>(mProcessesOnHold);
5523 for (int ip=0; ip<NP; ip++) {
5524 this.startProcessLocked(procs.get(ip), "on-hold", null);
5525 }
5526 }
5527 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5528 // Tell anyone interested that we are done booting!
5529 synchronized (this) {
5530 broadcastIntentLocked(null, null,
5531 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5532 null, null, 0, null, null,
5533 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5534 false, false, MY_PID, Process.SYSTEM_UID);
5535 }
5536 }
5537 }
5538
5539 final void ensureBootCompleted() {
5540 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005541 boolean enableScreen;
5542 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005543 booting = mBooting;
5544 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005545 enableScreen = !mBooted;
5546 mBooted = true;
5547 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005548
5549 if (booting) {
5550 finishBooting();
5551 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005552
5553 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005554 enableScreenAfterBoot();
5555 }
5556 }
5557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005558 public final void activityPaused(IBinder token, Bundle icicle) {
5559 // Refuse possible leaked file descriptors
5560 if (icicle != null && icicle.hasFileDescriptors()) {
5561 throw new IllegalArgumentException("File descriptors passed in Bundle");
5562 }
5563
5564 final long origId = Binder.clearCallingIdentity();
5565 activityPaused(token, icicle, false);
5566 Binder.restoreCallingIdentity(origId);
5567 }
5568
5569 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5570 if (DEBUG_PAUSE) Log.v(
5571 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5572 + ", timeout=" + timeout);
5573
5574 HistoryRecord r = null;
5575
5576 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005577 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005578 if (index >= 0) {
5579 r = (HistoryRecord)mHistory.get(index);
5580 if (!timeout) {
5581 r.icicle = icicle;
5582 r.haveState = true;
5583 }
5584 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5585 if (mPausingActivity == r) {
5586 r.state = ActivityState.PAUSED;
5587 completePauseLocked();
5588 } else {
5589 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5590 System.identityHashCode(r), r.shortComponentName,
5591 mPausingActivity != null
5592 ? mPausingActivity.shortComponentName : "(none)");
5593 }
5594 }
5595 }
5596 }
5597
5598 public final void activityStopped(IBinder token, Bitmap thumbnail,
5599 CharSequence description) {
5600 if (localLOGV) Log.v(
5601 TAG, "Activity stopped: token=" + token);
5602
5603 HistoryRecord r = null;
5604
5605 final long origId = Binder.clearCallingIdentity();
5606
5607 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005608 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005609 if (index >= 0) {
5610 r = (HistoryRecord)mHistory.get(index);
5611 r.thumbnail = thumbnail;
5612 r.description = description;
5613 r.stopped = true;
5614 r.state = ActivityState.STOPPED;
5615 if (!r.finishing) {
5616 if (r.configDestroy) {
5617 destroyActivityLocked(r, true);
5618 resumeTopActivityLocked(null);
5619 }
5620 }
5621 }
5622 }
5623
5624 if (r != null) {
5625 sendPendingThumbnail(r, null, null, null, false);
5626 }
5627
5628 trimApplications();
5629
5630 Binder.restoreCallingIdentity(origId);
5631 }
5632
5633 public final void activityDestroyed(IBinder token) {
5634 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5635 synchronized (this) {
5636 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5637
Dianne Hackborn75b03852009-06-12 15:43:26 -07005638 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005639 if (index >= 0) {
5640 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5641 if (r.state == ActivityState.DESTROYING) {
5642 final long origId = Binder.clearCallingIdentity();
5643 removeActivityFromHistoryLocked(r);
5644 Binder.restoreCallingIdentity(origId);
5645 }
5646 }
5647 }
5648 }
5649
5650 public String getCallingPackage(IBinder token) {
5651 synchronized (this) {
5652 HistoryRecord r = getCallingRecordLocked(token);
5653 return r != null && r.app != null ? r.app.processName : null;
5654 }
5655 }
5656
5657 public ComponentName getCallingActivity(IBinder token) {
5658 synchronized (this) {
5659 HistoryRecord r = getCallingRecordLocked(token);
5660 return r != null ? r.intent.getComponent() : null;
5661 }
5662 }
5663
5664 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005665 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005666 if (index >= 0) {
5667 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5668 if (r != null) {
5669 return r.resultTo;
5670 }
5671 }
5672 return null;
5673 }
5674
5675 public ComponentName getActivityClassForToken(IBinder token) {
5676 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005677 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005678 if (index >= 0) {
5679 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5680 return r.intent.getComponent();
5681 }
5682 return null;
5683 }
5684 }
5685
5686 public String getPackageForToken(IBinder token) {
5687 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005688 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005689 if (index >= 0) {
5690 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5691 return r.packageName;
5692 }
5693 return null;
5694 }
5695 }
5696
5697 public IIntentSender getIntentSender(int type,
5698 String packageName, IBinder token, String resultWho,
5699 int requestCode, Intent intent, String resolvedType, int flags) {
5700 // Refuse possible leaked file descriptors
5701 if (intent != null && intent.hasFileDescriptors() == true) {
5702 throw new IllegalArgumentException("File descriptors passed in Intent");
5703 }
5704
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005705 if (type == INTENT_SENDER_BROADCAST) {
5706 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5707 throw new IllegalArgumentException(
5708 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5709 }
5710 }
5711
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005712 synchronized(this) {
5713 int callingUid = Binder.getCallingUid();
5714 try {
5715 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5716 Process.supportsProcesses()) {
5717 int uid = ActivityThread.getPackageManager()
5718 .getPackageUid(packageName);
5719 if (uid != Binder.getCallingUid()) {
5720 String msg = "Permission Denial: getIntentSender() from pid="
5721 + Binder.getCallingPid()
5722 + ", uid=" + Binder.getCallingUid()
5723 + ", (need uid=" + uid + ")"
5724 + " is not allowed to send as package " + packageName;
5725 Log.w(TAG, msg);
5726 throw new SecurityException(msg);
5727 }
5728 }
5729 } catch (RemoteException e) {
5730 throw new SecurityException(e);
5731 }
5732 HistoryRecord activity = null;
5733 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005734 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005735 if (index < 0) {
5736 return null;
5737 }
5738 activity = (HistoryRecord)mHistory.get(index);
5739 if (activity.finishing) {
5740 return null;
5741 }
5742 }
5743
5744 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5745 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5746 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5747 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5748 |PendingIntent.FLAG_UPDATE_CURRENT);
5749
5750 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5751 type, packageName, activity, resultWho,
5752 requestCode, intent, resolvedType, flags);
5753 WeakReference<PendingIntentRecord> ref;
5754 ref = mIntentSenderRecords.get(key);
5755 PendingIntentRecord rec = ref != null ? ref.get() : null;
5756 if (rec != null) {
5757 if (!cancelCurrent) {
5758 if (updateCurrent) {
5759 rec.key.requestIntent.replaceExtras(intent);
5760 }
5761 return rec;
5762 }
5763 rec.canceled = true;
5764 mIntentSenderRecords.remove(key);
5765 }
5766 if (noCreate) {
5767 return rec;
5768 }
5769 rec = new PendingIntentRecord(this, key, callingUid);
5770 mIntentSenderRecords.put(key, rec.ref);
5771 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5772 if (activity.pendingResults == null) {
5773 activity.pendingResults
5774 = new HashSet<WeakReference<PendingIntentRecord>>();
5775 }
5776 activity.pendingResults.add(rec.ref);
5777 }
5778 return rec;
5779 }
5780 }
5781
5782 public void cancelIntentSender(IIntentSender sender) {
5783 if (!(sender instanceof PendingIntentRecord)) {
5784 return;
5785 }
5786 synchronized(this) {
5787 PendingIntentRecord rec = (PendingIntentRecord)sender;
5788 try {
5789 int uid = ActivityThread.getPackageManager()
5790 .getPackageUid(rec.key.packageName);
5791 if (uid != Binder.getCallingUid()) {
5792 String msg = "Permission Denial: cancelIntentSender() from pid="
5793 + Binder.getCallingPid()
5794 + ", uid=" + Binder.getCallingUid()
5795 + " is not allowed to cancel packges "
5796 + rec.key.packageName;
5797 Log.w(TAG, msg);
5798 throw new SecurityException(msg);
5799 }
5800 } catch (RemoteException e) {
5801 throw new SecurityException(e);
5802 }
5803 cancelIntentSenderLocked(rec, true);
5804 }
5805 }
5806
5807 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5808 rec.canceled = true;
5809 mIntentSenderRecords.remove(rec.key);
5810 if (cleanActivity && rec.key.activity != null) {
5811 rec.key.activity.pendingResults.remove(rec.ref);
5812 }
5813 }
5814
5815 public String getPackageForIntentSender(IIntentSender pendingResult) {
5816 if (!(pendingResult instanceof PendingIntentRecord)) {
5817 return null;
5818 }
5819 synchronized(this) {
5820 try {
5821 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5822 return res.key.packageName;
5823 } catch (ClassCastException e) {
5824 }
5825 }
5826 return null;
5827 }
5828
5829 public void setProcessLimit(int max) {
5830 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5831 "setProcessLimit()");
5832 mProcessLimit = max;
5833 }
5834
5835 public int getProcessLimit() {
5836 return mProcessLimit;
5837 }
5838
5839 void foregroundTokenDied(ForegroundToken token) {
5840 synchronized (ActivityManagerService.this) {
5841 synchronized (mPidsSelfLocked) {
5842 ForegroundToken cur
5843 = mForegroundProcesses.get(token.pid);
5844 if (cur != token) {
5845 return;
5846 }
5847 mForegroundProcesses.remove(token.pid);
5848 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5849 if (pr == null) {
5850 return;
5851 }
5852 pr.forcingToForeground = null;
5853 pr.foregroundServices = false;
5854 }
5855 updateOomAdjLocked();
5856 }
5857 }
5858
5859 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5860 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5861 "setProcessForeground()");
5862 synchronized(this) {
5863 boolean changed = false;
5864
5865 synchronized (mPidsSelfLocked) {
5866 ProcessRecord pr = mPidsSelfLocked.get(pid);
5867 if (pr == null) {
5868 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5869 return;
5870 }
5871 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5872 if (oldToken != null) {
5873 oldToken.token.unlinkToDeath(oldToken, 0);
5874 mForegroundProcesses.remove(pid);
5875 pr.forcingToForeground = null;
5876 changed = true;
5877 }
5878 if (isForeground && token != null) {
5879 ForegroundToken newToken = new ForegroundToken() {
5880 public void binderDied() {
5881 foregroundTokenDied(this);
5882 }
5883 };
5884 newToken.pid = pid;
5885 newToken.token = token;
5886 try {
5887 token.linkToDeath(newToken, 0);
5888 mForegroundProcesses.put(pid, newToken);
5889 pr.forcingToForeground = token;
5890 changed = true;
5891 } catch (RemoteException e) {
5892 // If the process died while doing this, we will later
5893 // do the cleanup with the process death link.
5894 }
5895 }
5896 }
5897
5898 if (changed) {
5899 updateOomAdjLocked();
5900 }
5901 }
5902 }
5903
5904 // =========================================================
5905 // PERMISSIONS
5906 // =========================================================
5907
5908 static class PermissionController extends IPermissionController.Stub {
5909 ActivityManagerService mActivityManagerService;
5910 PermissionController(ActivityManagerService activityManagerService) {
5911 mActivityManagerService = activityManagerService;
5912 }
5913
5914 public boolean checkPermission(String permission, int pid, int uid) {
5915 return mActivityManagerService.checkPermission(permission, pid,
5916 uid) == PackageManager.PERMISSION_GRANTED;
5917 }
5918 }
5919
5920 /**
5921 * This can be called with or without the global lock held.
5922 */
5923 int checkComponentPermission(String permission, int pid, int uid,
5924 int reqUid) {
5925 // We might be performing an operation on behalf of an indirect binder
5926 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5927 // client identity accordingly before proceeding.
5928 Identity tlsIdentity = sCallerIdentity.get();
5929 if (tlsIdentity != null) {
5930 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5931 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5932 uid = tlsIdentity.uid;
5933 pid = tlsIdentity.pid;
5934 }
5935
5936 // Root, system server and our own process get to do everything.
5937 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5938 !Process.supportsProcesses()) {
5939 return PackageManager.PERMISSION_GRANTED;
5940 }
5941 // If the target requires a specific UID, always fail for others.
5942 if (reqUid >= 0 && uid != reqUid) {
5943 return PackageManager.PERMISSION_DENIED;
5944 }
5945 if (permission == null) {
5946 return PackageManager.PERMISSION_GRANTED;
5947 }
5948 try {
5949 return ActivityThread.getPackageManager()
5950 .checkUidPermission(permission, uid);
5951 } catch (RemoteException e) {
5952 // Should never happen, but if it does... deny!
5953 Log.e(TAG, "PackageManager is dead?!?", e);
5954 }
5955 return PackageManager.PERMISSION_DENIED;
5956 }
5957
5958 /**
5959 * As the only public entry point for permissions checking, this method
5960 * can enforce the semantic that requesting a check on a null global
5961 * permission is automatically denied. (Internally a null permission
5962 * string is used when calling {@link #checkComponentPermission} in cases
5963 * when only uid-based security is needed.)
5964 *
5965 * This can be called with or without the global lock held.
5966 */
5967 public int checkPermission(String permission, int pid, int uid) {
5968 if (permission == null) {
5969 return PackageManager.PERMISSION_DENIED;
5970 }
5971 return checkComponentPermission(permission, pid, uid, -1);
5972 }
5973
5974 /**
5975 * Binder IPC calls go through the public entry point.
5976 * This can be called with or without the global lock held.
5977 */
5978 int checkCallingPermission(String permission) {
5979 return checkPermission(permission,
5980 Binder.getCallingPid(),
5981 Binder.getCallingUid());
5982 }
5983
5984 /**
5985 * This can be called with or without the global lock held.
5986 */
5987 void enforceCallingPermission(String permission, String func) {
5988 if (checkCallingPermission(permission)
5989 == PackageManager.PERMISSION_GRANTED) {
5990 return;
5991 }
5992
5993 String msg = "Permission Denial: " + func + " from pid="
5994 + Binder.getCallingPid()
5995 + ", uid=" + Binder.getCallingUid()
5996 + " requires " + permission;
5997 Log.w(TAG, msg);
5998 throw new SecurityException(msg);
5999 }
6000
6001 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6002 ProviderInfo pi, int uid, int modeFlags) {
6003 try {
6004 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6005 if ((pi.readPermission != null) &&
6006 (pm.checkUidPermission(pi.readPermission, uid)
6007 != PackageManager.PERMISSION_GRANTED)) {
6008 return false;
6009 }
6010 }
6011 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6012 if ((pi.writePermission != null) &&
6013 (pm.checkUidPermission(pi.writePermission, uid)
6014 != PackageManager.PERMISSION_GRANTED)) {
6015 return false;
6016 }
6017 }
6018 return true;
6019 } catch (RemoteException e) {
6020 return false;
6021 }
6022 }
6023
6024 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6025 int modeFlags) {
6026 // Root gets to do everything.
6027 if (uid == 0 || !Process.supportsProcesses()) {
6028 return true;
6029 }
6030 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6031 if (perms == null) return false;
6032 UriPermission perm = perms.get(uri);
6033 if (perm == null) return false;
6034 return (modeFlags&perm.modeFlags) == modeFlags;
6035 }
6036
6037 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6038 // Another redirected-binder-call permissions check as in
6039 // {@link checkComponentPermission}.
6040 Identity tlsIdentity = sCallerIdentity.get();
6041 if (tlsIdentity != null) {
6042 uid = tlsIdentity.uid;
6043 pid = tlsIdentity.pid;
6044 }
6045
6046 // Our own process gets to do everything.
6047 if (pid == MY_PID) {
6048 return PackageManager.PERMISSION_GRANTED;
6049 }
6050 synchronized(this) {
6051 return checkUriPermissionLocked(uri, uid, modeFlags)
6052 ? PackageManager.PERMISSION_GRANTED
6053 : PackageManager.PERMISSION_DENIED;
6054 }
6055 }
6056
6057 private void grantUriPermissionLocked(int callingUid,
6058 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6059 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6060 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6061 if (modeFlags == 0) {
6062 return;
6063 }
6064
6065 final IPackageManager pm = ActivityThread.getPackageManager();
6066
6067 // If this is not a content: uri, we can't do anything with it.
6068 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6069 return;
6070 }
6071
6072 String name = uri.getAuthority();
6073 ProviderInfo pi = null;
6074 ContentProviderRecord cpr
6075 = (ContentProviderRecord)mProvidersByName.get(name);
6076 if (cpr != null) {
6077 pi = cpr.info;
6078 } else {
6079 try {
6080 pi = pm.resolveContentProvider(name,
6081 PackageManager.GET_URI_PERMISSION_PATTERNS);
6082 } catch (RemoteException ex) {
6083 }
6084 }
6085 if (pi == null) {
6086 Log.w(TAG, "No content provider found for: " + name);
6087 return;
6088 }
6089
6090 int targetUid;
6091 try {
6092 targetUid = pm.getPackageUid(targetPkg);
6093 if (targetUid < 0) {
6094 return;
6095 }
6096 } catch (RemoteException ex) {
6097 return;
6098 }
6099
6100 // First... does the target actually need this permission?
6101 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6102 // No need to grant the target this permission.
6103 return;
6104 }
6105
6106 // Second... maybe someone else has already granted the
6107 // permission?
6108 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6109 // No need to grant the target this permission.
6110 return;
6111 }
6112
6113 // Third... is the provider allowing granting of URI permissions?
6114 if (!pi.grantUriPermissions) {
6115 throw new SecurityException("Provider " + pi.packageName
6116 + "/" + pi.name
6117 + " does not allow granting of Uri permissions (uri "
6118 + uri + ")");
6119 }
6120 if (pi.uriPermissionPatterns != null) {
6121 final int N = pi.uriPermissionPatterns.length;
6122 boolean allowed = false;
6123 for (int i=0; i<N; i++) {
6124 if (pi.uriPermissionPatterns[i] != null
6125 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6126 allowed = true;
6127 break;
6128 }
6129 }
6130 if (!allowed) {
6131 throw new SecurityException("Provider " + pi.packageName
6132 + "/" + pi.name
6133 + " does not allow granting of permission to path of Uri "
6134 + uri);
6135 }
6136 }
6137
6138 // Fourth... does the caller itself have permission to access
6139 // this uri?
6140 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6141 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6142 throw new SecurityException("Uid " + callingUid
6143 + " does not have permission to uri " + uri);
6144 }
6145 }
6146
6147 // Okay! So here we are: the caller has the assumed permission
6148 // to the uri, and the target doesn't. Let's now give this to
6149 // the target.
6150
6151 HashMap<Uri, UriPermission> targetUris
6152 = mGrantedUriPermissions.get(targetUid);
6153 if (targetUris == null) {
6154 targetUris = new HashMap<Uri, UriPermission>();
6155 mGrantedUriPermissions.put(targetUid, targetUris);
6156 }
6157
6158 UriPermission perm = targetUris.get(uri);
6159 if (perm == null) {
6160 perm = new UriPermission(targetUid, uri);
6161 targetUris.put(uri, perm);
6162
6163 }
6164 perm.modeFlags |= modeFlags;
6165 if (activity == null) {
6166 perm.globalModeFlags |= modeFlags;
6167 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6168 perm.readActivities.add(activity);
6169 if (activity.readUriPermissions == null) {
6170 activity.readUriPermissions = new HashSet<UriPermission>();
6171 }
6172 activity.readUriPermissions.add(perm);
6173 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6174 perm.writeActivities.add(activity);
6175 if (activity.writeUriPermissions == null) {
6176 activity.writeUriPermissions = new HashSet<UriPermission>();
6177 }
6178 activity.writeUriPermissions.add(perm);
6179 }
6180 }
6181
6182 private void grantUriPermissionFromIntentLocked(int callingUid,
6183 String targetPkg, Intent intent, HistoryRecord activity) {
6184 if (intent == null) {
6185 return;
6186 }
6187 Uri data = intent.getData();
6188 if (data == null) {
6189 return;
6190 }
6191 grantUriPermissionLocked(callingUid, targetPkg, data,
6192 intent.getFlags(), activity);
6193 }
6194
6195 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6196 Uri uri, int modeFlags) {
6197 synchronized(this) {
6198 final ProcessRecord r = getRecordForAppLocked(caller);
6199 if (r == null) {
6200 throw new SecurityException("Unable to find app for caller "
6201 + caller
6202 + " when granting permission to uri " + uri);
6203 }
6204 if (targetPkg == null) {
6205 Log.w(TAG, "grantUriPermission: null target");
6206 return;
6207 }
6208 if (uri == null) {
6209 Log.w(TAG, "grantUriPermission: null uri");
6210 return;
6211 }
6212
6213 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6214 null);
6215 }
6216 }
6217
6218 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6219 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6220 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6221 HashMap<Uri, UriPermission> perms
6222 = mGrantedUriPermissions.get(perm.uid);
6223 if (perms != null) {
6224 perms.remove(perm.uri);
6225 if (perms.size() == 0) {
6226 mGrantedUriPermissions.remove(perm.uid);
6227 }
6228 }
6229 }
6230 }
6231
6232 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6233 if (activity.readUriPermissions != null) {
6234 for (UriPermission perm : activity.readUriPermissions) {
6235 perm.readActivities.remove(activity);
6236 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6237 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6238 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6239 removeUriPermissionIfNeededLocked(perm);
6240 }
6241 }
6242 }
6243 if (activity.writeUriPermissions != null) {
6244 for (UriPermission perm : activity.writeUriPermissions) {
6245 perm.writeActivities.remove(activity);
6246 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6247 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6248 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6249 removeUriPermissionIfNeededLocked(perm);
6250 }
6251 }
6252 }
6253 }
6254
6255 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6256 int modeFlags) {
6257 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6258 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6259 if (modeFlags == 0) {
6260 return;
6261 }
6262
6263 final IPackageManager pm = ActivityThread.getPackageManager();
6264
6265 final String authority = uri.getAuthority();
6266 ProviderInfo pi = null;
6267 ContentProviderRecord cpr
6268 = (ContentProviderRecord)mProvidersByName.get(authority);
6269 if (cpr != null) {
6270 pi = cpr.info;
6271 } else {
6272 try {
6273 pi = pm.resolveContentProvider(authority,
6274 PackageManager.GET_URI_PERMISSION_PATTERNS);
6275 } catch (RemoteException ex) {
6276 }
6277 }
6278 if (pi == null) {
6279 Log.w(TAG, "No content provider found for: " + authority);
6280 return;
6281 }
6282
6283 // Does the caller have this permission on the URI?
6284 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6285 // Right now, if you are not the original owner of the permission,
6286 // you are not allowed to revoke it.
6287 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6288 throw new SecurityException("Uid " + callingUid
6289 + " does not have permission to uri " + uri);
6290 //}
6291 }
6292
6293 // Go through all of the permissions and remove any that match.
6294 final List<String> SEGMENTS = uri.getPathSegments();
6295 if (SEGMENTS != null) {
6296 final int NS = SEGMENTS.size();
6297 int N = mGrantedUriPermissions.size();
6298 for (int i=0; i<N; i++) {
6299 HashMap<Uri, UriPermission> perms
6300 = mGrantedUriPermissions.valueAt(i);
6301 Iterator<UriPermission> it = perms.values().iterator();
6302 toploop:
6303 while (it.hasNext()) {
6304 UriPermission perm = it.next();
6305 Uri targetUri = perm.uri;
6306 if (!authority.equals(targetUri.getAuthority())) {
6307 continue;
6308 }
6309 List<String> targetSegments = targetUri.getPathSegments();
6310 if (targetSegments == null) {
6311 continue;
6312 }
6313 if (targetSegments.size() < NS) {
6314 continue;
6315 }
6316 for (int j=0; j<NS; j++) {
6317 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6318 continue toploop;
6319 }
6320 }
6321 perm.clearModes(modeFlags);
6322 if (perm.modeFlags == 0) {
6323 it.remove();
6324 }
6325 }
6326 if (perms.size() == 0) {
6327 mGrantedUriPermissions.remove(
6328 mGrantedUriPermissions.keyAt(i));
6329 N--;
6330 i--;
6331 }
6332 }
6333 }
6334 }
6335
6336 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6337 int modeFlags) {
6338 synchronized(this) {
6339 final ProcessRecord r = getRecordForAppLocked(caller);
6340 if (r == null) {
6341 throw new SecurityException("Unable to find app for caller "
6342 + caller
6343 + " when revoking permission to uri " + uri);
6344 }
6345 if (uri == null) {
6346 Log.w(TAG, "revokeUriPermission: null uri");
6347 return;
6348 }
6349
6350 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6351 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6352 if (modeFlags == 0) {
6353 return;
6354 }
6355
6356 final IPackageManager pm = ActivityThread.getPackageManager();
6357
6358 final String authority = uri.getAuthority();
6359 ProviderInfo pi = null;
6360 ContentProviderRecord cpr
6361 = (ContentProviderRecord)mProvidersByName.get(authority);
6362 if (cpr != null) {
6363 pi = cpr.info;
6364 } else {
6365 try {
6366 pi = pm.resolveContentProvider(authority,
6367 PackageManager.GET_URI_PERMISSION_PATTERNS);
6368 } catch (RemoteException ex) {
6369 }
6370 }
6371 if (pi == null) {
6372 Log.w(TAG, "No content provider found for: " + authority);
6373 return;
6374 }
6375
6376 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6377 }
6378 }
6379
6380 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6381 synchronized (this) {
6382 ProcessRecord app =
6383 who != null ? getRecordForAppLocked(who) : null;
6384 if (app == null) return;
6385
6386 Message msg = Message.obtain();
6387 msg.what = WAIT_FOR_DEBUGGER_MSG;
6388 msg.obj = app;
6389 msg.arg1 = waiting ? 1 : 0;
6390 mHandler.sendMessage(msg);
6391 }
6392 }
6393
6394 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6395 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006396 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006397 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006398 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006399 }
6400
6401 // =========================================================
6402 // TASK MANAGEMENT
6403 // =========================================================
6404
6405 public List getTasks(int maxNum, int flags,
6406 IThumbnailReceiver receiver) {
6407 ArrayList list = new ArrayList();
6408
6409 PendingThumbnailsRecord pending = null;
6410 IApplicationThread topThumbnail = null;
6411 HistoryRecord topRecord = null;
6412
6413 synchronized(this) {
6414 if (localLOGV) Log.v(
6415 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6416 + ", receiver=" + receiver);
6417
6418 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6419 != PackageManager.PERMISSION_GRANTED) {
6420 if (receiver != null) {
6421 // If the caller wants to wait for pending thumbnails,
6422 // it ain't gonna get them.
6423 try {
6424 receiver.finished();
6425 } catch (RemoteException ex) {
6426 }
6427 }
6428 String msg = "Permission Denial: getTasks() from pid="
6429 + Binder.getCallingPid()
6430 + ", uid=" + Binder.getCallingUid()
6431 + " requires " + android.Manifest.permission.GET_TASKS;
6432 Log.w(TAG, msg);
6433 throw new SecurityException(msg);
6434 }
6435
6436 int pos = mHistory.size()-1;
6437 HistoryRecord next =
6438 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6439 HistoryRecord top = null;
6440 CharSequence topDescription = null;
6441 TaskRecord curTask = null;
6442 int numActivities = 0;
6443 int numRunning = 0;
6444 while (pos >= 0 && maxNum > 0) {
6445 final HistoryRecord r = next;
6446 pos--;
6447 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6448
6449 // Initialize state for next task if needed.
6450 if (top == null ||
6451 (top.state == ActivityState.INITIALIZING
6452 && top.task == r.task)) {
6453 top = r;
6454 topDescription = r.description;
6455 curTask = r.task;
6456 numActivities = numRunning = 0;
6457 }
6458
6459 // Add 'r' into the current task.
6460 numActivities++;
6461 if (r.app != null && r.app.thread != null) {
6462 numRunning++;
6463 }
6464 if (topDescription == null) {
6465 topDescription = r.description;
6466 }
6467
6468 if (localLOGV) Log.v(
6469 TAG, r.intent.getComponent().flattenToShortString()
6470 + ": task=" + r.task);
6471
6472 // If the next one is a different task, generate a new
6473 // TaskInfo entry for what we have.
6474 if (next == null || next.task != curTask) {
6475 ActivityManager.RunningTaskInfo ci
6476 = new ActivityManager.RunningTaskInfo();
6477 ci.id = curTask.taskId;
6478 ci.baseActivity = r.intent.getComponent();
6479 ci.topActivity = top.intent.getComponent();
6480 ci.thumbnail = top.thumbnail;
6481 ci.description = topDescription;
6482 ci.numActivities = numActivities;
6483 ci.numRunning = numRunning;
6484 //System.out.println(
6485 // "#" + maxNum + ": " + " descr=" + ci.description);
6486 if (ci.thumbnail == null && receiver != null) {
6487 if (localLOGV) Log.v(
6488 TAG, "State=" + top.state + "Idle=" + top.idle
6489 + " app=" + top.app
6490 + " thr=" + (top.app != null ? top.app.thread : null));
6491 if (top.state == ActivityState.RESUMED
6492 || top.state == ActivityState.PAUSING) {
6493 if (top.idle && top.app != null
6494 && top.app.thread != null) {
6495 topRecord = top;
6496 topThumbnail = top.app.thread;
6497 } else {
6498 top.thumbnailNeeded = true;
6499 }
6500 }
6501 if (pending == null) {
6502 pending = new PendingThumbnailsRecord(receiver);
6503 }
6504 pending.pendingRecords.add(top);
6505 }
6506 list.add(ci);
6507 maxNum--;
6508 top = null;
6509 }
6510 }
6511
6512 if (pending != null) {
6513 mPendingThumbnails.add(pending);
6514 }
6515 }
6516
6517 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6518
6519 if (topThumbnail != null) {
6520 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6521 try {
6522 topThumbnail.requestThumbnail(topRecord);
6523 } catch (Exception e) {
6524 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6525 sendPendingThumbnail(null, topRecord, null, null, true);
6526 }
6527 }
6528
6529 if (pending == null && receiver != null) {
6530 // In this case all thumbnails were available and the client
6531 // is being asked to be told when the remaining ones come in...
6532 // which is unusually, since the top-most currently running
6533 // activity should never have a canned thumbnail! Oh well.
6534 try {
6535 receiver.finished();
6536 } catch (RemoteException ex) {
6537 }
6538 }
6539
6540 return list;
6541 }
6542
6543 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6544 int flags) {
6545 synchronized (this) {
6546 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6547 "getRecentTasks()");
6548
6549 final int N = mRecentTasks.size();
6550 ArrayList<ActivityManager.RecentTaskInfo> res
6551 = new ArrayList<ActivityManager.RecentTaskInfo>(
6552 maxNum < N ? maxNum : N);
6553 for (int i=0; i<N && maxNum > 0; i++) {
6554 TaskRecord tr = mRecentTasks.get(i);
6555 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6556 || (tr.intent == null)
6557 || ((tr.intent.getFlags()
6558 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6559 ActivityManager.RecentTaskInfo rti
6560 = new ActivityManager.RecentTaskInfo();
6561 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6562 rti.baseIntent = new Intent(
6563 tr.intent != null ? tr.intent : tr.affinityIntent);
6564 rti.origActivity = tr.origActivity;
6565 res.add(rti);
6566 maxNum--;
6567 }
6568 }
6569 return res;
6570 }
6571 }
6572
6573 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6574 int j;
6575 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6576 TaskRecord jt = startTask;
6577
6578 // First look backwards
6579 for (j=startIndex-1; j>=0; j--) {
6580 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6581 if (r.task != jt) {
6582 jt = r.task;
6583 if (affinity.equals(jt.affinity)) {
6584 return j;
6585 }
6586 }
6587 }
6588
6589 // Now look forwards
6590 final int N = mHistory.size();
6591 jt = startTask;
6592 for (j=startIndex+1; j<N; j++) {
6593 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6594 if (r.task != jt) {
6595 if (affinity.equals(jt.affinity)) {
6596 return j;
6597 }
6598 jt = r.task;
6599 }
6600 }
6601
6602 // Might it be at the top?
6603 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6604 return N-1;
6605 }
6606
6607 return -1;
6608 }
6609
6610 /**
6611 * Perform a reset of the given task, if needed as part of launching it.
6612 * Returns the new HistoryRecord at the top of the task.
6613 */
6614 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6615 HistoryRecord newActivity) {
6616 boolean forceReset = (newActivity.info.flags
6617 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6618 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6619 if ((newActivity.info.flags
6620 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6621 forceReset = true;
6622 }
6623 }
6624
6625 final TaskRecord task = taskTop.task;
6626
6627 // We are going to move through the history list so that we can look
6628 // at each activity 'target' with 'below' either the interesting
6629 // activity immediately below it in the stack or null.
6630 HistoryRecord target = null;
6631 int targetI = 0;
6632 int taskTopI = -1;
6633 int replyChainEnd = -1;
6634 int lastReparentPos = -1;
6635 for (int i=mHistory.size()-1; i>=-1; i--) {
6636 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6637
6638 if (below != null && below.finishing) {
6639 continue;
6640 }
6641 if (target == null) {
6642 target = below;
6643 targetI = i;
6644 // If we were in the middle of a reply chain before this
6645 // task, it doesn't appear like the root of the chain wants
6646 // anything interesting, so drop it.
6647 replyChainEnd = -1;
6648 continue;
6649 }
6650
6651 final int flags = target.info.flags;
6652
6653 final boolean finishOnTaskLaunch =
6654 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6655 final boolean allowTaskReparenting =
6656 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6657
6658 if (target.task == task) {
6659 // We are inside of the task being reset... we'll either
6660 // finish this activity, push it out for another task,
6661 // or leave it as-is. We only do this
6662 // for activities that are not the root of the task (since
6663 // if we finish the root, we may no longer have the task!).
6664 if (taskTopI < 0) {
6665 taskTopI = targetI;
6666 }
6667 if (below != null && below.task == task) {
6668 final boolean clearWhenTaskReset =
6669 (target.intent.getFlags()
6670 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006671 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006672 // If this activity is sending a reply to a previous
6673 // activity, we can't do anything with it now until
6674 // we reach the start of the reply chain.
6675 // XXX note that we are assuming the result is always
6676 // to the previous activity, which is almost always
6677 // the case but we really shouldn't count on.
6678 if (replyChainEnd < 0) {
6679 replyChainEnd = targetI;
6680 }
Ed Heyl73798232009-03-24 21:32:21 -07006681 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006682 && target.taskAffinity != null
6683 && !target.taskAffinity.equals(task.affinity)) {
6684 // If this activity has an affinity for another
6685 // task, then we need to move it out of here. We will
6686 // move it as far out of the way as possible, to the
6687 // bottom of the activity stack. This also keeps it
6688 // correctly ordered with any activities we previously
6689 // moved.
6690 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6691 if (target.taskAffinity != null
6692 && target.taskAffinity.equals(p.task.affinity)) {
6693 // If the activity currently at the bottom has the
6694 // same task affinity as the one we are moving,
6695 // then merge it into the same task.
6696 target.task = p.task;
6697 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6698 + " out to bottom task " + p.task);
6699 } else {
6700 mCurTask++;
6701 if (mCurTask <= 0) {
6702 mCurTask = 1;
6703 }
6704 target.task = new TaskRecord(mCurTask, target.info, null,
6705 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6706 target.task.affinityIntent = target.intent;
6707 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6708 + " out to new task " + target.task);
6709 }
6710 mWindowManager.setAppGroupId(target, task.taskId);
6711 if (replyChainEnd < 0) {
6712 replyChainEnd = targetI;
6713 }
6714 int dstPos = 0;
6715 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6716 p = (HistoryRecord)mHistory.get(srcPos);
6717 if (p.finishing) {
6718 continue;
6719 }
6720 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6721 + " out to target's task " + target.task);
6722 task.numActivities--;
6723 p.task = target.task;
6724 target.task.numActivities++;
6725 mHistory.remove(srcPos);
6726 mHistory.add(dstPos, p);
6727 mWindowManager.moveAppToken(dstPos, p);
6728 mWindowManager.setAppGroupId(p, p.task.taskId);
6729 dstPos++;
6730 if (VALIDATE_TOKENS) {
6731 mWindowManager.validateAppTokens(mHistory);
6732 }
6733 i++;
6734 }
6735 if (taskTop == p) {
6736 taskTop = below;
6737 }
6738 if (taskTopI == replyChainEnd) {
6739 taskTopI = -1;
6740 }
6741 replyChainEnd = -1;
6742 addRecentTask(target.task);
6743 } else if (forceReset || finishOnTaskLaunch
6744 || clearWhenTaskReset) {
6745 // If the activity should just be removed -- either
6746 // because it asks for it, or the task should be
6747 // cleared -- then finish it and anything that is
6748 // part of its reply chain.
6749 if (clearWhenTaskReset) {
6750 // In this case, we want to finish this activity
6751 // and everything above it, so be sneaky and pretend
6752 // like these are all in the reply chain.
6753 replyChainEnd = targetI+1;
6754 while (replyChainEnd < mHistory.size() &&
6755 ((HistoryRecord)mHistory.get(
6756 replyChainEnd)).task == task) {
6757 replyChainEnd++;
6758 }
6759 replyChainEnd--;
6760 } else if (replyChainEnd < 0) {
6761 replyChainEnd = targetI;
6762 }
6763 HistoryRecord p = null;
6764 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6765 p = (HistoryRecord)mHistory.get(srcPos);
6766 if (p.finishing) {
6767 continue;
6768 }
6769 if (finishActivityLocked(p, srcPos,
6770 Activity.RESULT_CANCELED, null, "reset")) {
6771 replyChainEnd--;
6772 srcPos--;
6773 }
6774 }
6775 if (taskTop == p) {
6776 taskTop = below;
6777 }
6778 if (taskTopI == replyChainEnd) {
6779 taskTopI = -1;
6780 }
6781 replyChainEnd = -1;
6782 } else {
6783 // If we were in the middle of a chain, well the
6784 // activity that started it all doesn't want anything
6785 // special, so leave it all as-is.
6786 replyChainEnd = -1;
6787 }
6788 } else {
6789 // Reached the bottom of the task -- any reply chain
6790 // should be left as-is.
6791 replyChainEnd = -1;
6792 }
6793
6794 } else if (target.resultTo != null) {
6795 // If this activity is sending a reply to a previous
6796 // activity, we can't do anything with it now until
6797 // we reach the start of the reply chain.
6798 // XXX note that we are assuming the result is always
6799 // to the previous activity, which is almost always
6800 // the case but we really shouldn't count on.
6801 if (replyChainEnd < 0) {
6802 replyChainEnd = targetI;
6803 }
6804
6805 } else if (taskTopI >= 0 && allowTaskReparenting
6806 && task.affinity != null
6807 && task.affinity.equals(target.taskAffinity)) {
6808 // We are inside of another task... if this activity has
6809 // an affinity for our task, then either remove it if we are
6810 // clearing or move it over to our task. Note that
6811 // we currently punt on the case where we are resetting a
6812 // task that is not at the top but who has activities above
6813 // with an affinity to it... this is really not a normal
6814 // case, and we will need to later pull that task to the front
6815 // and usually at that point we will do the reset and pick
6816 // up those remaining activities. (This only happens if
6817 // someone starts an activity in a new task from an activity
6818 // in a task that is not currently on top.)
6819 if (forceReset || finishOnTaskLaunch) {
6820 if (replyChainEnd < 0) {
6821 replyChainEnd = targetI;
6822 }
6823 HistoryRecord p = null;
6824 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6825 p = (HistoryRecord)mHistory.get(srcPos);
6826 if (p.finishing) {
6827 continue;
6828 }
6829 if (finishActivityLocked(p, srcPos,
6830 Activity.RESULT_CANCELED, null, "reset")) {
6831 taskTopI--;
6832 lastReparentPos--;
6833 replyChainEnd--;
6834 srcPos--;
6835 }
6836 }
6837 replyChainEnd = -1;
6838 } else {
6839 if (replyChainEnd < 0) {
6840 replyChainEnd = targetI;
6841 }
6842 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6843 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6844 if (p.finishing) {
6845 continue;
6846 }
6847 if (lastReparentPos < 0) {
6848 lastReparentPos = taskTopI;
6849 taskTop = p;
6850 } else {
6851 lastReparentPos--;
6852 }
6853 mHistory.remove(srcPos);
6854 p.task.numActivities--;
6855 p.task = task;
6856 mHistory.add(lastReparentPos, p);
6857 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6858 + " in to resetting task " + task);
6859 task.numActivities++;
6860 mWindowManager.moveAppToken(lastReparentPos, p);
6861 mWindowManager.setAppGroupId(p, p.task.taskId);
6862 if (VALIDATE_TOKENS) {
6863 mWindowManager.validateAppTokens(mHistory);
6864 }
6865 }
6866 replyChainEnd = -1;
6867
6868 // Now we've moved it in to place... but what if this is
6869 // a singleTop activity and we have put it on top of another
6870 // instance of the same activity? Then we drop the instance
6871 // below so it remains singleTop.
6872 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6873 for (int j=lastReparentPos-1; j>=0; j--) {
6874 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6875 if (p.finishing) {
6876 continue;
6877 }
6878 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6879 if (finishActivityLocked(p, j,
6880 Activity.RESULT_CANCELED, null, "replace")) {
6881 taskTopI--;
6882 lastReparentPos--;
6883 }
6884 }
6885 }
6886 }
6887 }
6888 }
6889
6890 target = below;
6891 targetI = i;
6892 }
6893
6894 return taskTop;
6895 }
6896
6897 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006898 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006899 */
6900 public void moveTaskToFront(int task) {
6901 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6902 "moveTaskToFront()");
6903
6904 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006905 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6906 Binder.getCallingUid(), "Task to front")) {
6907 return;
6908 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006909 final long origId = Binder.clearCallingIdentity();
6910 try {
6911 int N = mRecentTasks.size();
6912 for (int i=0; i<N; i++) {
6913 TaskRecord tr = mRecentTasks.get(i);
6914 if (tr.taskId == task) {
6915 moveTaskToFrontLocked(tr);
6916 return;
6917 }
6918 }
6919 for (int i=mHistory.size()-1; i>=0; i--) {
6920 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6921 if (hr.task.taskId == task) {
6922 moveTaskToFrontLocked(hr.task);
6923 return;
6924 }
6925 }
6926 } finally {
6927 Binder.restoreCallingIdentity(origId);
6928 }
6929 }
6930 }
6931
6932 private final void moveTaskToFrontLocked(TaskRecord tr) {
6933 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6934
6935 final int task = tr.taskId;
6936 int top = mHistory.size()-1;
6937
6938 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6939 // nothing to do!
6940 return;
6941 }
6942
6943 if (DEBUG_TRANSITION) Log.v(TAG,
6944 "Prepare to front transition: task=" + tr);
6945 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6946
6947 ArrayList moved = new ArrayList();
6948
6949 // Applying the affinities may have removed entries from the history,
6950 // so get the size again.
6951 top = mHistory.size()-1;
6952 int pos = top;
6953
6954 // Shift all activities with this task up to the top
6955 // of the stack, keeping them in the same internal order.
6956 while (pos >= 0) {
6957 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6958 if (localLOGV) Log.v(
6959 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6960 boolean first = true;
6961 if (r.task.taskId == task) {
6962 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6963 mHistory.remove(pos);
6964 mHistory.add(top, r);
6965 moved.add(0, r);
6966 top--;
6967 if (first) {
6968 addRecentTask(r.task);
6969 first = false;
6970 }
6971 }
6972 pos--;
6973 }
6974
6975 mWindowManager.moveAppTokensToTop(moved);
6976 if (VALIDATE_TOKENS) {
6977 mWindowManager.validateAppTokens(mHistory);
6978 }
6979
6980 finishTaskMove(task);
6981 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6982 }
6983
6984 private final void finishTaskMove(int task) {
6985 resumeTopActivityLocked(null);
6986 }
6987
6988 public void moveTaskToBack(int task) {
6989 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6990 "moveTaskToBack()");
6991
6992 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006993 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6994 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6995 Binder.getCallingUid(), "Task to back")) {
6996 return;
6997 }
6998 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006999 final long origId = Binder.clearCallingIdentity();
7000 moveTaskToBackLocked(task);
7001 Binder.restoreCallingIdentity(origId);
7002 }
7003 }
7004
7005 /**
7006 * Moves an activity, and all of the other activities within the same task, to the bottom
7007 * of the history stack. The activity's order within the task is unchanged.
7008 *
7009 * @param token A reference to the activity we wish to move
7010 * @param nonRoot If false then this only works if the activity is the root
7011 * of a task; if true it will work for any activity in a task.
7012 * @return Returns true if the move completed, false if not.
7013 */
7014 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7015 synchronized(this) {
7016 final long origId = Binder.clearCallingIdentity();
7017 int taskId = getTaskForActivityLocked(token, !nonRoot);
7018 if (taskId >= 0) {
7019 return moveTaskToBackLocked(taskId);
7020 }
7021 Binder.restoreCallingIdentity(origId);
7022 }
7023 return false;
7024 }
7025
7026 /**
7027 * Worker method for rearranging history stack. Implements the function of moving all
7028 * activities for a specific task (gathering them if disjoint) into a single group at the
7029 * bottom of the stack.
7030 *
7031 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7032 * to premeptively cancel the move.
7033 *
7034 * @param task The taskId to collect and move to the bottom.
7035 * @return Returns true if the move completed, false if not.
7036 */
7037 private final boolean moveTaskToBackLocked(int task) {
7038 Log.i(TAG, "moveTaskToBack: " + task);
7039
7040 // If we have a watcher, preflight the move before committing to it. First check
7041 // for *other* available tasks, but if none are available, then try again allowing the
7042 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007043 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007044 HistoryRecord next = topRunningActivityLocked(null, task);
7045 if (next == null) {
7046 next = topRunningActivityLocked(null, 0);
7047 }
7048 if (next != null) {
7049 // ask watcher if this is allowed
7050 boolean moveOK = true;
7051 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007052 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007053 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007054 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007055 }
7056 if (!moveOK) {
7057 return false;
7058 }
7059 }
7060 }
7061
7062 ArrayList moved = new ArrayList();
7063
7064 if (DEBUG_TRANSITION) Log.v(TAG,
7065 "Prepare to back transition: task=" + task);
7066 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
7067
7068 final int N = mHistory.size();
7069 int bottom = 0;
7070 int pos = 0;
7071
7072 // Shift all activities with this task down to the bottom
7073 // of the stack, keeping them in the same internal order.
7074 while (pos < N) {
7075 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7076 if (localLOGV) Log.v(
7077 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7078 if (r.task.taskId == task) {
7079 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7080 mHistory.remove(pos);
7081 mHistory.add(bottom, r);
7082 moved.add(r);
7083 bottom++;
7084 }
7085 pos++;
7086 }
7087
7088 mWindowManager.moveAppTokensToBottom(moved);
7089 if (VALIDATE_TOKENS) {
7090 mWindowManager.validateAppTokens(mHistory);
7091 }
7092
7093 finishTaskMove(task);
7094 return true;
7095 }
7096
7097 public void moveTaskBackwards(int task) {
7098 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7099 "moveTaskBackwards()");
7100
7101 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007102 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7103 Binder.getCallingUid(), "Task backwards")) {
7104 return;
7105 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007106 final long origId = Binder.clearCallingIdentity();
7107 moveTaskBackwardsLocked(task);
7108 Binder.restoreCallingIdentity(origId);
7109 }
7110 }
7111
7112 private final void moveTaskBackwardsLocked(int task) {
7113 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7114 }
7115
7116 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7117 synchronized(this) {
7118 return getTaskForActivityLocked(token, onlyRoot);
7119 }
7120 }
7121
7122 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7123 final int N = mHistory.size();
7124 TaskRecord lastTask = null;
7125 for (int i=0; i<N; i++) {
7126 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7127 if (r == token) {
7128 if (!onlyRoot || lastTask != r.task) {
7129 return r.task.taskId;
7130 }
7131 return -1;
7132 }
7133 lastTask = r.task;
7134 }
7135
7136 return -1;
7137 }
7138
7139 /**
7140 * Returns the top activity in any existing task matching the given
7141 * Intent. Returns null if no such task is found.
7142 */
7143 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7144 ComponentName cls = intent.getComponent();
7145 if (info.targetActivity != null) {
7146 cls = new ComponentName(info.packageName, info.targetActivity);
7147 }
7148
7149 TaskRecord cp = null;
7150
7151 final int N = mHistory.size();
7152 for (int i=(N-1); i>=0; i--) {
7153 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7154 if (!r.finishing && r.task != cp
7155 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7156 cp = r.task;
7157 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7158 // + "/aff=" + r.task.affinity + " to new cls="
7159 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7160 if (r.task.affinity != null) {
7161 if (r.task.affinity.equals(info.taskAffinity)) {
7162 //Log.i(TAG, "Found matching affinity!");
7163 return r;
7164 }
7165 } else if (r.task.intent != null
7166 && r.task.intent.getComponent().equals(cls)) {
7167 //Log.i(TAG, "Found matching class!");
7168 //dump();
7169 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7170 return r;
7171 } else if (r.task.affinityIntent != null
7172 && r.task.affinityIntent.getComponent().equals(cls)) {
7173 //Log.i(TAG, "Found matching class!");
7174 //dump();
7175 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7176 return r;
7177 }
7178 }
7179 }
7180
7181 return null;
7182 }
7183
7184 /**
7185 * Returns the first activity (starting from the top of the stack) that
7186 * is the same as the given activity. Returns null if no such activity
7187 * is found.
7188 */
7189 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7190 ComponentName cls = intent.getComponent();
7191 if (info.targetActivity != null) {
7192 cls = new ComponentName(info.packageName, info.targetActivity);
7193 }
7194
7195 final int N = mHistory.size();
7196 for (int i=(N-1); i>=0; i--) {
7197 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7198 if (!r.finishing) {
7199 if (r.intent.getComponent().equals(cls)) {
7200 //Log.i(TAG, "Found matching class!");
7201 //dump();
7202 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7203 return r;
7204 }
7205 }
7206 }
7207
7208 return null;
7209 }
7210
7211 public void finishOtherInstances(IBinder token, ComponentName className) {
7212 synchronized(this) {
7213 final long origId = Binder.clearCallingIdentity();
7214
7215 int N = mHistory.size();
7216 TaskRecord lastTask = null;
7217 for (int i=0; i<N; i++) {
7218 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7219 if (r.realActivity.equals(className)
7220 && r != token && lastTask != r.task) {
7221 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7222 null, "others")) {
7223 i--;
7224 N--;
7225 }
7226 }
7227 lastTask = r.task;
7228 }
7229
7230 Binder.restoreCallingIdentity(origId);
7231 }
7232 }
7233
7234 // =========================================================
7235 // THUMBNAILS
7236 // =========================================================
7237
7238 public void reportThumbnail(IBinder token,
7239 Bitmap thumbnail, CharSequence description) {
7240 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7241 final long origId = Binder.clearCallingIdentity();
7242 sendPendingThumbnail(null, token, thumbnail, description, true);
7243 Binder.restoreCallingIdentity(origId);
7244 }
7245
7246 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7247 Bitmap thumbnail, CharSequence description, boolean always) {
7248 TaskRecord task = null;
7249 ArrayList receivers = null;
7250
7251 //System.out.println("Send pending thumbnail: " + r);
7252
7253 synchronized(this) {
7254 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007255 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007256 if (index < 0) {
7257 return;
7258 }
7259 r = (HistoryRecord)mHistory.get(index);
7260 }
7261 if (thumbnail == null) {
7262 thumbnail = r.thumbnail;
7263 description = r.description;
7264 }
7265 if (thumbnail == null && !always) {
7266 // If there is no thumbnail, and this entry is not actually
7267 // going away, then abort for now and pick up the next
7268 // thumbnail we get.
7269 return;
7270 }
7271 task = r.task;
7272
7273 int N = mPendingThumbnails.size();
7274 int i=0;
7275 while (i<N) {
7276 PendingThumbnailsRecord pr =
7277 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7278 //System.out.println("Looking in " + pr.pendingRecords);
7279 if (pr.pendingRecords.remove(r)) {
7280 if (receivers == null) {
7281 receivers = new ArrayList();
7282 }
7283 receivers.add(pr);
7284 if (pr.pendingRecords.size() == 0) {
7285 pr.finished = true;
7286 mPendingThumbnails.remove(i);
7287 N--;
7288 continue;
7289 }
7290 }
7291 i++;
7292 }
7293 }
7294
7295 if (receivers != null) {
7296 final int N = receivers.size();
7297 for (int i=0; i<N; i++) {
7298 try {
7299 PendingThumbnailsRecord pr =
7300 (PendingThumbnailsRecord)receivers.get(i);
7301 pr.receiver.newThumbnail(
7302 task != null ? task.taskId : -1, thumbnail, description);
7303 if (pr.finished) {
7304 pr.receiver.finished();
7305 }
7306 } catch (Exception e) {
7307 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7308 }
7309 }
7310 }
7311 }
7312
7313 // =========================================================
7314 // CONTENT PROVIDERS
7315 // =========================================================
7316
7317 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7318 List providers = null;
7319 try {
7320 providers = ActivityThread.getPackageManager().
7321 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007322 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007323 } catch (RemoteException ex) {
7324 }
7325 if (providers != null) {
7326 final int N = providers.size();
7327 for (int i=0; i<N; i++) {
7328 ProviderInfo cpi =
7329 (ProviderInfo)providers.get(i);
7330 ContentProviderRecord cpr =
7331 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7332 if (cpr == null) {
7333 cpr = new ContentProviderRecord(cpi, app.info);
7334 mProvidersByClass.put(cpi.name, cpr);
7335 }
7336 app.pubProviders.put(cpi.name, cpr);
7337 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007338 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007339 }
7340 }
7341 return providers;
7342 }
7343
7344 private final String checkContentProviderPermissionLocked(
7345 ProviderInfo cpi, ProcessRecord r, int mode) {
7346 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7347 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7348 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7349 cpi.exported ? -1 : cpi.applicationInfo.uid)
7350 == PackageManager.PERMISSION_GRANTED
7351 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7352 return null;
7353 }
7354 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7355 cpi.exported ? -1 : cpi.applicationInfo.uid)
7356 == PackageManager.PERMISSION_GRANTED) {
7357 return null;
7358 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007359
7360 PathPermission[] pps = cpi.pathPermissions;
7361 if (pps != null) {
7362 int i = pps.length;
7363 while (i > 0) {
7364 i--;
7365 PathPermission pp = pps[i];
7366 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7367 cpi.exported ? -1 : cpi.applicationInfo.uid)
7368 == PackageManager.PERMISSION_GRANTED
7369 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7370 return null;
7371 }
7372 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7373 cpi.exported ? -1 : cpi.applicationInfo.uid)
7374 == PackageManager.PERMISSION_GRANTED) {
7375 return null;
7376 }
7377 }
7378 }
7379
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007380 String msg = "Permission Denial: opening provider " + cpi.name
7381 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7382 + ", uid=" + callingUid + ") requires "
7383 + cpi.readPermission + " or " + cpi.writePermission;
7384 Log.w(TAG, msg);
7385 return msg;
7386 }
7387
7388 private final ContentProviderHolder getContentProviderImpl(
7389 IApplicationThread caller, String name) {
7390 ContentProviderRecord cpr;
7391 ProviderInfo cpi = null;
7392
7393 synchronized(this) {
7394 ProcessRecord r = null;
7395 if (caller != null) {
7396 r = getRecordForAppLocked(caller);
7397 if (r == null) {
7398 throw new SecurityException(
7399 "Unable to find app for caller " + caller
7400 + " (pid=" + Binder.getCallingPid()
7401 + ") when getting content provider " + name);
7402 }
7403 }
7404
7405 // First check if this content provider has been published...
7406 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7407 if (cpr != null) {
7408 cpi = cpr.info;
7409 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7410 return new ContentProviderHolder(cpi,
7411 cpi.readPermission != null
7412 ? cpi.readPermission : cpi.writePermission);
7413 }
7414
7415 if (r != null && cpr.canRunHere(r)) {
7416 // This provider has been published or is in the process
7417 // of being published... but it is also allowed to run
7418 // in the caller's process, so don't make a connection
7419 // and just let the caller instantiate its own instance.
7420 if (cpr.provider != null) {
7421 // don't give caller the provider object, it needs
7422 // to make its own.
7423 cpr = new ContentProviderRecord(cpr);
7424 }
7425 return cpr;
7426 }
7427
7428 final long origId = Binder.clearCallingIdentity();
7429
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007430 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007431 // return it right away.
7432 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007433 if (DEBUG_PROVIDER) Log.v(TAG,
7434 "Adding provider requested by "
7435 + r.processName + " from process "
7436 + cpr.info.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007437 r.conProviders.add(cpr);
7438 cpr.clients.add(r);
7439 } else {
7440 cpr.externals++;
7441 }
7442
7443 if (cpr.app != null) {
7444 updateOomAdjLocked(cpr.app);
7445 }
7446
7447 Binder.restoreCallingIdentity(origId);
7448
7449 } else {
7450 try {
7451 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007452 resolveContentProvider(name,
7453 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007454 } catch (RemoteException ex) {
7455 }
7456 if (cpi == null) {
7457 return null;
7458 }
7459
7460 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7461 return new ContentProviderHolder(cpi,
7462 cpi.readPermission != null
7463 ? cpi.readPermission : cpi.writePermission);
7464 }
7465
7466 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7467 final boolean firstClass = cpr == null;
7468 if (firstClass) {
7469 try {
7470 ApplicationInfo ai =
7471 ActivityThread.getPackageManager().
7472 getApplicationInfo(
7473 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007474 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007475 if (ai == null) {
7476 Log.w(TAG, "No package info for content provider "
7477 + cpi.name);
7478 return null;
7479 }
7480 cpr = new ContentProviderRecord(cpi, ai);
7481 } catch (RemoteException ex) {
7482 // pm is in same process, this will never happen.
7483 }
7484 }
7485
7486 if (r != null && cpr.canRunHere(r)) {
7487 // If this is a multiprocess provider, then just return its
7488 // info and allow the caller to instantiate it. Only do
7489 // this if the provider is the same user as the caller's
7490 // process, or can run as root (so can be in any process).
7491 return cpr;
7492 }
7493
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007494 if (DEBUG_PROVIDER) {
7495 RuntimeException e = new RuntimeException("here");
7496 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7497 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007498 }
7499
7500 // This is single process, and our app is now connecting to it.
7501 // See if we are already in the process of launching this
7502 // provider.
7503 final int N = mLaunchingProviders.size();
7504 int i;
7505 for (i=0; i<N; i++) {
7506 if (mLaunchingProviders.get(i) == cpr) {
7507 break;
7508 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007509 }
7510
7511 // If the provider is not already being launched, then get it
7512 // started.
7513 if (i >= N) {
7514 final long origId = Binder.clearCallingIdentity();
7515 ProcessRecord proc = startProcessLocked(cpi.processName,
7516 cpr.appInfo, false, 0, "content provider",
7517 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007518 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007519 if (proc == null) {
7520 Log.w(TAG, "Unable to launch app "
7521 + cpi.applicationInfo.packageName + "/"
7522 + cpi.applicationInfo.uid + " for provider "
7523 + name + ": process is bad");
7524 return null;
7525 }
7526 cpr.launchingApp = proc;
7527 mLaunchingProviders.add(cpr);
7528 Binder.restoreCallingIdentity(origId);
7529 }
7530
7531 // Make sure the provider is published (the same provider class
7532 // may be published under multiple names).
7533 if (firstClass) {
7534 mProvidersByClass.put(cpi.name, cpr);
7535 }
7536 mProvidersByName.put(name, cpr);
7537
7538 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007539 if (DEBUG_PROVIDER) Log.v(TAG,
7540 "Adding provider requested by "
7541 + r.processName + " from process "
7542 + cpr.info.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007543 r.conProviders.add(cpr);
7544 cpr.clients.add(r);
7545 } else {
7546 cpr.externals++;
7547 }
7548 }
7549 }
7550
7551 // Wait for the provider to be published...
7552 synchronized (cpr) {
7553 while (cpr.provider == null) {
7554 if (cpr.launchingApp == null) {
7555 Log.w(TAG, "Unable to launch app "
7556 + cpi.applicationInfo.packageName + "/"
7557 + cpi.applicationInfo.uid + " for provider "
7558 + name + ": launching app became null");
7559 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7560 cpi.applicationInfo.packageName,
7561 cpi.applicationInfo.uid, name);
7562 return null;
7563 }
7564 try {
7565 cpr.wait();
7566 } catch (InterruptedException ex) {
7567 }
7568 }
7569 }
7570 return cpr;
7571 }
7572
7573 public final ContentProviderHolder getContentProvider(
7574 IApplicationThread caller, String name) {
7575 if (caller == null) {
7576 String msg = "null IApplicationThread when getting content provider "
7577 + name;
7578 Log.w(TAG, msg);
7579 throw new SecurityException(msg);
7580 }
7581
7582 return getContentProviderImpl(caller, name);
7583 }
7584
7585 private ContentProviderHolder getContentProviderExternal(String name) {
7586 return getContentProviderImpl(null, name);
7587 }
7588
7589 /**
7590 * Drop a content provider from a ProcessRecord's bookkeeping
7591 * @param cpr
7592 */
7593 public void removeContentProvider(IApplicationThread caller, String name) {
7594 synchronized (this) {
7595 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7596 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007597 // remove from mProvidersByClass
7598 if (DEBUG_PROVIDER) Log.v(TAG, name +
7599 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007600 return;
7601 }
7602 final ProcessRecord r = getRecordForAppLocked(caller);
7603 if (r == null) {
7604 throw new SecurityException(
7605 "Unable to find app for caller " + caller +
7606 " when removing content provider " + name);
7607 }
7608 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007609 ContentProviderRecord localCpr = (ContentProviderRecord)
7610 mProvidersByClass.get(cpr.info.name);
7611 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7612 + r.info.processName + " from process "
7613 + localCpr.appInfo.processName);
7614 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007615 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007616 Log.w(TAG, "removeContentProvider called on local provider: "
7617 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007618 return;
7619 } else {
7620 localCpr.clients.remove(r);
7621 r.conProviders.remove(localCpr);
7622 }
7623 updateOomAdjLocked();
7624 }
7625 }
7626
7627 private void removeContentProviderExternal(String name) {
7628 synchronized (this) {
7629 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7630 if(cpr == null) {
7631 //remove from mProvidersByClass
7632 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7633 return;
7634 }
7635
7636 //update content provider record entry info
7637 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7638 localCpr.externals--;
7639 if (localCpr.externals < 0) {
7640 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7641 }
7642 updateOomAdjLocked();
7643 }
7644 }
7645
7646 public final void publishContentProviders(IApplicationThread caller,
7647 List<ContentProviderHolder> providers) {
7648 if (providers == null) {
7649 return;
7650 }
7651
7652 synchronized(this) {
7653 final ProcessRecord r = getRecordForAppLocked(caller);
7654 if (r == null) {
7655 throw new SecurityException(
7656 "Unable to find app for caller " + caller
7657 + " (pid=" + Binder.getCallingPid()
7658 + ") when publishing content providers");
7659 }
7660
7661 final long origId = Binder.clearCallingIdentity();
7662
7663 final int N = providers.size();
7664 for (int i=0; i<N; i++) {
7665 ContentProviderHolder src = providers.get(i);
7666 if (src == null || src.info == null || src.provider == null) {
7667 continue;
7668 }
7669 ContentProviderRecord dst =
7670 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7671 if (dst != null) {
7672 mProvidersByClass.put(dst.info.name, dst);
7673 String names[] = dst.info.authority.split(";");
7674 for (int j = 0; j < names.length; j++) {
7675 mProvidersByName.put(names[j], dst);
7676 }
7677
7678 int NL = mLaunchingProviders.size();
7679 int j;
7680 for (j=0; j<NL; j++) {
7681 if (mLaunchingProviders.get(j) == dst) {
7682 mLaunchingProviders.remove(j);
7683 j--;
7684 NL--;
7685 }
7686 }
7687 synchronized (dst) {
7688 dst.provider = src.provider;
7689 dst.app = r;
7690 dst.notifyAll();
7691 }
7692 updateOomAdjLocked(r);
7693 }
7694 }
7695
7696 Binder.restoreCallingIdentity(origId);
7697 }
7698 }
7699
7700 public static final void installSystemProviders() {
7701 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7702 List providers = mSelf.generateApplicationProvidersLocked(app);
7703 mSystemThread.installSystemProviders(providers);
7704 }
7705
7706 // =========================================================
7707 // GLOBAL MANAGEMENT
7708 // =========================================================
7709
7710 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7711 ApplicationInfo info, String customProcess) {
7712 String proc = customProcess != null ? customProcess : info.processName;
7713 BatteryStatsImpl.Uid.Proc ps = null;
7714 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7715 synchronized (stats) {
7716 ps = stats.getProcessStatsLocked(info.uid, proc);
7717 }
7718 return new ProcessRecord(ps, thread, info, proc);
7719 }
7720
7721 final ProcessRecord addAppLocked(ApplicationInfo info) {
7722 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7723
7724 if (app == null) {
7725 app = newProcessRecordLocked(null, info, null);
7726 mProcessNames.put(info.processName, info.uid, app);
7727 updateLRUListLocked(app, true);
7728 }
7729
7730 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7731 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7732 app.persistent = true;
7733 app.maxAdj = CORE_SERVER_ADJ;
7734 }
7735 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7736 mPersistentStartingProcesses.add(app);
7737 startProcessLocked(app, "added application", app.processName);
7738 }
7739
7740 return app;
7741 }
7742
7743 public void unhandledBack() {
7744 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7745 "unhandledBack()");
7746
7747 synchronized(this) {
7748 int count = mHistory.size();
7749 if (Config.LOGD) Log.d(
7750 TAG, "Performing unhandledBack(): stack size = " + count);
7751 if (count > 1) {
7752 final long origId = Binder.clearCallingIdentity();
7753 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7754 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7755 Binder.restoreCallingIdentity(origId);
7756 }
7757 }
7758 }
7759
7760 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7761 String name = uri.getAuthority();
7762 ContentProviderHolder cph = getContentProviderExternal(name);
7763 ParcelFileDescriptor pfd = null;
7764 if (cph != null) {
7765 // We record the binder invoker's uid in thread-local storage before
7766 // going to the content provider to open the file. Later, in the code
7767 // that handles all permissions checks, we look for this uid and use
7768 // that rather than the Activity Manager's own uid. The effect is that
7769 // we do the check against the caller's permissions even though it looks
7770 // to the content provider like the Activity Manager itself is making
7771 // the request.
7772 sCallerIdentity.set(new Identity(
7773 Binder.getCallingPid(), Binder.getCallingUid()));
7774 try {
7775 pfd = cph.provider.openFile(uri, "r");
7776 } catch (FileNotFoundException e) {
7777 // do nothing; pfd will be returned null
7778 } finally {
7779 // Ensure that whatever happens, we clean up the identity state
7780 sCallerIdentity.remove();
7781 }
7782
7783 // We've got the fd now, so we're done with the provider.
7784 removeContentProviderExternal(name);
7785 } else {
7786 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7787 }
7788 return pfd;
7789 }
7790
7791 public void goingToSleep() {
7792 synchronized(this) {
7793 mSleeping = true;
7794 mWindowManager.setEventDispatching(false);
7795
7796 if (mResumedActivity != null) {
7797 pauseIfSleepingLocked();
7798 } else {
7799 Log.w(TAG, "goingToSleep with no resumed activity!");
7800 }
7801 }
7802 }
7803
Dianne Hackborn55280a92009-05-07 15:53:46 -07007804 public boolean shutdown(int timeout) {
7805 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7806 != PackageManager.PERMISSION_GRANTED) {
7807 throw new SecurityException("Requires permission "
7808 + android.Manifest.permission.SHUTDOWN);
7809 }
7810
7811 boolean timedout = false;
7812
7813 synchronized(this) {
7814 mShuttingDown = true;
7815 mWindowManager.setEventDispatching(false);
7816
7817 if (mResumedActivity != null) {
7818 pauseIfSleepingLocked();
7819 final long endTime = System.currentTimeMillis() + timeout;
7820 while (mResumedActivity != null || mPausingActivity != null) {
7821 long delay = endTime - System.currentTimeMillis();
7822 if (delay <= 0) {
7823 Log.w(TAG, "Activity manager shutdown timed out");
7824 timedout = true;
7825 break;
7826 }
7827 try {
7828 this.wait();
7829 } catch (InterruptedException e) {
7830 }
7831 }
7832 }
7833 }
7834
7835 mUsageStatsService.shutdown();
7836 mBatteryStatsService.shutdown();
7837
7838 return timedout;
7839 }
7840
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007841 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007842 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007843 if (!mGoingToSleep.isHeld()) {
7844 mGoingToSleep.acquire();
7845 if (mLaunchingActivity.isHeld()) {
7846 mLaunchingActivity.release();
7847 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7848 }
7849 }
7850
7851 // If we are not currently pausing an activity, get the current
7852 // one to pause. If we are pausing one, we will just let that stuff
7853 // run and release the wake lock when all done.
7854 if (mPausingActivity == null) {
7855 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7856 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7857 startPausingLocked(false, true);
7858 }
7859 }
7860 }
7861
7862 public void wakingUp() {
7863 synchronized(this) {
7864 if (mGoingToSleep.isHeld()) {
7865 mGoingToSleep.release();
7866 }
7867 mWindowManager.setEventDispatching(true);
7868 mSleeping = false;
7869 resumeTopActivityLocked(null);
7870 }
7871 }
7872
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007873 public void stopAppSwitches() {
7874 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7875 != PackageManager.PERMISSION_GRANTED) {
7876 throw new SecurityException("Requires permission "
7877 + android.Manifest.permission.STOP_APP_SWITCHES);
7878 }
7879
7880 synchronized(this) {
7881 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7882 + APP_SWITCH_DELAY_TIME;
7883 mDidAppSwitch = false;
7884 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7885 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7886 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7887 }
7888 }
7889
7890 public void resumeAppSwitches() {
7891 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7892 != PackageManager.PERMISSION_GRANTED) {
7893 throw new SecurityException("Requires permission "
7894 + android.Manifest.permission.STOP_APP_SWITCHES);
7895 }
7896
7897 synchronized(this) {
7898 // Note that we don't execute any pending app switches... we will
7899 // let those wait until either the timeout, or the next start
7900 // activity request.
7901 mAppSwitchesAllowedTime = 0;
7902 }
7903 }
7904
7905 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7906 String name) {
7907 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7908 return true;
7909 }
7910
7911 final int perm = checkComponentPermission(
7912 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7913 callingUid, -1);
7914 if (perm == PackageManager.PERMISSION_GRANTED) {
7915 return true;
7916 }
7917
7918 Log.w(TAG, name + " request from " + callingUid + " stopped");
7919 return false;
7920 }
7921
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007922 public void setDebugApp(String packageName, boolean waitForDebugger,
7923 boolean persistent) {
7924 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7925 "setDebugApp()");
7926
7927 // Note that this is not really thread safe if there are multiple
7928 // callers into it at the same time, but that's not a situation we
7929 // care about.
7930 if (persistent) {
7931 final ContentResolver resolver = mContext.getContentResolver();
7932 Settings.System.putString(
7933 resolver, Settings.System.DEBUG_APP,
7934 packageName);
7935 Settings.System.putInt(
7936 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7937 waitForDebugger ? 1 : 0);
7938 }
7939
7940 synchronized (this) {
7941 if (!persistent) {
7942 mOrigDebugApp = mDebugApp;
7943 mOrigWaitForDebugger = mWaitForDebugger;
7944 }
7945 mDebugApp = packageName;
7946 mWaitForDebugger = waitForDebugger;
7947 mDebugTransient = !persistent;
7948 if (packageName != null) {
7949 final long origId = Binder.clearCallingIdentity();
7950 uninstallPackageLocked(packageName, -1, false);
7951 Binder.restoreCallingIdentity(origId);
7952 }
7953 }
7954 }
7955
7956 public void setAlwaysFinish(boolean enabled) {
7957 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7958 "setAlwaysFinish()");
7959
7960 Settings.System.putInt(
7961 mContext.getContentResolver(),
7962 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7963
7964 synchronized (this) {
7965 mAlwaysFinishActivities = enabled;
7966 }
7967 }
7968
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007969 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007970 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007971 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007972 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007973 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007974 }
7975 }
7976
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007977 public void registerActivityWatcher(IActivityWatcher watcher) {
7978 mWatchers.register(watcher);
7979 }
7980
7981 public void unregisterActivityWatcher(IActivityWatcher watcher) {
7982 mWatchers.unregister(watcher);
7983 }
7984
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007985 public final void enterSafeMode() {
7986 synchronized(this) {
7987 // It only makes sense to do this before the system is ready
7988 // and started launching other packages.
7989 if (!mSystemReady) {
7990 try {
7991 ActivityThread.getPackageManager().enterSafeMode();
7992 } catch (RemoteException e) {
7993 }
7994
7995 View v = LayoutInflater.from(mContext).inflate(
7996 com.android.internal.R.layout.safe_mode, null);
7997 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7998 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7999 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8000 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8001 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8002 lp.format = v.getBackground().getOpacity();
8003 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8004 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8005 ((WindowManager)mContext.getSystemService(
8006 Context.WINDOW_SERVICE)).addView(v, lp);
8007 }
8008 }
8009 }
8010
8011 public void noteWakeupAlarm(IIntentSender sender) {
8012 if (!(sender instanceof PendingIntentRecord)) {
8013 return;
8014 }
8015 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8016 synchronized (stats) {
8017 if (mBatteryStatsService.isOnBattery()) {
8018 mBatteryStatsService.enforceCallingPermission();
8019 PendingIntentRecord rec = (PendingIntentRecord)sender;
8020 int MY_UID = Binder.getCallingUid();
8021 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8022 BatteryStatsImpl.Uid.Pkg pkg =
8023 stats.getPackageStatsLocked(uid, rec.key.packageName);
8024 pkg.incWakeupsLocked();
8025 }
8026 }
8027 }
8028
8029 public boolean killPidsForMemory(int[] pids) {
8030 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8031 throw new SecurityException("killPidsForMemory only available to the system");
8032 }
8033
8034 // XXX Note: don't acquire main activity lock here, because the window
8035 // manager calls in with its locks held.
8036
8037 boolean killed = false;
8038 synchronized (mPidsSelfLocked) {
8039 int[] types = new int[pids.length];
8040 int worstType = 0;
8041 for (int i=0; i<pids.length; i++) {
8042 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8043 if (proc != null) {
8044 int type = proc.setAdj;
8045 types[i] = type;
8046 if (type > worstType) {
8047 worstType = type;
8048 }
8049 }
8050 }
8051
8052 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8053 // then constrain it so we will kill all hidden procs.
8054 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8055 worstType = HIDDEN_APP_MIN_ADJ;
8056 }
8057 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8058 for (int i=0; i<pids.length; i++) {
8059 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8060 if (proc == null) {
8061 continue;
8062 }
8063 int adj = proc.setAdj;
8064 if (adj >= worstType) {
8065 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8066 + adj + ")");
8067 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
8068 proc.processName, adj);
8069 killed = true;
8070 Process.killProcess(pids[i]);
8071 }
8072 }
8073 }
8074 return killed;
8075 }
8076
8077 public void reportPss(IApplicationThread caller, int pss) {
8078 Watchdog.PssRequestor req;
8079 String name;
8080 ProcessRecord callerApp;
8081 synchronized (this) {
8082 if (caller == null) {
8083 return;
8084 }
8085 callerApp = getRecordForAppLocked(caller);
8086 if (callerApp == null) {
8087 return;
8088 }
8089 callerApp.lastPss = pss;
8090 req = callerApp;
8091 name = callerApp.processName;
8092 }
8093 Watchdog.getInstance().reportPss(req, name, pss);
8094 if (!callerApp.persistent) {
8095 removeRequestedPss(callerApp);
8096 }
8097 }
8098
8099 public void requestPss(Runnable completeCallback) {
8100 ArrayList<ProcessRecord> procs;
8101 synchronized (this) {
8102 mRequestPssCallback = completeCallback;
8103 mRequestPssList.clear();
8104 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8105 ProcessRecord proc = mLRUProcesses.get(i);
8106 if (!proc.persistent) {
8107 mRequestPssList.add(proc);
8108 }
8109 }
8110 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8111 }
8112
8113 int oldPri = Process.getThreadPriority(Process.myTid());
8114 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8115 for (int i=procs.size()-1; i>=0; i--) {
8116 ProcessRecord proc = procs.get(i);
8117 proc.lastPss = 0;
8118 proc.requestPss();
8119 }
8120 Process.setThreadPriority(oldPri);
8121 }
8122
8123 void removeRequestedPss(ProcessRecord proc) {
8124 Runnable callback = null;
8125 synchronized (this) {
8126 if (mRequestPssList.remove(proc)) {
8127 if (mRequestPssList.size() == 0) {
8128 callback = mRequestPssCallback;
8129 mRequestPssCallback = null;
8130 }
8131 }
8132 }
8133
8134 if (callback != null) {
8135 callback.run();
8136 }
8137 }
8138
8139 public void collectPss(Watchdog.PssStats stats) {
8140 stats.mEmptyPss = 0;
8141 stats.mEmptyCount = 0;
8142 stats.mBackgroundPss = 0;
8143 stats.mBackgroundCount = 0;
8144 stats.mServicePss = 0;
8145 stats.mServiceCount = 0;
8146 stats.mVisiblePss = 0;
8147 stats.mVisibleCount = 0;
8148 stats.mForegroundPss = 0;
8149 stats.mForegroundCount = 0;
8150 stats.mNoPssCount = 0;
8151 synchronized (this) {
8152 int i;
8153 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8154 ? mProcDeaths.length : stats.mProcDeaths.length;
8155 int aggr = 0;
8156 for (i=0; i<NPD; i++) {
8157 aggr += mProcDeaths[i];
8158 stats.mProcDeaths[i] = aggr;
8159 }
8160 while (i<stats.mProcDeaths.length) {
8161 stats.mProcDeaths[i] = 0;
8162 i++;
8163 }
8164
8165 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8166 ProcessRecord proc = mLRUProcesses.get(i);
8167 if (proc.persistent) {
8168 continue;
8169 }
8170 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8171 if (proc.lastPss == 0) {
8172 stats.mNoPssCount++;
8173 continue;
8174 }
8175 if (proc.setAdj == EMPTY_APP_ADJ) {
8176 stats.mEmptyPss += proc.lastPss;
8177 stats.mEmptyCount++;
8178 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8179 stats.mEmptyPss += proc.lastPss;
8180 stats.mEmptyCount++;
8181 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8182 stats.mBackgroundPss += proc.lastPss;
8183 stats.mBackgroundCount++;
8184 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8185 stats.mVisiblePss += proc.lastPss;
8186 stats.mVisibleCount++;
8187 } else {
8188 stats.mForegroundPss += proc.lastPss;
8189 stats.mForegroundCount++;
8190 }
8191 }
8192 }
8193 }
8194
8195 public final void startRunning(String pkg, String cls, String action,
8196 String data) {
8197 synchronized(this) {
8198 if (mStartRunning) {
8199 return;
8200 }
8201 mStartRunning = true;
8202 mTopComponent = pkg != null && cls != null
8203 ? new ComponentName(pkg, cls) : null;
8204 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8205 mTopData = data;
8206 if (!mSystemReady) {
8207 return;
8208 }
8209 }
8210
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008211 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008212 }
8213
8214 private void retrieveSettings() {
8215 final ContentResolver resolver = mContext.getContentResolver();
8216 String debugApp = Settings.System.getString(
8217 resolver, Settings.System.DEBUG_APP);
8218 boolean waitForDebugger = Settings.System.getInt(
8219 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8220 boolean alwaysFinishActivities = Settings.System.getInt(
8221 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8222
8223 Configuration configuration = new Configuration();
8224 Settings.System.getConfiguration(resolver, configuration);
8225
8226 synchronized (this) {
8227 mDebugApp = mOrigDebugApp = debugApp;
8228 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8229 mAlwaysFinishActivities = alwaysFinishActivities;
8230 // This happens before any activities are started, so we can
8231 // change mConfiguration in-place.
8232 mConfiguration.updateFrom(configuration);
8233 }
8234 }
8235
8236 public boolean testIsSystemReady() {
8237 // no need to synchronize(this) just to read & return the value
8238 return mSystemReady;
8239 }
8240
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008241 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008242 // In the simulator, startRunning will never have been called, which
8243 // normally sets a few crucial variables. Do it here instead.
8244 if (!Process.supportsProcesses()) {
8245 mStartRunning = true;
8246 mTopAction = Intent.ACTION_MAIN;
8247 }
8248
8249 synchronized(this) {
8250 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008251 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008252 return;
8253 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008254
8255 // Check to see if there are any update receivers to run.
8256 if (!mDidUpdate) {
8257 if (mWaitingUpdate) {
8258 return;
8259 }
8260 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8261 List<ResolveInfo> ris = null;
8262 try {
8263 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8264 intent, null, 0);
8265 } catch (RemoteException e) {
8266 }
8267 if (ris != null) {
8268 for (int i=ris.size()-1; i>=0; i--) {
8269 if ((ris.get(i).activityInfo.applicationInfo.flags
8270 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8271 ris.remove(i);
8272 }
8273 }
8274 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8275 for (int i=0; i<ris.size(); i++) {
8276 ActivityInfo ai = ris.get(i).activityInfo;
8277 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8278 IIntentReceiver finisher = null;
8279 if (i == 0) {
8280 finisher = new IIntentReceiver.Stub() {
8281 public void performReceive(Intent intent, int resultCode,
8282 String data, Bundle extras, boolean ordered)
8283 throws RemoteException {
8284 synchronized (ActivityManagerService.this) {
8285 mDidUpdate = true;
8286 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008287 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008288 }
8289 };
8290 }
8291 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8292 broadcastIntentLocked(null, null, intent, null, finisher,
8293 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8294 if (i == 0) {
8295 mWaitingUpdate = true;
8296 }
8297 }
8298 }
8299 if (mWaitingUpdate) {
8300 return;
8301 }
8302 mDidUpdate = true;
8303 }
8304
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008305 mSystemReady = true;
8306 if (!mStartRunning) {
8307 return;
8308 }
8309 }
8310
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008311 ArrayList<ProcessRecord> procsToKill = null;
8312 synchronized(mPidsSelfLocked) {
8313 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8314 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8315 if (!isAllowedWhileBooting(proc.info)){
8316 if (procsToKill == null) {
8317 procsToKill = new ArrayList<ProcessRecord>();
8318 }
8319 procsToKill.add(proc);
8320 }
8321 }
8322 }
8323
8324 if (procsToKill != null) {
8325 synchronized(this) {
8326 for (int i=procsToKill.size()-1; i>=0; i--) {
8327 ProcessRecord proc = procsToKill.get(i);
8328 Log.i(TAG, "Removing system update proc: " + proc);
8329 removeProcessLocked(proc, true);
8330 }
8331 }
8332 }
8333
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008334 Log.i(TAG, "System now ready");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008335 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8336 SystemClock.uptimeMillis());
8337
8338 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008339 // Make sure we have no pre-ready processes sitting around.
8340
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008341 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8342 ResolveInfo ri = mContext.getPackageManager()
8343 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008344 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008345 CharSequence errorMsg = null;
8346 if (ri != null) {
8347 ActivityInfo ai = ri.activityInfo;
8348 ApplicationInfo app = ai.applicationInfo;
8349 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8350 mTopAction = Intent.ACTION_FACTORY_TEST;
8351 mTopData = null;
8352 mTopComponent = new ComponentName(app.packageName,
8353 ai.name);
8354 } else {
8355 errorMsg = mContext.getResources().getText(
8356 com.android.internal.R.string.factorytest_not_system);
8357 }
8358 } else {
8359 errorMsg = mContext.getResources().getText(
8360 com.android.internal.R.string.factorytest_no_action);
8361 }
8362 if (errorMsg != null) {
8363 mTopAction = null;
8364 mTopData = null;
8365 mTopComponent = null;
8366 Message msg = Message.obtain();
8367 msg.what = SHOW_FACTORY_ERROR_MSG;
8368 msg.getData().putCharSequence("msg", errorMsg);
8369 mHandler.sendMessage(msg);
8370 }
8371 }
8372 }
8373
8374 retrieveSettings();
8375
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008376 if (goingCallback != null) goingCallback.run();
8377
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008378 synchronized (this) {
8379 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8380 try {
8381 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008382 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008383 if (apps != null) {
8384 int N = apps.size();
8385 int i;
8386 for (i=0; i<N; i++) {
8387 ApplicationInfo info
8388 = (ApplicationInfo)apps.get(i);
8389 if (info != null &&
8390 !info.packageName.equals("android")) {
8391 addAppLocked(info);
8392 }
8393 }
8394 }
8395 } catch (RemoteException ex) {
8396 // pm is in same process, this will never happen.
8397 }
8398 }
8399
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008400 // Start up initial activity.
8401 mBooting = true;
8402
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008403 try {
8404 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8405 Message msg = Message.obtain();
8406 msg.what = SHOW_UID_ERROR_MSG;
8407 mHandler.sendMessage(msg);
8408 }
8409 } catch (RemoteException e) {
8410 }
8411
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008412 resumeTopActivityLocked(null);
8413 }
8414 }
8415
8416 boolean makeAppCrashingLocked(ProcessRecord app,
8417 String tag, String shortMsg, String longMsg, byte[] crashData) {
8418 app.crashing = true;
8419 app.crashingReport = generateProcessError(app,
8420 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8421 startAppProblemLocked(app);
8422 app.stopFreezingAllLocked();
8423 return handleAppCrashLocked(app);
8424 }
8425
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008426 private ComponentName getErrorReportReceiver(ProcessRecord app) {
8427 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008428
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008429 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008430 // look for receiver in the installer package
8431 String candidate = pm.getInstallerPackageName(app.info.packageName);
8432 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8433 if (result != null) {
8434 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008435 }
8436
Jacek Surazski82a73df2009-06-17 14:33:18 +02008437 // if the error app is on the system image, look for system apps
8438 // error receiver
8439 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8440 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8441 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8442 if (result != null) {
8443 return result;
8444 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008445 }
8446
Jacek Surazski82a73df2009-06-17 14:33:18 +02008447 // if there is a default receiver, try that
8448 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8449 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008450 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008451 // should not happen
8452 Log.e(TAG, "error talking to PackageManager", e);
8453 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008454 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008455 }
8456
8457 /**
8458 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8459 *
8460 * @param pm PackageManager isntance
8461 * @param errorPackage package which caused the error
8462 * @param receiverPackage candidate package to receive the error
8463 * @return activity component within receiverPackage which handles
8464 * ACTION_APP_ERROR, or null if not found
8465 */
8466 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8467 String receiverPackage) throws RemoteException {
8468 if (receiverPackage == null || receiverPackage.length() == 0) {
8469 return null;
8470 }
8471
8472 // break the loop if it's the error report receiver package that crashed
8473 if (receiverPackage.equals(errorPackage)) {
8474 return null;
8475 }
8476
8477 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8478 intent.setPackage(receiverPackage);
8479 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8480 if (info == null || info.activityInfo == null) {
8481 return null;
8482 }
8483 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008484 }
8485
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008486 void makeAppNotRespondingLocked(ProcessRecord app,
8487 String tag, String shortMsg, String longMsg, byte[] crashData) {
8488 app.notResponding = true;
8489 app.notRespondingReport = generateProcessError(app,
8490 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8491 crashData);
8492 startAppProblemLocked(app);
8493 app.stopFreezingAllLocked();
8494 }
8495
8496 /**
8497 * Generate a process error record, suitable for attachment to a ProcessRecord.
8498 *
8499 * @param app The ProcessRecord in which the error occurred.
8500 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8501 * ActivityManager.AppErrorStateInfo
8502 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8503 * @param shortMsg Short message describing the crash.
8504 * @param longMsg Long message describing the crash.
8505 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8506 *
8507 * @return Returns a fully-formed AppErrorStateInfo record.
8508 */
8509 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8510 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8511 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8512
8513 report.condition = condition;
8514 report.processName = app.processName;
8515 report.pid = app.pid;
8516 report.uid = app.info.uid;
8517 report.tag = tag;
8518 report.shortMsg = shortMsg;
8519 report.longMsg = longMsg;
8520 report.crashData = crashData;
8521
8522 return report;
8523 }
8524
8525 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8526 boolean crashed) {
8527 synchronized (this) {
8528 app.crashing = false;
8529 app.crashingReport = null;
8530 app.notResponding = false;
8531 app.notRespondingReport = null;
8532 if (app.anrDialog == fromDialog) {
8533 app.anrDialog = null;
8534 }
8535 if (app.waitDialog == fromDialog) {
8536 app.waitDialog = null;
8537 }
8538 if (app.pid > 0 && app.pid != MY_PID) {
8539 if (crashed) {
8540 handleAppCrashLocked(app);
8541 }
8542 Log.i(ActivityManagerService.TAG, "Killing process "
8543 + app.processName
8544 + " (pid=" + app.pid + ") at user's request");
8545 Process.killProcess(app.pid);
8546 }
8547
8548 }
8549 }
8550
8551 boolean handleAppCrashLocked(ProcessRecord app) {
8552 long now = SystemClock.uptimeMillis();
8553
8554 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8555 app.info.uid);
8556 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8557 // This process loses!
8558 Log.w(TAG, "Process " + app.info.processName
8559 + " has crashed too many times: killing!");
8560 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8561 app.info.processName, app.info.uid);
8562 killServicesLocked(app, false);
8563 for (int i=mHistory.size()-1; i>=0; i--) {
8564 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8565 if (r.app == app) {
8566 if (Config.LOGD) Log.d(
8567 TAG, " Force finishing activity "
8568 + r.intent.getComponent().flattenToShortString());
8569 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8570 }
8571 }
8572 if (!app.persistent) {
8573 // We don't want to start this process again until the user
8574 // explicitly does so... but for persistent process, we really
8575 // need to keep it running. If a persistent process is actually
8576 // repeatedly crashing, then badness for everyone.
8577 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8578 app.info.processName);
8579 mBadProcesses.put(app.info.processName, app.info.uid, now);
8580 app.bad = true;
8581 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8582 app.removed = true;
8583 removeProcessLocked(app, false);
8584 return false;
8585 }
8586 }
8587
8588 // Bump up the crash count of any services currently running in the proc.
8589 if (app.services.size() != 0) {
8590 // Any services running in the application need to be placed
8591 // back in the pending list.
8592 Iterator it = app.services.iterator();
8593 while (it.hasNext()) {
8594 ServiceRecord sr = (ServiceRecord)it.next();
8595 sr.crashCount++;
8596 }
8597 }
8598
8599 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8600 return true;
8601 }
8602
8603 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008604 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008605 skipCurrentReceiverLocked(app);
8606 }
8607
8608 void skipCurrentReceiverLocked(ProcessRecord app) {
8609 boolean reschedule = false;
8610 BroadcastRecord r = app.curReceiver;
8611 if (r != null) {
8612 // The current broadcast is waiting for this app's receiver
8613 // to be finished. Looks like that's not going to happen, so
8614 // let the broadcast continue.
8615 logBroadcastReceiverDiscard(r);
8616 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8617 r.resultExtras, r.resultAbort, true);
8618 reschedule = true;
8619 }
8620 r = mPendingBroadcast;
8621 if (r != null && r.curApp == app) {
8622 if (DEBUG_BROADCAST) Log.v(TAG,
8623 "skip & discard pending app " + r);
8624 logBroadcastReceiverDiscard(r);
8625 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8626 r.resultExtras, r.resultAbort, true);
8627 reschedule = true;
8628 }
8629 if (reschedule) {
8630 scheduleBroadcastsLocked();
8631 }
8632 }
8633
8634 public int handleApplicationError(IBinder app, int flags,
8635 String tag, String shortMsg, String longMsg, byte[] crashData) {
8636 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008637 ProcessRecord r = null;
8638 synchronized (this) {
8639 if (app != null) {
8640 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8641 final int NA = apps.size();
8642 for (int ia=0; ia<NA; ia++) {
8643 ProcessRecord p = apps.valueAt(ia);
8644 if (p.thread != null && p.thread.asBinder() == app) {
8645 r = p;
8646 break;
8647 }
8648 }
8649 }
8650 }
8651
8652 if (r != null) {
8653 // The application has crashed. Send the SIGQUIT to the process so
8654 // that it can dump its state.
8655 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8656 //Log.i(TAG, "Current system threads:");
8657 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8658 }
8659
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008660 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008661 try {
8662 String name = r != null ? r.processName : null;
8663 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008664 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008665 shortMsg, longMsg, crashData)) {
8666 Log.w(TAG, "Force-killing crashed app " + name
8667 + " at watcher's request");
8668 Process.killProcess(pid);
8669 return 0;
8670 }
8671 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008672 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008673 }
8674 }
8675
8676 final long origId = Binder.clearCallingIdentity();
8677
8678 // If this process is running instrumentation, finish it.
8679 if (r != null && r.instrumentationClass != null) {
8680 Log.w(TAG, "Error in app " + r.processName
8681 + " running instrumentation " + r.instrumentationClass + ":");
8682 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8683 if (longMsg != null) Log.w(TAG, " " + longMsg);
8684 Bundle info = new Bundle();
8685 info.putString("shortMsg", shortMsg);
8686 info.putString("longMsg", longMsg);
8687 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8688 Binder.restoreCallingIdentity(origId);
8689 return 0;
8690 }
8691
8692 if (r != null) {
8693 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8694 return 0;
8695 }
8696 } else {
8697 Log.w(TAG, "Some application object " + app + " tag " + tag
8698 + " has crashed, but I don't know who it is.");
8699 Log.w(TAG, "ShortMsg:" + shortMsg);
8700 Log.w(TAG, "LongMsg:" + longMsg);
8701 Binder.restoreCallingIdentity(origId);
8702 return 0;
8703 }
8704
8705 Message msg = Message.obtain();
8706 msg.what = SHOW_ERROR_MSG;
8707 HashMap data = new HashMap();
8708 data.put("result", result);
8709 data.put("app", r);
8710 data.put("flags", flags);
8711 data.put("shortMsg", shortMsg);
8712 data.put("longMsg", longMsg);
8713 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8714 // For system processes, submit crash data to the server.
8715 data.put("crashData", crashData);
8716 }
8717 msg.obj = data;
8718 mHandler.sendMessage(msg);
8719
8720 Binder.restoreCallingIdentity(origId);
8721 }
8722
8723 int res = result.get();
8724
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008725 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008726 synchronized (this) {
8727 if (r != null) {
8728 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8729 SystemClock.uptimeMillis());
8730 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008731 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8732 appErrorIntent = createAppErrorIntentLocked(r);
8733 res = AppErrorDialog.FORCE_QUIT;
8734 }
8735 }
8736
8737 if (appErrorIntent != null) {
8738 try {
8739 mContext.startActivity(appErrorIntent);
8740 } catch (ActivityNotFoundException e) {
8741 Log.w(TAG, "bug report receiver dissappeared", e);
8742 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008743 }
8744
8745 return res;
8746 }
8747
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008748 Intent createAppErrorIntentLocked(ProcessRecord r) {
8749 ApplicationErrorReport report = createAppErrorReportLocked(r);
8750 if (report == null) {
8751 return null;
8752 }
8753 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8754 result.setComponent(r.errorReportReceiver);
8755 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8756 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8757 return result;
8758 }
8759
8760 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8761 if (r.errorReportReceiver == null) {
8762 return null;
8763 }
8764
8765 if (!r.crashing && !r.notResponding) {
8766 return null;
8767 }
8768
8769 try {
8770 ApplicationErrorReport report = new ApplicationErrorReport();
8771 report.packageName = r.info.packageName;
8772 report.installerPackageName = r.errorReportReceiver.getPackageName();
8773 report.processName = r.processName;
8774
8775 if (r.crashing) {
8776 report.type = ApplicationErrorReport.TYPE_CRASH;
8777 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8778
8779 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8780 r.crashingReport.crashData);
8781 DataInputStream dataStream = new DataInputStream(byteStream);
8782 CrashData crashData = new CrashData(dataStream);
8783 ThrowableData throwData = crashData.getThrowableData();
8784
8785 report.time = crashData.getTime();
8786 report.crashInfo.stackTrace = throwData.toString();
8787
Jacek Surazskif829a782009-06-11 22:47:02 +02008788 // Extract the source of the exception, useful for report
8789 // clustering. Also extract the "deepest" non-null exception
8790 // message.
8791 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008792 while (throwData.getCause() != null) {
8793 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008794 String msg = throwData.getMessage();
8795 if (msg != null && msg.length() > 0) {
8796 exceptionMessage = msg;
8797 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008798 }
8799 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008800 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008801 report.crashInfo.exceptionClassName = throwData.getType();
8802 report.crashInfo.throwFileName = trace.getFileName();
8803 report.crashInfo.throwClassName = trace.getClassName();
8804 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008805 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008806 } else if (r.notResponding) {
8807 report.type = ApplicationErrorReport.TYPE_ANR;
8808 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8809
8810 report.anrInfo.activity = r.notRespondingReport.tag;
8811 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8812 report.anrInfo.info = r.notRespondingReport.longMsg;
8813 }
8814
8815 return report;
8816 } catch (IOException e) {
8817 // we don't send it
8818 }
8819
8820 return null;
8821 }
8822
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008823 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8824 // assume our apps are happy - lazy create the list
8825 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8826
8827 synchronized (this) {
8828
8829 // iterate across all processes
8830 final int N = mLRUProcesses.size();
8831 for (int i = 0; i < N; i++) {
8832 ProcessRecord app = mLRUProcesses.get(i);
8833 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8834 // This one's in trouble, so we'll generate a report for it
8835 // crashes are higher priority (in case there's a crash *and* an anr)
8836 ActivityManager.ProcessErrorStateInfo report = null;
8837 if (app.crashing) {
8838 report = app.crashingReport;
8839 } else if (app.notResponding) {
8840 report = app.notRespondingReport;
8841 }
8842
8843 if (report != null) {
8844 if (errList == null) {
8845 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8846 }
8847 errList.add(report);
8848 } else {
8849 Log.w(TAG, "Missing app error report, app = " + app.processName +
8850 " crashing = " + app.crashing +
8851 " notResponding = " + app.notResponding);
8852 }
8853 }
8854 }
8855 }
8856
8857 return errList;
8858 }
8859
8860 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8861 // Lazy instantiation of list
8862 List<ActivityManager.RunningAppProcessInfo> runList = null;
8863 synchronized (this) {
8864 // Iterate across all processes
8865 final int N = mLRUProcesses.size();
8866 for (int i = 0; i < N; i++) {
8867 ProcessRecord app = mLRUProcesses.get(i);
8868 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8869 // Generate process state info for running application
8870 ActivityManager.RunningAppProcessInfo currApp =
8871 new ActivityManager.RunningAppProcessInfo(app.processName,
8872 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07008873 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008874 int adj = app.curAdj;
8875 if (adj >= CONTENT_PROVIDER_ADJ) {
8876 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8877 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8878 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008879 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8880 } else if (adj >= HOME_APP_ADJ) {
8881 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8882 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008883 } else if (adj >= SECONDARY_SERVER_ADJ) {
8884 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8885 } else if (adj >= VISIBLE_APP_ADJ) {
8886 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8887 } else {
8888 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8889 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07008890 currApp.importanceReasonCode = app.adjTypeCode;
8891 if (app.adjSource instanceof ProcessRecord) {
8892 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
8893 } else if (app.adjSource instanceof HistoryRecord) {
8894 HistoryRecord r = (HistoryRecord)app.adjSource;
8895 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
8896 }
8897 if (app.adjTarget instanceof ComponentName) {
8898 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
8899 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008900 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8901 // + " lru=" + currApp.lru);
8902 if (runList == null) {
8903 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8904 }
8905 runList.add(currApp);
8906 }
8907 }
8908 }
8909 return runList;
8910 }
8911
8912 @Override
8913 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8914 synchronized (this) {
8915 if (checkCallingPermission(android.Manifest.permission.DUMP)
8916 != PackageManager.PERMISSION_GRANTED) {
8917 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8918 + Binder.getCallingPid()
8919 + ", uid=" + Binder.getCallingUid()
8920 + " without permission "
8921 + android.Manifest.permission.DUMP);
8922 return;
8923 }
8924 if (args.length != 0 && "service".equals(args[0])) {
8925 dumpService(fd, pw, args);
8926 return;
8927 }
8928 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008929 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008930 pw.println(" ");
8931 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008932 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008933 if (mWaitingVisibleActivities.size() > 0) {
8934 pw.println(" ");
8935 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008936 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008937 }
8938 if (mStoppingActivities.size() > 0) {
8939 pw.println(" ");
8940 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008941 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008942 }
8943 if (mFinishingActivities.size() > 0) {
8944 pw.println(" ");
8945 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008946 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008947 }
8948
8949 pw.println(" ");
8950 pw.println(" mPausingActivity: " + mPausingActivity);
8951 pw.println(" mResumedActivity: " + mResumedActivity);
8952 pw.println(" mFocusedActivity: " + mFocusedActivity);
8953 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8954
8955 if (mRecentTasks.size() > 0) {
8956 pw.println(" ");
8957 pw.println("Recent tasks in Current Activity Manager State:");
8958
8959 final int N = mRecentTasks.size();
8960 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008961 TaskRecord tr = mRecentTasks.get(i);
8962 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8963 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008964 mRecentTasks.get(i).dump(pw, " ");
8965 }
8966 }
8967
8968 pw.println(" ");
8969 pw.println(" mCurTask: " + mCurTask);
8970
8971 pw.println(" ");
8972 pw.println("Processes in Current Activity Manager State:");
8973
8974 boolean needSep = false;
8975 int numPers = 0;
8976
8977 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8978 final int NA = procs.size();
8979 for (int ia=0; ia<NA; ia++) {
8980 if (!needSep) {
8981 pw.println(" All known processes:");
8982 needSep = true;
8983 }
8984 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008985 pw.print(r.persistent ? " *PERS*" : " *APP*");
8986 pw.print(" UID "); pw.print(procs.keyAt(ia));
8987 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008988 r.dump(pw, " ");
8989 if (r.persistent) {
8990 numPers++;
8991 }
8992 }
8993 }
8994
8995 if (mLRUProcesses.size() > 0) {
8996 if (needSep) pw.println(" ");
8997 needSep = true;
8998 pw.println(" Running processes (most recent first):");
8999 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009000 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009001 needSep = true;
9002 }
9003
9004 synchronized (mPidsSelfLocked) {
9005 if (mPidsSelfLocked.size() > 0) {
9006 if (needSep) pw.println(" ");
9007 needSep = true;
9008 pw.println(" PID mappings:");
9009 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009010 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9011 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009012 }
9013 }
9014 }
9015
9016 if (mForegroundProcesses.size() > 0) {
9017 if (needSep) pw.println(" ");
9018 needSep = true;
9019 pw.println(" Foreground Processes:");
9020 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009021 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9022 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009023 }
9024 }
9025
9026 if (mPersistentStartingProcesses.size() > 0) {
9027 if (needSep) pw.println(" ");
9028 needSep = true;
9029 pw.println(" Persisent processes that are starting:");
9030 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009031 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009032 }
9033
9034 if (mStartingProcesses.size() > 0) {
9035 if (needSep) pw.println(" ");
9036 needSep = true;
9037 pw.println(" Processes that are starting:");
9038 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009039 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009040 }
9041
9042 if (mRemovedProcesses.size() > 0) {
9043 if (needSep) pw.println(" ");
9044 needSep = true;
9045 pw.println(" Processes that are being removed:");
9046 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009047 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009048 }
9049
9050 if (mProcessesOnHold.size() > 0) {
9051 if (needSep) pw.println(" ");
9052 needSep = true;
9053 pw.println(" Processes that are on old until the system is ready:");
9054 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009055 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009056 }
9057
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009058 if (mProcessesToGc.size() > 0) {
9059 if (needSep) pw.println(" ");
9060 needSep = true;
9061 pw.println(" Processes that are waiting to GC:");
9062 long now = SystemClock.uptimeMillis();
9063 for (int i=0; i<mProcessesToGc.size(); i++) {
9064 ProcessRecord proc = mProcessesToGc.get(i);
9065 pw.print(" Process "); pw.println(proc);
9066 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9067 pw.print(", last gced=");
9068 pw.print(now-proc.lastRequestedGc);
9069 pw.print(" ms ago, last lowMwm=");
9070 pw.print(now-proc.lastLowMemory);
9071 pw.println(" ms ago");
9072
9073 }
9074 }
9075
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009076 if (mProcessCrashTimes.getMap().size() > 0) {
9077 if (needSep) pw.println(" ");
9078 needSep = true;
9079 pw.println(" Time since processes crashed:");
9080 long now = SystemClock.uptimeMillis();
9081 for (Map.Entry<String, SparseArray<Long>> procs
9082 : mProcessCrashTimes.getMap().entrySet()) {
9083 SparseArray<Long> uids = procs.getValue();
9084 final int N = uids.size();
9085 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009086 pw.print(" Process "); pw.print(procs.getKey());
9087 pw.print(" uid "); pw.print(uids.keyAt(i));
9088 pw.print(": last crashed ");
9089 pw.print((now-uids.valueAt(i)));
9090 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009091 }
9092 }
9093 }
9094
9095 if (mBadProcesses.getMap().size() > 0) {
9096 if (needSep) pw.println(" ");
9097 needSep = true;
9098 pw.println(" Bad processes:");
9099 for (Map.Entry<String, SparseArray<Long>> procs
9100 : mBadProcesses.getMap().entrySet()) {
9101 SparseArray<Long> uids = procs.getValue();
9102 final int N = uids.size();
9103 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009104 pw.print(" Bad process "); pw.print(procs.getKey());
9105 pw.print(" uid "); pw.print(uids.keyAt(i));
9106 pw.print(": crashed at time ");
9107 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009108 }
9109 }
9110 }
9111
9112 pw.println(" ");
9113 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009114 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009115 pw.println(" mConfiguration: " + mConfiguration);
9116 pw.println(" mStartRunning=" + mStartRunning
9117 + " mSystemReady=" + mSystemReady
9118 + " mBooting=" + mBooting
9119 + " mBooted=" + mBooted
9120 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009121 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009122 pw.println(" mGoingToSleep=" + mGoingToSleep);
9123 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9124 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9125 + " mDebugTransient=" + mDebugTransient
9126 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9127 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009128 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009129 }
9130 }
9131
9132 /**
9133 * There are three ways to call this:
9134 * - no service specified: dump all the services
9135 * - a flattened component name that matched an existing service was specified as the
9136 * first arg: dump that one service
9137 * - the first arg isn't the flattened component name of an existing service:
9138 * dump all services whose component contains the first arg as a substring
9139 */
9140 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9141 String[] newArgs;
9142 String componentNameString;
9143 ServiceRecord r;
9144 if (args.length == 1) {
9145 componentNameString = null;
9146 newArgs = EMPTY_STRING_ARRAY;
9147 r = null;
9148 } else {
9149 componentNameString = args[1];
9150 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9151 r = componentName != null ? mServices.get(componentName) : null;
9152 newArgs = new String[args.length - 2];
9153 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9154 }
9155
9156 if (r != null) {
9157 dumpService(fd, pw, r, newArgs);
9158 } else {
9159 for (ServiceRecord r1 : mServices.values()) {
9160 if (componentNameString == null
9161 || r1.name.flattenToString().contains(componentNameString)) {
9162 dumpService(fd, pw, r1, newArgs);
9163 }
9164 }
9165 }
9166 }
9167
9168 /**
9169 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9170 * there is a thread associated with the service.
9171 */
9172 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9173 pw.println(" Service " + r.name.flattenToString());
9174 if (r.app != null && r.app.thread != null) {
9175 try {
9176 // flush anything that is already in the PrintWriter since the thread is going
9177 // to write to the file descriptor directly
9178 pw.flush();
9179 r.app.thread.dumpService(fd, r, args);
9180 pw.print("\n");
9181 } catch (RemoteException e) {
9182 pw.println("got a RemoteException while dumping the service");
9183 }
9184 }
9185 }
9186
9187 void dumpBroadcasts(PrintWriter pw) {
9188 synchronized (this) {
9189 if (checkCallingPermission(android.Manifest.permission.DUMP)
9190 != PackageManager.PERMISSION_GRANTED) {
9191 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9192 + Binder.getCallingPid()
9193 + ", uid=" + Binder.getCallingUid()
9194 + " without permission "
9195 + android.Manifest.permission.DUMP);
9196 return;
9197 }
9198 pw.println("Broadcasts in Current Activity Manager State:");
9199
9200 if (mRegisteredReceivers.size() > 0) {
9201 pw.println(" ");
9202 pw.println(" Registered Receivers:");
9203 Iterator it = mRegisteredReceivers.values().iterator();
9204 while (it.hasNext()) {
9205 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009206 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009207 r.dump(pw, " ");
9208 }
9209 }
9210
9211 pw.println(" ");
9212 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009213 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009214
9215 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9216 || mPendingBroadcast != null) {
9217 if (mParallelBroadcasts.size() > 0) {
9218 pw.println(" ");
9219 pw.println(" Active broadcasts:");
9220 }
9221 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9222 pw.println(" Broadcast #" + i + ":");
9223 mParallelBroadcasts.get(i).dump(pw, " ");
9224 }
9225 if (mOrderedBroadcasts.size() > 0) {
9226 pw.println(" ");
9227 pw.println(" Active serialized broadcasts:");
9228 }
9229 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9230 pw.println(" Serialized Broadcast #" + i + ":");
9231 mOrderedBroadcasts.get(i).dump(pw, " ");
9232 }
9233 pw.println(" ");
9234 pw.println(" Pending broadcast:");
9235 if (mPendingBroadcast != null) {
9236 mPendingBroadcast.dump(pw, " ");
9237 } else {
9238 pw.println(" (null)");
9239 }
9240 }
9241
9242 pw.println(" ");
9243 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9244 if (mStickyBroadcasts != null) {
9245 pw.println(" ");
9246 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009247 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009248 for (Map.Entry<String, ArrayList<Intent>> ent
9249 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009250 pw.print(" * Sticky action "); pw.print(ent.getKey());
9251 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009252 ArrayList<Intent> intents = ent.getValue();
9253 final int N = intents.size();
9254 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009255 sb.setLength(0);
9256 sb.append(" Intent: ");
9257 intents.get(i).toShortString(sb, true, false);
9258 pw.println(sb.toString());
9259 Bundle bundle = intents.get(i).getExtras();
9260 if (bundle != null) {
9261 pw.print(" ");
9262 pw.println(bundle.toString());
9263 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009264 }
9265 }
9266 }
9267
9268 pw.println(" ");
9269 pw.println(" mHandler:");
9270 mHandler.dump(new PrintWriterPrinter(pw), " ");
9271 }
9272 }
9273
9274 void dumpServices(PrintWriter pw) {
9275 synchronized (this) {
9276 if (checkCallingPermission(android.Manifest.permission.DUMP)
9277 != PackageManager.PERMISSION_GRANTED) {
9278 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9279 + Binder.getCallingPid()
9280 + ", uid=" + Binder.getCallingUid()
9281 + " without permission "
9282 + android.Manifest.permission.DUMP);
9283 return;
9284 }
9285 pw.println("Services in Current Activity Manager State:");
9286
9287 boolean needSep = false;
9288
9289 if (mServices.size() > 0) {
9290 pw.println(" Active services:");
9291 Iterator<ServiceRecord> it = mServices.values().iterator();
9292 while (it.hasNext()) {
9293 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009294 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009295 r.dump(pw, " ");
9296 }
9297 needSep = true;
9298 }
9299
9300 if (mPendingServices.size() > 0) {
9301 if (needSep) pw.println(" ");
9302 pw.println(" Pending services:");
9303 for (int i=0; i<mPendingServices.size(); i++) {
9304 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009305 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009306 r.dump(pw, " ");
9307 }
9308 needSep = true;
9309 }
9310
9311 if (mRestartingServices.size() > 0) {
9312 if (needSep) pw.println(" ");
9313 pw.println(" Restarting services:");
9314 for (int i=0; i<mRestartingServices.size(); i++) {
9315 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009316 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009317 r.dump(pw, " ");
9318 }
9319 needSep = true;
9320 }
9321
9322 if (mStoppingServices.size() > 0) {
9323 if (needSep) pw.println(" ");
9324 pw.println(" Stopping services:");
9325 for (int i=0; i<mStoppingServices.size(); i++) {
9326 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009327 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009328 r.dump(pw, " ");
9329 }
9330 needSep = true;
9331 }
9332
9333 if (mServiceConnections.size() > 0) {
9334 if (needSep) pw.println(" ");
9335 pw.println(" Connection bindings to services:");
9336 Iterator<ConnectionRecord> it
9337 = mServiceConnections.values().iterator();
9338 while (it.hasNext()) {
9339 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009340 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009341 r.dump(pw, " ");
9342 }
9343 }
9344 }
9345 }
9346
9347 void dumpProviders(PrintWriter pw) {
9348 synchronized (this) {
9349 if (checkCallingPermission(android.Manifest.permission.DUMP)
9350 != PackageManager.PERMISSION_GRANTED) {
9351 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9352 + Binder.getCallingPid()
9353 + ", uid=" + Binder.getCallingUid()
9354 + " without permission "
9355 + android.Manifest.permission.DUMP);
9356 return;
9357 }
9358
9359 pw.println("Content Providers in Current Activity Manager State:");
9360
9361 boolean needSep = false;
9362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009363 if (mProvidersByClass.size() > 0) {
9364 if (needSep) pw.println(" ");
9365 pw.println(" Published content providers (by class):");
9366 Iterator it = mProvidersByClass.entrySet().iterator();
9367 while (it.hasNext()) {
9368 Map.Entry e = (Map.Entry)it.next();
9369 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009370 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009371 r.dump(pw, " ");
9372 }
9373 needSep = true;
9374 }
9375
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009376 if (mProvidersByName.size() > 0) {
9377 pw.println(" ");
9378 pw.println(" Authority to provider mappings:");
9379 Iterator it = mProvidersByName.entrySet().iterator();
9380 while (it.hasNext()) {
9381 Map.Entry e = (Map.Entry)it.next();
9382 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9383 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9384 pw.println(r);
9385 }
9386 needSep = true;
9387 }
9388
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009389 if (mLaunchingProviders.size() > 0) {
9390 if (needSep) pw.println(" ");
9391 pw.println(" Launching content providers:");
9392 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009393 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9394 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009395 }
9396 needSep = true;
9397 }
9398
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009399 if (mGrantedUriPermissions.size() > 0) {
9400 pw.println();
9401 pw.println("Granted Uri Permissions:");
9402 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9403 int uid = mGrantedUriPermissions.keyAt(i);
9404 HashMap<Uri, UriPermission> perms
9405 = mGrantedUriPermissions.valueAt(i);
9406 pw.print(" * UID "); pw.print(uid);
9407 pw.println(" holds:");
9408 for (UriPermission perm : perms.values()) {
9409 pw.print(" "); pw.println(perm);
9410 perm.dump(pw, " ");
9411 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009412 }
9413 }
9414 }
9415 }
9416
9417 void dumpSenders(PrintWriter pw) {
9418 synchronized (this) {
9419 if (checkCallingPermission(android.Manifest.permission.DUMP)
9420 != PackageManager.PERMISSION_GRANTED) {
9421 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9422 + Binder.getCallingPid()
9423 + ", uid=" + Binder.getCallingUid()
9424 + " without permission "
9425 + android.Manifest.permission.DUMP);
9426 return;
9427 }
9428
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009429 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009430
9431 if (this.mIntentSenderRecords.size() > 0) {
9432 Iterator<WeakReference<PendingIntentRecord>> it
9433 = mIntentSenderRecords.values().iterator();
9434 while (it.hasNext()) {
9435 WeakReference<PendingIntentRecord> ref = it.next();
9436 PendingIntentRecord rec = ref != null ? ref.get(): null;
9437 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009438 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009439 rec.dump(pw, " ");
9440 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009441 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009442 }
9443 }
9444 }
9445 }
9446 }
9447
9448 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009449 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009450 TaskRecord lastTask = null;
9451 for (int i=list.size()-1; i>=0; i--) {
9452 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009453 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009454 if (lastTask != r.task) {
9455 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009456 pw.print(prefix);
9457 pw.print(full ? "* " : " ");
9458 pw.println(lastTask);
9459 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009460 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009461 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009462 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009463 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9464 pw.print(" #"); pw.print(i); pw.print(": ");
9465 pw.println(r);
9466 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009467 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009468 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009469 }
9470 }
9471
9472 private static final int dumpProcessList(PrintWriter pw, List list,
9473 String prefix, String normalLabel, String persistentLabel,
9474 boolean inclOomAdj) {
9475 int numPers = 0;
9476 for (int i=list.size()-1; i>=0; i--) {
9477 ProcessRecord r = (ProcessRecord)list.get(i);
9478 if (false) {
9479 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9480 + " #" + i + ":");
9481 r.dump(pw, prefix + " ");
9482 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009483 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009484 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009485 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9486 if (r.adjSource != null || r.adjTarget != null) {
9487 pw.println(prefix + " " + r.adjTarget
9488 + " used by " + r.adjSource);
9489 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009490 } else {
9491 pw.println(String.format("%s%s #%2d: %s",
9492 prefix, (r.persistent ? persistentLabel : normalLabel),
9493 i, r.toString()));
9494 }
9495 if (r.persistent) {
9496 numPers++;
9497 }
9498 }
9499 return numPers;
9500 }
9501
9502 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9503 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009504 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009505 long uptime = SystemClock.uptimeMillis();
9506 long realtime = SystemClock.elapsedRealtime();
9507
9508 if (isCheckinRequest) {
9509 // short checkin version
9510 pw.println(uptime + "," + realtime);
9511 pw.flush();
9512 } else {
9513 pw.println("Applications Memory Usage (kB):");
9514 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9515 }
9516 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9517 ProcessRecord r = (ProcessRecord)list.get(i);
9518 if (r.thread != null) {
9519 if (!isCheckinRequest) {
9520 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9521 pw.flush();
9522 }
9523 try {
9524 r.thread.asBinder().dump(fd, args);
9525 } catch (RemoteException e) {
9526 if (!isCheckinRequest) {
9527 pw.println("Got RemoteException!");
9528 pw.flush();
9529 }
9530 }
9531 }
9532 }
9533 }
9534
9535 /**
9536 * Searches array of arguments for the specified string
9537 * @param args array of argument strings
9538 * @param value value to search for
9539 * @return true if the value is contained in the array
9540 */
9541 private static boolean scanArgs(String[] args, String value) {
9542 if (args != null) {
9543 for (String arg : args) {
9544 if (value.equals(arg)) {
9545 return true;
9546 }
9547 }
9548 }
9549 return false;
9550 }
9551
Dianne Hackborn75b03852009-06-12 15:43:26 -07009552 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009553 int count = mHistory.size();
9554
9555 // convert the token to an entry in the history.
9556 HistoryRecord r = null;
9557 int index = -1;
9558 for (int i=count-1; i>=0; i--) {
9559 Object o = mHistory.get(i);
9560 if (o == token) {
9561 r = (HistoryRecord)o;
9562 index = i;
9563 break;
9564 }
9565 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009566
9567 return index;
9568 }
9569
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009570 private final void killServicesLocked(ProcessRecord app,
9571 boolean allowRestart) {
9572 // Report disconnected services.
9573 if (false) {
9574 // XXX we are letting the client link to the service for
9575 // death notifications.
9576 if (app.services.size() > 0) {
9577 Iterator it = app.services.iterator();
9578 while (it.hasNext()) {
9579 ServiceRecord r = (ServiceRecord)it.next();
9580 if (r.connections.size() > 0) {
9581 Iterator<ConnectionRecord> jt
9582 = r.connections.values().iterator();
9583 while (jt.hasNext()) {
9584 ConnectionRecord c = jt.next();
9585 if (c.binding.client != app) {
9586 try {
9587 //c.conn.connected(r.className, null);
9588 } catch (Exception e) {
9589 // todo: this should be asynchronous!
9590 Log.w(TAG, "Exception thrown disconnected servce "
9591 + r.shortName
9592 + " from app " + app.processName, e);
9593 }
9594 }
9595 }
9596 }
9597 }
9598 }
9599 }
9600
9601 // Clean up any connections this application has to other services.
9602 if (app.connections.size() > 0) {
9603 Iterator<ConnectionRecord> it = app.connections.iterator();
9604 while (it.hasNext()) {
9605 ConnectionRecord r = it.next();
9606 removeConnectionLocked(r, app, null);
9607 }
9608 }
9609 app.connections.clear();
9610
9611 if (app.services.size() != 0) {
9612 // Any services running in the application need to be placed
9613 // back in the pending list.
9614 Iterator it = app.services.iterator();
9615 while (it.hasNext()) {
9616 ServiceRecord sr = (ServiceRecord)it.next();
9617 synchronized (sr.stats.getBatteryStats()) {
9618 sr.stats.stopLaunchedLocked();
9619 }
9620 sr.app = null;
9621 sr.executeNesting = 0;
9622 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009623
9624 boolean hasClients = sr.bindings.size() > 0;
9625 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009626 Iterator<IntentBindRecord> bindings
9627 = sr.bindings.values().iterator();
9628 while (bindings.hasNext()) {
9629 IntentBindRecord b = bindings.next();
9630 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9631 + ": shouldUnbind=" + b.hasBound);
9632 b.binder = null;
9633 b.requested = b.received = b.hasBound = false;
9634 }
9635 }
9636
9637 if (sr.crashCount >= 2) {
9638 Log.w(TAG, "Service crashed " + sr.crashCount
9639 + " times, stopping: " + sr);
9640 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9641 sr.crashCount, sr.shortName, app.pid);
9642 bringDownServiceLocked(sr, true);
9643 } else if (!allowRestart) {
9644 bringDownServiceLocked(sr, true);
9645 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009646 boolean canceled = scheduleServiceRestartLocked(sr, true);
9647
9648 // Should the service remain running? Note that in the
9649 // extreme case of so many attempts to deliver a command
9650 // that it failed, that we also will stop it here.
9651 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9652 if (sr.pendingStarts.size() == 0) {
9653 sr.startRequested = false;
9654 if (!hasClients) {
9655 // Whoops, no reason to restart!
9656 bringDownServiceLocked(sr, true);
9657 }
9658 }
9659 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009660 }
9661 }
9662
9663 if (!allowRestart) {
9664 app.services.clear();
9665 }
9666 }
9667
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009668 // Make sure we have no more records on the stopping list.
9669 int i = mStoppingServices.size();
9670 while (i > 0) {
9671 i--;
9672 ServiceRecord sr = mStoppingServices.get(i);
9673 if (sr.app == app) {
9674 mStoppingServices.remove(i);
9675 }
9676 }
9677
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009678 app.executingServices.clear();
9679 }
9680
9681 private final void removeDyingProviderLocked(ProcessRecord proc,
9682 ContentProviderRecord cpr) {
9683 synchronized (cpr) {
9684 cpr.launchingApp = null;
9685 cpr.notifyAll();
9686 }
9687
9688 mProvidersByClass.remove(cpr.info.name);
9689 String names[] = cpr.info.authority.split(";");
9690 for (int j = 0; j < names.length; j++) {
9691 mProvidersByName.remove(names[j]);
9692 }
9693
9694 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9695 while (cit.hasNext()) {
9696 ProcessRecord capp = cit.next();
9697 if (!capp.persistent && capp.thread != null
9698 && capp.pid != 0
9699 && capp.pid != MY_PID) {
9700 Log.i(TAG, "Killing app " + capp.processName
9701 + " (pid " + capp.pid
9702 + ") because provider " + cpr.info.name
9703 + " is in dying process " + proc.processName);
9704 Process.killProcess(capp.pid);
9705 }
9706 }
9707
9708 mLaunchingProviders.remove(cpr);
9709 }
9710
9711 /**
9712 * Main code for cleaning up a process when it has gone away. This is
9713 * called both as a result of the process dying, or directly when stopping
9714 * a process when running in single process mode.
9715 */
9716 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9717 boolean restarting, int index) {
9718 if (index >= 0) {
9719 mLRUProcesses.remove(index);
9720 }
9721
9722 // Dismiss any open dialogs.
9723 if (app.crashDialog != null) {
9724 app.crashDialog.dismiss();
9725 app.crashDialog = null;
9726 }
9727 if (app.anrDialog != null) {
9728 app.anrDialog.dismiss();
9729 app.anrDialog = null;
9730 }
9731 if (app.waitDialog != null) {
9732 app.waitDialog.dismiss();
9733 app.waitDialog = null;
9734 }
9735
9736 app.crashing = false;
9737 app.notResponding = false;
9738
9739 app.resetPackageList();
9740 app.thread = null;
9741 app.forcingToForeground = null;
9742 app.foregroundServices = false;
9743
9744 killServicesLocked(app, true);
9745
9746 boolean restart = false;
9747
9748 int NL = mLaunchingProviders.size();
9749
9750 // Remove published content providers.
9751 if (!app.pubProviders.isEmpty()) {
9752 Iterator it = app.pubProviders.values().iterator();
9753 while (it.hasNext()) {
9754 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9755 cpr.provider = null;
9756 cpr.app = null;
9757
9758 // See if someone is waiting for this provider... in which
9759 // case we don't remove it, but just let it restart.
9760 int i = 0;
9761 if (!app.bad) {
9762 for (; i<NL; i++) {
9763 if (mLaunchingProviders.get(i) == cpr) {
9764 restart = true;
9765 break;
9766 }
9767 }
9768 } else {
9769 i = NL;
9770 }
9771
9772 if (i >= NL) {
9773 removeDyingProviderLocked(app, cpr);
9774 NL = mLaunchingProviders.size();
9775 }
9776 }
9777 app.pubProviders.clear();
9778 }
9779
9780 // Look through the content providers we are waiting to have launched,
9781 // and if any run in this process then either schedule a restart of
9782 // the process or kill the client waiting for it if this process has
9783 // gone bad.
9784 for (int i=0; i<NL; i++) {
9785 ContentProviderRecord cpr = (ContentProviderRecord)
9786 mLaunchingProviders.get(i);
9787 if (cpr.launchingApp == app) {
9788 if (!app.bad) {
9789 restart = true;
9790 } else {
9791 removeDyingProviderLocked(app, cpr);
9792 NL = mLaunchingProviders.size();
9793 }
9794 }
9795 }
9796
9797 // Unregister from connected content providers.
9798 if (!app.conProviders.isEmpty()) {
9799 Iterator it = app.conProviders.iterator();
9800 while (it.hasNext()) {
9801 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9802 cpr.clients.remove(app);
9803 }
9804 app.conProviders.clear();
9805 }
9806
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009807 // At this point there may be remaining entries in mLaunchingProviders
9808 // where we were the only one waiting, so they are no longer of use.
9809 // Look for these and clean up if found.
9810 // XXX Commented out for now. Trying to figure out a way to reproduce
9811 // the actual situation to identify what is actually going on.
9812 if (false) {
9813 for (int i=0; i<NL; i++) {
9814 ContentProviderRecord cpr = (ContentProviderRecord)
9815 mLaunchingProviders.get(i);
9816 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9817 synchronized (cpr) {
9818 cpr.launchingApp = null;
9819 cpr.notifyAll();
9820 }
9821 }
9822 }
9823 }
9824
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009825 skipCurrentReceiverLocked(app);
9826
9827 // Unregister any receivers.
9828 if (app.receivers.size() > 0) {
9829 Iterator<ReceiverList> it = app.receivers.iterator();
9830 while (it.hasNext()) {
9831 removeReceiverLocked(it.next());
9832 }
9833 app.receivers.clear();
9834 }
9835
Christopher Tate181fafa2009-05-14 11:12:14 -07009836 // If the app is undergoing backup, tell the backup manager about it
9837 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9838 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9839 try {
9840 IBackupManager bm = IBackupManager.Stub.asInterface(
9841 ServiceManager.getService(Context.BACKUP_SERVICE));
9842 bm.agentDisconnected(app.info.packageName);
9843 } catch (RemoteException e) {
9844 // can't happen; backup manager is local
9845 }
9846 }
9847
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009848 // If the caller is restarting this app, then leave it in its
9849 // current lists and let the caller take care of it.
9850 if (restarting) {
9851 return;
9852 }
9853
9854 if (!app.persistent) {
9855 if (DEBUG_PROCESSES) Log.v(TAG,
9856 "Removing non-persistent process during cleanup: " + app);
9857 mProcessNames.remove(app.processName, app.info.uid);
9858 } else if (!app.removed) {
9859 // This app is persistent, so we need to keep its record around.
9860 // If it is not already on the pending app list, add it there
9861 // and start a new process for it.
9862 app.thread = null;
9863 app.forcingToForeground = null;
9864 app.foregroundServices = false;
9865 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9866 mPersistentStartingProcesses.add(app);
9867 restart = true;
9868 }
9869 }
9870 mProcessesOnHold.remove(app);
9871
The Android Open Source Project4df24232009-03-05 14:34:35 -08009872 if (app == mHomeProcess) {
9873 mHomeProcess = null;
9874 }
9875
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009876 if (restart) {
9877 // We have components that still need to be running in the
9878 // process, so re-launch it.
9879 mProcessNames.put(app.processName, app.info.uid, app);
9880 startProcessLocked(app, "restart", app.processName);
9881 } else if (app.pid > 0 && app.pid != MY_PID) {
9882 // Goodbye!
9883 synchronized (mPidsSelfLocked) {
9884 mPidsSelfLocked.remove(app.pid);
9885 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9886 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009887 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009888 }
9889 }
9890
9891 // =========================================================
9892 // SERVICES
9893 // =========================================================
9894
9895 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9896 ActivityManager.RunningServiceInfo info =
9897 new ActivityManager.RunningServiceInfo();
9898 info.service = r.name;
9899 if (r.app != null) {
9900 info.pid = r.app.pid;
9901 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -07009902 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009903 info.process = r.processName;
9904 info.foreground = r.isForeground;
9905 info.activeSince = r.createTime;
9906 info.started = r.startRequested;
9907 info.clientCount = r.connections.size();
9908 info.crashCount = r.crashCount;
9909 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07009910 if (r.isForeground) {
9911 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
9912 }
9913 if (r.startRequested) {
9914 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
9915 }
9916 if (r.app != null && r.app.pid == Process.myPid()) {
9917 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
9918 }
9919 if (r.app != null && r.app.persistent) {
9920 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
9921 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009922 for (ConnectionRecord conn : r.connections.values()) {
9923 if (conn.clientLabel != 0) {
9924 info.clientPackage = conn.binding.client.info.packageName;
9925 info.clientLabel = conn.clientLabel;
9926 break;
9927 }
9928 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009929 return info;
9930 }
9931
9932 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9933 int flags) {
9934 synchronized (this) {
9935 ArrayList<ActivityManager.RunningServiceInfo> res
9936 = new ArrayList<ActivityManager.RunningServiceInfo>();
9937
9938 if (mServices.size() > 0) {
9939 Iterator<ServiceRecord> it = mServices.values().iterator();
9940 while (it.hasNext() && res.size() < maxNum) {
9941 res.add(makeRunningServiceInfoLocked(it.next()));
9942 }
9943 }
9944
9945 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9946 ServiceRecord r = mRestartingServices.get(i);
9947 ActivityManager.RunningServiceInfo info =
9948 makeRunningServiceInfoLocked(r);
9949 info.restarting = r.nextRestartTime;
9950 res.add(info);
9951 }
9952
9953 return res;
9954 }
9955 }
9956
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009957 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
9958 synchronized (this) {
9959 ServiceRecord r = mServices.get(name);
9960 if (r != null) {
9961 for (ConnectionRecord conn : r.connections.values()) {
9962 if (conn.clientIntent != null) {
9963 return conn.clientIntent;
9964 }
9965 }
9966 }
9967 }
9968 return null;
9969 }
9970
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009971 private final ServiceRecord findServiceLocked(ComponentName name,
9972 IBinder token) {
9973 ServiceRecord r = mServices.get(name);
9974 return r == token ? r : null;
9975 }
9976
9977 private final class ServiceLookupResult {
9978 final ServiceRecord record;
9979 final String permission;
9980
9981 ServiceLookupResult(ServiceRecord _record, String _permission) {
9982 record = _record;
9983 permission = _permission;
9984 }
9985 };
9986
9987 private ServiceLookupResult findServiceLocked(Intent service,
9988 String resolvedType) {
9989 ServiceRecord r = null;
9990 if (service.getComponent() != null) {
9991 r = mServices.get(service.getComponent());
9992 }
9993 if (r == null) {
9994 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9995 r = mServicesByIntent.get(filter);
9996 }
9997
9998 if (r == null) {
9999 try {
10000 ResolveInfo rInfo =
10001 ActivityThread.getPackageManager().resolveService(
10002 service, resolvedType, 0);
10003 ServiceInfo sInfo =
10004 rInfo != null ? rInfo.serviceInfo : null;
10005 if (sInfo == null) {
10006 return null;
10007 }
10008
10009 ComponentName name = new ComponentName(
10010 sInfo.applicationInfo.packageName, sInfo.name);
10011 r = mServices.get(name);
10012 } catch (RemoteException ex) {
10013 // pm is in same process, this will never happen.
10014 }
10015 }
10016 if (r != null) {
10017 int callingPid = Binder.getCallingPid();
10018 int callingUid = Binder.getCallingUid();
10019 if (checkComponentPermission(r.permission,
10020 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10021 != PackageManager.PERMISSION_GRANTED) {
10022 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10023 + " from pid=" + callingPid
10024 + ", uid=" + callingUid
10025 + " requires " + r.permission);
10026 return new ServiceLookupResult(null, r.permission);
10027 }
10028 return new ServiceLookupResult(r, null);
10029 }
10030 return null;
10031 }
10032
10033 private class ServiceRestarter implements Runnable {
10034 private ServiceRecord mService;
10035
10036 void setService(ServiceRecord service) {
10037 mService = service;
10038 }
10039
10040 public void run() {
10041 synchronized(ActivityManagerService.this) {
10042 performServiceRestartLocked(mService);
10043 }
10044 }
10045 }
10046
10047 private ServiceLookupResult retrieveServiceLocked(Intent service,
10048 String resolvedType, int callingPid, int callingUid) {
10049 ServiceRecord r = null;
10050 if (service.getComponent() != null) {
10051 r = mServices.get(service.getComponent());
10052 }
10053 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10054 r = mServicesByIntent.get(filter);
10055 if (r == null) {
10056 try {
10057 ResolveInfo rInfo =
10058 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010059 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010060 ServiceInfo sInfo =
10061 rInfo != null ? rInfo.serviceInfo : null;
10062 if (sInfo == null) {
10063 Log.w(TAG, "Unable to start service " + service +
10064 ": not found");
10065 return null;
10066 }
10067
10068 ComponentName name = new ComponentName(
10069 sInfo.applicationInfo.packageName, sInfo.name);
10070 r = mServices.get(name);
10071 if (r == null) {
10072 filter = new Intent.FilterComparison(service.cloneFilter());
10073 ServiceRestarter res = new ServiceRestarter();
10074 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10075 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10076 synchronized (stats) {
10077 ss = stats.getServiceStatsLocked(
10078 sInfo.applicationInfo.uid, sInfo.packageName,
10079 sInfo.name);
10080 }
10081 r = new ServiceRecord(ss, name, filter, sInfo, res);
10082 res.setService(r);
10083 mServices.put(name, r);
10084 mServicesByIntent.put(filter, r);
10085
10086 // Make sure this component isn't in the pending list.
10087 int N = mPendingServices.size();
10088 for (int i=0; i<N; i++) {
10089 ServiceRecord pr = mPendingServices.get(i);
10090 if (pr.name.equals(name)) {
10091 mPendingServices.remove(i);
10092 i--;
10093 N--;
10094 }
10095 }
10096 }
10097 } catch (RemoteException ex) {
10098 // pm is in same process, this will never happen.
10099 }
10100 }
10101 if (r != null) {
10102 if (checkComponentPermission(r.permission,
10103 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10104 != PackageManager.PERMISSION_GRANTED) {
10105 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10106 + " from pid=" + Binder.getCallingPid()
10107 + ", uid=" + Binder.getCallingUid()
10108 + " requires " + r.permission);
10109 return new ServiceLookupResult(null, r.permission);
10110 }
10111 return new ServiceLookupResult(r, null);
10112 }
10113 return null;
10114 }
10115
10116 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10117 long now = SystemClock.uptimeMillis();
10118 if (r.executeNesting == 0 && r.app != null) {
10119 if (r.app.executingServices.size() == 0) {
10120 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10121 msg.obj = r.app;
10122 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10123 }
10124 r.app.executingServices.add(r);
10125 }
10126 r.executeNesting++;
10127 r.executingStart = now;
10128 }
10129
10130 private final void sendServiceArgsLocked(ServiceRecord r,
10131 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010132 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010133 if (N == 0) {
10134 return;
10135 }
10136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010137 int i = 0;
10138 while (i < N) {
10139 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010140 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010141 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010142 + r.name + " " + r.intent + " args=" + si.intent);
10143 if (si.intent == null && N > 0) {
10144 // If somehow we got a dummy start at the front, then
10145 // just drop it here.
10146 i++;
10147 continue;
10148 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010149 bumpServiceExecutingLocked(r);
10150 if (!oomAdjusted) {
10151 oomAdjusted = true;
10152 updateOomAdjLocked(r.app);
10153 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010154 int flags = 0;
10155 if (si.deliveryCount > 0) {
10156 flags |= Service.START_FLAG_RETRY;
10157 }
10158 if (si.doneExecutingCount > 0) {
10159 flags |= Service.START_FLAG_REDELIVERY;
10160 }
10161 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10162 si.deliveredTime = SystemClock.uptimeMillis();
10163 r.deliveredStarts.add(si);
10164 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010165 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010166 } catch (RemoteException e) {
10167 // Remote process gone... we'll let the normal cleanup take
10168 // care of this.
10169 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010170 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010171 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010172 break;
10173 }
10174 }
10175 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010176 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010177 } else {
10178 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010179 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010180 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010181 }
10182 }
10183 }
10184
10185 private final boolean requestServiceBindingLocked(ServiceRecord r,
10186 IntentBindRecord i, boolean rebind) {
10187 if (r.app == null || r.app.thread == null) {
10188 // If service is not currently running, can't yet bind.
10189 return false;
10190 }
10191 if ((!i.requested || rebind) && i.apps.size() > 0) {
10192 try {
10193 bumpServiceExecutingLocked(r);
10194 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10195 + ": shouldUnbind=" + i.hasBound);
10196 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10197 if (!rebind) {
10198 i.requested = true;
10199 }
10200 i.hasBound = true;
10201 i.doRebind = false;
10202 } catch (RemoteException e) {
10203 return false;
10204 }
10205 }
10206 return true;
10207 }
10208
10209 private final void requestServiceBindingsLocked(ServiceRecord r) {
10210 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10211 while (bindings.hasNext()) {
10212 IntentBindRecord i = bindings.next();
10213 if (!requestServiceBindingLocked(r, i, false)) {
10214 break;
10215 }
10216 }
10217 }
10218
10219 private final void realStartServiceLocked(ServiceRecord r,
10220 ProcessRecord app) throws RemoteException {
10221 if (app.thread == null) {
10222 throw new RemoteException();
10223 }
10224
10225 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010226 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010227
10228 app.services.add(r);
10229 bumpServiceExecutingLocked(r);
10230 updateLRUListLocked(app, true);
10231
10232 boolean created = false;
10233 try {
10234 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10235 + r.name + " " + r.intent);
10236 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
10237 System.identityHashCode(r), r.shortName,
10238 r.intent.getIntent().toString(), r.app.pid);
10239 synchronized (r.stats.getBatteryStats()) {
10240 r.stats.startLaunchedLocked();
10241 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010242 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010243 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010244 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010245 created = true;
10246 } finally {
10247 if (!created) {
10248 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010249 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010250 }
10251 }
10252
10253 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010254
10255 // If the service is in the started state, and there are no
10256 // pending arguments, then fake up one so its onStartCommand() will
10257 // be called.
10258 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10259 r.lastStartId++;
10260 if (r.lastStartId < 1) {
10261 r.lastStartId = 1;
10262 }
10263 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10264 }
10265
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010266 sendServiceArgsLocked(r, true);
10267 }
10268
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010269 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10270 boolean allowCancel) {
10271 boolean canceled = false;
10272
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010273 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010274 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010275 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010276
10277 // Any delivered but not yet finished starts should be put back
10278 // on the pending list.
10279 final int N = r.deliveredStarts.size();
10280 if (N > 0) {
10281 for (int i=N-1; i>=0; i--) {
10282 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10283 if (si.intent == null) {
10284 // We'll generate this again if needed.
10285 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10286 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10287 r.pendingStarts.add(0, si);
10288 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10289 dur *= 2;
10290 if (minDuration < dur) minDuration = dur;
10291 if (resetTime < dur) resetTime = dur;
10292 } else {
10293 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10294 + r.name);
10295 canceled = true;
10296 }
10297 }
10298 r.deliveredStarts.clear();
10299 }
10300
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010301 r.totalRestartCount++;
10302 if (r.restartDelay == 0) {
10303 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010304 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010305 } else {
10306 // If it has been a "reasonably long time" since the service
10307 // was started, then reset our restart duration back to
10308 // the beginning, so we don't infinitely increase the duration
10309 // on a service that just occasionally gets killed (which is
10310 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010311 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010312 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010313 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010314 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010315 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010316 if (r.restartDelay < minDuration) {
10317 r.restartDelay = minDuration;
10318 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010319 }
10320 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010321
10322 r.nextRestartTime = now + r.restartDelay;
10323
10324 // Make sure that we don't end up restarting a bunch of services
10325 // all at the same time.
10326 boolean repeat;
10327 do {
10328 repeat = false;
10329 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10330 ServiceRecord r2 = mRestartingServices.get(i);
10331 if (r2 != r && r.nextRestartTime
10332 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10333 && r.nextRestartTime
10334 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10335 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10336 r.restartDelay = r.nextRestartTime - now;
10337 repeat = true;
10338 break;
10339 }
10340 }
10341 } while (repeat);
10342
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010343 if (!mRestartingServices.contains(r)) {
10344 mRestartingServices.add(r);
10345 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010346
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010347 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010349 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010350 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010351 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10352 Log.w(TAG, "Scheduling restart of crashed service "
10353 + r.shortName + " in " + r.restartDelay + "ms");
10354 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10355 r.shortName, r.restartDelay);
10356
10357 Message msg = Message.obtain();
10358 msg.what = SERVICE_ERROR_MSG;
10359 msg.obj = r;
10360 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010361
10362 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010363 }
10364
10365 final void performServiceRestartLocked(ServiceRecord r) {
10366 if (!mRestartingServices.contains(r)) {
10367 return;
10368 }
10369 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10370 }
10371
10372 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10373 if (r.restartDelay == 0) {
10374 return false;
10375 }
10376 r.resetRestartCounter();
10377 mRestartingServices.remove(r);
10378 mHandler.removeCallbacks(r.restarter);
10379 return true;
10380 }
10381
10382 private final boolean bringUpServiceLocked(ServiceRecord r,
10383 int intentFlags, boolean whileRestarting) {
10384 //Log.i(TAG, "Bring up service:");
10385 //r.dump(" ");
10386
10387 if (r.app != null) {
10388 sendServiceArgsLocked(r, false);
10389 return true;
10390 }
10391
10392 if (!whileRestarting && r.restartDelay > 0) {
10393 // If waiting for a restart, then do nothing.
10394 return true;
10395 }
10396
10397 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10398 + " " + r.intent);
10399
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010400 // We are now bringing the service up, so no longer in the
10401 // restarting state.
10402 mRestartingServices.remove(r);
10403
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010404 final String appName = r.processName;
10405 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10406 if (app != null && app.thread != null) {
10407 try {
10408 realStartServiceLocked(r, app);
10409 return true;
10410 } catch (RemoteException e) {
10411 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10412 }
10413
10414 // If a dead object exception was thrown -- fall through to
10415 // restart the application.
10416 }
10417
10418 if (!mPendingServices.contains(r)) {
10419 // Not running -- get it started, and enqueue this service record
10420 // to be executed when the app comes up.
10421 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070010422 "service", r.name, false) == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010423 Log.w(TAG, "Unable to launch app "
10424 + r.appInfo.packageName + "/"
10425 + r.appInfo.uid + " for service "
10426 + r.intent.getIntent() + ": process is bad");
10427 bringDownServiceLocked(r, true);
10428 return false;
10429 }
10430 mPendingServices.add(r);
10431 }
10432 return true;
10433 }
10434
10435 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10436 //Log.i(TAG, "Bring down service:");
10437 //r.dump(" ");
10438
10439 // Does it still need to run?
10440 if (!force && r.startRequested) {
10441 return;
10442 }
10443 if (r.connections.size() > 0) {
10444 if (!force) {
10445 // XXX should probably keep a count of the number of auto-create
10446 // connections directly in the service.
10447 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10448 while (it.hasNext()) {
10449 ConnectionRecord cr = it.next();
10450 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10451 return;
10452 }
10453 }
10454 }
10455
10456 // Report to all of the connections that the service is no longer
10457 // available.
10458 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10459 while (it.hasNext()) {
10460 ConnectionRecord c = it.next();
10461 try {
10462 // todo: shouldn't be a synchronous call!
10463 c.conn.connected(r.name, null);
10464 } catch (Exception e) {
10465 Log.w(TAG, "Failure disconnecting service " + r.name +
10466 " to connection " + c.conn.asBinder() +
10467 " (in " + c.binding.client.processName + ")", e);
10468 }
10469 }
10470 }
10471
10472 // Tell the service that it has been unbound.
10473 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10474 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10475 while (it.hasNext()) {
10476 IntentBindRecord ibr = it.next();
10477 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10478 + ": hasBound=" + ibr.hasBound);
10479 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10480 try {
10481 bumpServiceExecutingLocked(r);
10482 updateOomAdjLocked(r.app);
10483 ibr.hasBound = false;
10484 r.app.thread.scheduleUnbindService(r,
10485 ibr.intent.getIntent());
10486 } catch (Exception e) {
10487 Log.w(TAG, "Exception when unbinding service "
10488 + r.shortName, e);
10489 serviceDoneExecutingLocked(r, true);
10490 }
10491 }
10492 }
10493 }
10494
10495 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10496 + " " + r.intent);
10497 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10498 System.identityHashCode(r), r.shortName,
10499 (r.app != null) ? r.app.pid : -1);
10500
10501 mServices.remove(r.name);
10502 mServicesByIntent.remove(r.intent);
10503 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10504 r.totalRestartCount = 0;
10505 unscheduleServiceRestartLocked(r);
10506
10507 // Also make sure it is not on the pending list.
10508 int N = mPendingServices.size();
10509 for (int i=0; i<N; i++) {
10510 if (mPendingServices.get(i) == r) {
10511 mPendingServices.remove(i);
10512 if (DEBUG_SERVICE) Log.v(
10513 TAG, "Removed pending service: " + r.shortName);
10514 i--;
10515 N--;
10516 }
10517 }
10518
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010519 r.cancelNotification();
10520 r.isForeground = false;
10521 r.foregroundId = 0;
10522 r.foregroundNoti = null;
10523
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010524 // Clear start entries.
10525 r.deliveredStarts.clear();
10526 r.pendingStarts.clear();
10527
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010528 if (r.app != null) {
10529 synchronized (r.stats.getBatteryStats()) {
10530 r.stats.stopLaunchedLocked();
10531 }
10532 r.app.services.remove(r);
10533 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010534 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010535 if (DEBUG_SERVICE) Log.v(TAG,
10536 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010537 bumpServiceExecutingLocked(r);
10538 mStoppingServices.add(r);
10539 updateOomAdjLocked(r.app);
10540 r.app.thread.scheduleStopService(r);
10541 } catch (Exception e) {
10542 Log.w(TAG, "Exception when stopping service "
10543 + r.shortName, e);
10544 serviceDoneExecutingLocked(r, true);
10545 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010546 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010547 } else {
10548 if (DEBUG_SERVICE) Log.v(
10549 TAG, "Removed service that has no process: " + r.shortName);
10550 }
10551 } else {
10552 if (DEBUG_SERVICE) Log.v(
10553 TAG, "Removed service that is not running: " + r.shortName);
10554 }
10555 }
10556
10557 ComponentName startServiceLocked(IApplicationThread caller,
10558 Intent service, String resolvedType,
10559 int callingPid, int callingUid) {
10560 synchronized(this) {
10561 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10562 + " type=" + resolvedType + " args=" + service.getExtras());
10563
10564 if (caller != null) {
10565 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10566 if (callerApp == null) {
10567 throw new SecurityException(
10568 "Unable to find app for caller " + caller
10569 + " (pid=" + Binder.getCallingPid()
10570 + ") when starting service " + service);
10571 }
10572 }
10573
10574 ServiceLookupResult res =
10575 retrieveServiceLocked(service, resolvedType,
10576 callingPid, callingUid);
10577 if (res == null) {
10578 return null;
10579 }
10580 if (res.record == null) {
10581 return new ComponentName("!", res.permission != null
10582 ? res.permission : "private to package");
10583 }
10584 ServiceRecord r = res.record;
10585 if (unscheduleServiceRestartLocked(r)) {
10586 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10587 + r.shortName);
10588 }
10589 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010590 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010591 r.lastStartId++;
10592 if (r.lastStartId < 1) {
10593 r.lastStartId = 1;
10594 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010595 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010596 r.lastActivity = SystemClock.uptimeMillis();
10597 synchronized (r.stats.getBatteryStats()) {
10598 r.stats.startRunningLocked();
10599 }
10600 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10601 return new ComponentName("!", "Service process is bad");
10602 }
10603 return r.name;
10604 }
10605 }
10606
10607 public ComponentName startService(IApplicationThread caller, Intent service,
10608 String resolvedType) {
10609 // Refuse possible leaked file descriptors
10610 if (service != null && service.hasFileDescriptors() == true) {
10611 throw new IllegalArgumentException("File descriptors passed in Intent");
10612 }
10613
10614 synchronized(this) {
10615 final int callingPid = Binder.getCallingPid();
10616 final int callingUid = Binder.getCallingUid();
10617 final long origId = Binder.clearCallingIdentity();
10618 ComponentName res = startServiceLocked(caller, service,
10619 resolvedType, callingPid, callingUid);
10620 Binder.restoreCallingIdentity(origId);
10621 return res;
10622 }
10623 }
10624
10625 ComponentName startServiceInPackage(int uid,
10626 Intent service, String resolvedType) {
10627 synchronized(this) {
10628 final long origId = Binder.clearCallingIdentity();
10629 ComponentName res = startServiceLocked(null, service,
10630 resolvedType, -1, uid);
10631 Binder.restoreCallingIdentity(origId);
10632 return res;
10633 }
10634 }
10635
10636 public int stopService(IApplicationThread caller, Intent service,
10637 String resolvedType) {
10638 // Refuse possible leaked file descriptors
10639 if (service != null && service.hasFileDescriptors() == true) {
10640 throw new IllegalArgumentException("File descriptors passed in Intent");
10641 }
10642
10643 synchronized(this) {
10644 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10645 + " type=" + resolvedType);
10646
10647 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10648 if (caller != null && callerApp == null) {
10649 throw new SecurityException(
10650 "Unable to find app for caller " + caller
10651 + " (pid=" + Binder.getCallingPid()
10652 + ") when stopping service " + service);
10653 }
10654
10655 // If this service is active, make sure it is stopped.
10656 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10657 if (r != null) {
10658 if (r.record != null) {
10659 synchronized (r.record.stats.getBatteryStats()) {
10660 r.record.stats.stopRunningLocked();
10661 }
10662 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010663 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010664 final long origId = Binder.clearCallingIdentity();
10665 bringDownServiceLocked(r.record, false);
10666 Binder.restoreCallingIdentity(origId);
10667 return 1;
10668 }
10669 return -1;
10670 }
10671 }
10672
10673 return 0;
10674 }
10675
10676 public IBinder peekService(Intent service, String resolvedType) {
10677 // Refuse possible leaked file descriptors
10678 if (service != null && service.hasFileDescriptors() == true) {
10679 throw new IllegalArgumentException("File descriptors passed in Intent");
10680 }
10681
10682 IBinder ret = null;
10683
10684 synchronized(this) {
10685 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10686
10687 if (r != null) {
10688 // r.record is null if findServiceLocked() failed the caller permission check
10689 if (r.record == null) {
10690 throw new SecurityException(
10691 "Permission Denial: Accessing service " + r.record.name
10692 + " from pid=" + Binder.getCallingPid()
10693 + ", uid=" + Binder.getCallingUid()
10694 + " requires " + r.permission);
10695 }
10696 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10697 if (ib != null) {
10698 ret = ib.binder;
10699 }
10700 }
10701 }
10702
10703 return ret;
10704 }
10705
10706 public boolean stopServiceToken(ComponentName className, IBinder token,
10707 int startId) {
10708 synchronized(this) {
10709 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10710 + " " + token + " startId=" + startId);
10711 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010712 if (r != null) {
10713 if (startId >= 0) {
10714 // Asked to only stop if done with all work. Note that
10715 // to avoid leaks, we will take this as dropping all
10716 // start items up to and including this one.
10717 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10718 if (si != null) {
10719 while (r.deliveredStarts.size() > 0) {
10720 if (r.deliveredStarts.remove(0) == si) {
10721 break;
10722 }
10723 }
10724 }
10725
10726 if (r.lastStartId != startId) {
10727 return false;
10728 }
10729
10730 if (r.deliveredStarts.size() > 0) {
10731 Log.w(TAG, "stopServiceToken startId " + startId
10732 + " is last, but have " + r.deliveredStarts.size()
10733 + " remaining args");
10734 }
10735 }
10736
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010737 synchronized (r.stats.getBatteryStats()) {
10738 r.stats.stopRunningLocked();
10739 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010740 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010741 }
10742 final long origId = Binder.clearCallingIdentity();
10743 bringDownServiceLocked(r, false);
10744 Binder.restoreCallingIdentity(origId);
10745 return true;
10746 }
10747 }
10748 return false;
10749 }
10750
10751 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010752 int id, Notification notification, boolean removeNotification) {
10753 final long origId = Binder.clearCallingIdentity();
10754 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010755 synchronized(this) {
10756 ServiceRecord r = findServiceLocked(className, token);
10757 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010758 if (id != 0) {
10759 if (notification == null) {
10760 throw new IllegalArgumentException("null notification");
10761 }
10762 if (r.foregroundId != id) {
10763 r.cancelNotification();
10764 r.foregroundId = id;
10765 }
10766 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10767 r.foregroundNoti = notification;
10768 r.isForeground = true;
10769 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010770 if (r.app != null) {
10771 updateServiceForegroundLocked(r.app, true);
10772 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010773 } else {
10774 if (r.isForeground) {
10775 r.isForeground = false;
10776 if (r.app != null) {
10777 updateServiceForegroundLocked(r.app, true);
10778 }
10779 }
10780 if (removeNotification) {
10781 r.cancelNotification();
10782 r.foregroundId = 0;
10783 r.foregroundNoti = null;
10784 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010785 }
10786 }
10787 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010788 } finally {
10789 Binder.restoreCallingIdentity(origId);
10790 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010791 }
10792
10793 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10794 boolean anyForeground = false;
10795 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10796 if (sr.isForeground) {
10797 anyForeground = true;
10798 break;
10799 }
10800 }
10801 if (anyForeground != proc.foregroundServices) {
10802 proc.foregroundServices = anyForeground;
10803 if (oomAdj) {
10804 updateOomAdjLocked();
10805 }
10806 }
10807 }
10808
10809 public int bindService(IApplicationThread caller, IBinder token,
10810 Intent service, String resolvedType,
10811 IServiceConnection connection, int flags) {
10812 // Refuse possible leaked file descriptors
10813 if (service != null && service.hasFileDescriptors() == true) {
10814 throw new IllegalArgumentException("File descriptors passed in Intent");
10815 }
10816
10817 synchronized(this) {
10818 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10819 + " type=" + resolvedType + " conn=" + connection.asBinder()
10820 + " flags=0x" + Integer.toHexString(flags));
10821 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10822 if (callerApp == null) {
10823 throw new SecurityException(
10824 "Unable to find app for caller " + caller
10825 + " (pid=" + Binder.getCallingPid()
10826 + ") when binding service " + service);
10827 }
10828
10829 HistoryRecord activity = null;
10830 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010831 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010832 if (aindex < 0) {
10833 Log.w(TAG, "Binding with unknown activity: " + token);
10834 return 0;
10835 }
10836 activity = (HistoryRecord)mHistory.get(aindex);
10837 }
10838
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010839 int clientLabel = 0;
10840 PendingIntent clientIntent = null;
10841
10842 if (callerApp.info.uid == Process.SYSTEM_UID) {
10843 // Hacky kind of thing -- allow system stuff to tell us
10844 // what they are, so we can report this elsewhere for
10845 // others to know why certain services are running.
10846 try {
10847 clientIntent = (PendingIntent)service.getParcelableExtra(
10848 Intent.EXTRA_CLIENT_INTENT);
10849 } catch (RuntimeException e) {
10850 }
10851 if (clientIntent != null) {
10852 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
10853 if (clientLabel != 0) {
10854 // There are no useful extras in the intent, trash them.
10855 // System code calling with this stuff just needs to know
10856 // this will happen.
10857 service = service.cloneFilter();
10858 }
10859 }
10860 }
10861
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010862 ServiceLookupResult res =
10863 retrieveServiceLocked(service, resolvedType,
10864 Binder.getCallingPid(), Binder.getCallingUid());
10865 if (res == null) {
10866 return 0;
10867 }
10868 if (res.record == null) {
10869 return -1;
10870 }
10871 ServiceRecord s = res.record;
10872
10873 final long origId = Binder.clearCallingIdentity();
10874
10875 if (unscheduleServiceRestartLocked(s)) {
10876 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10877 + s.shortName);
10878 }
10879
10880 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10881 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010882 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010883
10884 IBinder binder = connection.asBinder();
10885 s.connections.put(binder, c);
10886 b.connections.add(c);
10887 if (activity != null) {
10888 if (activity.connections == null) {
10889 activity.connections = new HashSet<ConnectionRecord>();
10890 }
10891 activity.connections.add(c);
10892 }
10893 b.client.connections.add(c);
10894 mServiceConnections.put(binder, c);
10895
10896 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10897 s.lastActivity = SystemClock.uptimeMillis();
10898 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10899 return 0;
10900 }
10901 }
10902
10903 if (s.app != null) {
10904 // This could have made the service more important.
10905 updateOomAdjLocked(s.app);
10906 }
10907
10908 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10909 + ": received=" + b.intent.received
10910 + " apps=" + b.intent.apps.size()
10911 + " doRebind=" + b.intent.doRebind);
10912
10913 if (s.app != null && b.intent.received) {
10914 // Service is already running, so we can immediately
10915 // publish the connection.
10916 try {
10917 c.conn.connected(s.name, b.intent.binder);
10918 } catch (Exception e) {
10919 Log.w(TAG, "Failure sending service " + s.shortName
10920 + " to connection " + c.conn.asBinder()
10921 + " (in " + c.binding.client.processName + ")", e);
10922 }
10923
10924 // If this is the first app connected back to this binding,
10925 // and the service had previously asked to be told when
10926 // rebound, then do so.
10927 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10928 requestServiceBindingLocked(s, b.intent, true);
10929 }
10930 } else if (!b.intent.requested) {
10931 requestServiceBindingLocked(s, b.intent, false);
10932 }
10933
10934 Binder.restoreCallingIdentity(origId);
10935 }
10936
10937 return 1;
10938 }
10939
10940 private void removeConnectionLocked(
10941 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10942 IBinder binder = c.conn.asBinder();
10943 AppBindRecord b = c.binding;
10944 ServiceRecord s = b.service;
10945 s.connections.remove(binder);
10946 b.connections.remove(c);
10947 if (c.activity != null && c.activity != skipAct) {
10948 if (c.activity.connections != null) {
10949 c.activity.connections.remove(c);
10950 }
10951 }
10952 if (b.client != skipApp) {
10953 b.client.connections.remove(c);
10954 }
10955 mServiceConnections.remove(binder);
10956
10957 if (b.connections.size() == 0) {
10958 b.intent.apps.remove(b.client);
10959 }
10960
10961 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10962 + ": shouldUnbind=" + b.intent.hasBound);
10963 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10964 && b.intent.hasBound) {
10965 try {
10966 bumpServiceExecutingLocked(s);
10967 updateOomAdjLocked(s.app);
10968 b.intent.hasBound = false;
10969 // Assume the client doesn't want to know about a rebind;
10970 // we will deal with that later if it asks for one.
10971 b.intent.doRebind = false;
10972 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10973 } catch (Exception e) {
10974 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10975 serviceDoneExecutingLocked(s, true);
10976 }
10977 }
10978
10979 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10980 bringDownServiceLocked(s, false);
10981 }
10982 }
10983
10984 public boolean unbindService(IServiceConnection connection) {
10985 synchronized (this) {
10986 IBinder binder = connection.asBinder();
10987 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10988 ConnectionRecord r = mServiceConnections.get(binder);
10989 if (r == null) {
10990 Log.w(TAG, "Unbind failed: could not find connection for "
10991 + connection.asBinder());
10992 return false;
10993 }
10994
10995 final long origId = Binder.clearCallingIdentity();
10996
10997 removeConnectionLocked(r, null, null);
10998
10999 if (r.binding.service.app != null) {
11000 // This could have made the service less important.
11001 updateOomAdjLocked(r.binding.service.app);
11002 }
11003
11004 Binder.restoreCallingIdentity(origId);
11005 }
11006
11007 return true;
11008 }
11009
11010 public void publishService(IBinder token, Intent intent, IBinder service) {
11011 // Refuse possible leaked file descriptors
11012 if (intent != null && intent.hasFileDescriptors() == true) {
11013 throw new IllegalArgumentException("File descriptors passed in Intent");
11014 }
11015
11016 synchronized(this) {
11017 if (!(token instanceof ServiceRecord)) {
11018 throw new IllegalArgumentException("Invalid service token");
11019 }
11020 ServiceRecord r = (ServiceRecord)token;
11021
11022 final long origId = Binder.clearCallingIdentity();
11023
11024 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11025 + " " + intent + ": " + service);
11026 if (r != null) {
11027 Intent.FilterComparison filter
11028 = new Intent.FilterComparison(intent);
11029 IntentBindRecord b = r.bindings.get(filter);
11030 if (b != null && !b.received) {
11031 b.binder = service;
11032 b.requested = true;
11033 b.received = true;
11034 if (r.connections.size() > 0) {
11035 Iterator<ConnectionRecord> it
11036 = r.connections.values().iterator();
11037 while (it.hasNext()) {
11038 ConnectionRecord c = it.next();
11039 if (!filter.equals(c.binding.intent.intent)) {
11040 if (DEBUG_SERVICE) Log.v(
11041 TAG, "Not publishing to: " + c);
11042 if (DEBUG_SERVICE) Log.v(
11043 TAG, "Bound intent: " + c.binding.intent.intent);
11044 if (DEBUG_SERVICE) Log.v(
11045 TAG, "Published intent: " + intent);
11046 continue;
11047 }
11048 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11049 try {
11050 c.conn.connected(r.name, service);
11051 } catch (Exception e) {
11052 Log.w(TAG, "Failure sending service " + r.name +
11053 " to connection " + c.conn.asBinder() +
11054 " (in " + c.binding.client.processName + ")", e);
11055 }
11056 }
11057 }
11058 }
11059
11060 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11061
11062 Binder.restoreCallingIdentity(origId);
11063 }
11064 }
11065 }
11066
11067 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11068 // Refuse possible leaked file descriptors
11069 if (intent != null && intent.hasFileDescriptors() == true) {
11070 throw new IllegalArgumentException("File descriptors passed in Intent");
11071 }
11072
11073 synchronized(this) {
11074 if (!(token instanceof ServiceRecord)) {
11075 throw new IllegalArgumentException("Invalid service token");
11076 }
11077 ServiceRecord r = (ServiceRecord)token;
11078
11079 final long origId = Binder.clearCallingIdentity();
11080
11081 if (r != null) {
11082 Intent.FilterComparison filter
11083 = new Intent.FilterComparison(intent);
11084 IntentBindRecord b = r.bindings.get(filter);
11085 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11086 + " at " + b + ": apps="
11087 + (b != null ? b.apps.size() : 0));
11088 if (b != null) {
11089 if (b.apps.size() > 0) {
11090 // Applications have already bound since the last
11091 // unbind, so just rebind right here.
11092 requestServiceBindingLocked(r, b, true);
11093 } else {
11094 // Note to tell the service the next time there is
11095 // a new client.
11096 b.doRebind = true;
11097 }
11098 }
11099
11100 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11101
11102 Binder.restoreCallingIdentity(origId);
11103 }
11104 }
11105 }
11106
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011107 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011108 synchronized(this) {
11109 if (!(token instanceof ServiceRecord)) {
11110 throw new IllegalArgumentException("Invalid service token");
11111 }
11112 ServiceRecord r = (ServiceRecord)token;
11113 boolean inStopping = mStoppingServices.contains(token);
11114 if (r != null) {
11115 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11116 + ": nesting=" + r.executeNesting
11117 + ", inStopping=" + inStopping);
11118 if (r != token) {
11119 Log.w(TAG, "Done executing service " + r.name
11120 + " with incorrect token: given " + token
11121 + ", expected " + r);
11122 return;
11123 }
11124
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011125 if (type == 1) {
11126 // This is a call from a service start... take care of
11127 // book-keeping.
11128 r.callStart = true;
11129 switch (res) {
11130 case Service.START_STICKY_COMPATIBILITY:
11131 case Service.START_STICKY: {
11132 // We are done with the associated start arguments.
11133 r.findDeliveredStart(startId, true);
11134 // Don't stop if killed.
11135 r.stopIfKilled = false;
11136 break;
11137 }
11138 case Service.START_NOT_STICKY: {
11139 // We are done with the associated start arguments.
11140 r.findDeliveredStart(startId, true);
11141 if (r.lastStartId == startId) {
11142 // There is no more work, and this service
11143 // doesn't want to hang around if killed.
11144 r.stopIfKilled = true;
11145 }
11146 break;
11147 }
11148 case Service.START_REDELIVER_INTENT: {
11149 // We'll keep this item until they explicitly
11150 // call stop for it, but keep track of the fact
11151 // that it was delivered.
11152 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11153 if (si != null) {
11154 si.deliveryCount = 0;
11155 si.doneExecutingCount++;
11156 // Don't stop if killed.
11157 r.stopIfKilled = true;
11158 }
11159 break;
11160 }
11161 default:
11162 throw new IllegalArgumentException(
11163 "Unknown service start result: " + res);
11164 }
11165 if (res == Service.START_STICKY_COMPATIBILITY) {
11166 r.callStart = false;
11167 }
11168 }
11169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011170 final long origId = Binder.clearCallingIdentity();
11171 serviceDoneExecutingLocked(r, inStopping);
11172 Binder.restoreCallingIdentity(origId);
11173 } else {
11174 Log.w(TAG, "Done executing unknown service " + r.name
11175 + " with token " + token);
11176 }
11177 }
11178 }
11179
11180 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11181 r.executeNesting--;
11182 if (r.executeNesting <= 0 && r.app != null) {
11183 r.app.executingServices.remove(r);
11184 if (r.app.executingServices.size() == 0) {
11185 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11186 }
11187 if (inStopping) {
11188 mStoppingServices.remove(r);
11189 }
11190 updateOomAdjLocked(r.app);
11191 }
11192 }
11193
11194 void serviceTimeout(ProcessRecord proc) {
11195 synchronized(this) {
11196 if (proc.executingServices.size() == 0 || proc.thread == null) {
11197 return;
11198 }
11199 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11200 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11201 ServiceRecord timeout = null;
11202 long nextTime = 0;
11203 while (it.hasNext()) {
11204 ServiceRecord sr = it.next();
11205 if (sr.executingStart < maxTime) {
11206 timeout = sr;
11207 break;
11208 }
11209 if (sr.executingStart > nextTime) {
11210 nextTime = sr.executingStart;
11211 }
11212 }
11213 if (timeout != null && mLRUProcesses.contains(proc)) {
11214 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011215 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011216 + timeout.name);
11217 } else {
11218 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11219 msg.obj = proc;
11220 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11221 }
11222 }
11223 }
11224
11225 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011226 // BACKUP AND RESTORE
11227 // =========================================================
11228
11229 // Cause the target app to be launched if necessary and its backup agent
11230 // instantiated. The backup agent will invoke backupAgentCreated() on the
11231 // activity manager to announce its creation.
11232 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11233 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11234 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11235
11236 synchronized(this) {
11237 // !!! TODO: currently no check here that we're already bound
11238 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11239 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11240 synchronized (stats) {
11241 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11242 }
11243
11244 BackupRecord r = new BackupRecord(ss, app, backupMode);
11245 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11246 // startProcessLocked() returns existing proc's record if it's already running
11247 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011248 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011249 if (proc == null) {
11250 Log.e(TAG, "Unable to start backup agent process " + r);
11251 return false;
11252 }
11253
11254 r.app = proc;
11255 mBackupTarget = r;
11256 mBackupAppName = app.packageName;
11257
Christopher Tate6fa95972009-06-05 18:43:55 -070011258 // Try not to kill the process during backup
11259 updateOomAdjLocked(proc);
11260
Christopher Tate181fafa2009-05-14 11:12:14 -070011261 // If the process is already attached, schedule the creation of the backup agent now.
11262 // If it is not yet live, this will be done when it attaches to the framework.
11263 if (proc.thread != null) {
11264 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11265 try {
11266 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11267 } catch (RemoteException e) {
11268 // !!! TODO: notify the backup manager that we crashed, or rely on
11269 // death notices, or...?
11270 }
11271 } else {
11272 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11273 }
11274 // Invariants: at this point, the target app process exists and the application
11275 // is either already running or in the process of coming up. mBackupTarget and
11276 // mBackupAppName describe the app, so that when it binds back to the AM we
11277 // know that it's scheduled for a backup-agent operation.
11278 }
11279
11280 return true;
11281 }
11282
11283 // A backup agent has just come up
11284 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11285 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11286 + " = " + agent);
11287
11288 synchronized(this) {
11289 if (!agentPackageName.equals(mBackupAppName)) {
11290 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11291 return;
11292 }
11293
Christopher Tate043dadc2009-06-02 16:11:00 -070011294 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011295 try {
11296 IBackupManager bm = IBackupManager.Stub.asInterface(
11297 ServiceManager.getService(Context.BACKUP_SERVICE));
11298 bm.agentConnected(agentPackageName, agent);
11299 } catch (RemoteException e) {
11300 // can't happen; the backup manager service is local
11301 } catch (Exception e) {
11302 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11303 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011304 } finally {
11305 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011306 }
11307 }
11308 }
11309
11310 // done with this agent
11311 public void unbindBackupAgent(ApplicationInfo appInfo) {
11312 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011313 if (appInfo == null) {
11314 Log.w(TAG, "unbind backup agent for null app");
11315 return;
11316 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011317
11318 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011319 if (mBackupAppName == null) {
11320 Log.w(TAG, "Unbinding backup agent with no active backup");
11321 return;
11322 }
11323
Christopher Tate181fafa2009-05-14 11:12:14 -070011324 if (!mBackupAppName.equals(appInfo.packageName)) {
11325 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11326 return;
11327 }
11328
Christopher Tate6fa95972009-06-05 18:43:55 -070011329 ProcessRecord proc = mBackupTarget.app;
11330 mBackupTarget = null;
11331 mBackupAppName = null;
11332
11333 // Not backing this app up any more; reset its OOM adjustment
11334 updateOomAdjLocked(proc);
11335
Christopher Tatec7b31e32009-06-10 15:49:30 -070011336 // If the app crashed during backup, 'thread' will be null here
11337 if (proc.thread != null) {
11338 try {
11339 proc.thread.scheduleDestroyBackupAgent(appInfo);
11340 } catch (Exception e) {
11341 Log.e(TAG, "Exception when unbinding backup agent:");
11342 e.printStackTrace();
11343 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011344 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011345 }
11346 }
11347 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011348 // BROADCASTS
11349 // =========================================================
11350
11351 private final List getStickies(String action, IntentFilter filter,
11352 List cur) {
11353 final ContentResolver resolver = mContext.getContentResolver();
11354 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11355 if (list == null) {
11356 return cur;
11357 }
11358 int N = list.size();
11359 for (int i=0; i<N; i++) {
11360 Intent intent = list.get(i);
11361 if (filter.match(resolver, intent, true, TAG) >= 0) {
11362 if (cur == null) {
11363 cur = new ArrayList<Intent>();
11364 }
11365 cur.add(intent);
11366 }
11367 }
11368 return cur;
11369 }
11370
11371 private final void scheduleBroadcastsLocked() {
11372 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11373 + mBroadcastsScheduled);
11374
11375 if (mBroadcastsScheduled) {
11376 return;
11377 }
11378 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11379 mBroadcastsScheduled = true;
11380 }
11381
11382 public Intent registerReceiver(IApplicationThread caller,
11383 IIntentReceiver receiver, IntentFilter filter, String permission) {
11384 synchronized(this) {
11385 ProcessRecord callerApp = null;
11386 if (caller != null) {
11387 callerApp = getRecordForAppLocked(caller);
11388 if (callerApp == null) {
11389 throw new SecurityException(
11390 "Unable to find app for caller " + caller
11391 + " (pid=" + Binder.getCallingPid()
11392 + ") when registering receiver " + receiver);
11393 }
11394 }
11395
11396 List allSticky = null;
11397
11398 // Look for any matching sticky broadcasts...
11399 Iterator actions = filter.actionsIterator();
11400 if (actions != null) {
11401 while (actions.hasNext()) {
11402 String action = (String)actions.next();
11403 allSticky = getStickies(action, filter, allSticky);
11404 }
11405 } else {
11406 allSticky = getStickies(null, filter, allSticky);
11407 }
11408
11409 // The first sticky in the list is returned directly back to
11410 // the client.
11411 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11412
11413 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11414 + ": " + sticky);
11415
11416 if (receiver == null) {
11417 return sticky;
11418 }
11419
11420 ReceiverList rl
11421 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11422 if (rl == null) {
11423 rl = new ReceiverList(this, callerApp,
11424 Binder.getCallingPid(),
11425 Binder.getCallingUid(), receiver);
11426 if (rl.app != null) {
11427 rl.app.receivers.add(rl);
11428 } else {
11429 try {
11430 receiver.asBinder().linkToDeath(rl, 0);
11431 } catch (RemoteException e) {
11432 return sticky;
11433 }
11434 rl.linkedToDeath = true;
11435 }
11436 mRegisteredReceivers.put(receiver.asBinder(), rl);
11437 }
11438 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11439 rl.add(bf);
11440 if (!bf.debugCheck()) {
11441 Log.w(TAG, "==> For Dynamic broadast");
11442 }
11443 mReceiverResolver.addFilter(bf);
11444
11445 // Enqueue broadcasts for all existing stickies that match
11446 // this filter.
11447 if (allSticky != null) {
11448 ArrayList receivers = new ArrayList();
11449 receivers.add(bf);
11450
11451 int N = allSticky.size();
11452 for (int i=0; i<N; i++) {
11453 Intent intent = (Intent)allSticky.get(i);
11454 BroadcastRecord r = new BroadcastRecord(intent, null,
11455 null, -1, -1, null, receivers, null, 0, null, null,
11456 false);
11457 if (mParallelBroadcasts.size() == 0) {
11458 scheduleBroadcastsLocked();
11459 }
11460 mParallelBroadcasts.add(r);
11461 }
11462 }
11463
11464 return sticky;
11465 }
11466 }
11467
11468 public void unregisterReceiver(IIntentReceiver receiver) {
11469 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11470
11471 boolean doNext = false;
11472
11473 synchronized(this) {
11474 ReceiverList rl
11475 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11476 if (rl != null) {
11477 if (rl.curBroadcast != null) {
11478 BroadcastRecord r = rl.curBroadcast;
11479 doNext = finishReceiverLocked(
11480 receiver.asBinder(), r.resultCode, r.resultData,
11481 r.resultExtras, r.resultAbort, true);
11482 }
11483
11484 if (rl.app != null) {
11485 rl.app.receivers.remove(rl);
11486 }
11487 removeReceiverLocked(rl);
11488 if (rl.linkedToDeath) {
11489 rl.linkedToDeath = false;
11490 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11491 }
11492 }
11493 }
11494
11495 if (!doNext) {
11496 return;
11497 }
11498
11499 final long origId = Binder.clearCallingIdentity();
11500 processNextBroadcast(false);
11501 trimApplications();
11502 Binder.restoreCallingIdentity(origId);
11503 }
11504
11505 void removeReceiverLocked(ReceiverList rl) {
11506 mRegisteredReceivers.remove(rl.receiver.asBinder());
11507 int N = rl.size();
11508 for (int i=0; i<N; i++) {
11509 mReceiverResolver.removeFilter(rl.get(i));
11510 }
11511 }
11512
11513 private final int broadcastIntentLocked(ProcessRecord callerApp,
11514 String callerPackage, Intent intent, String resolvedType,
11515 IIntentReceiver resultTo, int resultCode, String resultData,
11516 Bundle map, String requiredPermission,
11517 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11518 intent = new Intent(intent);
11519
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011520 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011521 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11522 + " ordered=" + ordered);
11523 if ((resultTo != null) && !ordered) {
11524 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11525 }
11526
11527 // Handle special intents: if this broadcast is from the package
11528 // manager about a package being removed, we need to remove all of
11529 // its activities from the history stack.
11530 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11531 intent.getAction());
11532 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11533 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11534 || uidRemoved) {
11535 if (checkComponentPermission(
11536 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11537 callingPid, callingUid, -1)
11538 == PackageManager.PERMISSION_GRANTED) {
11539 if (uidRemoved) {
11540 final Bundle intentExtras = intent.getExtras();
11541 final int uid = intentExtras != null
11542 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11543 if (uid >= 0) {
11544 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11545 synchronized (bs) {
11546 bs.removeUidStatsLocked(uid);
11547 }
11548 }
11549 } else {
11550 Uri data = intent.getData();
11551 String ssp;
11552 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11553 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11554 uninstallPackageLocked(ssp,
11555 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011556 AttributeCache ac = AttributeCache.instance();
11557 if (ac != null) {
11558 ac.removePackage(ssp);
11559 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011560 }
11561 }
11562 }
11563 } else {
11564 String msg = "Permission Denial: " + intent.getAction()
11565 + " broadcast from " + callerPackage + " (pid=" + callingPid
11566 + ", uid=" + callingUid + ")"
11567 + " requires "
11568 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11569 Log.w(TAG, msg);
11570 throw new SecurityException(msg);
11571 }
11572 }
11573
11574 /*
11575 * If this is the time zone changed action, queue up a message that will reset the timezone
11576 * of all currently running processes. This message will get queued up before the broadcast
11577 * happens.
11578 */
11579 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11580 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11581 }
11582
Dianne Hackborn854060af2009-07-09 18:14:31 -070011583 /*
11584 * Prevent non-system code (defined here to be non-persistent
11585 * processes) from sending protected broadcasts.
11586 */
11587 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11588 || callingUid == Process.SHELL_UID || callingUid == 0) {
11589 // Always okay.
11590 } else if (callerApp == null || !callerApp.persistent) {
11591 try {
11592 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11593 intent.getAction())) {
11594 String msg = "Permission Denial: not allowed to send broadcast "
11595 + intent.getAction() + " from pid="
11596 + callingPid + ", uid=" + callingUid;
11597 Log.w(TAG, msg);
11598 throw new SecurityException(msg);
11599 }
11600 } catch (RemoteException e) {
11601 Log.w(TAG, "Remote exception", e);
11602 return BROADCAST_SUCCESS;
11603 }
11604 }
11605
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011606 // Add to the sticky list if requested.
11607 if (sticky) {
11608 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11609 callingPid, callingUid)
11610 != PackageManager.PERMISSION_GRANTED) {
11611 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11612 + callingPid + ", uid=" + callingUid
11613 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11614 Log.w(TAG, msg);
11615 throw new SecurityException(msg);
11616 }
11617 if (requiredPermission != null) {
11618 Log.w(TAG, "Can't broadcast sticky intent " + intent
11619 + " and enforce permission " + requiredPermission);
11620 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11621 }
11622 if (intent.getComponent() != null) {
11623 throw new SecurityException(
11624 "Sticky broadcasts can't target a specific component");
11625 }
11626 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11627 if (list == null) {
11628 list = new ArrayList<Intent>();
11629 mStickyBroadcasts.put(intent.getAction(), list);
11630 }
11631 int N = list.size();
11632 int i;
11633 for (i=0; i<N; i++) {
11634 if (intent.filterEquals(list.get(i))) {
11635 // This sticky already exists, replace it.
11636 list.set(i, new Intent(intent));
11637 break;
11638 }
11639 }
11640 if (i >= N) {
11641 list.add(new Intent(intent));
11642 }
11643 }
11644
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011645 // Figure out who all will receive this broadcast.
11646 List receivers = null;
11647 List<BroadcastFilter> registeredReceivers = null;
11648 try {
11649 if (intent.getComponent() != null) {
11650 // Broadcast is going to one specific receiver class...
11651 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011652 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011653 if (ai != null) {
11654 receivers = new ArrayList();
11655 ResolveInfo ri = new ResolveInfo();
11656 ri.activityInfo = ai;
11657 receivers.add(ri);
11658 }
11659 } else {
11660 // Need to resolve the intent to interested receivers...
11661 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11662 == 0) {
11663 receivers =
11664 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011665 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011666 }
Mihai Preda074edef2009-05-18 17:13:31 +020011667 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011668 }
11669 } catch (RemoteException ex) {
11670 // pm is in same process, this will never happen.
11671 }
11672
11673 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11674 if (!ordered && NR > 0) {
11675 // If we are not serializing this broadcast, then send the
11676 // registered receivers separately so they don't wait for the
11677 // components to be launched.
11678 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11679 callerPackage, callingPid, callingUid, requiredPermission,
11680 registeredReceivers, resultTo, resultCode, resultData, map,
11681 ordered);
11682 if (DEBUG_BROADCAST) Log.v(
11683 TAG, "Enqueueing parallel broadcast " + r
11684 + ": prev had " + mParallelBroadcasts.size());
11685 mParallelBroadcasts.add(r);
11686 scheduleBroadcastsLocked();
11687 registeredReceivers = null;
11688 NR = 0;
11689 }
11690
11691 // Merge into one list.
11692 int ir = 0;
11693 if (receivers != null) {
11694 // A special case for PACKAGE_ADDED: do not allow the package
11695 // being added to see this broadcast. This prevents them from
11696 // using this as a back door to get run as soon as they are
11697 // installed. Maybe in the future we want to have a special install
11698 // broadcast or such for apps, but we'd like to deliberately make
11699 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011700 boolean skip = false;
11701 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011702 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011703 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11704 skip = true;
11705 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11706 skip = true;
11707 }
11708 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011709 ? intent.getData().getSchemeSpecificPart()
11710 : null;
11711 if (skipPackage != null && receivers != null) {
11712 int NT = receivers.size();
11713 for (int it=0; it<NT; it++) {
11714 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11715 if (curt.activityInfo.packageName.equals(skipPackage)) {
11716 receivers.remove(it);
11717 it--;
11718 NT--;
11719 }
11720 }
11721 }
11722
11723 int NT = receivers != null ? receivers.size() : 0;
11724 int it = 0;
11725 ResolveInfo curt = null;
11726 BroadcastFilter curr = null;
11727 while (it < NT && ir < NR) {
11728 if (curt == null) {
11729 curt = (ResolveInfo)receivers.get(it);
11730 }
11731 if (curr == null) {
11732 curr = registeredReceivers.get(ir);
11733 }
11734 if (curr.getPriority() >= curt.priority) {
11735 // Insert this broadcast record into the final list.
11736 receivers.add(it, curr);
11737 ir++;
11738 curr = null;
11739 it++;
11740 NT++;
11741 } else {
11742 // Skip to the next ResolveInfo in the final list.
11743 it++;
11744 curt = null;
11745 }
11746 }
11747 }
11748 while (ir < NR) {
11749 if (receivers == null) {
11750 receivers = new ArrayList();
11751 }
11752 receivers.add(registeredReceivers.get(ir));
11753 ir++;
11754 }
11755
11756 if ((receivers != null && receivers.size() > 0)
11757 || resultTo != null) {
11758 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11759 callerPackage, callingPid, callingUid, requiredPermission,
11760 receivers, resultTo, resultCode, resultData, map, ordered);
11761 if (DEBUG_BROADCAST) Log.v(
11762 TAG, "Enqueueing ordered broadcast " + r
11763 + ": prev had " + mOrderedBroadcasts.size());
11764 if (DEBUG_BROADCAST) {
11765 int seq = r.intent.getIntExtra("seq", -1);
11766 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11767 }
11768 mOrderedBroadcasts.add(r);
11769 scheduleBroadcastsLocked();
11770 }
11771
11772 return BROADCAST_SUCCESS;
11773 }
11774
11775 public final int broadcastIntent(IApplicationThread caller,
11776 Intent intent, String resolvedType, IIntentReceiver resultTo,
11777 int resultCode, String resultData, Bundle map,
11778 String requiredPermission, boolean serialized, boolean sticky) {
11779 // Refuse possible leaked file descriptors
11780 if (intent != null && intent.hasFileDescriptors() == true) {
11781 throw new IllegalArgumentException("File descriptors passed in Intent");
11782 }
11783
11784 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011785 int flags = intent.getFlags();
11786
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011787 if (!mSystemReady) {
11788 // if the caller really truly claims to know what they're doing, go
11789 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011790 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11791 intent = new Intent(intent);
11792 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11793 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11794 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11795 + " before boot completion");
11796 throw new IllegalStateException("Cannot broadcast before boot completed");
11797 }
11798 }
11799
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011800 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
11801 throw new IllegalArgumentException(
11802 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
11803 }
11804
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011805 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11806 final int callingPid = Binder.getCallingPid();
11807 final int callingUid = Binder.getCallingUid();
11808 final long origId = Binder.clearCallingIdentity();
11809 int res = broadcastIntentLocked(callerApp,
11810 callerApp != null ? callerApp.info.packageName : null,
11811 intent, resolvedType, resultTo,
11812 resultCode, resultData, map, requiredPermission, serialized,
11813 sticky, callingPid, callingUid);
11814 Binder.restoreCallingIdentity(origId);
11815 return res;
11816 }
11817 }
11818
11819 int broadcastIntentInPackage(String packageName, int uid,
11820 Intent intent, String resolvedType, IIntentReceiver resultTo,
11821 int resultCode, String resultData, Bundle map,
11822 String requiredPermission, boolean serialized, boolean sticky) {
11823 synchronized(this) {
11824 final long origId = Binder.clearCallingIdentity();
11825 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11826 resultTo, resultCode, resultData, map, requiredPermission,
11827 serialized, sticky, -1, uid);
11828 Binder.restoreCallingIdentity(origId);
11829 return res;
11830 }
11831 }
11832
11833 public final void unbroadcastIntent(IApplicationThread caller,
11834 Intent intent) {
11835 // Refuse possible leaked file descriptors
11836 if (intent != null && intent.hasFileDescriptors() == true) {
11837 throw new IllegalArgumentException("File descriptors passed in Intent");
11838 }
11839
11840 synchronized(this) {
11841 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11842 != PackageManager.PERMISSION_GRANTED) {
11843 String msg = "Permission Denial: unbroadcastIntent() from pid="
11844 + Binder.getCallingPid()
11845 + ", uid=" + Binder.getCallingUid()
11846 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11847 Log.w(TAG, msg);
11848 throw new SecurityException(msg);
11849 }
11850 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11851 if (list != null) {
11852 int N = list.size();
11853 int i;
11854 for (i=0; i<N; i++) {
11855 if (intent.filterEquals(list.get(i))) {
11856 list.remove(i);
11857 break;
11858 }
11859 }
11860 }
11861 }
11862 }
11863
11864 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11865 String resultData, Bundle resultExtras, boolean resultAbort,
11866 boolean explicit) {
11867 if (mOrderedBroadcasts.size() == 0) {
11868 if (explicit) {
11869 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11870 }
11871 return false;
11872 }
11873 BroadcastRecord r = mOrderedBroadcasts.get(0);
11874 if (r.receiver == null) {
11875 if (explicit) {
11876 Log.w(TAG, "finishReceiver called but none active");
11877 }
11878 return false;
11879 }
11880 if (r.receiver != receiver) {
11881 Log.w(TAG, "finishReceiver called but active receiver is different");
11882 return false;
11883 }
11884 int state = r.state;
11885 r.state = r.IDLE;
11886 if (state == r.IDLE) {
11887 if (explicit) {
11888 Log.w(TAG, "finishReceiver called but state is IDLE");
11889 }
11890 }
11891 r.receiver = null;
11892 r.intent.setComponent(null);
11893 if (r.curApp != null) {
11894 r.curApp.curReceiver = null;
11895 }
11896 if (r.curFilter != null) {
11897 r.curFilter.receiverList.curBroadcast = null;
11898 }
11899 r.curFilter = null;
11900 r.curApp = null;
11901 r.curComponent = null;
11902 r.curReceiver = null;
11903 mPendingBroadcast = null;
11904
11905 r.resultCode = resultCode;
11906 r.resultData = resultData;
11907 r.resultExtras = resultExtras;
11908 r.resultAbort = resultAbort;
11909
11910 // We will process the next receiver right now if this is finishing
11911 // an app receiver (which is always asynchronous) or after we have
11912 // come back from calling a receiver.
11913 return state == BroadcastRecord.APP_RECEIVE
11914 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11915 }
11916
11917 public void finishReceiver(IBinder who, int resultCode, String resultData,
11918 Bundle resultExtras, boolean resultAbort) {
11919 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11920
11921 // Refuse possible leaked file descriptors
11922 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11923 throw new IllegalArgumentException("File descriptors passed in Bundle");
11924 }
11925
11926 boolean doNext;
11927
11928 final long origId = Binder.clearCallingIdentity();
11929
11930 synchronized(this) {
11931 doNext = finishReceiverLocked(
11932 who, resultCode, resultData, resultExtras, resultAbort, true);
11933 }
11934
11935 if (doNext) {
11936 processNextBroadcast(false);
11937 }
11938 trimApplications();
11939
11940 Binder.restoreCallingIdentity(origId);
11941 }
11942
11943 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11944 if (r.nextReceiver > 0) {
11945 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11946 if (curReceiver instanceof BroadcastFilter) {
11947 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11948 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11949 System.identityHashCode(r),
11950 r.intent.getAction(),
11951 r.nextReceiver - 1,
11952 System.identityHashCode(bf));
11953 } else {
11954 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11955 System.identityHashCode(r),
11956 r.intent.getAction(),
11957 r.nextReceiver - 1,
11958 ((ResolveInfo)curReceiver).toString());
11959 }
11960 } else {
11961 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11962 + r);
11963 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11964 System.identityHashCode(r),
11965 r.intent.getAction(),
11966 r.nextReceiver,
11967 "NONE");
11968 }
11969 }
11970
11971 private final void broadcastTimeout() {
11972 synchronized (this) {
11973 if (mOrderedBroadcasts.size() == 0) {
11974 return;
11975 }
11976 long now = SystemClock.uptimeMillis();
11977 BroadcastRecord r = mOrderedBroadcasts.get(0);
11978 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11979 if (DEBUG_BROADCAST) Log.v(TAG,
11980 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11981 + (r.startTime + BROADCAST_TIMEOUT));
11982 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11983 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11984 return;
11985 }
11986
11987 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11988 r.startTime = now;
11989 r.anrCount++;
11990
11991 // Current receiver has passed its expiration date.
11992 if (r.nextReceiver <= 0) {
11993 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11994 return;
11995 }
11996
11997 ProcessRecord app = null;
11998
11999 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12000 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12001 logBroadcastReceiverDiscard(r);
12002 if (curReceiver instanceof BroadcastFilter) {
12003 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12004 if (bf.receiverList.pid != 0
12005 && bf.receiverList.pid != MY_PID) {
12006 synchronized (this.mPidsSelfLocked) {
12007 app = this.mPidsSelfLocked.get(
12008 bf.receiverList.pid);
12009 }
12010 }
12011 } else {
12012 app = r.curApp;
12013 }
12014
12015 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070012016 appNotRespondingLocked(app, null, null,
12017 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012018 }
12019
12020 if (mPendingBroadcast == r) {
12021 mPendingBroadcast = null;
12022 }
12023
12024 // Move on to the next receiver.
12025 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12026 r.resultExtras, r.resultAbort, true);
12027 scheduleBroadcastsLocked();
12028 }
12029 }
12030
12031 private final void processCurBroadcastLocked(BroadcastRecord r,
12032 ProcessRecord app) throws RemoteException {
12033 if (app.thread == null) {
12034 throw new RemoteException();
12035 }
12036 r.receiver = app.thread.asBinder();
12037 r.curApp = app;
12038 app.curReceiver = r;
12039 updateLRUListLocked(app, true);
12040
12041 // Tell the application to launch this receiver.
12042 r.intent.setComponent(r.curComponent);
12043
12044 boolean started = false;
12045 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012046 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012047 "Delivering to component " + r.curComponent
12048 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012049 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012050 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12051 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12052 started = true;
12053 } finally {
12054 if (!started) {
12055 r.receiver = null;
12056 r.curApp = null;
12057 app.curReceiver = null;
12058 }
12059 }
12060
12061 }
12062
12063 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
12064 Intent intent, int resultCode, String data,
12065 Bundle extras, boolean ordered) throws RemoteException {
12066 if (app != null && app.thread != null) {
12067 // If we have an app thread, do the call through that so it is
12068 // correctly ordered with other one-way calls.
12069 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
12070 data, extras, ordered);
12071 } else {
12072 receiver.performReceive(intent, resultCode, data, extras, ordered);
12073 }
12074 }
12075
12076 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12077 BroadcastFilter filter, boolean ordered) {
12078 boolean skip = false;
12079 if (filter.requiredPermission != null) {
12080 int perm = checkComponentPermission(filter.requiredPermission,
12081 r.callingPid, r.callingUid, -1);
12082 if (perm != PackageManager.PERMISSION_GRANTED) {
12083 Log.w(TAG, "Permission Denial: broadcasting "
12084 + r.intent.toString()
12085 + " from " + r.callerPackage + " (pid="
12086 + r.callingPid + ", uid=" + r.callingUid + ")"
12087 + " requires " + filter.requiredPermission
12088 + " due to registered receiver " + filter);
12089 skip = true;
12090 }
12091 }
12092 if (r.requiredPermission != null) {
12093 int perm = checkComponentPermission(r.requiredPermission,
12094 filter.receiverList.pid, filter.receiverList.uid, -1);
12095 if (perm != PackageManager.PERMISSION_GRANTED) {
12096 Log.w(TAG, "Permission Denial: receiving "
12097 + r.intent.toString()
12098 + " to " + filter.receiverList.app
12099 + " (pid=" + filter.receiverList.pid
12100 + ", uid=" + filter.receiverList.uid + ")"
12101 + " requires " + r.requiredPermission
12102 + " due to sender " + r.callerPackage
12103 + " (uid " + r.callingUid + ")");
12104 skip = true;
12105 }
12106 }
12107
12108 if (!skip) {
12109 // If this is not being sent as an ordered broadcast, then we
12110 // don't want to touch the fields that keep track of the current
12111 // state of ordered broadcasts.
12112 if (ordered) {
12113 r.receiver = filter.receiverList.receiver.asBinder();
12114 r.curFilter = filter;
12115 filter.receiverList.curBroadcast = r;
12116 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012117 if (filter.receiverList.app != null) {
12118 // Bump hosting application to no longer be in background
12119 // scheduling class. Note that we can't do that if there
12120 // isn't an app... but we can only be in that case for
12121 // things that directly call the IActivityManager API, which
12122 // are already core system stuff so don't matter for this.
12123 r.curApp = filter.receiverList.app;
12124 filter.receiverList.app.curReceiver = r;
12125 updateOomAdjLocked();
12126 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012127 }
12128 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012129 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012130 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012131 Log.i(TAG, "Delivering to " + filter.receiverList.app
12132 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012133 }
12134 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12135 new Intent(r.intent), r.resultCode,
12136 r.resultData, r.resultExtras, r.ordered);
12137 if (ordered) {
12138 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12139 }
12140 } catch (RemoteException e) {
12141 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12142 if (ordered) {
12143 r.receiver = null;
12144 r.curFilter = null;
12145 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012146 if (filter.receiverList.app != null) {
12147 filter.receiverList.app.curReceiver = null;
12148 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012149 }
12150 }
12151 }
12152 }
12153
12154 private final void processNextBroadcast(boolean fromMsg) {
12155 synchronized(this) {
12156 BroadcastRecord r;
12157
12158 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12159 + mParallelBroadcasts.size() + " broadcasts, "
12160 + mOrderedBroadcasts.size() + " serialized broadcasts");
12161
12162 updateCpuStats();
12163
12164 if (fromMsg) {
12165 mBroadcastsScheduled = false;
12166 }
12167
12168 // First, deliver any non-serialized broadcasts right away.
12169 while (mParallelBroadcasts.size() > 0) {
12170 r = mParallelBroadcasts.remove(0);
12171 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012172 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12173 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012174 for (int i=0; i<N; i++) {
12175 Object target = r.receivers.get(i);
12176 if (DEBUG_BROADCAST) Log.v(TAG,
12177 "Delivering non-serialized to registered "
12178 + target + ": " + r);
12179 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12180 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012181 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12182 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012183 }
12184
12185 // Now take care of the next serialized one...
12186
12187 // If we are waiting for a process to come up to handle the next
12188 // broadcast, then do nothing at this point. Just in case, we
12189 // check that the process we're waiting for still exists.
12190 if (mPendingBroadcast != null) {
12191 Log.i(TAG, "processNextBroadcast: waiting for "
12192 + mPendingBroadcast.curApp);
12193
12194 boolean isDead;
12195 synchronized (mPidsSelfLocked) {
12196 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12197 }
12198 if (!isDead) {
12199 // It's still alive, so keep waiting
12200 return;
12201 } else {
12202 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12203 + " died before responding to broadcast");
12204 mPendingBroadcast = null;
12205 }
12206 }
12207
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012208 boolean looped = false;
12209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012210 do {
12211 if (mOrderedBroadcasts.size() == 0) {
12212 // No more broadcasts pending, so all done!
12213 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012214 if (looped) {
12215 // If we had finished the last ordered broadcast, then
12216 // make sure all processes have correct oom and sched
12217 // adjustments.
12218 updateOomAdjLocked();
12219 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012220 return;
12221 }
12222 r = mOrderedBroadcasts.get(0);
12223 boolean forceReceive = false;
12224
12225 // Ensure that even if something goes awry with the timeout
12226 // detection, we catch "hung" broadcasts here, discard them,
12227 // and continue to make progress.
12228 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12229 long now = SystemClock.uptimeMillis();
12230 if (r.dispatchTime > 0) {
12231 if ((numReceivers > 0) &&
12232 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12233 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12234 + " now=" + now
12235 + " dispatchTime=" + r.dispatchTime
12236 + " startTime=" + r.startTime
12237 + " intent=" + r.intent
12238 + " numReceivers=" + numReceivers
12239 + " nextReceiver=" + r.nextReceiver
12240 + " state=" + r.state);
12241 broadcastTimeout(); // forcibly finish this broadcast
12242 forceReceive = true;
12243 r.state = BroadcastRecord.IDLE;
12244 }
12245 }
12246
12247 if (r.state != BroadcastRecord.IDLE) {
12248 if (DEBUG_BROADCAST) Log.d(TAG,
12249 "processNextBroadcast() called when not idle (state="
12250 + r.state + ")");
12251 return;
12252 }
12253
12254 if (r.receivers == null || r.nextReceiver >= numReceivers
12255 || r.resultAbort || forceReceive) {
12256 // No more receivers for this broadcast! Send the final
12257 // result if requested...
12258 if (r.resultTo != null) {
12259 try {
12260 if (DEBUG_BROADCAST) {
12261 int seq = r.intent.getIntExtra("seq", -1);
12262 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12263 + " seq=" + seq + " app=" + r.callerApp);
12264 }
12265 performReceive(r.callerApp, r.resultTo,
12266 new Intent(r.intent), r.resultCode,
12267 r.resultData, r.resultExtras, false);
12268 } catch (RemoteException e) {
12269 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12270 }
12271 }
12272
12273 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12274 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12275
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012276 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12277 + r);
12278
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012279 // ... and on to the next...
12280 mOrderedBroadcasts.remove(0);
12281 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012282 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012283 continue;
12284 }
12285 } while (r == null);
12286
12287 // Get the next receiver...
12288 int recIdx = r.nextReceiver++;
12289
12290 // Keep track of when this receiver started, and make sure there
12291 // is a timeout message pending to kill it if need be.
12292 r.startTime = SystemClock.uptimeMillis();
12293 if (recIdx == 0) {
12294 r.dispatchTime = r.startTime;
12295
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012296 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12297 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012298 if (DEBUG_BROADCAST) Log.v(TAG,
12299 "Submitting BROADCAST_TIMEOUT_MSG for "
12300 + (r.startTime + BROADCAST_TIMEOUT));
12301 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12302 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12303 }
12304
12305 Object nextReceiver = r.receivers.get(recIdx);
12306 if (nextReceiver instanceof BroadcastFilter) {
12307 // Simple case: this is a registered receiver who gets
12308 // a direct call.
12309 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12310 if (DEBUG_BROADCAST) Log.v(TAG,
12311 "Delivering serialized to registered "
12312 + filter + ": " + r);
12313 deliverToRegisteredReceiver(r, filter, r.ordered);
12314 if (r.receiver == null || !r.ordered) {
12315 // The receiver has already finished, so schedule to
12316 // process the next one.
12317 r.state = BroadcastRecord.IDLE;
12318 scheduleBroadcastsLocked();
12319 }
12320 return;
12321 }
12322
12323 // Hard case: need to instantiate the receiver, possibly
12324 // starting its application process to host it.
12325
12326 ResolveInfo info =
12327 (ResolveInfo)nextReceiver;
12328
12329 boolean skip = false;
12330 int perm = checkComponentPermission(info.activityInfo.permission,
12331 r.callingPid, r.callingUid,
12332 info.activityInfo.exported
12333 ? -1 : info.activityInfo.applicationInfo.uid);
12334 if (perm != PackageManager.PERMISSION_GRANTED) {
12335 Log.w(TAG, "Permission Denial: broadcasting "
12336 + r.intent.toString()
12337 + " from " + r.callerPackage + " (pid=" + r.callingPid
12338 + ", uid=" + r.callingUid + ")"
12339 + " requires " + info.activityInfo.permission
12340 + " due to receiver " + info.activityInfo.packageName
12341 + "/" + info.activityInfo.name);
12342 skip = true;
12343 }
12344 if (r.callingUid != Process.SYSTEM_UID &&
12345 r.requiredPermission != null) {
12346 try {
12347 perm = ActivityThread.getPackageManager().
12348 checkPermission(r.requiredPermission,
12349 info.activityInfo.applicationInfo.packageName);
12350 } catch (RemoteException e) {
12351 perm = PackageManager.PERMISSION_DENIED;
12352 }
12353 if (perm != PackageManager.PERMISSION_GRANTED) {
12354 Log.w(TAG, "Permission Denial: receiving "
12355 + r.intent + " to "
12356 + info.activityInfo.applicationInfo.packageName
12357 + " requires " + r.requiredPermission
12358 + " due to sender " + r.callerPackage
12359 + " (uid " + r.callingUid + ")");
12360 skip = true;
12361 }
12362 }
12363 if (r.curApp != null && r.curApp.crashing) {
12364 // If the target process is crashing, just skip it.
12365 skip = true;
12366 }
12367
12368 if (skip) {
12369 r.receiver = null;
12370 r.curFilter = null;
12371 r.state = BroadcastRecord.IDLE;
12372 scheduleBroadcastsLocked();
12373 return;
12374 }
12375
12376 r.state = BroadcastRecord.APP_RECEIVE;
12377 String targetProcess = info.activityInfo.processName;
12378 r.curComponent = new ComponentName(
12379 info.activityInfo.applicationInfo.packageName,
12380 info.activityInfo.name);
12381 r.curReceiver = info.activityInfo;
12382
12383 // Is this receiver's application already running?
12384 ProcessRecord app = getProcessRecordLocked(targetProcess,
12385 info.activityInfo.applicationInfo.uid);
12386 if (app != null && app.thread != null) {
12387 try {
12388 processCurBroadcastLocked(r, app);
12389 return;
12390 } catch (RemoteException e) {
12391 Log.w(TAG, "Exception when sending broadcast to "
12392 + r.curComponent, e);
12393 }
12394
12395 // If a dead object exception was thrown -- fall through to
12396 // restart the application.
12397 }
12398
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012399 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012400 if ((r.curApp=startProcessLocked(targetProcess,
12401 info.activityInfo.applicationInfo, true,
12402 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012403 "broadcast", r.curComponent,
12404 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12405 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012406 // Ah, this recipient is unavailable. Finish it if necessary,
12407 // and mark the broadcast record as ready for the next.
12408 Log.w(TAG, "Unable to launch app "
12409 + info.activityInfo.applicationInfo.packageName + "/"
12410 + info.activityInfo.applicationInfo.uid + " for broadcast "
12411 + r.intent + ": process is bad");
12412 logBroadcastReceiverDiscard(r);
12413 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12414 r.resultExtras, r.resultAbort, true);
12415 scheduleBroadcastsLocked();
12416 r.state = BroadcastRecord.IDLE;
12417 return;
12418 }
12419
12420 mPendingBroadcast = r;
12421 }
12422 }
12423
12424 // =========================================================
12425 // INSTRUMENTATION
12426 // =========================================================
12427
12428 public boolean startInstrumentation(ComponentName className,
12429 String profileFile, int flags, Bundle arguments,
12430 IInstrumentationWatcher watcher) {
12431 // Refuse possible leaked file descriptors
12432 if (arguments != null && arguments.hasFileDescriptors()) {
12433 throw new IllegalArgumentException("File descriptors passed in Bundle");
12434 }
12435
12436 synchronized(this) {
12437 InstrumentationInfo ii = null;
12438 ApplicationInfo ai = null;
12439 try {
12440 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012441 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012442 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012443 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012444 } catch (PackageManager.NameNotFoundException e) {
12445 }
12446 if (ii == null) {
12447 reportStartInstrumentationFailure(watcher, className,
12448 "Unable to find instrumentation info for: " + className);
12449 return false;
12450 }
12451 if (ai == null) {
12452 reportStartInstrumentationFailure(watcher, className,
12453 "Unable to find instrumentation target package: " + ii.targetPackage);
12454 return false;
12455 }
12456
12457 int match = mContext.getPackageManager().checkSignatures(
12458 ii.targetPackage, ii.packageName);
12459 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12460 String msg = "Permission Denial: starting instrumentation "
12461 + className + " from pid="
12462 + Binder.getCallingPid()
12463 + ", uid=" + Binder.getCallingPid()
12464 + " not allowed because package " + ii.packageName
12465 + " does not have a signature matching the target "
12466 + ii.targetPackage;
12467 reportStartInstrumentationFailure(watcher, className, msg);
12468 throw new SecurityException(msg);
12469 }
12470
12471 final long origId = Binder.clearCallingIdentity();
12472 uninstallPackageLocked(ii.targetPackage, -1, true);
12473 ProcessRecord app = addAppLocked(ai);
12474 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012475 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012476 app.instrumentationProfileFile = profileFile;
12477 app.instrumentationArguments = arguments;
12478 app.instrumentationWatcher = watcher;
12479 app.instrumentationResultClass = className;
12480 Binder.restoreCallingIdentity(origId);
12481 }
12482
12483 return true;
12484 }
12485
12486 /**
12487 * Report errors that occur while attempting to start Instrumentation. Always writes the
12488 * error to the logs, but if somebody is watching, send the report there too. This enables
12489 * the "am" command to report errors with more information.
12490 *
12491 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12492 * @param cn The component name of the instrumentation.
12493 * @param report The error report.
12494 */
12495 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12496 ComponentName cn, String report) {
12497 Log.w(TAG, report);
12498 try {
12499 if (watcher != null) {
12500 Bundle results = new Bundle();
12501 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12502 results.putString("Error", report);
12503 watcher.instrumentationStatus(cn, -1, results);
12504 }
12505 } catch (RemoteException e) {
12506 Log.w(TAG, e);
12507 }
12508 }
12509
12510 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12511 if (app.instrumentationWatcher != null) {
12512 try {
12513 // NOTE: IInstrumentationWatcher *must* be oneway here
12514 app.instrumentationWatcher.instrumentationFinished(
12515 app.instrumentationClass,
12516 resultCode,
12517 results);
12518 } catch (RemoteException e) {
12519 }
12520 }
12521 app.instrumentationWatcher = null;
12522 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012523 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012524 app.instrumentationProfileFile = null;
12525 app.instrumentationArguments = null;
12526
12527 uninstallPackageLocked(app.processName, -1, false);
12528 }
12529
12530 public void finishInstrumentation(IApplicationThread target,
12531 int resultCode, Bundle results) {
12532 // Refuse possible leaked file descriptors
12533 if (results != null && results.hasFileDescriptors()) {
12534 throw new IllegalArgumentException("File descriptors passed in Intent");
12535 }
12536
12537 synchronized(this) {
12538 ProcessRecord app = getRecordForAppLocked(target);
12539 if (app == null) {
12540 Log.w(TAG, "finishInstrumentation: no app for " + target);
12541 return;
12542 }
12543 final long origId = Binder.clearCallingIdentity();
12544 finishInstrumentationLocked(app, resultCode, results);
12545 Binder.restoreCallingIdentity(origId);
12546 }
12547 }
12548
12549 // =========================================================
12550 // CONFIGURATION
12551 // =========================================================
12552
12553 public ConfigurationInfo getDeviceConfigurationInfo() {
12554 ConfigurationInfo config = new ConfigurationInfo();
12555 synchronized (this) {
12556 config.reqTouchScreen = mConfiguration.touchscreen;
12557 config.reqKeyboardType = mConfiguration.keyboard;
12558 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012559 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12560 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012561 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12562 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012563 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12564 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012565 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12566 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012567 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012568 }
12569 return config;
12570 }
12571
12572 public Configuration getConfiguration() {
12573 Configuration ci;
12574 synchronized(this) {
12575 ci = new Configuration(mConfiguration);
12576 }
12577 return ci;
12578 }
12579
12580 public void updateConfiguration(Configuration values) {
12581 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12582 "updateConfiguration()");
12583
12584 synchronized(this) {
12585 if (values == null && mWindowManager != null) {
12586 // sentinel: fetch the current configuration from the window manager
12587 values = mWindowManager.computeNewConfiguration();
12588 }
12589
12590 final long origId = Binder.clearCallingIdentity();
12591 updateConfigurationLocked(values, null);
12592 Binder.restoreCallingIdentity(origId);
12593 }
12594 }
12595
12596 /**
12597 * Do either or both things: (1) change the current configuration, and (2)
12598 * make sure the given activity is running with the (now) current
12599 * configuration. Returns true if the activity has been left running, or
12600 * false if <var>starting</var> is being destroyed to match the new
12601 * configuration.
12602 */
12603 public boolean updateConfigurationLocked(Configuration values,
12604 HistoryRecord starting) {
12605 int changes = 0;
12606
12607 boolean kept = true;
12608
12609 if (values != null) {
12610 Configuration newConfig = new Configuration(mConfiguration);
12611 changes = newConfig.updateFrom(values);
12612 if (changes != 0) {
12613 if (DEBUG_SWITCH) {
12614 Log.i(TAG, "Updating configuration to: " + values);
12615 }
12616
12617 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12618
12619 if (values.locale != null) {
12620 saveLocaleLocked(values.locale,
12621 !values.locale.equals(mConfiguration.locale),
12622 values.userSetLocale);
12623 }
12624
12625 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012626 Log.i(TAG, "Config changed: " + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012627
12628 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12629 msg.obj = new Configuration(mConfiguration);
12630 mHandler.sendMessage(msg);
12631
12632 final int N = mLRUProcesses.size();
12633 for (int i=0; i<N; i++) {
12634 ProcessRecord app = mLRUProcesses.get(i);
12635 try {
12636 if (app.thread != null) {
12637 app.thread.scheduleConfigurationChanged(mConfiguration);
12638 }
12639 } catch (Exception e) {
12640 }
12641 }
12642 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12643 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12644 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012645
12646 AttributeCache ac = AttributeCache.instance();
12647 if (ac != null) {
12648 ac.updateConfiguration(mConfiguration);
12649 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012650 }
12651 }
12652
12653 if (changes != 0 && starting == null) {
12654 // If the configuration changed, and the caller is not already
12655 // in the process of starting an activity, then find the top
12656 // activity to check if its configuration needs to change.
12657 starting = topRunningActivityLocked(null);
12658 }
12659
12660 if (starting != null) {
12661 kept = ensureActivityConfigurationLocked(starting, changes);
12662 if (kept) {
12663 // If this didn't result in the starting activity being
12664 // destroyed, then we need to make sure at this point that all
12665 // other activities are made visible.
12666 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12667 + ", ensuring others are correct.");
12668 ensureActivitiesVisibleLocked(starting, changes);
12669 }
12670 }
12671
12672 return kept;
12673 }
12674
12675 private final boolean relaunchActivityLocked(HistoryRecord r,
12676 int changes, boolean andResume) {
12677 List<ResultInfo> results = null;
12678 List<Intent> newIntents = null;
12679 if (andResume) {
12680 results = r.results;
12681 newIntents = r.newIntents;
12682 }
12683 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12684 + " with results=" + results + " newIntents=" + newIntents
12685 + " andResume=" + andResume);
12686 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12687 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12688 r.task.taskId, r.shortComponentName);
12689
12690 r.startFreezingScreenLocked(r.app, 0);
12691
12692 try {
12693 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12694 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12695 changes, !andResume);
12696 // Note: don't need to call pauseIfSleepingLocked() here, because
12697 // the caller will only pass in 'andResume' if this activity is
12698 // currently resumed, which implies we aren't sleeping.
12699 } catch (RemoteException e) {
12700 return false;
12701 }
12702
12703 if (andResume) {
12704 r.results = null;
12705 r.newIntents = null;
12706 }
12707
12708 return true;
12709 }
12710
12711 /**
12712 * Make sure the given activity matches the current configuration. Returns
12713 * false if the activity had to be destroyed. Returns true if the
12714 * configuration is the same, or the activity will remain running as-is
12715 * for whatever reason. Ensures the HistoryRecord is updated with the
12716 * correct configuration and all other bookkeeping is handled.
12717 */
12718 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12719 int globalChanges) {
12720 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12721
12722 // Short circuit: if the two configurations are the exact same
12723 // object (the common case), then there is nothing to do.
12724 Configuration newConfig = mConfiguration;
12725 if (r.configuration == newConfig) {
12726 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12727 return true;
12728 }
12729
12730 // We don't worry about activities that are finishing.
12731 if (r.finishing) {
12732 if (DEBUG_SWITCH) Log.i(TAG,
12733 "Configuration doesn't matter in finishing " + r);
12734 r.stopFreezingScreenLocked(false);
12735 return true;
12736 }
12737
12738 // Okay we now are going to make this activity have the new config.
12739 // But then we need to figure out how it needs to deal with that.
12740 Configuration oldConfig = r.configuration;
12741 r.configuration = newConfig;
12742
12743 // If the activity isn't currently running, just leave the new
12744 // configuration and it will pick that up next time it starts.
12745 if (r.app == null || r.app.thread == null) {
12746 if (DEBUG_SWITCH) Log.i(TAG,
12747 "Configuration doesn't matter not running " + r);
12748 r.stopFreezingScreenLocked(false);
12749 return true;
12750 }
12751
12752 // If the activity isn't persistent, there is a chance we will
12753 // need to restart it.
12754 if (!r.persistent) {
12755
12756 // Figure out what has changed between the two configurations.
12757 int changes = oldConfig.diff(newConfig);
12758 if (DEBUG_SWITCH) {
12759 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12760 + Integer.toHexString(changes) + ", handles=0x"
12761 + Integer.toHexString(r.info.configChanges));
12762 }
12763 if ((changes&(~r.info.configChanges)) != 0) {
12764 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12765 r.configChangeFlags |= changes;
12766 r.startFreezingScreenLocked(r.app, globalChanges);
12767 if (r.app == null || r.app.thread == null) {
12768 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12769 destroyActivityLocked(r, true);
12770 } else if (r.state == ActivityState.PAUSING) {
12771 // A little annoying: we are waiting for this activity to
12772 // finish pausing. Let's not do anything now, but just
12773 // flag that it needs to be restarted when done pausing.
12774 r.configDestroy = true;
12775 return true;
12776 } else if (r.state == ActivityState.RESUMED) {
12777 // Try to optimize this case: the configuration is changing
12778 // and we need to restart the top, resumed activity.
12779 // Instead of doing the normal handshaking, just say
12780 // "restart!".
12781 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12782 relaunchActivityLocked(r, r.configChangeFlags, true);
12783 r.configChangeFlags = 0;
12784 } else {
12785 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12786 relaunchActivityLocked(r, r.configChangeFlags, false);
12787 r.configChangeFlags = 0;
12788 }
12789
12790 // All done... tell the caller we weren't able to keep this
12791 // activity around.
12792 return false;
12793 }
12794 }
12795
12796 // Default case: the activity can handle this new configuration, so
12797 // hand it over. Note that we don't need to give it the new
12798 // configuration, since we always send configuration changes to all
12799 // process when they happen so it can just use whatever configuration
12800 // it last got.
12801 if (r.app != null && r.app.thread != null) {
12802 try {
12803 r.app.thread.scheduleActivityConfigurationChanged(r);
12804 } catch (RemoteException e) {
12805 // If process died, whatever.
12806 }
12807 }
12808 r.stopFreezingScreenLocked(false);
12809
12810 return true;
12811 }
12812
12813 /**
12814 * Save the locale. You must be inside a synchronized (this) block.
12815 */
12816 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12817 if(isDiff) {
12818 SystemProperties.set("user.language", l.getLanguage());
12819 SystemProperties.set("user.region", l.getCountry());
12820 }
12821
12822 if(isPersist) {
12823 SystemProperties.set("persist.sys.language", l.getLanguage());
12824 SystemProperties.set("persist.sys.country", l.getCountry());
12825 SystemProperties.set("persist.sys.localevar", l.getVariant());
12826 }
12827 }
12828
12829 // =========================================================
12830 // LIFETIME MANAGEMENT
12831 // =========================================================
12832
12833 private final int computeOomAdjLocked(
12834 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12835 if (mAdjSeq == app.adjSeq) {
12836 // This adjustment has already been computed.
12837 return app.curAdj;
12838 }
12839
12840 if (app.thread == null) {
12841 app.adjSeq = mAdjSeq;
12842 return (app.curAdj=EMPTY_APP_ADJ);
12843 }
12844
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012845 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
12846 // The max adjustment doesn't allow this app to be anything
12847 // below foreground, so it is not worth doing work for it.
12848 app.adjType = "fixed";
12849 app.adjSeq = mAdjSeq;
12850 app.curRawAdj = app.maxAdj;
12851 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
12852 return (app.curAdj=app.maxAdj);
12853 }
12854
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070012855 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012856 app.adjSource = null;
12857 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012858
The Android Open Source Project4df24232009-03-05 14:34:35 -080012859 // Determine the importance of the process, starting with most
12860 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012861 int adj;
12862 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012863 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012864 // The last app on the list is the foreground app.
12865 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012866 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012867 } else if (app.instrumentationClass != null) {
12868 // Don't want to kill running instrumentation.
12869 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012870 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012871 } else if (app.persistentActivities > 0) {
12872 // Special persistent activities... shouldn't be used these days.
12873 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012874 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012875 } else if (app.curReceiver != null ||
12876 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12877 // An app that is currently receiving a broadcast also
12878 // counts as being in the foreground.
12879 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012880 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012881 } else if (app.executingServices.size() > 0) {
12882 // An app that is currently executing a service callback also
12883 // counts as being in the foreground.
12884 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012885 app.adjType = "exec-service";
12886 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012887 // The user is aware of this app, so make it visible.
12888 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012889 app.adjType = "foreground-service";
12890 } else if (app.forcingToForeground != null) {
12891 // The user is aware of this app, so make it visible.
12892 adj = VISIBLE_APP_ADJ;
12893 app.adjType = "force-foreground";
12894 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012895 } else if (app == mHomeProcess) {
12896 // This process is hosting what we currently consider to be the
12897 // home app, so we don't want to let it go into the background.
12898 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012899 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012900 } else if ((N=app.activities.size()) != 0) {
12901 // This app is in the background with paused activities.
12902 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012903 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012904 for (int j=0; j<N; j++) {
12905 if (((HistoryRecord)app.activities.get(j)).visible) {
12906 // This app has a visible activity!
12907 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012908 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012909 break;
12910 }
12911 }
12912 } else {
12913 // A very not-needed process.
12914 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012915 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012916 }
12917
The Android Open Source Project4df24232009-03-05 14:34:35 -080012918 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012919 // there are applications dependent on our services or providers, but
12920 // this gives us a baseline and makes sure we don't get into an
12921 // infinite recursion.
12922 app.adjSeq = mAdjSeq;
12923 app.curRawAdj = adj;
12924 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12925
Christopher Tate6fa95972009-06-05 18:43:55 -070012926 if (mBackupTarget != null && app == mBackupTarget.app) {
12927 // If possible we want to avoid killing apps while they're being backed up
12928 if (adj > BACKUP_APP_ADJ) {
12929 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12930 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012931 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070012932 }
12933 }
12934
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012935 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012936 final long now = SystemClock.uptimeMillis();
12937 // This process is more important if the top activity is
12938 // bound to the service.
12939 Iterator jt = app.services.iterator();
12940 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12941 ServiceRecord s = (ServiceRecord)jt.next();
12942 if (s.startRequested) {
12943 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12944 // This service has seen some activity within
12945 // recent memory, so we will keep its process ahead
12946 // of the background processes.
12947 if (adj > SECONDARY_SERVER_ADJ) {
12948 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012949 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012950 }
12951 }
12952 }
12953 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12954 Iterator<ConnectionRecord> kt
12955 = s.connections.values().iterator();
12956 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12957 // XXX should compute this based on the max of
12958 // all connected clients.
12959 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012960 if (cr.binding.client == app) {
12961 // Binding to ourself is not interesting.
12962 continue;
12963 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012964 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12965 ProcessRecord client = cr.binding.client;
12966 int myHiddenAdj = hiddenAdj;
12967 if (myHiddenAdj > client.hiddenAdj) {
12968 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12969 myHiddenAdj = client.hiddenAdj;
12970 } else {
12971 myHiddenAdj = VISIBLE_APP_ADJ;
12972 }
12973 }
12974 int clientAdj = computeOomAdjLocked(
12975 client, myHiddenAdj, TOP_APP);
12976 if (adj > clientAdj) {
12977 adj = clientAdj > VISIBLE_APP_ADJ
12978 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012979 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070012980 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
12981 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012982 app.adjSource = cr.binding.client;
12983 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012984 }
12985 }
12986 HistoryRecord a = cr.activity;
12987 //if (a != null) {
12988 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12989 //}
12990 if (a != null && adj > FOREGROUND_APP_ADJ &&
12991 (a.state == ActivityState.RESUMED
12992 || a.state == ActivityState.PAUSING)) {
12993 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012994 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070012995 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
12996 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012997 app.adjSource = a;
12998 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012999 }
13000 }
13001 }
13002 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013003
13004 // Finally, f this process has active services running in it, we
13005 // would like to avoid killing it unless it would prevent the current
13006 // application from running. By default we put the process in
13007 // with the rest of the background processes; as we scan through
13008 // its services we may bump it up from there.
13009 if (adj > hiddenAdj) {
13010 adj = hiddenAdj;
13011 app.adjType = "bg-services";
13012 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013013 }
13014
13015 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013016 Iterator jt = app.pubProviders.values().iterator();
13017 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13018 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13019 if (cpr.clients.size() != 0) {
13020 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13021 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13022 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013023 if (client == app) {
13024 // Being our own client is not interesting.
13025 continue;
13026 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013027 int myHiddenAdj = hiddenAdj;
13028 if (myHiddenAdj > client.hiddenAdj) {
13029 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13030 myHiddenAdj = client.hiddenAdj;
13031 } else {
13032 myHiddenAdj = FOREGROUND_APP_ADJ;
13033 }
13034 }
13035 int clientAdj = computeOomAdjLocked(
13036 client, myHiddenAdj, TOP_APP);
13037 if (adj > clientAdj) {
13038 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013039 ? clientAdj : FOREGROUND_APP_ADJ;
13040 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013041 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13042 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013043 app.adjSource = client;
13044 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013045 }
13046 }
13047 }
13048 // If the provider has external (non-framework) process
13049 // dependencies, ensure that its adjustment is at least
13050 // FOREGROUND_APP_ADJ.
13051 if (cpr.externals != 0) {
13052 if (adj > FOREGROUND_APP_ADJ) {
13053 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013054 app.adjType = "provider";
13055 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013056 }
13057 }
13058 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013059
13060 // Finally, if this process has published any content providers,
13061 // then its adjustment makes it at least as important as any of the
13062 // processes using those providers, and no less important than
13063 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
13064 if (adj > CONTENT_PROVIDER_ADJ) {
13065 adj = CONTENT_PROVIDER_ADJ;
13066 app.adjType = "pub-providers";
13067 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013068 }
13069
13070 app.curRawAdj = adj;
13071
13072 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13073 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13074 if (adj > app.maxAdj) {
13075 adj = app.maxAdj;
13076 }
13077
13078 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013079 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013080 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
13081 : Process.THREAD_GROUP_DEFAULT;
13082
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013083 return adj;
13084 }
13085
13086 /**
13087 * Ask a given process to GC right now.
13088 */
13089 final void performAppGcLocked(ProcessRecord app) {
13090 try {
13091 app.lastRequestedGc = SystemClock.uptimeMillis();
13092 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013093 if (app.reportLowMemory) {
13094 app.reportLowMemory = false;
13095 app.thread.scheduleLowMemory();
13096 } else {
13097 app.thread.processInBackground();
13098 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013099 }
13100 } catch (Exception e) {
13101 // whatever.
13102 }
13103 }
13104
13105 /**
13106 * Returns true if things are idle enough to perform GCs.
13107 */
13108 private final boolean canGcNow() {
13109 return mParallelBroadcasts.size() == 0
13110 && mOrderedBroadcasts.size() == 0
13111 && (mSleeping || (mResumedActivity != null &&
13112 mResumedActivity.idle));
13113 }
13114
13115 /**
13116 * Perform GCs on all processes that are waiting for it, but only
13117 * if things are idle.
13118 */
13119 final void performAppGcsLocked() {
13120 final int N = mProcessesToGc.size();
13121 if (N <= 0) {
13122 return;
13123 }
13124 if (canGcNow()) {
13125 while (mProcessesToGc.size() > 0) {
13126 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013127 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13128 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13129 <= SystemClock.uptimeMillis()) {
13130 // To avoid spamming the system, we will GC processes one
13131 // at a time, waiting a few seconds between each.
13132 performAppGcLocked(proc);
13133 scheduleAppGcsLocked();
13134 return;
13135 } else {
13136 // It hasn't been long enough since we last GCed this
13137 // process... put it in the list to wait for its time.
13138 addProcessToGcListLocked(proc);
13139 break;
13140 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013141 }
13142 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013143
13144 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013145 }
13146 }
13147
13148 /**
13149 * If all looks good, perform GCs on all processes waiting for them.
13150 */
13151 final void performAppGcsIfAppropriateLocked() {
13152 if (canGcNow()) {
13153 performAppGcsLocked();
13154 return;
13155 }
13156 // Still not idle, wait some more.
13157 scheduleAppGcsLocked();
13158 }
13159
13160 /**
13161 * Schedule the execution of all pending app GCs.
13162 */
13163 final void scheduleAppGcsLocked() {
13164 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013165
13166 if (mProcessesToGc.size() > 0) {
13167 // Schedule a GC for the time to the next process.
13168 ProcessRecord proc = mProcessesToGc.get(0);
13169 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13170
13171 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13172 long now = SystemClock.uptimeMillis();
13173 if (when < (now+GC_TIMEOUT)) {
13174 when = now + GC_TIMEOUT;
13175 }
13176 mHandler.sendMessageAtTime(msg, when);
13177 }
13178 }
13179
13180 /**
13181 * Add a process to the array of processes waiting to be GCed. Keeps the
13182 * list in sorted order by the last GC time. The process can't already be
13183 * on the list.
13184 */
13185 final void addProcessToGcListLocked(ProcessRecord proc) {
13186 boolean added = false;
13187 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13188 if (mProcessesToGc.get(i).lastRequestedGc <
13189 proc.lastRequestedGc) {
13190 added = true;
13191 mProcessesToGc.add(i+1, proc);
13192 break;
13193 }
13194 }
13195 if (!added) {
13196 mProcessesToGc.add(0, proc);
13197 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013198 }
13199
13200 /**
13201 * Set up to ask a process to GC itself. This will either do it
13202 * immediately, or put it on the list of processes to gc the next
13203 * time things are idle.
13204 */
13205 final void scheduleAppGcLocked(ProcessRecord app) {
13206 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013207 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013208 return;
13209 }
13210 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013211 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013212 scheduleAppGcsLocked();
13213 }
13214 }
13215
13216 private final boolean updateOomAdjLocked(
13217 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13218 app.hiddenAdj = hiddenAdj;
13219
13220 if (app.thread == null) {
13221 return true;
13222 }
13223
13224 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
13225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013226 if (app.pid != 0 && app.pid != MY_PID) {
13227 if (app.curRawAdj != app.setRawAdj) {
13228 if (app.curRawAdj > FOREGROUND_APP_ADJ
13229 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13230 // If this app is transitioning from foreground to
13231 // non-foreground, have it do a gc.
13232 scheduleAppGcLocked(app);
13233 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13234 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13235 // Likewise do a gc when an app is moving in to the
13236 // background (such as a service stopping).
13237 scheduleAppGcLocked(app);
13238 }
13239 app.setRawAdj = app.curRawAdj;
13240 }
13241 if (adj != app.setAdj) {
13242 if (Process.setOomAdj(app.pid, adj)) {
13243 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13244 TAG, "Set app " + app.processName +
13245 " oom adj to " + adj);
13246 app.setAdj = adj;
13247 } else {
13248 return false;
13249 }
13250 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013251 if (app.setSchedGroup != app.curSchedGroup) {
13252 app.setSchedGroup = app.curSchedGroup;
13253 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13254 "Setting process group of " + app.processName
13255 + " to " + app.curSchedGroup);
13256 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013257 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013258 try {
13259 Process.setProcessGroup(app.pid, app.curSchedGroup);
13260 } catch (Exception e) {
13261 Log.w(TAG, "Failed setting process group of " + app.pid
13262 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013263 e.printStackTrace();
13264 } finally {
13265 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013266 }
13267 }
13268 if (false) {
13269 if (app.thread != null) {
13270 try {
13271 app.thread.setSchedulingGroup(app.curSchedGroup);
13272 } catch (RemoteException e) {
13273 }
13274 }
13275 }
13276 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013277 }
13278
13279 return true;
13280 }
13281
13282 private final HistoryRecord resumedAppLocked() {
13283 HistoryRecord resumedActivity = mResumedActivity;
13284 if (resumedActivity == null || resumedActivity.app == null) {
13285 resumedActivity = mPausingActivity;
13286 if (resumedActivity == null || resumedActivity.app == null) {
13287 resumedActivity = topRunningActivityLocked(null);
13288 }
13289 }
13290 return resumedActivity;
13291 }
13292
13293 private final boolean updateOomAdjLocked(ProcessRecord app) {
13294 final HistoryRecord TOP_ACT = resumedAppLocked();
13295 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13296 int curAdj = app.curAdj;
13297 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13298 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13299
13300 mAdjSeq++;
13301
13302 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13303 if (res) {
13304 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13305 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13306 if (nowHidden != wasHidden) {
13307 // Changed to/from hidden state, so apps after it in the LRU
13308 // list may also be changed.
13309 updateOomAdjLocked();
13310 }
13311 }
13312 return res;
13313 }
13314
13315 private final boolean updateOomAdjLocked() {
13316 boolean didOomAdj = true;
13317 final HistoryRecord TOP_ACT = resumedAppLocked();
13318 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13319
13320 if (false) {
13321 RuntimeException e = new RuntimeException();
13322 e.fillInStackTrace();
13323 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13324 }
13325
13326 mAdjSeq++;
13327
13328 // First try updating the OOM adjustment for each of the
13329 // application processes based on their current state.
13330 int i = mLRUProcesses.size();
13331 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13332 while (i > 0) {
13333 i--;
13334 ProcessRecord app = mLRUProcesses.get(i);
13335 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13336 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13337 && app.curAdj == curHiddenAdj) {
13338 curHiddenAdj++;
13339 }
13340 } else {
13341 didOomAdj = false;
13342 }
13343 }
13344
13345 // todo: for now pretend like OOM ADJ didn't work, because things
13346 // aren't behaving as expected on Linux -- it's not killing processes.
13347 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13348 }
13349
13350 private final void trimApplications() {
13351 synchronized (this) {
13352 int i;
13353
13354 // First remove any unused application processes whose package
13355 // has been removed.
13356 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13357 final ProcessRecord app = mRemovedProcesses.get(i);
13358 if (app.activities.size() == 0
13359 && app.curReceiver == null && app.services.size() == 0) {
13360 Log.i(
13361 TAG, "Exiting empty application process "
13362 + app.processName + " ("
13363 + (app.thread != null ? app.thread.asBinder() : null)
13364 + ")\n");
13365 if (app.pid > 0 && app.pid != MY_PID) {
13366 Process.killProcess(app.pid);
13367 } else {
13368 try {
13369 app.thread.scheduleExit();
13370 } catch (Exception e) {
13371 // Ignore exceptions.
13372 }
13373 }
13374 cleanUpApplicationRecordLocked(app, false, -1);
13375 mRemovedProcesses.remove(i);
13376
13377 if (app.persistent) {
13378 if (app.persistent) {
13379 addAppLocked(app.info);
13380 }
13381 }
13382 }
13383 }
13384
13385 // Now try updating the OOM adjustment for each of the
13386 // application processes based on their current state.
13387 // If the setOomAdj() API is not supported, then go with our
13388 // back-up plan...
13389 if (!updateOomAdjLocked()) {
13390
13391 // Count how many processes are running services.
13392 int numServiceProcs = 0;
13393 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13394 final ProcessRecord app = mLRUProcesses.get(i);
13395
13396 if (app.persistent || app.services.size() != 0
13397 || app.curReceiver != null
13398 || app.persistentActivities > 0) {
13399 // Don't count processes holding services against our
13400 // maximum process count.
13401 if (localLOGV) Log.v(
13402 TAG, "Not trimming app " + app + " with services: "
13403 + app.services);
13404 numServiceProcs++;
13405 }
13406 }
13407
13408 int curMaxProcs = mProcessLimit;
13409 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13410 if (mAlwaysFinishActivities) {
13411 curMaxProcs = 1;
13412 }
13413 curMaxProcs += numServiceProcs;
13414
13415 // Quit as many processes as we can to get down to the desired
13416 // process count. First remove any processes that no longer
13417 // have activites running in them.
13418 for ( i=0;
13419 i<mLRUProcesses.size()
13420 && mLRUProcesses.size() > curMaxProcs;
13421 i++) {
13422 final ProcessRecord app = mLRUProcesses.get(i);
13423 // Quit an application only if it is not currently
13424 // running any activities.
13425 if (!app.persistent && app.activities.size() == 0
13426 && app.curReceiver == null && app.services.size() == 0) {
13427 Log.i(
13428 TAG, "Exiting empty application process "
13429 + app.processName + " ("
13430 + (app.thread != null ? app.thread.asBinder() : null)
13431 + ")\n");
13432 if (app.pid > 0 && app.pid != MY_PID) {
13433 Process.killProcess(app.pid);
13434 } else {
13435 try {
13436 app.thread.scheduleExit();
13437 } catch (Exception e) {
13438 // Ignore exceptions.
13439 }
13440 }
13441 // todo: For now we assume the application is not buggy
13442 // or evil, and will quit as a result of our request.
13443 // Eventually we need to drive this off of the death
13444 // notification, and kill the process if it takes too long.
13445 cleanUpApplicationRecordLocked(app, false, i);
13446 i--;
13447 }
13448 }
13449
13450 // If we still have too many processes, now from the least
13451 // recently used process we start finishing activities.
13452 if (Config.LOGV) Log.v(
13453 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13454 " of " + curMaxProcs + " processes");
13455 for ( i=0;
13456 i<mLRUProcesses.size()
13457 && mLRUProcesses.size() > curMaxProcs;
13458 i++) {
13459 final ProcessRecord app = mLRUProcesses.get(i);
13460 // Quit the application only if we have a state saved for
13461 // all of its activities.
13462 boolean canQuit = !app.persistent && app.curReceiver == null
13463 && app.services.size() == 0
13464 && app.persistentActivities == 0;
13465 int NUMA = app.activities.size();
13466 int j;
13467 if (Config.LOGV) Log.v(
13468 TAG, "Looking to quit " + app.processName);
13469 for (j=0; j<NUMA && canQuit; j++) {
13470 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13471 if (Config.LOGV) Log.v(
13472 TAG, " " + r.intent.getComponent().flattenToShortString()
13473 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13474 canQuit = (r.haveState || !r.stateNotNeeded)
13475 && !r.visible && r.stopped;
13476 }
13477 if (canQuit) {
13478 // Finish all of the activities, and then the app itself.
13479 for (j=0; j<NUMA; j++) {
13480 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13481 if (!r.finishing) {
13482 destroyActivityLocked(r, false);
13483 }
13484 r.resultTo = null;
13485 }
13486 Log.i(TAG, "Exiting application process "
13487 + app.processName + " ("
13488 + (app.thread != null ? app.thread.asBinder() : null)
13489 + ")\n");
13490 if (app.pid > 0 && app.pid != MY_PID) {
13491 Process.killProcess(app.pid);
13492 } else {
13493 try {
13494 app.thread.scheduleExit();
13495 } catch (Exception e) {
13496 // Ignore exceptions.
13497 }
13498 }
13499 // todo: For now we assume the application is not buggy
13500 // or evil, and will quit as a result of our request.
13501 // Eventually we need to drive this off of the death
13502 // notification, and kill the process if it takes too long.
13503 cleanUpApplicationRecordLocked(app, false, i);
13504 i--;
13505 //dump();
13506 }
13507 }
13508
13509 }
13510
13511 int curMaxActivities = MAX_ACTIVITIES;
13512 if (mAlwaysFinishActivities) {
13513 curMaxActivities = 1;
13514 }
13515
13516 // Finally, if there are too many activities now running, try to
13517 // finish as many as we can to get back down to the limit.
13518 for ( i=0;
13519 i<mLRUActivities.size()
13520 && mLRUActivities.size() > curMaxActivities;
13521 i++) {
13522 final HistoryRecord r
13523 = (HistoryRecord)mLRUActivities.get(i);
13524
13525 // We can finish this one if we have its icicle saved and
13526 // it is not persistent.
13527 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13528 && r.stopped && !r.persistent && !r.finishing) {
13529 final int origSize = mLRUActivities.size();
13530 destroyActivityLocked(r, true);
13531
13532 // This will remove it from the LRU list, so keep
13533 // our index at the same value. Note that this check to
13534 // see if the size changes is just paranoia -- if
13535 // something unexpected happens, we don't want to end up
13536 // in an infinite loop.
13537 if (origSize > mLRUActivities.size()) {
13538 i--;
13539 }
13540 }
13541 }
13542 }
13543 }
13544
13545 /** This method sends the specified signal to each of the persistent apps */
13546 public void signalPersistentProcesses(int sig) throws RemoteException {
13547 if (sig != Process.SIGNAL_USR1) {
13548 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13549 }
13550
13551 synchronized (this) {
13552 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13553 != PackageManager.PERMISSION_GRANTED) {
13554 throw new SecurityException("Requires permission "
13555 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13556 }
13557
13558 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13559 ProcessRecord r = mLRUProcesses.get(i);
13560 if (r.thread != null && r.persistent) {
13561 Process.sendSignal(r.pid, sig);
13562 }
13563 }
13564 }
13565 }
13566
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013567 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013568 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013569
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013570 try {
13571 synchronized (this) {
13572 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13573 // its own permission.
13574 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13575 != PackageManager.PERMISSION_GRANTED) {
13576 throw new SecurityException("Requires permission "
13577 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013578 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013579
13580 if (start && fd == null) {
13581 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013582 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013583
13584 ProcessRecord proc = null;
13585 try {
13586 int pid = Integer.parseInt(process);
13587 synchronized (mPidsSelfLocked) {
13588 proc = mPidsSelfLocked.get(pid);
13589 }
13590 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013591 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013592
13593 if (proc == null) {
13594 HashMap<String, SparseArray<ProcessRecord>> all
13595 = mProcessNames.getMap();
13596 SparseArray<ProcessRecord> procs = all.get(process);
13597 if (procs != null && procs.size() > 0) {
13598 proc = procs.valueAt(0);
13599 }
13600 }
13601
13602 if (proc == null || proc.thread == null) {
13603 throw new IllegalArgumentException("Unknown process: " + process);
13604 }
13605
13606 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13607 if (isSecure) {
13608 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13609 throw new SecurityException("Process not debuggable: " + proc);
13610 }
13611 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013612
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013613 proc.thread.profilerControl(start, path, fd);
13614 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013615 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013616 }
13617 } catch (RemoteException e) {
13618 throw new IllegalStateException("Process disappeared");
13619 } finally {
13620 if (fd != null) {
13621 try {
13622 fd.close();
13623 } catch (IOException e) {
13624 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013625 }
13626 }
13627 }
13628
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013629 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13630 public void monitor() {
13631 synchronized (this) { }
13632 }
13633}