blob: d4f7207ecbd41e3f0c32bfc3493ef9ab735b6261 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
19import com.android.internal.os.BatteryStatsImpl;
Dianne Hackbornde7faf62009-06-30 13:27:30 -070020import com.android.server.AttributeCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import com.android.server.IntentResolver;
22import com.android.server.ProcessMap;
23import com.android.server.ProcessStats;
24import com.android.server.SystemServer;
25import com.android.server.Watchdog;
26import com.android.server.WindowManagerService;
27
28import android.app.Activity;
29import android.app.ActivityManager;
30import android.app.ActivityManagerNative;
31import android.app.ActivityThread;
32import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020033import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.app.Dialog;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070035import android.app.IActivityController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.app.IActivityWatcher;
37import android.app.IApplicationThread;
38import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.app.IServiceConnection;
40import android.app.IThumbnailReceiver;
41import android.app.Instrumentation;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070042import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.app.PendingIntent;
44import android.app.ResultInfo;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070045import android.app.Service;
Christopher Tate181fafa2009-05-14 11:12:14 -070046import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020047import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.ComponentName;
49import android.content.ContentResolver;
50import android.content.Context;
51import android.content.Intent;
52import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070053import android.content.IIntentReceiver;
54import android.content.IIntentSender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -070055import android.content.IntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.content.pm.ActivityInfo;
57import android.content.pm.ApplicationInfo;
58import android.content.pm.ConfigurationInfo;
59import android.content.pm.IPackageDataObserver;
60import android.content.pm.IPackageManager;
61import android.content.pm.InstrumentationInfo;
62import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070063import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import android.content.pm.ProviderInfo;
65import android.content.pm.ResolveInfo;
66import android.content.pm.ServiceInfo;
67import android.content.res.Configuration;
68import android.graphics.Bitmap;
69import android.net.Uri;
70import android.os.Binder;
71import android.os.Bundle;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070072import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.os.Environment;
74import android.os.FileUtils;
75import android.os.Handler;
76import android.os.IBinder;
77import android.os.IPermissionController;
78import android.os.Looper;
79import android.os.Message;
80import android.os.Parcel;
81import android.os.ParcelFileDescriptor;
82import android.os.PowerManager;
83import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070084import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.os.RemoteException;
86import android.os.ServiceManager;
87import android.os.SystemClock;
88import android.os.SystemProperties;
89import android.provider.Checkin;
90import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020091import android.server.data.CrashData;
92import android.server.data.StackTraceElementData;
93import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094import android.text.TextUtils;
95import android.util.Config;
96import android.util.EventLog;
97import android.util.Log;
98import android.util.PrintWriterPrinter;
99import android.util.SparseArray;
100import android.view.Gravity;
101import android.view.LayoutInflater;
102import android.view.View;
103import android.view.WindowManager;
104import android.view.WindowManagerPolicy;
105
106import dalvik.system.Zygote;
107
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200108import java.io.ByteArrayInputStream;
109import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110import java.io.File;
111import java.io.FileDescriptor;
112import java.io.FileInputStream;
113import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200114import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115import java.io.PrintWriter;
116import java.lang.IllegalStateException;
117import java.lang.ref.WeakReference;
118import java.util.ArrayList;
119import java.util.HashMap;
120import java.util.HashSet;
121import java.util.Iterator;
122import java.util.List;
123import java.util.Locale;
124import java.util.Map;
125
126public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
127 static final String TAG = "ActivityManager";
128 static final boolean DEBUG = false;
129 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
130 static final boolean DEBUG_SWITCH = localLOGV || false;
131 static final boolean DEBUG_TASKS = localLOGV || false;
132 static final boolean DEBUG_PAUSE = localLOGV || false;
133 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
134 static final boolean DEBUG_TRANSITION = localLOGV || false;
135 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700136 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 static final boolean DEBUG_SERVICE = localLOGV || false;
138 static final boolean DEBUG_VISBILITY = localLOGV || false;
139 static final boolean DEBUG_PROCESSES = localLOGV || false;
Dianne Hackborna1e989b2009-09-01 19:54:29 -0700140 static final boolean DEBUG_PROVIDER = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700142 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700143 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 static final boolean VALIDATE_TOKENS = false;
145 static final boolean SHOW_ACTIVITY_START_TIME = true;
146
147 // Control over CPU and battery monitoring.
148 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
149 static final boolean MONITOR_CPU_USAGE = true;
150 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
151 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
152 static final boolean MONITOR_THREAD_CPU_USAGE = false;
153
154 // Event log tags
155 static final int LOG_CONFIGURATION_CHANGED = 2719;
156 static final int LOG_CPU = 2721;
157 static final int LOG_AM_FINISH_ACTIVITY = 30001;
158 static final int LOG_TASK_TO_FRONT = 30002;
159 static final int LOG_AM_NEW_INTENT = 30003;
160 static final int LOG_AM_CREATE_TASK = 30004;
161 static final int LOG_AM_CREATE_ACTIVITY = 30005;
162 static final int LOG_AM_RESTART_ACTIVITY = 30006;
163 static final int LOG_AM_RESUME_ACTIVITY = 30007;
164 static final int LOG_ANR = 30008;
165 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
166 static final int LOG_AM_PROCESS_BOUND = 30010;
167 static final int LOG_AM_PROCESS_DIED = 30011;
168 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
169 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
170 static final int LOG_AM_PROCESS_START = 30014;
171 static final int LOG_AM_PROCESS_BAD = 30015;
172 static final int LOG_AM_PROCESS_GOOD = 30016;
173 static final int LOG_AM_LOW_MEMORY = 30017;
174 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
175 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
176 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
177 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
178 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
179 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
180 static final int LOG_AM_CREATE_SERVICE = 30030;
181 static final int LOG_AM_DESTROY_SERVICE = 30031;
182 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
183 static final int LOG_AM_DROP_PROCESS = 30033;
184 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
185 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
186 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
187
188 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
189 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
190
Dianne Hackborn1655be42009-05-08 14:29:01 -0700191 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700192 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700193
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 private static final String SYSTEM_SECURE = "ro.secure";
195
196 // This is the maximum number of application processes we would like
197 // to have running. Due to the asynchronous nature of things, we can
198 // temporarily go beyond this limit.
199 static final int MAX_PROCESSES = 2;
200
201 // Set to false to leave processes running indefinitely, relying on
202 // the kernel killing them as resources are required.
203 static final boolean ENFORCE_PROCESS_LIMIT = false;
204
205 // This is the maximum number of activities that we would like to have
206 // running at a given time.
207 static final int MAX_ACTIVITIES = 20;
208
209 // Maximum number of recent tasks that we can remember.
210 static final int MAX_RECENT_TASKS = 20;
211
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700212 // Amount of time after a call to stopAppSwitches() during which we will
213 // prevent further untrusted switches from happening.
214 static final long APP_SWITCH_DELAY_TIME = 5*1000;
215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 // How long until we reset a task when the user returns to it. Currently
217 // 30 minutes.
218 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
219
220 // Set to true to disable the icon that is shown while a new activity
221 // is being started.
222 static final boolean SHOW_APP_STARTING_ICON = true;
223
224 // How long we wait until giving up on the last activity to pause. This
225 // is short because it directly impacts the responsiveness of starting the
226 // next activity.
227 static final int PAUSE_TIMEOUT = 500;
228
229 /**
230 * How long we can hold the launch wake lock before giving up.
231 */
232 static final int LAUNCH_TIMEOUT = 10*1000;
233
234 // How long we wait for a launched process to attach to the activity manager
235 // before we decide it's never going to come up for real.
236 static final int PROC_START_TIMEOUT = 10*1000;
237
238 // How long we wait until giving up on the last activity telling us it
239 // is idle.
240 static final int IDLE_TIMEOUT = 10*1000;
241
242 // How long to wait after going idle before forcing apps to GC.
243 static final int GC_TIMEOUT = 5*1000;
244
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700245 // The minimum amount of time between successive GC requests for a process.
246 static final int GC_MIN_INTERVAL = 60*1000;
247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 // How long we wait until giving up on an activity telling us it has
249 // finished destroying itself.
250 static final int DESTROY_TIMEOUT = 10*1000;
251
252 // How long we allow a receiver to run before giving up on it.
253 static final int BROADCAST_TIMEOUT = 10*1000;
254
255 // How long we wait for a service to finish executing.
256 static final int SERVICE_TIMEOUT = 20*1000;
257
258 // How long a service needs to be running until restarting its process
259 // is no longer considered to be a relaunch of the service.
260 static final int SERVICE_RESTART_DURATION = 5*1000;
261
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700262 // How long a service needs to be running until it will start back at
263 // SERVICE_RESTART_DURATION after being killed.
264 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
265
266 // Multiplying factor to increase restart duration time by, for each time
267 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
268 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
269
270 // The minimum amount of time between restarting services that we allow.
271 // That is, when multiple services are restarting, we won't allow each
272 // to restart less than this amount of time from the last one.
273 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
274
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 // Maximum amount of time for there to be no activity on a service before
276 // we consider it non-essential and allow its process to go on the
277 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700278 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279
280 // How long we wait until we timeout on key dispatching.
281 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
282
283 // The minimum time we allow between crashes, for us to consider this
284 // application to be bad and stop and its services and reject broadcasts.
285 static final int MIN_CRASH_INTERVAL = 60*1000;
286
287 // How long we wait until we timeout on key dispatching during instrumentation.
288 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
289
290 // OOM adjustments for processes in various states:
291
292 // This is a process without anything currently running in it. Definitely
293 // the first to go! Value set in system/rootdir/init.rc on startup.
294 // This value is initalized in the constructor, careful when refering to
295 // this static variable externally.
296 static int EMPTY_APP_ADJ;
297
298 // This is a process with a content provider that does not have any clients
299 // attached to it. If it did have any clients, its adjustment would be the
300 // one for the highest-priority of those processes.
301 static int CONTENT_PROVIDER_ADJ;
302
303 // This is a process only hosting activities that are not visible,
304 // so it can be killed without any disruption. Value set in
305 // system/rootdir/init.rc on startup.
306 final int HIDDEN_APP_MAX_ADJ;
307 static int HIDDEN_APP_MIN_ADJ;
308
The Android Open Source Project4df24232009-03-05 14:34:35 -0800309 // This is a process holding the home application -- we want to try
310 // avoiding killing it, even if it would normally be in the background,
311 // because the user interacts with it so much.
312 final int HOME_APP_ADJ;
313
Christopher Tate6fa95972009-06-05 18:43:55 -0700314 // This is a process currently hosting a backup operation. Killing it
315 // is not entirely fatal but is generally a bad idea.
316 final int BACKUP_APP_ADJ;
317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 // This is a process holding a secondary server -- killing it will not
319 // have much of an impact as far as the user is concerned. Value set in
320 // system/rootdir/init.rc on startup.
321 final int SECONDARY_SERVER_ADJ;
322
323 // This is a process only hosting activities that are visible to the
324 // user, so we'd prefer they don't disappear. Value set in
325 // system/rootdir/init.rc on startup.
326 final int VISIBLE_APP_ADJ;
327
328 // This is the process running the current foreground app. We'd really
329 // rather not kill it! Value set in system/rootdir/init.rc on startup.
330 final int FOREGROUND_APP_ADJ;
331
332 // This is a process running a core server, such as telephony. Definitely
333 // don't want to kill it, but doing so is not completely fatal.
334 static final int CORE_SERVER_ADJ = -12;
335
336 // The system process runs at the default adjustment.
337 static final int SYSTEM_ADJ = -16;
338
339 // Memory pages are 4K.
340 static final int PAGE_SIZE = 4*1024;
341
Jacek Surazski82a73df2009-06-17 14:33:18 +0200342 // System property defining error report receiver for system apps
343 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
344
345 // System property defining default error report receiver
346 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 // Corresponding memory levels for above adjustments.
349 final int EMPTY_APP_MEM;
350 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800351 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700352 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 final int SECONDARY_SERVER_MEM;
354 final int VISIBLE_APP_MEM;
355 final int FOREGROUND_APP_MEM;
356
357 final int MY_PID;
358
359 static final String[] EMPTY_STRING_ARRAY = new String[0];
360
361 enum ActivityState {
362 INITIALIZING,
363 RESUMED,
364 PAUSING,
365 PAUSED,
366 STOPPING,
367 STOPPED,
368 FINISHING,
369 DESTROYING,
370 DESTROYED
371 }
372
373 /**
374 * The back history of all previous (and possibly still
375 * running) activities. It contains HistoryRecord objects.
376 */
377 final ArrayList mHistory = new ArrayList();
378
379 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700380 * Description of a request to start a new activity, which has been held
381 * due to app switches being disabled.
382 */
383 class PendingActivityLaunch {
384 HistoryRecord r;
385 HistoryRecord sourceRecord;
386 Uri[] grantedUriPermissions;
387 int grantedMode;
388 boolean onlyIfNeeded;
389 }
390
391 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
392 = new ArrayList<PendingActivityLaunch>();
393
394 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 * List of all active broadcasts that are to be executed immediately
396 * (without waiting for another broadcast to finish). Currently this only
397 * contains broadcasts to registered receivers, to avoid spinning up
398 * a bunch of processes to execute IntentReceiver components.
399 */
400 final ArrayList<BroadcastRecord> mParallelBroadcasts
401 = new ArrayList<BroadcastRecord>();
402
403 /**
404 * List of all active broadcasts that are to be executed one at a time.
405 * The object at the top of the list is the currently activity broadcasts;
406 * those after it are waiting for the top to finish..
407 */
408 final ArrayList<BroadcastRecord> mOrderedBroadcasts
409 = new ArrayList<BroadcastRecord>();
410
411 /**
412 * Set when we current have a BROADCAST_INTENT_MSG in flight.
413 */
414 boolean mBroadcastsScheduled = false;
415
416 /**
417 * Set to indicate whether to issue an onUserLeaving callback when a
418 * newly launched activity is being brought in front of us.
419 */
420 boolean mUserLeaving = false;
421
422 /**
423 * When we are in the process of pausing an activity, before starting the
424 * next one, this variable holds the activity that is currently being paused.
425 */
426 HistoryRecord mPausingActivity = null;
427
428 /**
429 * Current activity that is resumed, or null if there is none.
430 */
431 HistoryRecord mResumedActivity = null;
432
433 /**
434 * Activity we have told the window manager to have key focus.
435 */
436 HistoryRecord mFocusedActivity = null;
437
438 /**
439 * This is the last activity that we put into the paused state. This is
440 * used to determine if we need to do an activity transition while sleeping,
441 * when we normally hold the top activity paused.
442 */
443 HistoryRecord mLastPausedActivity = null;
444
445 /**
446 * List of activities that are waiting for a new activity
447 * to become visible before completing whatever operation they are
448 * supposed to do.
449 */
450 final ArrayList mWaitingVisibleActivities = new ArrayList();
451
452 /**
453 * List of activities that are ready to be stopped, but waiting
454 * for the next activity to settle down before doing so. It contains
455 * HistoryRecord objects.
456 */
457 final ArrayList<HistoryRecord> mStoppingActivities
458 = new ArrayList<HistoryRecord>();
459
460 /**
461 * List of intents that were used to start the most recent tasks.
462 */
463 final ArrayList<TaskRecord> mRecentTasks
464 = new ArrayList<TaskRecord>();
465
466 /**
467 * List of activities that are ready to be finished, but waiting
468 * for the previous activity to settle down before doing so. It contains
469 * HistoryRecord objects.
470 */
471 final ArrayList mFinishingActivities = new ArrayList();
472
473 /**
474 * All of the applications we currently have running organized by name.
475 * The keys are strings of the application package name (as
476 * returned by the package manager), and the keys are ApplicationRecord
477 * objects.
478 */
479 final ProcessMap<ProcessRecord> mProcessNames
480 = new ProcessMap<ProcessRecord>();
481
482 /**
483 * The last time that various processes have crashed.
484 */
485 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
486
487 /**
488 * Set of applications that we consider to be bad, and will reject
489 * incoming broadcasts from (which the user has no control over).
490 * Processes are added to this set when they have crashed twice within
491 * a minimum amount of time; they are removed from it when they are
492 * later restarted (hopefully due to some user action). The value is the
493 * time it was added to the list.
494 */
495 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
496
497 /**
498 * All of the processes we currently have running organized by pid.
499 * The keys are the pid running the application.
500 *
501 * <p>NOTE: This object is protected by its own lock, NOT the global
502 * activity manager lock!
503 */
504 final SparseArray<ProcessRecord> mPidsSelfLocked
505 = new SparseArray<ProcessRecord>();
506
507 /**
508 * All of the processes that have been forced to be foreground. The key
509 * is the pid of the caller who requested it (we hold a death
510 * link on it).
511 */
512 abstract class ForegroundToken implements IBinder.DeathRecipient {
513 int pid;
514 IBinder token;
515 }
516 final SparseArray<ForegroundToken> mForegroundProcesses
517 = new SparseArray<ForegroundToken>();
518
519 /**
520 * List of records for processes that someone had tried to start before the
521 * system was ready. We don't start them at that point, but ensure they
522 * are started by the time booting is complete.
523 */
524 final ArrayList<ProcessRecord> mProcessesOnHold
525 = new ArrayList<ProcessRecord>();
526
527 /**
528 * List of records for processes that we have started and are waiting
529 * for them to call back. This is really only needed when running in
530 * single processes mode, in which case we do not have a unique pid for
531 * each process.
532 */
533 final ArrayList<ProcessRecord> mStartingProcesses
534 = new ArrayList<ProcessRecord>();
535
536 /**
537 * List of persistent applications that are in the process
538 * of being started.
539 */
540 final ArrayList<ProcessRecord> mPersistentStartingProcesses
541 = new ArrayList<ProcessRecord>();
542
543 /**
544 * Processes that are being forcibly torn down.
545 */
546 final ArrayList<ProcessRecord> mRemovedProcesses
547 = new ArrayList<ProcessRecord>();
548
549 /**
550 * List of running applications, sorted by recent usage.
551 * The first entry in the list is the least recently used.
552 * It contains ApplicationRecord objects. This list does NOT include
553 * any persistent application records (since we never want to exit them).
554 */
555 final ArrayList<ProcessRecord> mLRUProcesses
556 = new ArrayList<ProcessRecord>();
557
558 /**
559 * List of processes that should gc as soon as things are idle.
560 */
561 final ArrayList<ProcessRecord> mProcessesToGc
562 = new ArrayList<ProcessRecord>();
563
564 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800565 * This is the process holding what we currently consider to be
566 * the "home" activity.
567 */
568 private ProcessRecord mHomeProcess;
569
570 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 * List of running activities, sorted by recent usage.
572 * The first entry in the list is the least recently used.
573 * It contains HistoryRecord objects.
574 */
575 private final ArrayList mLRUActivities = new ArrayList();
576
577 /**
578 * Set of PendingResultRecord objects that are currently active.
579 */
580 final HashSet mPendingResultRecords = new HashSet();
581
582 /**
583 * Set of IntentSenderRecord objects that are currently active.
584 */
585 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
586 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
587
588 /**
589 * Intent broadcast that we have tried to start, but are
590 * waiting for its application's process to be created. We only
591 * need one (instead of a list) because we always process broadcasts
592 * one at a time, so no others can be started while waiting for this
593 * one.
594 */
595 BroadcastRecord mPendingBroadcast = null;
596
597 /**
598 * Keeps track of all IIntentReceivers that have been registered for
599 * broadcasts. Hash keys are the receiver IBinder, hash value is
600 * a ReceiverList.
601 */
602 final HashMap mRegisteredReceivers = new HashMap();
603
604 /**
605 * Resolver for broadcast intents to registered receivers.
606 * Holds BroadcastFilter (subclass of IntentFilter).
607 */
608 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
609 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
610 @Override
611 protected boolean allowFilterResult(
612 BroadcastFilter filter, List<BroadcastFilter> dest) {
613 IBinder target = filter.receiverList.receiver.asBinder();
614 for (int i=dest.size()-1; i>=0; i--) {
615 if (dest.get(i).receiverList.receiver.asBinder() == target) {
616 return false;
617 }
618 }
619 return true;
620 }
621 };
622
623 /**
624 * State of all active sticky broadcasts. Keys are the action of the
625 * sticky Intent, values are an ArrayList of all broadcasted intents with
626 * that action (which should usually be one).
627 */
628 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
629 new HashMap<String, ArrayList<Intent>>();
630
631 /**
632 * All currently running services.
633 */
634 final HashMap<ComponentName, ServiceRecord> mServices =
635 new HashMap<ComponentName, ServiceRecord>();
636
637 /**
638 * All currently running services indexed by the Intent used to start them.
639 */
640 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
641 new HashMap<Intent.FilterComparison, ServiceRecord>();
642
643 /**
644 * All currently bound service connections. Keys are the IBinder of
645 * the client's IServiceConnection.
646 */
647 final HashMap<IBinder, ConnectionRecord> mServiceConnections
648 = new HashMap<IBinder, ConnectionRecord>();
649
650 /**
651 * List of services that we have been asked to start,
652 * but haven't yet been able to. It is used to hold start requests
653 * while waiting for their corresponding application thread to get
654 * going.
655 */
656 final ArrayList<ServiceRecord> mPendingServices
657 = new ArrayList<ServiceRecord>();
658
659 /**
660 * List of services that are scheduled to restart following a crash.
661 */
662 final ArrayList<ServiceRecord> mRestartingServices
663 = new ArrayList<ServiceRecord>();
664
665 /**
666 * List of services that are in the process of being stopped.
667 */
668 final ArrayList<ServiceRecord> mStoppingServices
669 = new ArrayList<ServiceRecord>();
670
671 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700672 * Backup/restore process management
673 */
674 String mBackupAppName = null;
675 BackupRecord mBackupTarget = null;
676
677 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 * List of PendingThumbnailsRecord objects of clients who are still
679 * waiting to receive all of the thumbnails for a task.
680 */
681 final ArrayList mPendingThumbnails = new ArrayList();
682
683 /**
684 * List of HistoryRecord objects that have been finished and must
685 * still report back to a pending thumbnail receiver.
686 */
687 final ArrayList mCancelledThumbnails = new ArrayList();
688
689 /**
690 * All of the currently running global content providers. Keys are a
691 * string containing the provider name and values are a
692 * ContentProviderRecord object containing the data about it. Note
693 * that a single provider may be published under multiple names, so
694 * there may be multiple entries here for a single one in mProvidersByClass.
695 */
696 final HashMap mProvidersByName = new HashMap();
697
698 /**
699 * All of the currently running global content providers. Keys are a
700 * string containing the provider's implementation class and values are a
701 * ContentProviderRecord object containing the data about it.
702 */
703 final HashMap mProvidersByClass = new HashMap();
704
705 /**
706 * List of content providers who have clients waiting for them. The
707 * application is currently being launched and the provider will be
708 * removed from this list once it is published.
709 */
710 final ArrayList mLaunchingProviders = new ArrayList();
711
712 /**
713 * Global set of specific Uri permissions that have been granted.
714 */
715 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
716 = new SparseArray<HashMap<Uri, UriPermission>>();
717
718 /**
719 * Thread-local storage used to carry caller permissions over through
720 * indirect content-provider access.
721 * @see #ActivityManagerService.openContentUri()
722 */
723 private class Identity {
724 public int pid;
725 public int uid;
726
727 Identity(int _pid, int _uid) {
728 pid = _pid;
729 uid = _uid;
730 }
731 }
732 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
733
734 /**
735 * All information we have collected about the runtime performance of
736 * any user id that can impact battery performance.
737 */
738 final BatteryStatsService mBatteryStatsService;
739
740 /**
741 * information about component usage
742 */
743 final UsageStatsService mUsageStatsService;
744
745 /**
746 * Current configuration information. HistoryRecord objects are given
747 * a reference to this object to indicate which configuration they are
748 * currently running in, so this object must be kept immutable.
749 */
750 Configuration mConfiguration = new Configuration();
751
752 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700753 * Hardware-reported OpenGLES version.
754 */
755 final int GL_ES_VERSION;
756
757 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 * List of initialization arguments to pass to all processes when binding applications to them.
759 * For example, references to the commonly used services.
760 */
761 HashMap<String, IBinder> mAppBindArgs;
762
763 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700764 * Temporary to avoid allocations. Protected by main lock.
765 */
766 final StringBuilder mStringBuilder = new StringBuilder(256);
767
768 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 * Used to control how we initialize the service.
770 */
771 boolean mStartRunning = false;
772 ComponentName mTopComponent;
773 String mTopAction;
774 String mTopData;
775 boolean mSystemReady = false;
776 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700777 boolean mWaitingUpdate = false;
778 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779
780 Context mContext;
781
782 int mFactoryTest;
783
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700784 boolean mCheckedForSetup;
785
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700787 * The time at which we will allow normal application switches again,
788 * after a call to {@link #stopAppSwitches()}.
789 */
790 long mAppSwitchesAllowedTime;
791
792 /**
793 * This is set to true after the first switch after mAppSwitchesAllowedTime
794 * is set; any switches after that will clear the time.
795 */
796 boolean mDidAppSwitch;
797
798 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 * Set while we are wanting to sleep, to prevent any
800 * activities from being started/resumed.
801 */
802 boolean mSleeping = false;
803
804 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700805 * Set if we are shutting down the system, similar to sleeping.
806 */
807 boolean mShuttingDown = false;
808
809 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 * Set when the system is going to sleep, until we have
811 * successfully paused the current activity and released our wake lock.
812 * At that point the system is allowed to actually sleep.
813 */
814 PowerManager.WakeLock mGoingToSleep;
815
816 /**
817 * We don't want to allow the device to go to sleep while in the process
818 * of launching an activity. This is primarily to allow alarm intent
819 * receivers to launch an activity and get that to run before the device
820 * goes back to sleep.
821 */
822 PowerManager.WakeLock mLaunchingActivity;
823
824 /**
825 * Task identifier that activities are currently being started
826 * in. Incremented each time a new task is created.
827 * todo: Replace this with a TokenSpace class that generates non-repeating
828 * integers that won't wrap.
829 */
830 int mCurTask = 1;
831
832 /**
833 * Current sequence id for oom_adj computation traversal.
834 */
835 int mAdjSeq = 0;
836
837 /**
838 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
839 * is set, indicating the user wants processes started in such a way
840 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
841 * running in each process (thus no pre-initialized process, etc).
842 */
843 boolean mSimpleProcessManagement = false;
844
845 /**
846 * System monitoring: number of processes that died since the last
847 * N procs were started.
848 */
849 int[] mProcDeaths = new int[20];
850
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700851 /**
852 * This is set if we had to do a delayed dexopt of an app before launching
853 * it, to increasing the ANR timeouts in that case.
854 */
855 boolean mDidDexOpt;
856
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 String mDebugApp = null;
858 boolean mWaitForDebugger = false;
859 boolean mDebugTransient = false;
860 String mOrigDebugApp = null;
861 boolean mOrigWaitForDebugger = false;
862 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700863 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700865 final RemoteCallbackList<IActivityWatcher> mWatchers
866 = new RemoteCallbackList<IActivityWatcher>();
867
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 /**
869 * Callback of last caller to {@link #requestPss}.
870 */
871 Runnable mRequestPssCallback;
872
873 /**
874 * Remaining processes for which we are waiting results from the last
875 * call to {@link #requestPss}.
876 */
877 final ArrayList<ProcessRecord> mRequestPssList
878 = new ArrayList<ProcessRecord>();
879
880 /**
881 * Runtime statistics collection thread. This object's lock is used to
882 * protect all related state.
883 */
884 final Thread mProcessStatsThread;
885
886 /**
887 * Used to collect process stats when showing not responding dialog.
888 * Protected by mProcessStatsThread.
889 */
890 final ProcessStats mProcessStats = new ProcessStats(
891 MONITOR_THREAD_CPU_USAGE);
892 long mLastCpuTime = 0;
893 long mLastWriteTime = 0;
894
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700895 long mInitialStartTime = 0;
896
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 /**
898 * Set to true after the system has finished booting.
899 */
900 boolean mBooted = false;
901
902 int mProcessLimit = 0;
903
904 WindowManagerService mWindowManager;
905
906 static ActivityManagerService mSelf;
907 static ActivityThread mSystemThread;
908
909 private final class AppDeathRecipient implements IBinder.DeathRecipient {
910 final ProcessRecord mApp;
911 final int mPid;
912 final IApplicationThread mAppThread;
913
914 AppDeathRecipient(ProcessRecord app, int pid,
915 IApplicationThread thread) {
916 if (localLOGV) Log.v(
917 TAG, "New death recipient " + this
918 + " for thread " + thread.asBinder());
919 mApp = app;
920 mPid = pid;
921 mAppThread = thread;
922 }
923
924 public void binderDied() {
925 if (localLOGV) Log.v(
926 TAG, "Death received in " + this
927 + " for thread " + mAppThread.asBinder());
928 removeRequestedPss(mApp);
929 synchronized(ActivityManagerService.this) {
930 appDiedLocked(mApp, mPid, mAppThread);
931 }
932 }
933 }
934
935 static final int SHOW_ERROR_MSG = 1;
936 static final int SHOW_NOT_RESPONDING_MSG = 2;
937 static final int SHOW_FACTORY_ERROR_MSG = 3;
938 static final int UPDATE_CONFIGURATION_MSG = 4;
939 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
940 static final int WAIT_FOR_DEBUGGER_MSG = 6;
941 static final int BROADCAST_INTENT_MSG = 7;
942 static final int BROADCAST_TIMEOUT_MSG = 8;
943 static final int PAUSE_TIMEOUT_MSG = 9;
944 static final int IDLE_TIMEOUT_MSG = 10;
945 static final int IDLE_NOW_MSG = 11;
946 static final int SERVICE_TIMEOUT_MSG = 12;
947 static final int UPDATE_TIME_ZONE = 13;
948 static final int SHOW_UID_ERROR_MSG = 14;
949 static final int IM_FEELING_LUCKY_MSG = 15;
950 static final int LAUNCH_TIMEOUT_MSG = 16;
951 static final int DESTROY_TIMEOUT_MSG = 17;
952 static final int SERVICE_ERROR_MSG = 18;
953 static final int RESUME_TOP_ACTIVITY_MSG = 19;
954 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700955 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700956 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957
958 AlertDialog mUidAlert;
959
960 final Handler mHandler = new Handler() {
961 //public Handler() {
962 // if (localLOGV) Log.v(TAG, "Handler started!");
963 //}
964
965 public void handleMessage(Message msg) {
966 switch (msg.what) {
967 case SHOW_ERROR_MSG: {
968 HashMap data = (HashMap) msg.obj;
969 byte[] crashData = (byte[])data.get("crashData");
970 if (crashData != null) {
971 // This needs to be *un*synchronized to avoid deadlock.
972 ContentResolver resolver = mContext.getContentResolver();
973 Checkin.reportCrash(resolver, crashData);
974 }
975 synchronized (ActivityManagerService.this) {
976 ProcessRecord proc = (ProcessRecord)data.get("app");
977 if (proc != null && proc.crashDialog != null) {
978 Log.e(TAG, "App already has crash dialog: " + proc);
979 return;
980 }
981 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700982 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 Dialog d = new AppErrorDialog(
984 mContext, res, proc,
985 (Integer)data.get("flags"),
986 (String)data.get("shortMsg"),
987 (String)data.get("longMsg"));
988 d.show();
989 proc.crashDialog = d;
990 } else {
991 // The device is asleep, so just pretend that the user
992 // saw a crash dialog and hit "force quit".
993 res.set(0);
994 }
995 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700996
997 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 } break;
999 case SHOW_NOT_RESPONDING_MSG: {
1000 synchronized (ActivityManagerService.this) {
1001 HashMap data = (HashMap) msg.obj;
1002 ProcessRecord proc = (ProcessRecord)data.get("app");
1003 if (proc != null && proc.anrDialog != null) {
1004 Log.e(TAG, "App already has anr dialog: " + proc);
1005 return;
1006 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001007
1008 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1009 null, null, 0, null, null, null,
1010 false, false, MY_PID, Process.SYSTEM_UID);
1011
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1013 mContext, proc, (HistoryRecord)data.get("activity"));
1014 d.show();
1015 proc.anrDialog = d;
1016 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001017
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001018 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 } break;
1020 case SHOW_FACTORY_ERROR_MSG: {
1021 Dialog d = new FactoryErrorDialog(
1022 mContext, msg.getData().getCharSequence("msg"));
1023 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001024 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001025 } break;
1026 case UPDATE_CONFIGURATION_MSG: {
1027 final ContentResolver resolver = mContext.getContentResolver();
1028 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1029 } break;
1030 case GC_BACKGROUND_PROCESSES_MSG: {
1031 synchronized (ActivityManagerService.this) {
1032 performAppGcsIfAppropriateLocked();
1033 }
1034 } break;
1035 case WAIT_FOR_DEBUGGER_MSG: {
1036 synchronized (ActivityManagerService.this) {
1037 ProcessRecord app = (ProcessRecord)msg.obj;
1038 if (msg.arg1 != 0) {
1039 if (!app.waitedForDebugger) {
1040 Dialog d = new AppWaitingForDebuggerDialog(
1041 ActivityManagerService.this,
1042 mContext, app);
1043 app.waitDialog = d;
1044 app.waitedForDebugger = true;
1045 d.show();
1046 }
1047 } else {
1048 if (app.waitDialog != null) {
1049 app.waitDialog.dismiss();
1050 app.waitDialog = null;
1051 }
1052 }
1053 }
1054 } break;
1055 case BROADCAST_INTENT_MSG: {
1056 if (DEBUG_BROADCAST) Log.v(
1057 TAG, "Received BROADCAST_INTENT_MSG");
1058 processNextBroadcast(true);
1059 } break;
1060 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001061 if (mDidDexOpt) {
1062 mDidDexOpt = false;
1063 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1064 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1065 return;
1066 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 broadcastTimeout();
1068 } break;
1069 case PAUSE_TIMEOUT_MSG: {
1070 IBinder token = (IBinder)msg.obj;
1071 // We don't at this point know if the activity is fullscreen,
1072 // so we need to be conservative and assume it isn't.
1073 Log.w(TAG, "Activity pause timeout for " + token);
1074 activityPaused(token, null, true);
1075 } break;
1076 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001077 if (mDidDexOpt) {
1078 mDidDexOpt = false;
1079 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1080 nmsg.obj = msg.obj;
1081 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1082 return;
1083 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001084 // We don't at this point know if the activity is fullscreen,
1085 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001086 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 Log.w(TAG, "Activity idle timeout for " + token);
1088 activityIdleInternal(token, true);
1089 } break;
1090 case DESTROY_TIMEOUT_MSG: {
1091 IBinder token = (IBinder)msg.obj;
1092 // We don't at this point know if the activity is fullscreen,
1093 // so we need to be conservative and assume it isn't.
1094 Log.w(TAG, "Activity destroy timeout for " + token);
1095 activityDestroyed(token);
1096 } break;
1097 case IDLE_NOW_MSG: {
1098 IBinder token = (IBinder)msg.obj;
1099 activityIdle(token);
1100 } break;
1101 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001102 if (mDidDexOpt) {
1103 mDidDexOpt = false;
1104 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1105 nmsg.obj = msg.obj;
1106 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1107 return;
1108 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 serviceTimeout((ProcessRecord)msg.obj);
1110 } break;
1111 case UPDATE_TIME_ZONE: {
1112 synchronized (ActivityManagerService.this) {
1113 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1114 ProcessRecord r = mLRUProcesses.get(i);
1115 if (r.thread != null) {
1116 try {
1117 r.thread.updateTimeZone();
1118 } catch (RemoteException ex) {
1119 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1120 }
1121 }
1122 }
1123 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001124 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 case SHOW_UID_ERROR_MSG: {
1126 // XXX This is a temporary dialog, no need to localize.
1127 AlertDialog d = new BaseErrorDialog(mContext);
1128 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1129 d.setCancelable(false);
1130 d.setTitle("System UIDs Inconsistent");
1131 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1132 d.setButton("I'm Feeling Lucky",
1133 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1134 mUidAlert = d;
1135 d.show();
1136 } break;
1137 case IM_FEELING_LUCKY_MSG: {
1138 if (mUidAlert != null) {
1139 mUidAlert.dismiss();
1140 mUidAlert = null;
1141 }
1142 } break;
1143 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001144 if (mDidDexOpt) {
1145 mDidDexOpt = false;
1146 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1147 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1148 return;
1149 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 synchronized (ActivityManagerService.this) {
1151 if (mLaunchingActivity.isHeld()) {
1152 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1153 mLaunchingActivity.release();
1154 }
1155 }
1156 } break;
1157 case SERVICE_ERROR_MSG: {
1158 ServiceRecord srv = (ServiceRecord)msg.obj;
1159 // This needs to be *un*synchronized to avoid deadlock.
1160 Checkin.logEvent(mContext.getContentResolver(),
1161 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1162 srv.name.toShortString());
1163 } break;
1164 case RESUME_TOP_ACTIVITY_MSG: {
1165 synchronized (ActivityManagerService.this) {
1166 resumeTopActivityLocked(null);
1167 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001168 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001170 if (mDidDexOpt) {
1171 mDidDexOpt = false;
1172 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1173 nmsg.obj = msg.obj;
1174 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1175 return;
1176 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177 ProcessRecord app = (ProcessRecord)msg.obj;
1178 synchronized (ActivityManagerService.this) {
1179 processStartTimedOutLocked(app);
1180 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001181 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001182 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1183 synchronized (ActivityManagerService.this) {
1184 doPendingActivityLaunchesLocked(true);
1185 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001186 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001187 case KILL_APPLICATION_MSG: {
1188 synchronized (ActivityManagerService.this) {
1189 int uid = msg.arg1;
1190 boolean restart = (msg.arg2 == 1);
1191 String pkg = (String) msg.obj;
1192 uninstallPackageLocked(pkg, uid, restart);
1193 }
1194 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195 }
1196 }
1197 };
1198
1199 public static void setSystemProcess() {
1200 try {
1201 ActivityManagerService m = mSelf;
1202
1203 ServiceManager.addService("activity", m);
1204 ServiceManager.addService("meminfo", new MemBinder(m));
1205 if (MONITOR_CPU_USAGE) {
1206 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1207 }
1208 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1209 ServiceManager.addService("activity.services", new ServicesBinder(m));
1210 ServiceManager.addService("activity.senders", new SendersBinder(m));
1211 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1212 ServiceManager.addService("permission", new PermissionController(m));
1213
1214 ApplicationInfo info =
1215 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001216 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217 synchronized (mSelf) {
1218 ProcessRecord app = mSelf.newProcessRecordLocked(
1219 mSystemThread.getApplicationThread(), info,
1220 info.processName);
1221 app.persistent = true;
1222 app.pid = Process.myPid();
1223 app.maxAdj = SYSTEM_ADJ;
1224 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1225 synchronized (mSelf.mPidsSelfLocked) {
1226 mSelf.mPidsSelfLocked.put(app.pid, app);
1227 }
1228 mSelf.updateLRUListLocked(app, true);
1229 }
1230 } catch (PackageManager.NameNotFoundException e) {
1231 throw new RuntimeException(
1232 "Unable to find android system package", e);
1233 }
1234 }
1235
1236 public void setWindowManager(WindowManagerService wm) {
1237 mWindowManager = wm;
1238 }
1239
1240 public static final Context main(int factoryTest) {
1241 AThread thr = new AThread();
1242 thr.start();
1243
1244 synchronized (thr) {
1245 while (thr.mService == null) {
1246 try {
1247 thr.wait();
1248 } catch (InterruptedException e) {
1249 }
1250 }
1251 }
1252
1253 ActivityManagerService m = thr.mService;
1254 mSelf = m;
1255 ActivityThread at = ActivityThread.systemMain();
1256 mSystemThread = at;
1257 Context context = at.getSystemContext();
1258 m.mContext = context;
1259 m.mFactoryTest = factoryTest;
1260 PowerManager pm =
1261 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1262 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1263 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1264 m.mLaunchingActivity.setReferenceCounted(false);
1265
1266 m.mBatteryStatsService.publish(context);
1267 m.mUsageStatsService.publish(context);
1268
1269 synchronized (thr) {
1270 thr.mReady = true;
1271 thr.notifyAll();
1272 }
1273
1274 m.startRunning(null, null, null, null);
1275
1276 return context;
1277 }
1278
1279 public static ActivityManagerService self() {
1280 return mSelf;
1281 }
1282
1283 static class AThread extends Thread {
1284 ActivityManagerService mService;
1285 boolean mReady = false;
1286
1287 public AThread() {
1288 super("ActivityManager");
1289 }
1290
1291 public void run() {
1292 Looper.prepare();
1293
1294 android.os.Process.setThreadPriority(
1295 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1296
1297 ActivityManagerService m = new ActivityManagerService();
1298
1299 synchronized (this) {
1300 mService = m;
1301 notifyAll();
1302 }
1303
1304 synchronized (this) {
1305 while (!mReady) {
1306 try {
1307 wait();
1308 } catch (InterruptedException e) {
1309 }
1310 }
1311 }
1312
1313 Looper.loop();
1314 }
1315 }
1316
1317 static class BroadcastsBinder extends Binder {
1318 ActivityManagerService mActivityManagerService;
1319 BroadcastsBinder(ActivityManagerService activityManagerService) {
1320 mActivityManagerService = activityManagerService;
1321 }
1322
1323 @Override
1324 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1325 mActivityManagerService.dumpBroadcasts(pw);
1326 }
1327 }
1328
1329 static class ServicesBinder extends Binder {
1330 ActivityManagerService mActivityManagerService;
1331 ServicesBinder(ActivityManagerService activityManagerService) {
1332 mActivityManagerService = activityManagerService;
1333 }
1334
1335 @Override
1336 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1337 mActivityManagerService.dumpServices(pw);
1338 }
1339 }
1340
1341 static class SendersBinder extends Binder {
1342 ActivityManagerService mActivityManagerService;
1343 SendersBinder(ActivityManagerService activityManagerService) {
1344 mActivityManagerService = activityManagerService;
1345 }
1346
1347 @Override
1348 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1349 mActivityManagerService.dumpSenders(pw);
1350 }
1351 }
1352
1353 static class ProvidersBinder extends Binder {
1354 ActivityManagerService mActivityManagerService;
1355 ProvidersBinder(ActivityManagerService activityManagerService) {
1356 mActivityManagerService = activityManagerService;
1357 }
1358
1359 @Override
1360 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1361 mActivityManagerService.dumpProviders(pw);
1362 }
1363 }
1364
1365 static class MemBinder extends Binder {
1366 ActivityManagerService mActivityManagerService;
1367 MemBinder(ActivityManagerService activityManagerService) {
1368 mActivityManagerService = activityManagerService;
1369 }
1370
1371 @Override
1372 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1373 ActivityManagerService service = mActivityManagerService;
1374 ArrayList<ProcessRecord> procs;
1375 synchronized (mActivityManagerService) {
1376 if (args != null && args.length > 0
1377 && args[0].charAt(0) != '-') {
1378 procs = new ArrayList<ProcessRecord>();
1379 int pid = -1;
1380 try {
1381 pid = Integer.parseInt(args[0]);
1382 } catch (NumberFormatException e) {
1383
1384 }
1385 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1386 ProcessRecord proc = service.mLRUProcesses.get(i);
1387 if (proc.pid == pid) {
1388 procs.add(proc);
1389 } else if (proc.processName.equals(args[0])) {
1390 procs.add(proc);
1391 }
1392 }
1393 if (procs.size() <= 0) {
1394 pw.println("No process found for: " + args[0]);
1395 return;
1396 }
1397 } else {
1398 procs = service.mLRUProcesses;
1399 }
1400 }
1401 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1402 }
1403 }
1404
1405 static class CpuBinder extends Binder {
1406 ActivityManagerService mActivityManagerService;
1407 CpuBinder(ActivityManagerService activityManagerService) {
1408 mActivityManagerService = activityManagerService;
1409 }
1410
1411 @Override
1412 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1413 synchronized (mActivityManagerService.mProcessStatsThread) {
1414 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1415 }
1416 }
1417 }
1418
1419 private ActivityManagerService() {
1420 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1421 if (v != null && Integer.getInteger(v) != 0) {
1422 mSimpleProcessManagement = true;
1423 }
1424 v = System.getenv("ANDROID_DEBUG_APP");
1425 if (v != null) {
1426 mSimpleProcessManagement = true;
1427 }
1428
1429 MY_PID = Process.myPid();
1430
1431 File dataDir = Environment.getDataDirectory();
1432 File systemDir = new File(dataDir, "system");
1433 systemDir.mkdirs();
1434 mBatteryStatsService = new BatteryStatsService(new File(
1435 systemDir, "batterystats.bin").toString());
1436 mBatteryStatsService.getActiveStatistics().readLocked();
1437 mBatteryStatsService.getActiveStatistics().writeLocked();
1438
1439 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001440 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001441
Jack Palevichb90d28c2009-07-22 15:35:24 -07001442 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1443 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001445 mConfiguration.makeDefault();
1446 mProcessStats.init();
1447
1448 // Add ourself to the Watchdog monitors.
1449 Watchdog.getInstance().addMonitor(this);
1450
1451 // These values are set in system/rootdir/init.rc on startup.
1452 FOREGROUND_APP_ADJ =
1453 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1454 VISIBLE_APP_ADJ =
1455 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1456 SECONDARY_SERVER_ADJ =
1457 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001458 BACKUP_APP_ADJ =
1459 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001460 HOME_APP_ADJ =
1461 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001462 HIDDEN_APP_MIN_ADJ =
1463 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1464 CONTENT_PROVIDER_ADJ =
1465 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1466 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1467 EMPTY_APP_ADJ =
1468 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1469 FOREGROUND_APP_MEM =
1470 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1471 VISIBLE_APP_MEM =
1472 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1473 SECONDARY_SERVER_MEM =
1474 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001475 BACKUP_APP_MEM =
1476 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001477 HOME_APP_MEM =
1478 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001479 HIDDEN_APP_MEM =
1480 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1481 EMPTY_APP_MEM =
1482 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1483
1484 mProcessStatsThread = new Thread("ProcessStats") {
1485 public void run() {
1486 while (true) {
1487 try {
1488 try {
1489 synchronized(this) {
1490 final long now = SystemClock.uptimeMillis();
1491 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1492 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1493 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1494 // + ", write delay=" + nextWriteDelay);
1495 if (nextWriteDelay < nextCpuDelay) {
1496 nextCpuDelay = nextWriteDelay;
1497 }
1498 if (nextCpuDelay > 0) {
1499 this.wait(nextCpuDelay);
1500 }
1501 }
1502 } catch (InterruptedException e) {
1503 }
1504
1505 updateCpuStatsNow();
1506 } catch (Exception e) {
1507 Log.e(TAG, "Unexpected exception collecting process stats", e);
1508 }
1509 }
1510 }
1511 };
1512 mProcessStatsThread.start();
1513 }
1514
1515 @Override
1516 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1517 throws RemoteException {
1518 try {
1519 return super.onTransact(code, data, reply, flags);
1520 } catch (RuntimeException e) {
1521 // The activity manager only throws security exceptions, so let's
1522 // log all others.
1523 if (!(e instanceof SecurityException)) {
1524 Log.e(TAG, "Activity Manager Crash", e);
1525 }
1526 throw e;
1527 }
1528 }
1529
1530 void updateCpuStats() {
1531 synchronized (mProcessStatsThread) {
1532 final long now = SystemClock.uptimeMillis();
1533 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1534 mProcessStatsThread.notify();
1535 }
1536 }
1537 }
1538
1539 void updateCpuStatsNow() {
1540 synchronized (mProcessStatsThread) {
1541 final long now = SystemClock.uptimeMillis();
1542 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001544 if (MONITOR_CPU_USAGE &&
1545 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1546 mLastCpuTime = now;
1547 haveNewCpuStats = true;
1548 mProcessStats.update();
1549 //Log.i(TAG, mProcessStats.printCurrentState());
1550 //Log.i(TAG, "Total CPU usage: "
1551 // + mProcessStats.getTotalCpuPercent() + "%");
1552
1553 // Log the cpu usage if the property is set.
1554 if ("true".equals(SystemProperties.get("events.cpu"))) {
1555 int user = mProcessStats.getLastUserTime();
1556 int system = mProcessStats.getLastSystemTime();
1557 int iowait = mProcessStats.getLastIoWaitTime();
1558 int irq = mProcessStats.getLastIrqTime();
1559 int softIrq = mProcessStats.getLastSoftIrqTime();
1560 int idle = mProcessStats.getLastIdleTime();
1561
1562 int total = user + system + iowait + irq + softIrq + idle;
1563 if (total == 0) total = 1;
1564
1565 EventLog.writeEvent(LOG_CPU,
1566 ((user+system+iowait+irq+softIrq) * 100) / total,
1567 (user * 100) / total,
1568 (system * 100) / total,
1569 (iowait * 100) / total,
1570 (irq * 100) / total,
1571 (softIrq * 100) / total);
1572 }
1573 }
1574
Amith Yamasanie43530a2009-08-21 13:11:37 -07001575 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001576 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001577 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001578 synchronized(mPidsSelfLocked) {
1579 if (haveNewCpuStats) {
1580 if (mBatteryStatsService.isOnBattery()) {
1581 final int N = mProcessStats.countWorkingStats();
1582 for (int i=0; i<N; i++) {
1583 ProcessStats.Stats st
1584 = mProcessStats.getWorkingStats(i);
1585 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1586 if (pr != null) {
1587 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1588 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001589 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001590 } else {
1591 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001592 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001593 if (ps != null) {
1594 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001595 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001596 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001597 }
1598 }
1599 }
1600 }
1601 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001602
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001603 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1604 mLastWriteTime = now;
1605 mBatteryStatsService.getActiveStatistics().writeLocked();
1606 }
1607 }
1608 }
1609 }
1610
1611 /**
1612 * Initialize the application bind args. These are passed to each
1613 * process when the bindApplication() IPC is sent to the process. They're
1614 * lazily setup to make sure the services are running when they're asked for.
1615 */
1616 private HashMap<String, IBinder> getCommonServicesLocked() {
1617 if (mAppBindArgs == null) {
1618 mAppBindArgs = new HashMap<String, IBinder>();
1619
1620 // Setup the application init args
1621 mAppBindArgs.put("package", ServiceManager.getService("package"));
1622 mAppBindArgs.put("window", ServiceManager.getService("window"));
1623 mAppBindArgs.put(Context.ALARM_SERVICE,
1624 ServiceManager.getService(Context.ALARM_SERVICE));
1625 }
1626 return mAppBindArgs;
1627 }
1628
1629 private final void setFocusedActivityLocked(HistoryRecord r) {
1630 if (mFocusedActivity != r) {
1631 mFocusedActivity = r;
1632 mWindowManager.setFocusedApp(r, true);
1633 }
1634 }
1635
1636 private final void updateLRUListLocked(ProcessRecord app,
1637 boolean oomAdj) {
1638 // put it on the LRU to keep track of when it should be exited.
1639 int lrui = mLRUProcesses.indexOf(app);
1640 if (lrui >= 0) mLRUProcesses.remove(lrui);
1641 mLRUProcesses.add(app);
1642 //Log.i(TAG, "Putting proc to front: " + app.processName);
1643 if (oomAdj) {
1644 updateOomAdjLocked();
1645 }
1646 }
1647
1648 private final boolean updateLRUListLocked(HistoryRecord r) {
1649 final boolean hadit = mLRUActivities.remove(r);
1650 mLRUActivities.add(r);
1651 return hadit;
1652 }
1653
1654 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1655 int i = mHistory.size()-1;
1656 while (i >= 0) {
1657 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1658 if (!r.finishing && r != notTop) {
1659 return r;
1660 }
1661 i--;
1662 }
1663 return null;
1664 }
1665
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001666 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1667 int i = mHistory.size()-1;
1668 while (i >= 0) {
1669 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1670 if (!r.finishing && !r.delayedResume && r != notTop) {
1671 return r;
1672 }
1673 i--;
1674 }
1675 return null;
1676 }
1677
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001678 /**
1679 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001680 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001681 *
1682 * @param token If non-null, any history records matching this token will be skipped.
1683 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1684 *
1685 * @return Returns the HistoryRecord of the next activity on the stack.
1686 */
1687 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1688 int i = mHistory.size()-1;
1689 while (i >= 0) {
1690 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1691 // Note: the taskId check depends on real taskId fields being non-zero
1692 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1693 return r;
1694 }
1695 i--;
1696 }
1697 return null;
1698 }
1699
1700 private final ProcessRecord getProcessRecordLocked(
1701 String processName, int uid) {
1702 if (uid == Process.SYSTEM_UID) {
1703 // The system gets to run in any process. If there are multiple
1704 // processes with the same uid, just pick the first (this
1705 // should never happen).
1706 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1707 processName);
1708 return procs != null ? procs.valueAt(0) : null;
1709 }
1710 ProcessRecord proc = mProcessNames.get(processName, uid);
1711 return proc;
1712 }
1713
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001714 private void ensurePackageDexOpt(String packageName) {
1715 IPackageManager pm = ActivityThread.getPackageManager();
1716 try {
1717 if (pm.performDexOpt(packageName)) {
1718 mDidDexOpt = true;
1719 }
1720 } catch (RemoteException e) {
1721 }
1722 }
1723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001724 private boolean isNextTransitionForward() {
1725 int transit = mWindowManager.getPendingAppTransition();
1726 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1727 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1728 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1729 }
1730
1731 private final boolean realStartActivityLocked(HistoryRecord r,
1732 ProcessRecord app, boolean andResume, boolean checkConfig)
1733 throws RemoteException {
1734
1735 r.startFreezingScreenLocked(app, 0);
1736 mWindowManager.setAppVisibility(r, true);
1737
1738 // Have the window manager re-evaluate the orientation of
1739 // the screen based on the new activity order. Note that
1740 // as a result of this, it can call back into the activity
1741 // manager with a new orientation. We don't care about that,
1742 // because the activity is not currently running so we are
1743 // just restarting it anyway.
1744 if (checkConfig) {
1745 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001746 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001747 r.mayFreezeScreenLocked(app) ? r : null);
1748 updateConfigurationLocked(config, r);
1749 }
1750
1751 r.app = app;
1752
1753 if (localLOGV) Log.v(TAG, "Launching: " + r);
1754
1755 int idx = app.activities.indexOf(r);
1756 if (idx < 0) {
1757 app.activities.add(r);
1758 }
1759 updateLRUListLocked(app, true);
1760
1761 try {
1762 if (app.thread == null) {
1763 throw new RemoteException();
1764 }
1765 List<ResultInfo> results = null;
1766 List<Intent> newIntents = null;
1767 if (andResume) {
1768 results = r.results;
1769 newIntents = r.newIntents;
1770 }
1771 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1772 + " icicle=" + r.icicle
1773 + " with results=" + results + " newIntents=" + newIntents
1774 + " andResume=" + andResume);
1775 if (andResume) {
1776 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1777 System.identityHashCode(r),
1778 r.task.taskId, r.shortComponentName);
1779 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001780 if (r.isHomeActivity) {
1781 mHomeProcess = app;
1782 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001783 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001784 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001785 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001786 r.info, r.icicle, results, newIntents, !andResume,
1787 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001788 } catch (RemoteException e) {
1789 if (r.launchFailed) {
1790 // This is the second time we failed -- finish activity
1791 // and give up.
1792 Log.e(TAG, "Second failure launching "
1793 + r.intent.getComponent().flattenToShortString()
1794 + ", giving up", e);
1795 appDiedLocked(app, app.pid, app.thread);
1796 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1797 "2nd-crash");
1798 return false;
1799 }
1800
1801 // This is the first time we failed -- restart process and
1802 // retry.
1803 app.activities.remove(r);
1804 throw e;
1805 }
1806
1807 r.launchFailed = false;
1808 if (updateLRUListLocked(r)) {
1809 Log.w(TAG, "Activity " + r
1810 + " being launched, but already in LRU list");
1811 }
1812
1813 if (andResume) {
1814 // As part of the process of launching, ActivityThread also performs
1815 // a resume.
1816 r.state = ActivityState.RESUMED;
1817 r.icicle = null;
1818 r.haveState = false;
1819 r.stopped = false;
1820 mResumedActivity = r;
1821 r.task.touchActiveTime();
1822 completeResumeLocked(r);
1823 pauseIfSleepingLocked();
1824 } else {
1825 // This activity is not starting in the resumed state... which
1826 // should look like we asked it to pause+stop (but remain visible),
1827 // and it has done so and reported back the current icicle and
1828 // other state.
1829 r.state = ActivityState.STOPPED;
1830 r.stopped = true;
1831 }
1832
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001833 // Launch the new version setup screen if needed. We do this -after-
1834 // launching the initial activity (that is, home), so that it can have
1835 // a chance to initialize itself while in the background, making the
1836 // switch back to it faster and look better.
1837 startSetupActivityLocked();
1838
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001839 return true;
1840 }
1841
1842 private final void startSpecificActivityLocked(HistoryRecord r,
1843 boolean andResume, boolean checkConfig) {
1844 // Is this activity's application already running?
1845 ProcessRecord app = getProcessRecordLocked(r.processName,
1846 r.info.applicationInfo.uid);
1847
1848 if (r.startTime == 0) {
1849 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001850 if (mInitialStartTime == 0) {
1851 mInitialStartTime = r.startTime;
1852 }
1853 } else if (mInitialStartTime == 0) {
1854 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001855 }
1856
1857 if (app != null && app.thread != null) {
1858 try {
1859 realStartActivityLocked(r, app, andResume, checkConfig);
1860 return;
1861 } catch (RemoteException e) {
1862 Log.w(TAG, "Exception when starting activity "
1863 + r.intent.getComponent().flattenToShortString(), e);
1864 }
1865
1866 // If a dead object exception was thrown -- fall through to
1867 // restart the application.
1868 }
1869
1870 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001871 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001872 }
1873
1874 private final ProcessRecord startProcessLocked(String processName,
1875 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001876 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001877 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1878 // We don't have to do anything more if:
1879 // (1) There is an existing application record; and
1880 // (2) The caller doesn't think it is dead, OR there is no thread
1881 // object attached to it so we know it couldn't have crashed; and
1882 // (3) There is a pid assigned to it, so it is either starting or
1883 // already running.
1884 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1885 + " app=" + app + " knownToBeDead=" + knownToBeDead
1886 + " thread=" + (app != null ? app.thread : null)
1887 + " pid=" + (app != null ? app.pid : -1));
1888 if (app != null &&
1889 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1890 return app;
1891 }
1892
1893 String hostingNameStr = hostingName != null
1894 ? hostingName.flattenToShortString() : null;
1895
1896 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1897 // If we are in the background, then check to see if this process
1898 // is bad. If so, we will just silently fail.
1899 if (mBadProcesses.get(info.processName, info.uid) != null) {
1900 return null;
1901 }
1902 } else {
1903 // When the user is explicitly starting a process, then clear its
1904 // crash count so that we won't make it bad until they see at
1905 // least one crash dialog again, and make the process good again
1906 // if it had been bad.
1907 mProcessCrashTimes.remove(info.processName, info.uid);
1908 if (mBadProcesses.get(info.processName, info.uid) != null) {
1909 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1910 info.processName);
1911 mBadProcesses.remove(info.processName, info.uid);
1912 if (app != null) {
1913 app.bad = false;
1914 }
1915 }
1916 }
1917
1918 if (app == null) {
1919 app = newProcessRecordLocked(null, info, processName);
1920 mProcessNames.put(processName, info.uid, app);
1921 } else {
1922 // If this is a new package in the process, add the package to the list
1923 app.addPackage(info.packageName);
1924 }
1925
1926 // If the system is not ready yet, then hold off on starting this
1927 // process until it is.
1928 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001929 && !isAllowedWhileBooting(info)
1930 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001931 if (!mProcessesOnHold.contains(app)) {
1932 mProcessesOnHold.add(app);
1933 }
1934 return app;
1935 }
1936
1937 startProcessLocked(app, hostingType, hostingNameStr);
1938 return (app.pid != 0) ? app : null;
1939 }
1940
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001941 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1942 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1943 }
1944
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001945 private final void startProcessLocked(ProcessRecord app,
1946 String hostingType, String hostingNameStr) {
1947 if (app.pid > 0 && app.pid != MY_PID) {
1948 synchronized (mPidsSelfLocked) {
1949 mPidsSelfLocked.remove(app.pid);
1950 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1951 }
1952 app.pid = 0;
1953 }
1954
1955 mProcessesOnHold.remove(app);
1956
1957 updateCpuStats();
1958
1959 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1960 mProcDeaths[0] = 0;
1961
1962 try {
1963 int uid = app.info.uid;
1964 int[] gids = null;
1965 try {
1966 gids = mContext.getPackageManager().getPackageGids(
1967 app.info.packageName);
1968 } catch (PackageManager.NameNotFoundException e) {
1969 Log.w(TAG, "Unable to retrieve gids", e);
1970 }
1971 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1972 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1973 && mTopComponent != null
1974 && app.processName.equals(mTopComponent.getPackageName())) {
1975 uid = 0;
1976 }
1977 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1978 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1979 uid = 0;
1980 }
1981 }
1982 int debugFlags = 0;
1983 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1984 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1985 }
1986 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1987 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1988 }
1989 if ("1".equals(SystemProperties.get("debug.assert"))) {
1990 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1991 }
1992 int pid = Process.start("android.app.ActivityThread",
1993 mSimpleProcessManagement ? app.processName : null, uid, uid,
1994 gids, debugFlags, null);
1995 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1996 synchronized (bs) {
1997 if (bs.isOnBattery()) {
1998 app.batteryStats.incStartsLocked();
1999 }
2000 }
2001
2002 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
2003 app.processName, hostingType,
2004 hostingNameStr != null ? hostingNameStr : "");
2005
2006 if (app.persistent) {
2007 Watchdog.getInstance().processStarted(app, app.processName, pid);
2008 }
2009
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07002010 StringBuilder buf = mStringBuilder;
2011 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002012 buf.append("Start proc ");
2013 buf.append(app.processName);
2014 buf.append(" for ");
2015 buf.append(hostingType);
2016 if (hostingNameStr != null) {
2017 buf.append(" ");
2018 buf.append(hostingNameStr);
2019 }
2020 buf.append(": pid=");
2021 buf.append(pid);
2022 buf.append(" uid=");
2023 buf.append(uid);
2024 buf.append(" gids={");
2025 if (gids != null) {
2026 for (int gi=0; gi<gids.length; gi++) {
2027 if (gi != 0) buf.append(", ");
2028 buf.append(gids[gi]);
2029
2030 }
2031 }
2032 buf.append("}");
2033 Log.i(TAG, buf.toString());
2034 if (pid == 0 || pid == MY_PID) {
2035 // Processes are being emulated with threads.
2036 app.pid = MY_PID;
2037 app.removed = false;
2038 mStartingProcesses.add(app);
2039 } else if (pid > 0) {
2040 app.pid = pid;
2041 app.removed = false;
2042 synchronized (mPidsSelfLocked) {
2043 this.mPidsSelfLocked.put(pid, app);
2044 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2045 msg.obj = app;
2046 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2047 }
2048 } else {
2049 app.pid = 0;
2050 RuntimeException e = new RuntimeException(
2051 "Failure starting process " + app.processName
2052 + ": returned pid=" + pid);
2053 Log.e(TAG, e.getMessage(), e);
2054 }
2055 } catch (RuntimeException e) {
2056 // XXX do better error recovery.
2057 app.pid = 0;
2058 Log.e(TAG, "Failure starting process " + app.processName, e);
2059 }
2060 }
2061
2062 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2063 if (mPausingActivity != null) {
2064 RuntimeException e = new RuntimeException();
2065 Log.e(TAG, "Trying to pause when pause is already pending for "
2066 + mPausingActivity, e);
2067 }
2068 HistoryRecord prev = mResumedActivity;
2069 if (prev == null) {
2070 RuntimeException e = new RuntimeException();
2071 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2072 resumeTopActivityLocked(null);
2073 return;
2074 }
2075 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2076 mResumedActivity = null;
2077 mPausingActivity = prev;
2078 mLastPausedActivity = prev;
2079 prev.state = ActivityState.PAUSING;
2080 prev.task.touchActiveTime();
2081
2082 updateCpuStats();
2083
2084 if (prev.app != null && prev.app.thread != null) {
2085 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2086 try {
2087 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2088 System.identityHashCode(prev),
2089 prev.shortComponentName);
2090 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2091 prev.configChangeFlags);
2092 updateUsageStats(prev, false);
2093 } catch (Exception e) {
2094 // Ignore exception, if process died other code will cleanup.
2095 Log.w(TAG, "Exception thrown during pause", e);
2096 mPausingActivity = null;
2097 mLastPausedActivity = null;
2098 }
2099 } else {
2100 mPausingActivity = null;
2101 mLastPausedActivity = null;
2102 }
2103
2104 // If we are not going to sleep, we want to ensure the device is
2105 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002106 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002107 mLaunchingActivity.acquire();
2108 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2109 // To be safe, don't allow the wake lock to be held for too long.
2110 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2111 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2112 }
2113 }
2114
2115
2116 if (mPausingActivity != null) {
2117 // Have the window manager pause its key dispatching until the new
2118 // activity has started. If we're pausing the activity just because
2119 // the screen is being turned off and the UI is sleeping, don't interrupt
2120 // key dispatch; the same activity will pick it up again on wakeup.
2121 if (!uiSleeping) {
2122 prev.pauseKeyDispatchingLocked();
2123 } else {
2124 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2125 }
2126
2127 // Schedule a pause timeout in case the app doesn't respond.
2128 // We don't give it much time because this directly impacts the
2129 // responsiveness seen by the user.
2130 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2131 msg.obj = prev;
2132 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2133 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2134 } else {
2135 // This activity failed to schedule the
2136 // pause, so just treat it as being paused now.
2137 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2138 resumeTopActivityLocked(null);
2139 }
2140 }
2141
2142 private final void completePauseLocked() {
2143 HistoryRecord prev = mPausingActivity;
2144 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2145
2146 if (prev != null) {
2147 if (prev.finishing) {
2148 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2149 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2150 } else if (prev.app != null) {
2151 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2152 if (prev.waitingVisible) {
2153 prev.waitingVisible = false;
2154 mWaitingVisibleActivities.remove(prev);
2155 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2156 TAG, "Complete pause, no longer waiting: " + prev);
2157 }
2158 if (prev.configDestroy) {
2159 // The previous is being paused because the configuration
2160 // is changing, which means it is actually stopping...
2161 // To juggle the fact that we are also starting a new
2162 // instance right now, we need to first completely stop
2163 // the current instance before starting the new one.
2164 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2165 destroyActivityLocked(prev, true);
2166 } else {
2167 mStoppingActivities.add(prev);
2168 if (mStoppingActivities.size() > 3) {
2169 // If we already have a few activities waiting to stop,
2170 // then give up on things going idle and start clearing
2171 // them out.
2172 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2173 Message msg = Message.obtain();
2174 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2175 mHandler.sendMessage(msg);
2176 }
2177 }
2178 } else {
2179 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2180 prev = null;
2181 }
2182 mPausingActivity = null;
2183 }
2184
Dianne Hackborn55280a92009-05-07 15:53:46 -07002185 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002186 resumeTopActivityLocked(prev);
2187 } else {
2188 if (mGoingToSleep.isHeld()) {
2189 mGoingToSleep.release();
2190 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002191 if (mShuttingDown) {
2192 notifyAll();
2193 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002194 }
2195
2196 if (prev != null) {
2197 prev.resumeKeyDispatchingLocked();
2198 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002199
2200 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2201 long diff = 0;
2202 synchronized (mProcessStatsThread) {
2203 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2204 }
2205 if (diff > 0) {
2206 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2207 synchronized (bsi) {
2208 BatteryStatsImpl.Uid.Proc ps =
2209 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2210 prev.info.packageName);
2211 if (ps != null) {
2212 ps.addForegroundTimeLocked(diff);
2213 }
2214 }
2215 }
2216 }
2217 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002218 }
2219
2220 /**
2221 * Once we know that we have asked an application to put an activity in
2222 * the resumed state (either by launching it or explicitly telling it),
2223 * this function updates the rest of our state to match that fact.
2224 */
2225 private final void completeResumeLocked(HistoryRecord next) {
2226 next.idle = false;
2227 next.results = null;
2228 next.newIntents = null;
2229
2230 // schedule an idle timeout in case the app doesn't do it for us.
2231 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2232 msg.obj = next;
2233 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2234
2235 if (false) {
2236 // The activity was never told to pause, so just keep
2237 // things going as-is. To maintain our own state,
2238 // we need to emulate it coming back and saying it is
2239 // idle.
2240 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2241 msg.obj = next;
2242 mHandler.sendMessage(msg);
2243 }
2244
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002245 reportResumedActivity(next);
2246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002247 next.thumbnail = null;
2248 setFocusedActivityLocked(next);
2249 next.resumeKeyDispatchingLocked();
2250 ensureActivitiesVisibleLocked(null, 0);
2251 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002252
2253 // Mark the point when the activity is resuming
2254 // TODO: To be more accurate, the mark should be before the onCreate,
2255 // not after the onResume. But for subsequent starts, onResume is fine.
2256 if (next.app != null) {
2257 synchronized (mProcessStatsThread) {
2258 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2259 }
2260 } else {
2261 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2262 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002263 }
2264
2265 /**
2266 * Make sure that all activities that need to be visible (that is, they
2267 * currently can be seen by the user) actually are.
2268 */
2269 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2270 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2271 if (DEBUG_VISBILITY) Log.v(
2272 TAG, "ensureActivitiesVisible behind " + top
2273 + " configChanges=0x" + Integer.toHexString(configChanges));
2274
2275 // If the top activity is not fullscreen, then we need to
2276 // make sure any activities under it are now visible.
2277 final int count = mHistory.size();
2278 int i = count-1;
2279 while (mHistory.get(i) != top) {
2280 i--;
2281 }
2282 HistoryRecord r;
2283 boolean behindFullscreen = false;
2284 for (; i>=0; i--) {
2285 r = (HistoryRecord)mHistory.get(i);
2286 if (DEBUG_VISBILITY) Log.v(
2287 TAG, "Make visible? " + r + " finishing=" + r.finishing
2288 + " state=" + r.state);
2289 if (r.finishing) {
2290 continue;
2291 }
2292
2293 final boolean doThisProcess = onlyThisProcess == null
2294 || onlyThisProcess.equals(r.processName);
2295
2296 // First: if this is not the current activity being started, make
2297 // sure it matches the current configuration.
2298 if (r != starting && doThisProcess) {
2299 ensureActivityConfigurationLocked(r, 0);
2300 }
2301
2302 if (r.app == null || r.app.thread == null) {
2303 if (onlyThisProcess == null
2304 || onlyThisProcess.equals(r.processName)) {
2305 // This activity needs to be visible, but isn't even
2306 // running... get it started, but don't resume it
2307 // at this point.
2308 if (DEBUG_VISBILITY) Log.v(
2309 TAG, "Start and freeze screen for " + r);
2310 if (r != starting) {
2311 r.startFreezingScreenLocked(r.app, configChanges);
2312 }
2313 if (!r.visible) {
2314 if (DEBUG_VISBILITY) Log.v(
2315 TAG, "Starting and making visible: " + r);
2316 mWindowManager.setAppVisibility(r, true);
2317 }
2318 if (r != starting) {
2319 startSpecificActivityLocked(r, false, false);
2320 }
2321 }
2322
2323 } else if (r.visible) {
2324 // If this activity is already visible, then there is nothing
2325 // else to do here.
2326 if (DEBUG_VISBILITY) Log.v(
2327 TAG, "Skipping: already visible at " + r);
2328 r.stopFreezingScreenLocked(false);
2329
2330 } else if (onlyThisProcess == null) {
2331 // This activity is not currently visible, but is running.
2332 // Tell it to become visible.
2333 r.visible = true;
2334 if (r.state != ActivityState.RESUMED && r != starting) {
2335 // If this activity is paused, tell it
2336 // to now show its window.
2337 if (DEBUG_VISBILITY) Log.v(
2338 TAG, "Making visible and scheduling visibility: " + r);
2339 try {
2340 mWindowManager.setAppVisibility(r, true);
2341 r.app.thread.scheduleWindowVisibility(r, true);
2342 r.stopFreezingScreenLocked(false);
2343 } catch (Exception e) {
2344 // Just skip on any failure; we'll make it
2345 // visible when it next restarts.
2346 Log.w(TAG, "Exception thrown making visibile: "
2347 + r.intent.getComponent(), e);
2348 }
2349 }
2350 }
2351
2352 // Aggregate current change flags.
2353 configChanges |= r.configChangeFlags;
2354
2355 if (r.fullscreen) {
2356 // At this point, nothing else needs to be shown
2357 if (DEBUG_VISBILITY) Log.v(
2358 TAG, "Stopping: fullscreen at " + r);
2359 behindFullscreen = true;
2360 i--;
2361 break;
2362 }
2363 }
2364
2365 // Now for any activities that aren't visible to the user, make
2366 // sure they no longer are keeping the screen frozen.
2367 while (i >= 0) {
2368 r = (HistoryRecord)mHistory.get(i);
2369 if (DEBUG_VISBILITY) Log.v(
2370 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2371 + " state=" + r.state
2372 + " behindFullscreen=" + behindFullscreen);
2373 if (!r.finishing) {
2374 if (behindFullscreen) {
2375 if (r.visible) {
2376 if (DEBUG_VISBILITY) Log.v(
2377 TAG, "Making invisible: " + r);
2378 r.visible = false;
2379 try {
2380 mWindowManager.setAppVisibility(r, false);
2381 if ((r.state == ActivityState.STOPPING
2382 || r.state == ActivityState.STOPPED)
2383 && r.app != null && r.app.thread != null) {
2384 if (DEBUG_VISBILITY) Log.v(
2385 TAG, "Scheduling invisibility: " + r);
2386 r.app.thread.scheduleWindowVisibility(r, false);
2387 }
2388 } catch (Exception e) {
2389 // Just skip on any failure; we'll make it
2390 // visible when it next restarts.
2391 Log.w(TAG, "Exception thrown making hidden: "
2392 + r.intent.getComponent(), e);
2393 }
2394 } else {
2395 if (DEBUG_VISBILITY) Log.v(
2396 TAG, "Already invisible: " + r);
2397 }
2398 } else if (r.fullscreen) {
2399 if (DEBUG_VISBILITY) Log.v(
2400 TAG, "Now behindFullscreen: " + r);
2401 behindFullscreen = true;
2402 }
2403 }
2404 i--;
2405 }
2406 }
2407
2408 /**
2409 * Version of ensureActivitiesVisible that can easily be called anywhere.
2410 */
2411 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2412 int configChanges) {
2413 HistoryRecord r = topRunningActivityLocked(null);
2414 if (r != null) {
2415 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2416 }
2417 }
2418
2419 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2420 if (resumed) {
2421 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2422 } else {
2423 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2424 }
2425 }
2426
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002427 private boolean startHomeActivityLocked() {
2428 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2429 && mTopAction == null) {
2430 // We are running in factory test mode, but unable to find
2431 // the factory test app, so just sit around displaying the
2432 // error message and don't try to start anything.
2433 return false;
2434 }
2435 Intent intent = new Intent(
2436 mTopAction,
2437 mTopData != null ? Uri.parse(mTopData) : null);
2438 intent.setComponent(mTopComponent);
2439 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2440 intent.addCategory(Intent.CATEGORY_HOME);
2441 }
2442 ActivityInfo aInfo =
2443 intent.resolveActivityInfo(mContext.getPackageManager(),
2444 STOCK_PM_FLAGS);
2445 if (aInfo != null) {
2446 intent.setComponent(new ComponentName(
2447 aInfo.applicationInfo.packageName, aInfo.name));
2448 // Don't do this if the home app is currently being
2449 // instrumented.
2450 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2451 aInfo.applicationInfo.uid);
2452 if (app == null || app.instrumentationClass == null) {
2453 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2454 startActivityLocked(null, intent, null, null, 0, aInfo,
2455 null, null, 0, 0, 0, false, false);
2456 }
2457 }
2458
2459
2460 return true;
2461 }
2462
2463 /**
2464 * Starts the "new version setup screen" if appropriate.
2465 */
2466 private void startSetupActivityLocked() {
2467 // Only do this once per boot.
2468 if (mCheckedForSetup) {
2469 return;
2470 }
2471
2472 // We will show this screen if the current one is a different
2473 // version than the last one shown, and we are not running in
2474 // low-level factory test mode.
2475 final ContentResolver resolver = mContext.getContentResolver();
2476 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2477 Settings.Secure.getInt(resolver,
2478 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2479 mCheckedForSetup = true;
2480
2481 // See if we should be showing the platform update setup UI.
2482 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2483 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2484 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2485
2486 // We don't allow third party apps to replace this.
2487 ResolveInfo ri = null;
2488 for (int i=0; ris != null && i<ris.size(); i++) {
2489 if ((ris.get(i).activityInfo.applicationInfo.flags
2490 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2491 ri = ris.get(i);
2492 break;
2493 }
2494 }
2495
2496 if (ri != null) {
2497 String vers = ri.activityInfo.metaData != null
2498 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2499 : null;
2500 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2501 vers = ri.activityInfo.applicationInfo.metaData.getString(
2502 Intent.METADATA_SETUP_VERSION);
2503 }
2504 String lastVers = Settings.Secure.getString(
2505 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2506 if (vers != null && !vers.equals(lastVers)) {
2507 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2508 intent.setComponent(new ComponentName(
2509 ri.activityInfo.packageName, ri.activityInfo.name));
2510 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2511 null, null, 0, 0, 0, false, false);
2512 }
2513 }
2514 }
2515 }
2516
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002517 private void reportResumedActivity(HistoryRecord r) {
2518 //Log.i(TAG, "**** REPORT RESUME: " + r);
2519
2520 final int identHash = System.identityHashCode(r);
2521 updateUsageStats(r, true);
2522
2523 int i = mWatchers.beginBroadcast();
2524 while (i > 0) {
2525 i--;
2526 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2527 if (w != null) {
2528 try {
2529 w.activityResuming(identHash);
2530 } catch (RemoteException e) {
2531 }
2532 }
2533 }
2534 mWatchers.finishBroadcast();
2535 }
2536
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002537 /**
2538 * Ensure that the top activity in the stack is resumed.
2539 *
2540 * @param prev The previously resumed activity, for when in the process
2541 * of pausing; can be null to call from elsewhere.
2542 *
2543 * @return Returns true if something is being resumed, or false if
2544 * nothing happened.
2545 */
2546 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2547 // Find the first activity that is not finishing.
2548 HistoryRecord next = topRunningActivityLocked(null);
2549
2550 // Remember how we'll process this pause/resume situation, and ensure
2551 // that the state is reset however we wind up proceeding.
2552 final boolean userLeaving = mUserLeaving;
2553 mUserLeaving = false;
2554
2555 if (next == null) {
2556 // There are no more activities! Let's just start up the
2557 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002558 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002559 }
2560
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002561 next.delayedResume = false;
2562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002563 // If the top activity is the resumed one, nothing to do.
2564 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2565 // Make sure we have executed any pending transitions, since there
2566 // should be nothing left to do at this point.
2567 mWindowManager.executeAppTransition();
2568 return false;
2569 }
2570
2571 // If we are sleeping, and there is no resumed activity, and the top
2572 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002573 if ((mSleeping || mShuttingDown)
2574 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002575 // Make sure we have executed any pending transitions, since there
2576 // should be nothing left to do at this point.
2577 mWindowManager.executeAppTransition();
2578 return false;
2579 }
2580
2581 // The activity may be waiting for stop, but that is no longer
2582 // appropriate for it.
2583 mStoppingActivities.remove(next);
2584 mWaitingVisibleActivities.remove(next);
2585
2586 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2587
2588 // If we are currently pausing an activity, then don't do anything
2589 // until that is done.
2590 if (mPausingActivity != null) {
2591 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2592 return false;
2593 }
2594
2595 // We need to start pausing the current activity so the top one
2596 // can be resumed...
2597 if (mResumedActivity != null) {
2598 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2599 startPausingLocked(userLeaving, false);
2600 return true;
2601 }
2602
2603 if (prev != null && prev != next) {
2604 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2605 prev.waitingVisible = true;
2606 mWaitingVisibleActivities.add(prev);
2607 if (DEBUG_SWITCH) Log.v(
2608 TAG, "Resuming top, waiting visible to hide: " + prev);
2609 } else {
2610 // The next activity is already visible, so hide the previous
2611 // activity's windows right now so we can show the new one ASAP.
2612 // We only do this if the previous is finishing, which should mean
2613 // it is on top of the one being resumed so hiding it quickly
2614 // is good. Otherwise, we want to do the normal route of allowing
2615 // the resumed activity to be shown so we can decide if the
2616 // previous should actually be hidden depending on whether the
2617 // new one is found to be full-screen or not.
2618 if (prev.finishing) {
2619 mWindowManager.setAppVisibility(prev, false);
2620 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2621 + prev + ", waitingVisible="
2622 + (prev != null ? prev.waitingVisible : null)
2623 + ", nowVisible=" + next.nowVisible);
2624 } else {
2625 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2626 + prev + ", waitingVisible="
2627 + (prev != null ? prev.waitingVisible : null)
2628 + ", nowVisible=" + next.nowVisible);
2629 }
2630 }
2631 }
2632
2633 // We are starting up the next activity, so tell the window manager
2634 // that the previous one will be hidden soon. This way it can know
2635 // to ignore it when computing the desired screen orientation.
2636 if (prev != null) {
2637 if (prev.finishing) {
2638 if (DEBUG_TRANSITION) Log.v(TAG,
2639 "Prepare close transition: prev=" + prev);
2640 mWindowManager.prepareAppTransition(prev.task == next.task
2641 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2642 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2643 mWindowManager.setAppWillBeHidden(prev);
2644 mWindowManager.setAppVisibility(prev, false);
2645 } else {
2646 if (DEBUG_TRANSITION) Log.v(TAG,
2647 "Prepare open transition: prev=" + prev);
2648 mWindowManager.prepareAppTransition(prev.task == next.task
2649 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2650 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2651 }
2652 if (false) {
2653 mWindowManager.setAppWillBeHidden(prev);
2654 mWindowManager.setAppVisibility(prev, false);
2655 }
2656 } else if (mHistory.size() > 1) {
2657 if (DEBUG_TRANSITION) Log.v(TAG,
2658 "Prepare open transition: no previous");
2659 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2660 }
2661
2662 if (next.app != null && next.app.thread != null) {
2663 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2664
2665 // This activity is now becoming visible.
2666 mWindowManager.setAppVisibility(next, true);
2667
2668 HistoryRecord lastResumedActivity = mResumedActivity;
2669 ActivityState lastState = next.state;
2670
2671 updateCpuStats();
2672
2673 next.state = ActivityState.RESUMED;
2674 mResumedActivity = next;
2675 next.task.touchActiveTime();
2676 updateLRUListLocked(next.app, true);
2677 updateLRUListLocked(next);
2678
2679 // Have the window manager re-evaluate the orientation of
2680 // the screen based on the new activity order.
2681 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002682 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002683 next.mayFreezeScreenLocked(next.app) ? next : null);
2684 if (config != null) {
2685 next.frozenBeforeDestroy = true;
2686 }
2687 if (!updateConfigurationLocked(config, next)) {
2688 // The configuration update wasn't able to keep the existing
2689 // instance of the activity, and instead started a new one.
2690 // We should be all done, but let's just make sure our activity
2691 // is still at the top and schedule another run if something
2692 // weird happened.
2693 HistoryRecord nextNext = topRunningActivityLocked(null);
2694 if (DEBUG_SWITCH) Log.i(TAG,
2695 "Activity config changed during resume: " + next
2696 + ", new next: " + nextNext);
2697 if (nextNext != next) {
2698 // Do over!
2699 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2700 }
2701 mWindowManager.executeAppTransition();
2702 return true;
2703 }
2704
2705 try {
2706 // Deliver all pending results.
2707 ArrayList a = next.results;
2708 if (a != null) {
2709 final int N = a.size();
2710 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002711 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002712 TAG, "Delivering results to " + next
2713 + ": " + a);
2714 next.app.thread.scheduleSendResult(next, a);
2715 }
2716 }
2717
2718 if (next.newIntents != null) {
2719 next.app.thread.scheduleNewIntent(next.newIntents, next);
2720 }
2721
2722 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2723 System.identityHashCode(next),
2724 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002725
2726 next.app.thread.scheduleResumeActivity(next,
2727 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002728
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002729 pauseIfSleepingLocked();
2730
2731 } catch (Exception e) {
2732 // Whoops, need to restart this activity!
2733 next.state = lastState;
2734 mResumedActivity = lastResumedActivity;
2735 if (Config.LOGD) Log.d(TAG,
2736 "Restarting because process died: " + next);
2737 if (!next.hasBeenLaunched) {
2738 next.hasBeenLaunched = true;
2739 } else {
2740 if (SHOW_APP_STARTING_ICON) {
2741 mWindowManager.setAppStartingWindow(
2742 next, next.packageName, next.theme,
2743 next.nonLocalizedLabel,
2744 next.labelRes, next.icon, null, true);
2745 }
2746 }
2747 startSpecificActivityLocked(next, true, false);
2748 return true;
2749 }
2750
2751 // From this point on, if something goes wrong there is no way
2752 // to recover the activity.
2753 try {
2754 next.visible = true;
2755 completeResumeLocked(next);
2756 } catch (Exception e) {
2757 // If any exception gets thrown, toss away this
2758 // activity and try the next one.
2759 Log.w(TAG, "Exception thrown during resume of " + next, e);
2760 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2761 "resume-exception");
2762 return true;
2763 }
2764
2765 // Didn't need to use the icicle, and it is now out of date.
2766 next.icicle = null;
2767 next.haveState = false;
2768 next.stopped = false;
2769
2770 } else {
2771 // Whoops, need to restart this activity!
2772 if (!next.hasBeenLaunched) {
2773 next.hasBeenLaunched = true;
2774 } else {
2775 if (SHOW_APP_STARTING_ICON) {
2776 mWindowManager.setAppStartingWindow(
2777 next, next.packageName, next.theme,
2778 next.nonLocalizedLabel,
2779 next.labelRes, next.icon, null, true);
2780 }
2781 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2782 }
2783 startSpecificActivityLocked(next, true, true);
2784 }
2785
2786 return true;
2787 }
2788
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002789 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2790 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002791 final int NH = mHistory.size();
2792
2793 int addPos = -1;
2794
2795 if (!newTask) {
2796 // If starting in an existing task, find where that is...
2797 HistoryRecord next = null;
2798 boolean startIt = true;
2799 for (int i = NH-1; i >= 0; i--) {
2800 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2801 if (p.finishing) {
2802 continue;
2803 }
2804 if (p.task == r.task) {
2805 // Here it is! Now, if this is not yet visible to the
2806 // user, then just add it without starting; it will
2807 // get started when the user navigates back to it.
2808 addPos = i+1;
2809 if (!startIt) {
2810 mHistory.add(addPos, r);
2811 r.inHistory = true;
2812 r.task.numActivities++;
2813 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2814 r.info.screenOrientation, r.fullscreen);
2815 if (VALIDATE_TOKENS) {
2816 mWindowManager.validateAppTokens(mHistory);
2817 }
2818 return;
2819 }
2820 break;
2821 }
2822 if (p.fullscreen) {
2823 startIt = false;
2824 }
2825 next = p;
2826 }
2827 }
2828
2829 // Place a new activity at top of stack, so it is next to interact
2830 // with the user.
2831 if (addPos < 0) {
2832 addPos = mHistory.size();
2833 }
2834
2835 // If we are not placing the new activity frontmost, we do not want
2836 // to deliver the onUserLeaving callback to the actual frontmost
2837 // activity
2838 if (addPos < NH) {
2839 mUserLeaving = false;
2840 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2841 }
2842
2843 // Slot the activity into the history stack and proceed
2844 mHistory.add(addPos, r);
2845 r.inHistory = true;
2846 r.frontOfTask = newTask;
2847 r.task.numActivities++;
2848 if (NH > 0) {
2849 // We want to show the starting preview window if we are
2850 // switching to a new task, or the next activity's process is
2851 // not currently running.
2852 boolean showStartingIcon = newTask;
2853 ProcessRecord proc = r.app;
2854 if (proc == null) {
2855 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2856 }
2857 if (proc == null || proc.thread == null) {
2858 showStartingIcon = true;
2859 }
2860 if (DEBUG_TRANSITION) Log.v(TAG,
2861 "Prepare open transition: starting " + r);
2862 mWindowManager.prepareAppTransition(newTask
2863 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2864 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2865 mWindowManager.addAppToken(
2866 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2867 boolean doShow = true;
2868 if (newTask) {
2869 // Even though this activity is starting fresh, we still need
2870 // to reset it to make sure we apply affinities to move any
2871 // existing activities from other tasks in to it.
2872 // If the caller has requested that the target task be
2873 // reset, then do so.
2874 if ((r.intent.getFlags()
2875 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2876 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002877 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002878 }
2879 }
2880 if (SHOW_APP_STARTING_ICON && doShow) {
2881 // Figure out if we are transitioning from another activity that is
2882 // "has the same starting icon" as the next one. This allows the
2883 // window manager to keep the previous window it had previously
2884 // created, if it still had one.
2885 HistoryRecord prev = mResumedActivity;
2886 if (prev != null) {
2887 // We don't want to reuse the previous starting preview if:
2888 // (1) The current activity is in a different task.
2889 if (prev.task != r.task) prev = null;
2890 // (2) The current activity is already displayed.
2891 else if (prev.nowVisible) prev = null;
2892 }
2893 mWindowManager.setAppStartingWindow(
2894 r, r.packageName, r.theme, r.nonLocalizedLabel,
2895 r.labelRes, r.icon, prev, showStartingIcon);
2896 }
2897 } else {
2898 // If this is the first activity, don't do any fancy animations,
2899 // because there is nothing for it to animate on top of.
2900 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2901 r.info.screenOrientation, r.fullscreen);
2902 }
2903 if (VALIDATE_TOKENS) {
2904 mWindowManager.validateAppTokens(mHistory);
2905 }
2906
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002907 if (doResume) {
2908 resumeTopActivityLocked(null);
2909 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002910 }
2911
2912 /**
2913 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002914 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2915 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002916 * an instance of that activity in the stack and, if found, finish all
2917 * activities on top of it and return the instance.
2918 *
2919 * @param newR Description of the new activity being started.
2920 * @return Returns the old activity that should be continue to be used,
2921 * or null if none was found.
2922 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002923 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002924 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002925 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002926
2927 // First find the requested task.
2928 while (i > 0) {
2929 i--;
2930 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2931 if (r.task.taskId == taskId) {
2932 i++;
2933 break;
2934 }
2935 }
2936
2937 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002938 while (i > 0) {
2939 i--;
2940 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2941 if (r.finishing) {
2942 continue;
2943 }
2944 if (r.task.taskId != taskId) {
2945 return null;
2946 }
2947 if (r.realActivity.equals(newR.realActivity)) {
2948 // Here it is! Now finish everything in front...
2949 HistoryRecord ret = r;
2950 if (doClear) {
2951 while (i < (mHistory.size()-1)) {
2952 i++;
2953 r = (HistoryRecord)mHistory.get(i);
2954 if (r.finishing) {
2955 continue;
2956 }
2957 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2958 null, "clear")) {
2959 i--;
2960 }
2961 }
2962 }
2963
2964 // Finally, if this is a normal launch mode (that is, not
2965 // expecting onNewIntent()), then we will finish the current
2966 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002967 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
2968 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002969 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002970 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002971 if (index >= 0) {
2972 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2973 null, "clear");
2974 }
2975 return null;
2976 }
2977 }
2978
2979 return ret;
2980 }
2981 }
2982
2983 return null;
2984 }
2985
2986 /**
2987 * Find the activity in the history stack within the given task. Returns
2988 * the index within the history at which it's found, or < 0 if not found.
2989 */
2990 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2991 int i = mHistory.size();
2992 while (i > 0) {
2993 i--;
2994 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2995 if (candidate.task.taskId != task) {
2996 break;
2997 }
2998 if (candidate.realActivity.equals(r.realActivity)) {
2999 return i;
3000 }
3001 }
3002
3003 return -1;
3004 }
3005
3006 /**
3007 * Reorder the history stack so that the activity at the given index is
3008 * brought to the front.
3009 */
3010 private final HistoryRecord moveActivityToFrontLocked(int where) {
3011 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3012 int top = mHistory.size();
3013 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3014 mHistory.add(top, newTop);
3015 oldTop.frontOfTask = false;
3016 newTop.frontOfTask = true;
3017 return newTop;
3018 }
3019
3020 /**
3021 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3022 * method will be called at the proper time.
3023 */
3024 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3025 boolean sent = false;
3026 if (r.state == ActivityState.RESUMED
3027 && r.app != null && r.app.thread != null) {
3028 try {
3029 ArrayList<Intent> ar = new ArrayList<Intent>();
3030 ar.add(new Intent(intent));
3031 r.app.thread.scheduleNewIntent(ar, r);
3032 sent = true;
3033 } catch (Exception e) {
3034 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3035 }
3036 }
3037 if (!sent) {
3038 r.addNewIntentLocked(new Intent(intent));
3039 }
3040 }
3041
3042 private final void logStartActivity(int tag, HistoryRecord r,
3043 TaskRecord task) {
3044 EventLog.writeEvent(tag,
3045 System.identityHashCode(r), task.taskId,
3046 r.shortComponentName, r.intent.getAction(),
3047 r.intent.getType(), r.intent.getDataString(),
3048 r.intent.getFlags());
3049 }
3050
3051 private final int startActivityLocked(IApplicationThread caller,
3052 Intent intent, String resolvedType,
3053 Uri[] grantedUriPermissions,
3054 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3055 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003056 int callingPid, int callingUid, boolean onlyIfNeeded,
3057 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003058 Log.i(TAG, "Starting activity: " + intent);
3059
3060 HistoryRecord sourceRecord = null;
3061 HistoryRecord resultRecord = null;
3062 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003063 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003064 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003065 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3066 if (index >= 0) {
3067 sourceRecord = (HistoryRecord)mHistory.get(index);
3068 if (requestCode >= 0 && !sourceRecord.finishing) {
3069 resultRecord = sourceRecord;
3070 }
3071 }
3072 }
3073
3074 int launchFlags = intent.getFlags();
3075
3076 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3077 && sourceRecord != null) {
3078 // Transfer the result target from the source activity to the new
3079 // one being started, including any failures.
3080 if (requestCode >= 0) {
3081 return START_FORWARD_AND_REQUEST_CONFLICT;
3082 }
3083 resultRecord = sourceRecord.resultTo;
3084 resultWho = sourceRecord.resultWho;
3085 requestCode = sourceRecord.requestCode;
3086 sourceRecord.resultTo = null;
3087 if (resultRecord != null) {
3088 resultRecord.removeResultsLocked(
3089 sourceRecord, resultWho, requestCode);
3090 }
3091 }
3092
3093 int err = START_SUCCESS;
3094
3095 if (intent.getComponent() == null) {
3096 // We couldn't find a class that can handle the given Intent.
3097 // That's the end of that!
3098 err = START_INTENT_NOT_RESOLVED;
3099 }
3100
3101 if (err == START_SUCCESS && aInfo == null) {
3102 // We couldn't find the specific class specified in the Intent.
3103 // Also the end of the line.
3104 err = START_CLASS_NOT_FOUND;
3105 }
3106
3107 ProcessRecord callerApp = null;
3108 if (err == START_SUCCESS && caller != null) {
3109 callerApp = getRecordForAppLocked(caller);
3110 if (callerApp != null) {
3111 callingPid = callerApp.pid;
3112 callingUid = callerApp.info.uid;
3113 } else {
3114 Log.w(TAG, "Unable to find app for caller " + caller
3115 + " (pid=" + callingPid + ") when starting: "
3116 + intent.toString());
3117 err = START_PERMISSION_DENIED;
3118 }
3119 }
3120
3121 if (err != START_SUCCESS) {
3122 if (resultRecord != null) {
3123 sendActivityResultLocked(-1,
3124 resultRecord, resultWho, requestCode,
3125 Activity.RESULT_CANCELED, null);
3126 }
3127 return err;
3128 }
3129
3130 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3131 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3132 if (perm != PackageManager.PERMISSION_GRANTED) {
3133 if (resultRecord != null) {
3134 sendActivityResultLocked(-1,
3135 resultRecord, resultWho, requestCode,
3136 Activity.RESULT_CANCELED, null);
3137 }
3138 String msg = "Permission Denial: starting " + intent.toString()
3139 + " from " + callerApp + " (pid=" + callingPid
3140 + ", uid=" + callingUid + ")"
3141 + " requires " + aInfo.permission;
3142 Log.w(TAG, msg);
3143 throw new SecurityException(msg);
3144 }
3145
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003146 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003147 boolean abort = false;
3148 try {
3149 // The Intent we give to the watcher has the extra data
3150 // stripped off, since it can contain private information.
3151 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003152 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003153 aInfo.applicationInfo.packageName);
3154 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003155 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003156 }
3157
3158 if (abort) {
3159 if (resultRecord != null) {
3160 sendActivityResultLocked(-1,
3161 resultRecord, resultWho, requestCode,
3162 Activity.RESULT_CANCELED, null);
3163 }
3164 // We pretend to the caller that it was really started, but
3165 // they will just get a cancel result.
3166 return START_SUCCESS;
3167 }
3168 }
3169
3170 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3171 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003172 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003173
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003174 if (mResumedActivity == null
3175 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3176 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3177 PendingActivityLaunch pal = new PendingActivityLaunch();
3178 pal.r = r;
3179 pal.sourceRecord = sourceRecord;
3180 pal.grantedUriPermissions = grantedUriPermissions;
3181 pal.grantedMode = grantedMode;
3182 pal.onlyIfNeeded = onlyIfNeeded;
3183 mPendingActivityLaunches.add(pal);
3184 return START_SWITCHES_CANCELED;
3185 }
3186 }
3187
3188 if (mDidAppSwitch) {
3189 // This is the second allowed switch since we stopped switches,
3190 // so now just generally allow switches. Use case: user presses
3191 // home (switches disabled, switch to home, mDidAppSwitch now true);
3192 // user taps a home icon (coming from home so allowed, we hit here
3193 // and now allow anyone to switch again).
3194 mAppSwitchesAllowedTime = 0;
3195 } else {
3196 mDidAppSwitch = true;
3197 }
3198
3199 doPendingActivityLaunchesLocked(false);
3200
3201 return startActivityUncheckedLocked(r, sourceRecord,
3202 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3203 }
3204
3205 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3206 final int N = mPendingActivityLaunches.size();
3207 if (N <= 0) {
3208 return;
3209 }
3210 for (int i=0; i<N; i++) {
3211 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3212 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3213 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3214 doResume && i == (N-1));
3215 }
3216 mPendingActivityLaunches.clear();
3217 }
3218
3219 private final int startActivityUncheckedLocked(HistoryRecord r,
3220 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3221 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3222 final Intent intent = r.intent;
3223 final int callingUid = r.launchedFromUid;
3224
3225 int launchFlags = intent.getFlags();
3226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003227 // We'll invoke onUserLeaving before onPause only if the launching
3228 // activity did not explicitly state that this is an automated launch.
3229 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3230 if (DEBUG_USER_LEAVING) Log.v(TAG,
3231 "startActivity() => mUserLeaving=" + mUserLeaving);
3232
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003233 // If the caller has asked not to resume at this point, we make note
3234 // of this in the record so that we can skip it when trying to find
3235 // the top running activity.
3236 if (!doResume) {
3237 r.delayedResume = true;
3238 }
3239
3240 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3241 != 0 ? r : null;
3242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003243 // If the onlyIfNeeded flag is set, then we can do this if the activity
3244 // being launched is the same as the one making the call... or, as
3245 // a special case, if we do not know the caller then we count the
3246 // current top activity as the caller.
3247 if (onlyIfNeeded) {
3248 HistoryRecord checkedCaller = sourceRecord;
3249 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003250 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003251 }
3252 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3253 // Caller is not the same as launcher, so always needed.
3254 onlyIfNeeded = false;
3255 }
3256 }
3257
3258 if (grantedUriPermissions != null && callingUid > 0) {
3259 for (int i=0; i<grantedUriPermissions.length; i++) {
3260 grantUriPermissionLocked(callingUid, r.packageName,
3261 grantedUriPermissions[i], grantedMode, r);
3262 }
3263 }
3264
3265 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3266 intent, r);
3267
3268 if (sourceRecord == null) {
3269 // This activity is not being started from another... in this
3270 // case we -always- start a new task.
3271 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3272 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3273 + intent);
3274 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3275 }
3276 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3277 // The original activity who is starting us is running as a single
3278 // instance... this new activity it is starting must go on its
3279 // own task.
3280 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3281 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3282 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3283 // The activity being started is a single instance... it always
3284 // gets launched into its own task.
3285 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3286 }
3287
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003288 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003289 // For whatever reason this activity is being launched into a new
3290 // task... yet the caller has requested a result back. Well, that
3291 // is pretty messed up, so instead immediately send back a cancel
3292 // and let the new task continue launched as normal without a
3293 // dependency on its originator.
3294 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3295 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003296 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003297 Activity.RESULT_CANCELED, null);
3298 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003299 }
3300
3301 boolean addingToTask = false;
3302 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3303 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3304 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3305 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3306 // If bring to front is requested, and no result is requested, and
3307 // we can find a task that was started with this same
3308 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003309 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003310 // See if there is a task to bring to the front. If this is
3311 // a SINGLE_INSTANCE activity, there can be one and only one
3312 // instance of it in the history, and it is always in its own
3313 // unique task, so we do a special search.
3314 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3315 ? findTaskLocked(intent, r.info)
3316 : findActivityLocked(intent, r.info);
3317 if (taskTop != null) {
3318 if (taskTop.task.intent == null) {
3319 // This task was started because of movement of
3320 // the activity based on affinity... now that we
3321 // are actually launching it, we can assign the
3322 // base intent.
3323 taskTop.task.setIntent(intent, r.info);
3324 }
3325 // If the target task is not in the front, then we need
3326 // to bring it to the front... except... well, with
3327 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3328 // to have the same behavior as if a new instance was
3329 // being started, which means not bringing it to the front
3330 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003331 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003332 if (curTop.task != taskTop.task) {
3333 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3334 boolean callerAtFront = sourceRecord == null
3335 || curTop.task == sourceRecord.task;
3336 if (callerAtFront) {
3337 // We really do want to push this one into the
3338 // user's face, right now.
3339 moveTaskToFrontLocked(taskTop.task);
3340 }
3341 }
3342 // If the caller has requested that the target task be
3343 // reset, then do so.
3344 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3345 taskTop = resetTaskIfNeededLocked(taskTop, r);
3346 }
3347 if (onlyIfNeeded) {
3348 // We don't need to start a new activity, and
3349 // the client said not to do anything if that
3350 // is the case, so this is it! And for paranoia, make
3351 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003352 if (doResume) {
3353 resumeTopActivityLocked(null);
3354 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003355 return START_RETURN_INTENT_TO_CALLER;
3356 }
3357 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3358 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3359 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3360 // In this situation we want to remove all activities
3361 // from the task up to the one being started. In most
3362 // cases this means we are resetting the task to its
3363 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003364 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003365 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003366 if (top != null) {
3367 if (top.frontOfTask) {
3368 // Activity aliases may mean we use different
3369 // intents for the top activity, so make sure
3370 // the task now has the identity of the new
3371 // intent.
3372 top.task.setIntent(r.intent, r.info);
3373 }
3374 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3375 deliverNewIntentLocked(top, r.intent);
3376 } else {
3377 // A special case: we need to
3378 // start the activity because it is not currently
3379 // running, and the caller has asked to clear the
3380 // current task to have this activity at the top.
3381 addingToTask = true;
3382 // Now pretend like this activity is being started
3383 // by the top of its task, so it is put in the
3384 // right place.
3385 sourceRecord = taskTop;
3386 }
3387 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3388 // In this case the top activity on the task is the
3389 // same as the one being launched, so we take that
3390 // as a request to bring the task to the foreground.
3391 // If the top activity in the task is the root
3392 // activity, deliver this new intent to it if it
3393 // desires.
3394 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3395 && taskTop.realActivity.equals(r.realActivity)) {
3396 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3397 if (taskTop.frontOfTask) {
3398 taskTop.task.setIntent(r.intent, r.info);
3399 }
3400 deliverNewIntentLocked(taskTop, r.intent);
3401 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3402 // In this case we are launching the root activity
3403 // of the task, but with a different intent. We
3404 // should start a new instance on top.
3405 addingToTask = true;
3406 sourceRecord = taskTop;
3407 }
3408 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3409 // In this case an activity is being launched in to an
3410 // existing task, without resetting that task. This
3411 // is typically the situation of launching an activity
3412 // from a notification or shortcut. We want to place
3413 // the new activity on top of the current task.
3414 addingToTask = true;
3415 sourceRecord = taskTop;
3416 } else if (!taskTop.task.rootWasReset) {
3417 // In this case we are launching in to an existing task
3418 // that has not yet been started from its front door.
3419 // The current task has been brought to the front.
3420 // Ideally, we'd probably like to place this new task
3421 // at the bottom of its stack, but that's a little hard
3422 // to do with the current organization of the code so
3423 // for now we'll just drop it.
3424 taskTop.task.setIntent(r.intent, r.info);
3425 }
3426 if (!addingToTask) {
3427 // We didn't do anything... but it was needed (a.k.a., client
3428 // don't use that intent!) And for paranoia, make
3429 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003430 if (doResume) {
3431 resumeTopActivityLocked(null);
3432 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003433 return START_TASK_TO_FRONT;
3434 }
3435 }
3436 }
3437 }
3438
3439 //String uri = r.intent.toURI();
3440 //Intent intent2 = new Intent(uri);
3441 //Log.i(TAG, "Given intent: " + r.intent);
3442 //Log.i(TAG, "URI is: " + uri);
3443 //Log.i(TAG, "To intent: " + intent2);
3444
3445 if (r.packageName != null) {
3446 // If the activity being launched is the same as the one currently
3447 // at the top, then we need to check if it should only be launched
3448 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003449 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3450 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003451 if (top.realActivity.equals(r.realActivity)) {
3452 if (top.app != null && top.app.thread != null) {
3453 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3454 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3455 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3456 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3457 // For paranoia, make sure we have correctly
3458 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003459 if (doResume) {
3460 resumeTopActivityLocked(null);
3461 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003462 if (onlyIfNeeded) {
3463 // We don't need to start a new activity, and
3464 // the client said not to do anything if that
3465 // is the case, so this is it!
3466 return START_RETURN_INTENT_TO_CALLER;
3467 }
3468 deliverNewIntentLocked(top, r.intent);
3469 return START_DELIVERED_TO_TOP;
3470 }
3471 }
3472 }
3473 }
3474
3475 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003476 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003477 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003478 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003479 Activity.RESULT_CANCELED, null);
3480 }
3481 return START_CLASS_NOT_FOUND;
3482 }
3483
3484 boolean newTask = false;
3485
3486 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003487 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003488 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3489 // todo: should do better management of integers.
3490 mCurTask++;
3491 if (mCurTask <= 0) {
3492 mCurTask = 1;
3493 }
3494 r.task = new TaskRecord(mCurTask, r.info, intent,
3495 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3496 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3497 + " in new task " + r.task);
3498 newTask = true;
3499 addRecentTask(r.task);
3500
3501 } else if (sourceRecord != null) {
3502 if (!addingToTask &&
3503 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3504 // In this case, we are adding the activity to an existing
3505 // task, but the caller has asked to clear that task if the
3506 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003507 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003508 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003509 if (top != null) {
3510 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3511 deliverNewIntentLocked(top, r.intent);
3512 // For paranoia, make sure we have correctly
3513 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003514 if (doResume) {
3515 resumeTopActivityLocked(null);
3516 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003517 return START_DELIVERED_TO_TOP;
3518 }
3519 } else if (!addingToTask &&
3520 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3521 // In this case, we are launching an activity in our own task
3522 // that may already be running somewhere in the history, and
3523 // we want to shuffle it to the front of the stack if so.
3524 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3525 if (where >= 0) {
3526 HistoryRecord top = moveActivityToFrontLocked(where);
3527 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3528 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003529 if (doResume) {
3530 resumeTopActivityLocked(null);
3531 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003532 return START_DELIVERED_TO_TOP;
3533 }
3534 }
3535 // An existing activity is starting this new activity, so we want
3536 // to keep the new one in the same task as the one that is starting
3537 // it.
3538 r.task = sourceRecord.task;
3539 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3540 + " in existing task " + r.task);
3541
3542 } else {
3543 // This not being started from an existing activity, and not part
3544 // of a new task... just put it in the top task, though these days
3545 // this case should never happen.
3546 final int N = mHistory.size();
3547 HistoryRecord prev =
3548 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3549 r.task = prev != null
3550 ? prev.task
3551 : new TaskRecord(mCurTask, r.info, intent,
3552 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3553 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3554 + " in new guessed " + r.task);
3555 }
3556 if (newTask) {
3557 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3558 }
3559 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003560 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003561 return START_SUCCESS;
3562 }
3563
3564 public final int startActivity(IApplicationThread caller,
3565 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3566 int grantedMode, IBinder resultTo,
3567 String resultWho, int requestCode, boolean onlyIfNeeded,
3568 boolean debug) {
3569 // Refuse possible leaked file descriptors
3570 if (intent != null && intent.hasFileDescriptors()) {
3571 throw new IllegalArgumentException("File descriptors passed in Intent");
3572 }
3573
The Android Open Source Project4df24232009-03-05 14:34:35 -08003574 final boolean componentSpecified = intent.getComponent() != null;
3575
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003576 // Don't modify the client's object!
3577 intent = new Intent(intent);
3578
3579 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003580 ActivityInfo aInfo;
3581 try {
3582 ResolveInfo rInfo =
3583 ActivityThread.getPackageManager().resolveIntent(
3584 intent, resolvedType,
3585 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003586 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003587 aInfo = rInfo != null ? rInfo.activityInfo : null;
3588 } catch (RemoteException e) {
3589 aInfo = null;
3590 }
3591
3592 if (aInfo != null) {
3593 // Store the found target back into the intent, because now that
3594 // we have it we never want to do this again. For example, if the
3595 // user navigates back to this point in the history, we should
3596 // always restart the exact same activity.
3597 intent.setComponent(new ComponentName(
3598 aInfo.applicationInfo.packageName, aInfo.name));
3599
3600 // Don't debug things in the system process
3601 if (debug) {
3602 if (!aInfo.processName.equals("system")) {
3603 setDebugApp(aInfo.processName, true, false);
3604 }
3605 }
3606 }
3607
3608 synchronized(this) {
3609 final long origId = Binder.clearCallingIdentity();
3610 int res = startActivityLocked(caller, intent, resolvedType,
3611 grantedUriPermissions, grantedMode, aInfo,
3612 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003613 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003614 Binder.restoreCallingIdentity(origId);
3615 return res;
3616 }
3617 }
3618
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003619 public int startActivityIntentSender(IApplicationThread caller,
3620 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003621 IBinder resultTo, String resultWho, int requestCode,
3622 int flagsMask, int flagsValues) {
3623 // Refuse possible leaked file descriptors
3624 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3625 throw new IllegalArgumentException("File descriptors passed in Intent");
3626 }
3627
3628 IIntentSender sender = intent.getTarget();
3629 if (!(sender instanceof PendingIntentRecord)) {
3630 throw new IllegalArgumentException("Bad PendingIntent object");
3631 }
3632
3633 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003634
3635 synchronized (this) {
3636 // If this is coming from the currently resumed activity, it is
3637 // effectively saying that app switches are allowed at this point.
3638 if (mResumedActivity != null
3639 && mResumedActivity.info.applicationInfo.uid ==
3640 Binder.getCallingUid()) {
3641 mAppSwitchesAllowedTime = 0;
3642 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003643 }
3644
3645 return pir.sendInner(0, fillInIntent, resolvedType,
3646 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3647 }
3648
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003649 public boolean startNextMatchingActivity(IBinder callingActivity,
3650 Intent intent) {
3651 // Refuse possible leaked file descriptors
3652 if (intent != null && intent.hasFileDescriptors() == true) {
3653 throw new IllegalArgumentException("File descriptors passed in Intent");
3654 }
3655
3656 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003657 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003658 if (index < 0) {
3659 return false;
3660 }
3661 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3662 if (r.app == null || r.app.thread == null) {
3663 // The caller is not running... d'oh!
3664 return false;
3665 }
3666 intent = new Intent(intent);
3667 // The caller is not allowed to change the data.
3668 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3669 // And we are resetting to find the next component...
3670 intent.setComponent(null);
3671
3672 ActivityInfo aInfo = null;
3673 try {
3674 List<ResolveInfo> resolves =
3675 ActivityThread.getPackageManager().queryIntentActivities(
3676 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003677 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003678
3679 // Look for the original activity in the list...
3680 final int N = resolves != null ? resolves.size() : 0;
3681 for (int i=0; i<N; i++) {
3682 ResolveInfo rInfo = resolves.get(i);
3683 if (rInfo.activityInfo.packageName.equals(r.packageName)
3684 && rInfo.activityInfo.name.equals(r.info.name)) {
3685 // We found the current one... the next matching is
3686 // after it.
3687 i++;
3688 if (i<N) {
3689 aInfo = resolves.get(i).activityInfo;
3690 }
3691 break;
3692 }
3693 }
3694 } catch (RemoteException e) {
3695 }
3696
3697 if (aInfo == null) {
3698 // Nobody who is next!
3699 return false;
3700 }
3701
3702 intent.setComponent(new ComponentName(
3703 aInfo.applicationInfo.packageName, aInfo.name));
3704 intent.setFlags(intent.getFlags()&~(
3705 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3706 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3707 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3708 Intent.FLAG_ACTIVITY_NEW_TASK));
3709
3710 // Okay now we need to start the new activity, replacing the
3711 // currently running activity. This is a little tricky because
3712 // we want to start the new one as if the current one is finished,
3713 // but not finish the current one first so that there is no flicker.
3714 // And thus...
3715 final boolean wasFinishing = r.finishing;
3716 r.finishing = true;
3717
3718 // Propagate reply information over to the new activity.
3719 final HistoryRecord resultTo = r.resultTo;
3720 final String resultWho = r.resultWho;
3721 final int requestCode = r.requestCode;
3722 r.resultTo = null;
3723 if (resultTo != null) {
3724 resultTo.removeResultsLocked(r, resultWho, requestCode);
3725 }
3726
3727 final long origId = Binder.clearCallingIdentity();
3728 // XXX we are not dealing with propagating grantedUriPermissions...
3729 // those are not yet exposed to user code, so there is no need.
3730 int res = startActivityLocked(r.app.thread, intent,
3731 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003732 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003733 Binder.restoreCallingIdentity(origId);
3734
3735 r.finishing = wasFinishing;
3736 if (res != START_SUCCESS) {
3737 return false;
3738 }
3739 return true;
3740 }
3741 }
3742
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003743 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003744 Intent intent, String resolvedType, IBinder resultTo,
3745 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003746
3747 // This is so super not safe, that only the system (or okay root)
3748 // can do it.
3749 final int callingUid = Binder.getCallingUid();
3750 if (callingUid != 0 && callingUid != Process.myUid()) {
3751 throw new SecurityException(
3752 "startActivityInPackage only available to the system");
3753 }
3754
The Android Open Source Project4df24232009-03-05 14:34:35 -08003755 final boolean componentSpecified = intent.getComponent() != null;
3756
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003757 // Don't modify the client's object!
3758 intent = new Intent(intent);
3759
3760 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003761 ActivityInfo aInfo;
3762 try {
3763 ResolveInfo rInfo =
3764 ActivityThread.getPackageManager().resolveIntent(
3765 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003766 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003767 aInfo = rInfo != null ? rInfo.activityInfo : null;
3768 } catch (RemoteException e) {
3769 aInfo = null;
3770 }
3771
3772 if (aInfo != null) {
3773 // Store the found target back into the intent, because now that
3774 // we have it we never want to do this again. For example, if the
3775 // user navigates back to this point in the history, we should
3776 // always restart the exact same activity.
3777 intent.setComponent(new ComponentName(
3778 aInfo.applicationInfo.packageName, aInfo.name));
3779 }
3780
3781 synchronized(this) {
3782 return startActivityLocked(null, intent, resolvedType,
3783 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003784 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003785 }
3786 }
3787
3788 private final void addRecentTask(TaskRecord task) {
3789 // Remove any existing entries that are the same kind of task.
3790 int N = mRecentTasks.size();
3791 for (int i=0; i<N; i++) {
3792 TaskRecord tr = mRecentTasks.get(i);
3793 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3794 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3795 mRecentTasks.remove(i);
3796 i--;
3797 N--;
3798 if (task.intent == null) {
3799 // If the new recent task we are adding is not fully
3800 // specified, then replace it with the existing recent task.
3801 task = tr;
3802 }
3803 }
3804 }
3805 if (N >= MAX_RECENT_TASKS) {
3806 mRecentTasks.remove(N-1);
3807 }
3808 mRecentTasks.add(0, task);
3809 }
3810
3811 public void setRequestedOrientation(IBinder token,
3812 int requestedOrientation) {
3813 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003814 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003815 if (index < 0) {
3816 return;
3817 }
3818 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3819 final long origId = Binder.clearCallingIdentity();
3820 mWindowManager.setAppOrientation(r, requestedOrientation);
3821 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003822 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003823 r.mayFreezeScreenLocked(r.app) ? r : null);
3824 if (config != null) {
3825 r.frozenBeforeDestroy = true;
3826 if (!updateConfigurationLocked(config, r)) {
3827 resumeTopActivityLocked(null);
3828 }
3829 }
3830 Binder.restoreCallingIdentity(origId);
3831 }
3832 }
3833
3834 public int getRequestedOrientation(IBinder token) {
3835 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003836 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003837 if (index < 0) {
3838 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3839 }
3840 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3841 return mWindowManager.getAppOrientation(r);
3842 }
3843 }
3844
3845 private final void stopActivityLocked(HistoryRecord r) {
3846 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3847 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3848 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3849 if (!r.finishing) {
3850 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3851 "no-history");
3852 }
3853 } else if (r.app != null && r.app.thread != null) {
3854 if (mFocusedActivity == r) {
3855 setFocusedActivityLocked(topRunningActivityLocked(null));
3856 }
3857 r.resumeKeyDispatchingLocked();
3858 try {
3859 r.stopped = false;
3860 r.state = ActivityState.STOPPING;
3861 if (DEBUG_VISBILITY) Log.v(
3862 TAG, "Stopping visible=" + r.visible + " for " + r);
3863 if (!r.visible) {
3864 mWindowManager.setAppVisibility(r, false);
3865 }
3866 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3867 } catch (Exception e) {
3868 // Maybe just ignore exceptions here... if the process
3869 // has crashed, our death notification will clean things
3870 // up.
3871 Log.w(TAG, "Exception thrown during pause", e);
3872 // Just in case, assume it to be stopped.
3873 r.stopped = true;
3874 r.state = ActivityState.STOPPED;
3875 if (r.configDestroy) {
3876 destroyActivityLocked(r, true);
3877 }
3878 }
3879 }
3880 }
3881
3882 /**
3883 * @return Returns true if the activity is being finished, false if for
3884 * some reason it is being left as-is.
3885 */
3886 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3887 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003888 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003889 TAG, "Finishing activity: token=" + token
3890 + ", result=" + resultCode + ", data=" + resultData);
3891
Dianne Hackborn75b03852009-06-12 15:43:26 -07003892 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003893 if (index < 0) {
3894 return false;
3895 }
3896 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3897
3898 // Is this the last activity left?
3899 boolean lastActivity = true;
3900 for (int i=mHistory.size()-1; i>=0; i--) {
3901 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3902 if (!p.finishing && p != r) {
3903 lastActivity = false;
3904 break;
3905 }
3906 }
3907
3908 // If this is the last activity, but it is the home activity, then
3909 // just don't finish it.
3910 if (lastActivity) {
3911 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3912 return false;
3913 }
3914 }
3915
3916 finishActivityLocked(r, index, resultCode, resultData, reason);
3917 return true;
3918 }
3919
3920 /**
3921 * @return Returns true if this activity has been removed from the history
3922 * list, or false if it is still in the list and will be removed later.
3923 */
3924 private final boolean finishActivityLocked(HistoryRecord r, int index,
3925 int resultCode, Intent resultData, String reason) {
3926 if (r.finishing) {
3927 Log.w(TAG, "Duplicate finish request for " + r);
3928 return false;
3929 }
3930
3931 r.finishing = true;
3932 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3933 System.identityHashCode(r),
3934 r.task.taskId, r.shortComponentName, reason);
3935 r.task.numActivities--;
3936 if (r.frontOfTask && index < (mHistory.size()-1)) {
3937 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3938 if (next.task == r.task) {
3939 next.frontOfTask = true;
3940 }
3941 }
3942
3943 r.pauseKeyDispatchingLocked();
3944 if (mFocusedActivity == r) {
3945 setFocusedActivityLocked(topRunningActivityLocked(null));
3946 }
3947
3948 // send the result
3949 HistoryRecord resultTo = r.resultTo;
3950 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003951 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3952 + " who=" + r.resultWho + " req=" + r.requestCode
3953 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003954 if (r.info.applicationInfo.uid > 0) {
3955 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3956 r.packageName, resultData, r);
3957 }
3958 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3959 resultData);
3960 r.resultTo = null;
3961 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003962 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003963
3964 // Make sure this HistoryRecord is not holding on to other resources,
3965 // because clients have remote IPC references to this object so we
3966 // can't assume that will go away and want to avoid circular IPC refs.
3967 r.results = null;
3968 r.pendingResults = null;
3969 r.newIntents = null;
3970 r.icicle = null;
3971
3972 if (mPendingThumbnails.size() > 0) {
3973 // There are clients waiting to receive thumbnails so, in case
3974 // this is an activity that someone is waiting for, add it
3975 // to the pending list so we can correctly update the clients.
3976 mCancelledThumbnails.add(r);
3977 }
3978
3979 if (mResumedActivity == r) {
3980 boolean endTask = index <= 0
3981 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3982 if (DEBUG_TRANSITION) Log.v(TAG,
3983 "Prepare close transition: finishing " + r);
3984 mWindowManager.prepareAppTransition(endTask
3985 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3986 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3987
3988 // Tell window manager to prepare for this one to be removed.
3989 mWindowManager.setAppVisibility(r, false);
3990
3991 if (mPausingActivity == null) {
3992 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3993 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3994 startPausingLocked(false, false);
3995 }
3996
3997 } else if (r.state != ActivityState.PAUSING) {
3998 // If the activity is PAUSING, we will complete the finish once
3999 // it is done pausing; else we can just directly finish it here.
4000 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4001 return finishCurrentActivityLocked(r, index,
4002 FINISH_AFTER_PAUSE) == null;
4003 } else {
4004 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4005 }
4006
4007 return false;
4008 }
4009
4010 private static final int FINISH_IMMEDIATELY = 0;
4011 private static final int FINISH_AFTER_PAUSE = 1;
4012 private static final int FINISH_AFTER_VISIBLE = 2;
4013
4014 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4015 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004016 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004017 if (index < 0) {
4018 return null;
4019 }
4020
4021 return finishCurrentActivityLocked(r, index, mode);
4022 }
4023
4024 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4025 int index, int mode) {
4026 // First things first: if this activity is currently visible,
4027 // and the resumed activity is not yet visible, then hold off on
4028 // finishing until the resumed one becomes visible.
4029 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4030 if (!mStoppingActivities.contains(r)) {
4031 mStoppingActivities.add(r);
4032 if (mStoppingActivities.size() > 3) {
4033 // If we already have a few activities waiting to stop,
4034 // then give up on things going idle and start clearing
4035 // them out.
4036 Message msg = Message.obtain();
4037 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4038 mHandler.sendMessage(msg);
4039 }
4040 }
4041 r.state = ActivityState.STOPPING;
4042 updateOomAdjLocked();
4043 return r;
4044 }
4045
4046 // make sure the record is cleaned out of other places.
4047 mStoppingActivities.remove(r);
4048 mWaitingVisibleActivities.remove(r);
4049 if (mResumedActivity == r) {
4050 mResumedActivity = null;
4051 }
4052 final ActivityState prevState = r.state;
4053 r.state = ActivityState.FINISHING;
4054
4055 if (mode == FINISH_IMMEDIATELY
4056 || prevState == ActivityState.STOPPED
4057 || prevState == ActivityState.INITIALIZING) {
4058 // If this activity is already stopped, we can just finish
4059 // it right now.
4060 return destroyActivityLocked(r, true) ? null : r;
4061 } else {
4062 // Need to go through the full pause cycle to get this
4063 // activity into the stopped state and then finish it.
4064 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4065 mFinishingActivities.add(r);
4066 resumeTopActivityLocked(null);
4067 }
4068 return r;
4069 }
4070
4071 /**
4072 * This is the internal entry point for handling Activity.finish().
4073 *
4074 * @param token The Binder token referencing the Activity we want to finish.
4075 * @param resultCode Result code, if any, from this Activity.
4076 * @param resultData Result data (Intent), if any, from this Activity.
4077 *
4078 * @result Returns true if the activity successfully finished, or false if it is still running.
4079 */
4080 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4081 // Refuse possible leaked file descriptors
4082 if (resultData != null && resultData.hasFileDescriptors() == true) {
4083 throw new IllegalArgumentException("File descriptors passed in Intent");
4084 }
4085
4086 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004087 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004088 // Find the first activity that is not finishing.
4089 HistoryRecord next = topRunningActivityLocked(token, 0);
4090 if (next != null) {
4091 // ask watcher if this is allowed
4092 boolean resumeOK = true;
4093 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004094 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004095 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004096 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004097 }
4098
4099 if (!resumeOK) {
4100 return false;
4101 }
4102 }
4103 }
4104 final long origId = Binder.clearCallingIdentity();
4105 boolean res = requestFinishActivityLocked(token, resultCode,
4106 resultData, "app-request");
4107 Binder.restoreCallingIdentity(origId);
4108 return res;
4109 }
4110 }
4111
4112 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4113 String resultWho, int requestCode, int resultCode, Intent data) {
4114
4115 if (callingUid > 0) {
4116 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4117 data, r);
4118 }
4119
The Android Open Source Project10592532009-03-18 17:39:46 -07004120 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4121 + " : who=" + resultWho + " req=" + requestCode
4122 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004123 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4124 try {
4125 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4126 list.add(new ResultInfo(resultWho, requestCode,
4127 resultCode, data));
4128 r.app.thread.scheduleSendResult(r, list);
4129 return;
4130 } catch (Exception e) {
4131 Log.w(TAG, "Exception thrown sending result to " + r, e);
4132 }
4133 }
4134
4135 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4136 }
4137
4138 public final void finishSubActivity(IBinder token, String resultWho,
4139 int requestCode) {
4140 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004141 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004142 if (index < 0) {
4143 return;
4144 }
4145 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4146
4147 final long origId = Binder.clearCallingIdentity();
4148
4149 int i;
4150 for (i=mHistory.size()-1; i>=0; i--) {
4151 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4152 if (r.resultTo == self && r.requestCode == requestCode) {
4153 if ((r.resultWho == null && resultWho == null) ||
4154 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4155 finishActivityLocked(r, i,
4156 Activity.RESULT_CANCELED, null, "request-sub");
4157 }
4158 }
4159 }
4160
4161 Binder.restoreCallingIdentity(origId);
4162 }
4163 }
4164
4165 /**
4166 * Perform clean-up of service connections in an activity record.
4167 */
4168 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4169 // Throw away any services that have been bound by this activity.
4170 if (r.connections != null) {
4171 Iterator<ConnectionRecord> it = r.connections.iterator();
4172 while (it.hasNext()) {
4173 ConnectionRecord c = it.next();
4174 removeConnectionLocked(c, null, r);
4175 }
4176 r.connections = null;
4177 }
4178 }
4179
4180 /**
4181 * Perform the common clean-up of an activity record. This is called both
4182 * as part of destroyActivityLocked() (when destroying the client-side
4183 * representation) and cleaning things up as a result of its hosting
4184 * processing going away, in which case there is no remaining client-side
4185 * state to destroy so only the cleanup here is needed.
4186 */
4187 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4188 if (mResumedActivity == r) {
4189 mResumedActivity = null;
4190 }
4191 if (mFocusedActivity == r) {
4192 mFocusedActivity = null;
4193 }
4194
4195 r.configDestroy = false;
4196 r.frozenBeforeDestroy = false;
4197
4198 // Make sure this record is no longer in the pending finishes list.
4199 // This could happen, for example, if we are trimming activities
4200 // down to the max limit while they are still waiting to finish.
4201 mFinishingActivities.remove(r);
4202 mWaitingVisibleActivities.remove(r);
4203
4204 // Remove any pending results.
4205 if (r.finishing && r.pendingResults != null) {
4206 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4207 PendingIntentRecord rec = apr.get();
4208 if (rec != null) {
4209 cancelIntentSenderLocked(rec, false);
4210 }
4211 }
4212 r.pendingResults = null;
4213 }
4214
4215 if (cleanServices) {
4216 cleanUpActivityServicesLocked(r);
4217 }
4218
4219 if (mPendingThumbnails.size() > 0) {
4220 // There are clients waiting to receive thumbnails so, in case
4221 // this is an activity that someone is waiting for, add it
4222 // to the pending list so we can correctly update the clients.
4223 mCancelledThumbnails.add(r);
4224 }
4225
4226 // Get rid of any pending idle timeouts.
4227 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4228 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4229 }
4230
4231 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4232 if (r.state != ActivityState.DESTROYED) {
4233 mHistory.remove(r);
4234 r.inHistory = false;
4235 r.state = ActivityState.DESTROYED;
4236 mWindowManager.removeAppToken(r);
4237 if (VALIDATE_TOKENS) {
4238 mWindowManager.validateAppTokens(mHistory);
4239 }
4240 cleanUpActivityServicesLocked(r);
4241 removeActivityUriPermissionsLocked(r);
4242 }
4243 }
4244
4245 /**
4246 * Destroy the current CLIENT SIDE instance of an activity. This may be
4247 * called both when actually finishing an activity, or when performing
4248 * a configuration switch where we destroy the current client-side object
4249 * but then create a new client-side object for this same HistoryRecord.
4250 */
4251 private final boolean destroyActivityLocked(HistoryRecord r,
4252 boolean removeFromApp) {
4253 if (DEBUG_SWITCH) Log.v(
4254 TAG, "Removing activity: token=" + r
4255 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4256 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4257 System.identityHashCode(r),
4258 r.task.taskId, r.shortComponentName);
4259
4260 boolean removedFromHistory = false;
4261
4262 cleanUpActivityLocked(r, false);
4263
4264 if (r.app != null) {
4265 if (removeFromApp) {
4266 int idx = r.app.activities.indexOf(r);
4267 if (idx >= 0) {
4268 r.app.activities.remove(idx);
4269 }
4270 if (r.persistent) {
4271 decPersistentCountLocked(r.app);
4272 }
4273 }
4274
4275 boolean skipDestroy = false;
4276
4277 try {
4278 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4279 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4280 r.configChangeFlags);
4281 } catch (Exception e) {
4282 // We can just ignore exceptions here... if the process
4283 // has crashed, our death notification will clean things
4284 // up.
4285 //Log.w(TAG, "Exception thrown during finish", e);
4286 if (r.finishing) {
4287 removeActivityFromHistoryLocked(r);
4288 removedFromHistory = true;
4289 skipDestroy = true;
4290 }
4291 }
4292
4293 r.app = null;
4294 r.nowVisible = false;
4295
4296 if (r.finishing && !skipDestroy) {
4297 r.state = ActivityState.DESTROYING;
4298 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4299 msg.obj = r;
4300 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4301 } else {
4302 r.state = ActivityState.DESTROYED;
4303 }
4304 } else {
4305 // remove this record from the history.
4306 if (r.finishing) {
4307 removeActivityFromHistoryLocked(r);
4308 removedFromHistory = true;
4309 } else {
4310 r.state = ActivityState.DESTROYED;
4311 }
4312 }
4313
4314 r.configChangeFlags = 0;
4315
4316 if (!mLRUActivities.remove(r)) {
4317 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4318 }
4319
4320 return removedFromHistory;
4321 }
4322
4323 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4324 ProcessRecord app)
4325 {
4326 int i = list.size();
4327 if (localLOGV) Log.v(
4328 TAG, "Removing app " + app + " from list " + list
4329 + " with " + i + " entries");
4330 while (i > 0) {
4331 i--;
4332 HistoryRecord r = (HistoryRecord)list.get(i);
4333 if (localLOGV) Log.v(
4334 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4335 if (r.app == app) {
4336 if (localLOGV) Log.v(TAG, "Removing this entry!");
4337 list.remove(i);
4338 }
4339 }
4340 }
4341
4342 /**
4343 * Main function for removing an existing process from the activity manager
4344 * as a result of that process going away. Clears out all connections
4345 * to the process.
4346 */
4347 private final void handleAppDiedLocked(ProcessRecord app,
4348 boolean restarting) {
4349 cleanUpApplicationRecordLocked(app, restarting, -1);
4350 if (!restarting) {
4351 mLRUProcesses.remove(app);
4352 }
4353
4354 // Just in case...
4355 if (mPausingActivity != null && mPausingActivity.app == app) {
4356 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4357 mPausingActivity = null;
4358 }
4359 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4360 mLastPausedActivity = null;
4361 }
4362
4363 // Remove this application's activities from active lists.
4364 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4365 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4366 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4367 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4368
4369 boolean atTop = true;
4370 boolean hasVisibleActivities = false;
4371
4372 // Clean out the history list.
4373 int i = mHistory.size();
4374 if (localLOGV) Log.v(
4375 TAG, "Removing app " + app + " from history with " + i + " entries");
4376 while (i > 0) {
4377 i--;
4378 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4379 if (localLOGV) Log.v(
4380 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4381 if (r.app == app) {
4382 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4383 if (localLOGV) Log.v(
4384 TAG, "Removing this entry! frozen=" + r.haveState
4385 + " finishing=" + r.finishing);
4386 mHistory.remove(i);
4387
4388 r.inHistory = false;
4389 mWindowManager.removeAppToken(r);
4390 if (VALIDATE_TOKENS) {
4391 mWindowManager.validateAppTokens(mHistory);
4392 }
4393 removeActivityUriPermissionsLocked(r);
4394
4395 } else {
4396 // We have the current state for this activity, so
4397 // it can be restarted later when needed.
4398 if (localLOGV) Log.v(
4399 TAG, "Keeping entry, setting app to null");
4400 if (r.visible) {
4401 hasVisibleActivities = true;
4402 }
4403 r.app = null;
4404 r.nowVisible = false;
4405 if (!r.haveState) {
4406 r.icicle = null;
4407 }
4408 }
4409
4410 cleanUpActivityLocked(r, true);
4411 r.state = ActivityState.STOPPED;
4412 }
4413 atTop = false;
4414 }
4415
4416 app.activities.clear();
4417
4418 if (app.instrumentationClass != null) {
4419 Log.w(TAG, "Crash of app " + app.processName
4420 + " running instrumentation " + app.instrumentationClass);
4421 Bundle info = new Bundle();
4422 info.putString("shortMsg", "Process crashed.");
4423 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4424 }
4425
4426 if (!restarting) {
4427 if (!resumeTopActivityLocked(null)) {
4428 // If there was nothing to resume, and we are not already
4429 // restarting this process, but there is a visible activity that
4430 // is hosted by the process... then make sure all visible
4431 // activities are running, taking care of restarting this
4432 // process.
4433 if (hasVisibleActivities) {
4434 ensureActivitiesVisibleLocked(null, 0);
4435 }
4436 }
4437 }
4438 }
4439
4440 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4441 IBinder threadBinder = thread.asBinder();
4442
4443 // Find the application record.
4444 int count = mLRUProcesses.size();
4445 int i;
4446 for (i=0; i<count; i++) {
4447 ProcessRecord rec = mLRUProcesses.get(i);
4448 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4449 return i;
4450 }
4451 }
4452 return -1;
4453 }
4454
4455 private final ProcessRecord getRecordForAppLocked(
4456 IApplicationThread thread) {
4457 if (thread == null) {
4458 return null;
4459 }
4460
4461 int appIndex = getLRURecordIndexForAppLocked(thread);
4462 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4463 }
4464
4465 private final void appDiedLocked(ProcessRecord app, int pid,
4466 IApplicationThread thread) {
4467
4468 mProcDeaths[0]++;
4469
4470 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4471 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4472 + ") has died.");
4473 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4474 if (localLOGV) Log.v(
4475 TAG, "Dying app: " + app + ", pid: " + pid
4476 + ", thread: " + thread.asBinder());
4477 boolean doLowMem = app.instrumentationClass == null;
4478 handleAppDiedLocked(app, false);
4479
4480 if (doLowMem) {
4481 // If there are no longer any background processes running,
4482 // and the app that died was not running instrumentation,
4483 // then tell everyone we are now low on memory.
4484 boolean haveBg = false;
4485 int count = mLRUProcesses.size();
4486 int i;
4487 for (i=0; i<count; i++) {
4488 ProcessRecord rec = mLRUProcesses.get(i);
4489 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4490 haveBg = true;
4491 break;
4492 }
4493 }
4494
4495 if (!haveBg) {
4496 Log.i(TAG, "Low Memory: No more background processes.");
4497 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004498 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004499 for (i=0; i<count; i++) {
4500 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004501 if (rec.thread != null &&
4502 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4503 // The low memory report is overriding any current
4504 // state for a GC request. Make sure to do
4505 // visible/foreground processes first.
4506 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4507 rec.lastRequestedGc = 0;
4508 } else {
4509 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004510 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004511 rec.reportLowMemory = true;
4512 rec.lastLowMemory = now;
4513 mProcessesToGc.remove(rec);
4514 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004515 }
4516 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004517 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004518 }
4519 }
4520 } else if (Config.LOGD) {
4521 Log.d(TAG, "Received spurious death notification for thread "
4522 + thread.asBinder());
4523 }
4524 }
4525
4526 final String readFile(String filename) {
4527 try {
4528 FileInputStream fs = new FileInputStream(filename);
4529 byte[] inp = new byte[8192];
4530 int size = fs.read(inp);
4531 fs.close();
4532 return new String(inp, 0, 0, size);
4533 } catch (java.io.IOException e) {
4534 }
4535 return "";
4536 }
4537
4538 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004539 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004540 if (app.notResponding || app.crashing) {
4541 return;
4542 }
4543
4544 // Log the ANR to the event log.
4545 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4546
4547 // If we are on a secure build and the application is not interesting to the user (it is
4548 // not visible or in the background), just kill it instead of displaying a dialog.
4549 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4550 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4551 Process.killProcess(app.pid);
4552 return;
4553 }
4554
4555 // DeviceMonitor.start();
4556
4557 String processInfo = null;
4558 if (MONITOR_CPU_USAGE) {
4559 updateCpuStatsNow();
4560 synchronized (mProcessStatsThread) {
4561 processInfo = mProcessStats.printCurrentState();
4562 }
4563 }
4564
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004565 StringBuilder info = mStringBuilder;
4566 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004567 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004568 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004569 if (reportedActivity != null && reportedActivity.app != null) {
4570 info.append(" (last in ");
4571 info.append(reportedActivity.app.processName);
4572 info.append(")");
4573 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004574 if (annotation != null) {
4575 info.append("\nAnnotation: ");
4576 info.append(annotation);
4577 }
4578 if (MONITOR_CPU_USAGE) {
4579 info.append("\nCPU usage:\n");
4580 info.append(processInfo);
4581 }
4582 Log.i(TAG, info.toString());
4583
4584 // The application is not responding. Dump as many thread traces as we can.
4585 boolean fileDump = prepareTraceFile(true);
4586 if (!fileDump) {
4587 // Dumping traces to the log, just dump the process that isn't responding so
4588 // we don't overflow the log
4589 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4590 } else {
4591 // Dumping traces to a file so dump all active processes we know about
4592 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004593 // First, these are the most important processes.
4594 final int[] imppids = new int[3];
4595 int i=0;
4596 imppids[0] = app.pid;
4597 i++;
4598 if (reportedActivity != null && reportedActivity.app != null
4599 && reportedActivity.app.thread != null
4600 && reportedActivity.app.pid != app.pid) {
4601 imppids[i] = reportedActivity.app.pid;
4602 i++;
4603 }
4604 imppids[i] = Process.myPid();
4605 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4606 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4607 synchronized (this) {
4608 try {
4609 wait(200);
4610 } catch (InterruptedException e) {
4611 }
4612 }
4613 }
4614 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004615 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004616 boolean done = false;
4617 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4618 if (imppids[j] == r.pid) {
4619 done = true;
4620 break;
4621 }
4622 }
4623 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004624 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004625 synchronized (this) {
4626 try {
4627 wait(200);
4628 } catch (InterruptedException e) {
4629 }
4630 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004631 }
4632 }
4633 }
4634 }
4635
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004636 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004637 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004638 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004639 app.pid, info.toString());
4640 if (res != 0) {
4641 if (res < 0) {
4642 // wait until the SIGQUIT has had a chance to process before killing the
4643 // process.
4644 try {
4645 wait(2000);
4646 } catch (InterruptedException e) {
4647 }
4648
4649 Process.killProcess(app.pid);
4650 return;
4651 }
4652 }
4653 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004654 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004655 }
4656 }
4657
4658 makeAppNotRespondingLocked(app,
4659 activity != null ? activity.shortComponentName : null,
4660 annotation != null ? "ANR " + annotation : "ANR",
4661 info.toString(), null);
4662 Message msg = Message.obtain();
4663 HashMap map = new HashMap();
4664 msg.what = SHOW_NOT_RESPONDING_MSG;
4665 msg.obj = map;
4666 map.put("app", app);
4667 if (activity != null) {
4668 map.put("activity", activity);
4669 }
4670
4671 mHandler.sendMessage(msg);
4672 return;
4673 }
4674
4675 /**
4676 * If a stack trace file has been configured, prepare the filesystem
4677 * by creating the directory if it doesn't exist and optionally
4678 * removing the old trace file.
4679 *
4680 * @param removeExisting If set, the existing trace file will be removed.
4681 * @return Returns true if the trace file preparations succeeded
4682 */
4683 public static boolean prepareTraceFile(boolean removeExisting) {
4684 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4685 boolean fileReady = false;
4686 if (!TextUtils.isEmpty(tracesPath)) {
4687 File f = new File(tracesPath);
4688 if (!f.exists()) {
4689 // Ensure the enclosing directory exists
4690 File dir = f.getParentFile();
4691 if (!dir.exists()) {
4692 fileReady = dir.mkdirs();
4693 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004694 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004695 } else if (dir.isDirectory()) {
4696 fileReady = true;
4697 }
4698 } else if (removeExisting) {
4699 // Remove the previous traces file, so we don't fill the disk.
4700 // The VM will recreate it
4701 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4702 fileReady = f.delete();
4703 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004704
4705 if (removeExisting) {
4706 try {
4707 f.createNewFile();
4708 FileUtils.setPermissions(f.getAbsolutePath(),
4709 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4710 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4711 fileReady = true;
4712 } catch (IOException e) {
4713 Log.w(TAG, "Unable to make ANR traces file", e);
4714 }
4715 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004716 }
4717
4718 return fileReady;
4719 }
4720
4721
4722 private final void decPersistentCountLocked(ProcessRecord app)
4723 {
4724 app.persistentActivities--;
4725 if (app.persistentActivities > 0) {
4726 // Still more of 'em...
4727 return;
4728 }
4729 if (app.persistent) {
4730 // Ah, but the application itself is persistent. Whatever!
4731 return;
4732 }
4733
4734 // App is no longer persistent... make sure it and the ones
4735 // following it in the LRU list have the correc oom_adj.
4736 updateOomAdjLocked();
4737 }
4738
4739 public void setPersistent(IBinder token, boolean isPersistent) {
4740 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4741 != PackageManager.PERMISSION_GRANTED) {
4742 String msg = "Permission Denial: setPersistent() from pid="
4743 + Binder.getCallingPid()
4744 + ", uid=" + Binder.getCallingUid()
4745 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4746 Log.w(TAG, msg);
4747 throw new SecurityException(msg);
4748 }
4749
4750 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004751 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004752 if (index < 0) {
4753 return;
4754 }
4755 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4756 ProcessRecord app = r.app;
4757
4758 if (localLOGV) Log.v(
4759 TAG, "Setting persistence " + isPersistent + ": " + r);
4760
4761 if (isPersistent) {
4762 if (r.persistent) {
4763 // Okay okay, I heard you already!
4764 if (localLOGV) Log.v(TAG, "Already persistent!");
4765 return;
4766 }
4767 r.persistent = true;
4768 app.persistentActivities++;
4769 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4770 if (app.persistentActivities > 1) {
4771 // We aren't the first...
4772 if (localLOGV) Log.v(TAG, "Not the first!");
4773 return;
4774 }
4775 if (app.persistent) {
4776 // This would be redundant.
4777 if (localLOGV) Log.v(TAG, "App is persistent!");
4778 return;
4779 }
4780
4781 // App is now persistent... make sure it and the ones
4782 // following it now have the correct oom_adj.
4783 final long origId = Binder.clearCallingIdentity();
4784 updateOomAdjLocked();
4785 Binder.restoreCallingIdentity(origId);
4786
4787 } else {
4788 if (!r.persistent) {
4789 // Okay okay, I heard you already!
4790 return;
4791 }
4792 r.persistent = false;
4793 final long origId = Binder.clearCallingIdentity();
4794 decPersistentCountLocked(app);
4795 Binder.restoreCallingIdentity(origId);
4796
4797 }
4798 }
4799 }
4800
4801 public boolean clearApplicationUserData(final String packageName,
4802 final IPackageDataObserver observer) {
4803 int uid = Binder.getCallingUid();
4804 int pid = Binder.getCallingPid();
4805 long callingId = Binder.clearCallingIdentity();
4806 try {
4807 IPackageManager pm = ActivityThread.getPackageManager();
4808 int pkgUid = -1;
4809 synchronized(this) {
4810 try {
4811 pkgUid = pm.getPackageUid(packageName);
4812 } catch (RemoteException e) {
4813 }
4814 if (pkgUid == -1) {
4815 Log.w(TAG, "Invalid packageName:" + packageName);
4816 return false;
4817 }
4818 if (uid == pkgUid || checkComponentPermission(
4819 android.Manifest.permission.CLEAR_APP_USER_DATA,
4820 pid, uid, -1)
4821 == PackageManager.PERMISSION_GRANTED) {
4822 restartPackageLocked(packageName, pkgUid);
4823 } else {
4824 throw new SecurityException(pid+" does not have permission:"+
4825 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4826 "for process:"+packageName);
4827 }
4828 }
4829
4830 try {
4831 //clear application user data
4832 pm.clearApplicationUserData(packageName, observer);
4833 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4834 Uri.fromParts("package", packageName, null));
4835 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4836 broadcastIntentLocked(null, null, intent,
4837 null, null, 0, null, null, null,
4838 false, false, MY_PID, Process.SYSTEM_UID);
4839 } catch (RemoteException e) {
4840 }
4841 } finally {
4842 Binder.restoreCallingIdentity(callingId);
4843 }
4844 return true;
4845 }
4846
4847 public void restartPackage(final String packageName) {
4848 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4849 != PackageManager.PERMISSION_GRANTED) {
4850 String msg = "Permission Denial: restartPackage() from pid="
4851 + Binder.getCallingPid()
4852 + ", uid=" + Binder.getCallingUid()
4853 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4854 Log.w(TAG, msg);
4855 throw new SecurityException(msg);
4856 }
4857
4858 long callingId = Binder.clearCallingIdentity();
4859 try {
4860 IPackageManager pm = ActivityThread.getPackageManager();
4861 int pkgUid = -1;
4862 synchronized(this) {
4863 try {
4864 pkgUid = pm.getPackageUid(packageName);
4865 } catch (RemoteException e) {
4866 }
4867 if (pkgUid == -1) {
4868 Log.w(TAG, "Invalid packageName: " + packageName);
4869 return;
4870 }
4871 restartPackageLocked(packageName, pkgUid);
4872 }
4873 } finally {
4874 Binder.restoreCallingIdentity(callingId);
4875 }
4876 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004877
4878 /*
4879 * The pkg name and uid have to be specified.
4880 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4881 */
4882 public void killApplicationWithUid(String pkg, int uid) {
4883 if (pkg == null) {
4884 return;
4885 }
4886 // Make sure the uid is valid.
4887 if (uid < 0) {
4888 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4889 return;
4890 }
4891 int callerUid = Binder.getCallingUid();
4892 // Only the system server can kill an application
4893 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004894 // Post an aysnc message to kill the application
4895 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4896 msg.arg1 = uid;
4897 msg.arg2 = 0;
4898 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004899 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004900 } else {
4901 throw new SecurityException(callerUid + " cannot kill pkg: " +
4902 pkg);
4903 }
4904 }
4905
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004906 public void closeSystemDialogs(String reason) {
4907 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4908 if (reason != null) {
4909 intent.putExtra("reason", reason);
4910 }
4911
4912 final int uid = Binder.getCallingUid();
4913 final long origId = Binder.clearCallingIdentity();
4914 synchronized (this) {
4915 int i = mWatchers.beginBroadcast();
4916 while (i > 0) {
4917 i--;
4918 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4919 if (w != null) {
4920 try {
4921 w.closingSystemDialogs(reason);
4922 } catch (RemoteException e) {
4923 }
4924 }
4925 }
4926 mWatchers.finishBroadcast();
4927
4928 broadcastIntentLocked(null, null, intent, null,
4929 null, 0, null, null, null, false, false, -1, uid);
4930 }
4931 Binder.restoreCallingIdentity(origId);
4932 }
4933
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004934 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004935 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004936 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
4937 for (int i=pids.length-1; i>=0; i--) {
4938 infos[i] = new Debug.MemoryInfo();
4939 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004940 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004941 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004942 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07004943
4944 public void killApplicationProcess(String processName, int uid) {
4945 if (processName == null) {
4946 return;
4947 }
4948
4949 int callerUid = Binder.getCallingUid();
4950 // Only the system server can kill an application
4951 if (callerUid == Process.SYSTEM_UID) {
4952 synchronized (this) {
4953 ProcessRecord app = getProcessRecordLocked(processName, uid);
4954 if (app != null) {
4955 try {
4956 app.thread.scheduleSuicide();
4957 } catch (RemoteException e) {
4958 // If the other end already died, then our work here is done.
4959 }
4960 } else {
4961 Log.w(TAG, "Process/uid not found attempting kill of "
4962 + processName + " / " + uid);
4963 }
4964 }
4965 } else {
4966 throw new SecurityException(callerUid + " cannot kill app process: " +
4967 processName);
4968 }
4969 }
4970
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004971 private void restartPackageLocked(final String packageName, int uid) {
4972 uninstallPackageLocked(packageName, uid, false);
4973 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4974 Uri.fromParts("package", packageName, null));
4975 intent.putExtra(Intent.EXTRA_UID, uid);
4976 broadcastIntentLocked(null, null, intent,
4977 null, null, 0, null, null, null,
4978 false, false, MY_PID, Process.SYSTEM_UID);
4979 }
4980
4981 private final void uninstallPackageLocked(String name, int uid,
4982 boolean callerWillRestart) {
4983 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4984
4985 int i, N;
4986
4987 final String procNamePrefix = name + ":";
4988 if (uid < 0) {
4989 try {
4990 uid = ActivityThread.getPackageManager().getPackageUid(name);
4991 } catch (RemoteException e) {
4992 }
4993 }
4994
4995 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4996 while (badApps.hasNext()) {
4997 SparseArray<Long> ba = badApps.next();
4998 if (ba.get(uid) != null) {
4999 badApps.remove();
5000 }
5001 }
5002
5003 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
5004
5005 // Remove all processes this package may have touched: all with the
5006 // same UID (except for the system or root user), and all whose name
5007 // matches the package name.
5008 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5009 final int NA = apps.size();
5010 for (int ia=0; ia<NA; ia++) {
5011 ProcessRecord app = apps.valueAt(ia);
5012 if (app.removed) {
5013 procs.add(app);
5014 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5015 || app.processName.equals(name)
5016 || app.processName.startsWith(procNamePrefix)) {
5017 app.removed = true;
5018 procs.add(app);
5019 }
5020 }
5021 }
5022
5023 N = procs.size();
5024 for (i=0; i<N; i++) {
5025 removeProcessLocked(procs.get(i), callerWillRestart);
5026 }
5027
5028 for (i=mHistory.size()-1; i>=0; i--) {
5029 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5030 if (r.packageName.equals(name)) {
5031 if (Config.LOGD) Log.d(
5032 TAG, " Force finishing activity "
5033 + r.intent.getComponent().flattenToShortString());
5034 if (r.app != null) {
5035 r.app.removed = true;
5036 }
5037 r.app = null;
5038 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5039 }
5040 }
5041
5042 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5043 for (ServiceRecord service : mServices.values()) {
5044 if (service.packageName.equals(name)) {
5045 if (service.app != null) {
5046 service.app.removed = true;
5047 }
5048 service.app = null;
5049 services.add(service);
5050 }
5051 }
5052
5053 N = services.size();
5054 for (i=0; i<N; i++) {
5055 bringDownServiceLocked(services.get(i), true);
5056 }
5057
5058 resumeTopActivityLocked(null);
5059 }
5060
5061 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5062 final String name = app.processName;
5063 final int uid = app.info.uid;
5064 if (Config.LOGD) Log.d(
5065 TAG, "Force removing process " + app + " (" + name
5066 + "/" + uid + ")");
5067
5068 mProcessNames.remove(name, uid);
5069 boolean needRestart = false;
5070 if (app.pid > 0 && app.pid != MY_PID) {
5071 int pid = app.pid;
5072 synchronized (mPidsSelfLocked) {
5073 mPidsSelfLocked.remove(pid);
5074 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5075 }
5076 handleAppDiedLocked(app, true);
5077 mLRUProcesses.remove(app);
5078 Process.killProcess(pid);
5079
5080 if (app.persistent) {
5081 if (!callerWillRestart) {
5082 addAppLocked(app.info);
5083 } else {
5084 needRestart = true;
5085 }
5086 }
5087 } else {
5088 mRemovedProcesses.add(app);
5089 }
5090
5091 return needRestart;
5092 }
5093
5094 private final void processStartTimedOutLocked(ProcessRecord app) {
5095 final int pid = app.pid;
5096 boolean gone = false;
5097 synchronized (mPidsSelfLocked) {
5098 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5099 if (knownApp != null && knownApp.thread == null) {
5100 mPidsSelfLocked.remove(pid);
5101 gone = true;
5102 }
5103 }
5104
5105 if (gone) {
5106 Log.w(TAG, "Process " + app + " failed to attach");
5107 mProcessNames.remove(app.processName, app.info.uid);
5108 Process.killProcess(pid);
5109 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5110 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5111 mPendingBroadcast = null;
5112 scheduleBroadcastsLocked();
5113 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005114 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5115 Log.w(TAG, "Unattached app died before backup, skipping");
5116 try {
5117 IBackupManager bm = IBackupManager.Stub.asInterface(
5118 ServiceManager.getService(Context.BACKUP_SERVICE));
5119 bm.agentDisconnected(app.info.packageName);
5120 } catch (RemoteException e) {
5121 // Can't happen; the backup manager is local
5122 }
5123 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005124 } else {
5125 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5126 }
5127 }
5128
5129 private final boolean attachApplicationLocked(IApplicationThread thread,
5130 int pid) {
5131
5132 // Find the application record that is being attached... either via
5133 // the pid if we are running in multiple processes, or just pull the
5134 // next app record if we are emulating process with anonymous threads.
5135 ProcessRecord app;
5136 if (pid != MY_PID && pid >= 0) {
5137 synchronized (mPidsSelfLocked) {
5138 app = mPidsSelfLocked.get(pid);
5139 }
5140 } else if (mStartingProcesses.size() > 0) {
5141 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005142 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005143 } else {
5144 app = null;
5145 }
5146
5147 if (app == null) {
5148 Log.w(TAG, "No pending application record for pid " + pid
5149 + " (IApplicationThread " + thread + "); dropping process");
5150 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5151 if (pid > 0 && pid != MY_PID) {
5152 Process.killProcess(pid);
5153 } else {
5154 try {
5155 thread.scheduleExit();
5156 } catch (Exception e) {
5157 // Ignore exceptions.
5158 }
5159 }
5160 return false;
5161 }
5162
5163 // If this application record is still attached to a previous
5164 // process, clean it up now.
5165 if (app.thread != null) {
5166 handleAppDiedLocked(app, true);
5167 }
5168
5169 // Tell the process all about itself.
5170
5171 if (localLOGV) Log.v(
5172 TAG, "Binding process pid " + pid + " to record " + app);
5173
5174 String processName = app.processName;
5175 try {
5176 thread.asBinder().linkToDeath(new AppDeathRecipient(
5177 app, pid, thread), 0);
5178 } catch (RemoteException e) {
5179 app.resetPackageList();
5180 startProcessLocked(app, "link fail", processName);
5181 return false;
5182 }
5183
5184 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5185
5186 app.thread = thread;
5187 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005188 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005189 app.forcingToForeground = null;
5190 app.foregroundServices = false;
5191 app.debugging = false;
5192
5193 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5194
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005195 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5196 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005197
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005198 if (!normalMode) {
5199 Log.i(TAG, "Launching preboot mode app: " + app);
5200 }
5201
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005202 if (localLOGV) Log.v(
5203 TAG, "New app record " + app
5204 + " thread=" + thread.asBinder() + " pid=" + pid);
5205 try {
5206 int testMode = IApplicationThread.DEBUG_OFF;
5207 if (mDebugApp != null && mDebugApp.equals(processName)) {
5208 testMode = mWaitForDebugger
5209 ? IApplicationThread.DEBUG_WAIT
5210 : IApplicationThread.DEBUG_ON;
5211 app.debugging = true;
5212 if (mDebugTransient) {
5213 mDebugApp = mOrigDebugApp;
5214 mWaitForDebugger = mOrigWaitForDebugger;
5215 }
5216 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005217
Christopher Tate181fafa2009-05-14 11:12:14 -07005218 // If the app is being launched for restore or full backup, set it up specially
5219 boolean isRestrictedBackupMode = false;
5220 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5221 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5222 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5223 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005224
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005225 ensurePackageDexOpt(app.instrumentationInfo != null
5226 ? app.instrumentationInfo.packageName
5227 : app.info.packageName);
5228 if (app.instrumentationClass != null) {
5229 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005230 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07005231 thread.bindApplication(processName, app.instrumentationInfo != null
5232 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005233 app.instrumentationClass, app.instrumentationProfileFile,
5234 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005235 isRestrictedBackupMode || !normalMode,
5236 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005237 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005238 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005239 } catch (Exception e) {
5240 // todo: Yikes! What should we do? For now we will try to
5241 // start another process, but that could easily get us in
5242 // an infinite loop of restarting processes...
5243 Log.w(TAG, "Exception thrown during bind!", e);
5244
5245 app.resetPackageList();
5246 startProcessLocked(app, "bind fail", processName);
5247 return false;
5248 }
5249
5250 // Remove this record from the list of starting applications.
5251 mPersistentStartingProcesses.remove(app);
5252 mProcessesOnHold.remove(app);
5253
5254 boolean badApp = false;
5255 boolean didSomething = false;
5256
5257 // See if the top visible activity is waiting to run in this process...
5258 HistoryRecord hr = topRunningActivityLocked(null);
5259 if (hr != null) {
5260 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5261 && processName.equals(hr.processName)) {
5262 try {
5263 if (realStartActivityLocked(hr, app, true, true)) {
5264 didSomething = true;
5265 }
5266 } catch (Exception e) {
5267 Log.w(TAG, "Exception in new application when starting activity "
5268 + hr.intent.getComponent().flattenToShortString(), e);
5269 badApp = true;
5270 }
5271 } else {
5272 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5273 }
5274 }
5275
5276 // Find any services that should be running in this process...
5277 if (!badApp && mPendingServices.size() > 0) {
5278 ServiceRecord sr = null;
5279 try {
5280 for (int i=0; i<mPendingServices.size(); i++) {
5281 sr = mPendingServices.get(i);
5282 if (app.info.uid != sr.appInfo.uid
5283 || !processName.equals(sr.processName)) {
5284 continue;
5285 }
5286
5287 mPendingServices.remove(i);
5288 i--;
5289 realStartServiceLocked(sr, app);
5290 didSomething = true;
5291 }
5292 } catch (Exception e) {
5293 Log.w(TAG, "Exception in new application when starting service "
5294 + sr.shortName, e);
5295 badApp = true;
5296 }
5297 }
5298
5299 // Check if the next broadcast receiver is in this process...
5300 BroadcastRecord br = mPendingBroadcast;
5301 if (!badApp && br != null && br.curApp == app) {
5302 try {
5303 mPendingBroadcast = null;
5304 processCurBroadcastLocked(br, app);
5305 didSomething = true;
5306 } catch (Exception e) {
5307 Log.w(TAG, "Exception in new application when starting receiver "
5308 + br.curComponent.flattenToShortString(), e);
5309 badApp = true;
5310 logBroadcastReceiverDiscard(br);
5311 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5312 br.resultExtras, br.resultAbort, true);
5313 scheduleBroadcastsLocked();
5314 }
5315 }
5316
Christopher Tate181fafa2009-05-14 11:12:14 -07005317 // Check whether the next backup agent is in this process...
5318 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5319 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005320 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005321 try {
5322 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5323 } catch (Exception e) {
5324 Log.w(TAG, "Exception scheduling backup agent creation: ");
5325 e.printStackTrace();
5326 }
5327 }
5328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005329 if (badApp) {
5330 // todo: Also need to kill application to deal with all
5331 // kinds of exceptions.
5332 handleAppDiedLocked(app, false);
5333 return false;
5334 }
5335
5336 if (!didSomething) {
5337 updateOomAdjLocked();
5338 }
5339
5340 return true;
5341 }
5342
5343 public final void attachApplication(IApplicationThread thread) {
5344 synchronized (this) {
5345 int callingPid = Binder.getCallingPid();
5346 final long origId = Binder.clearCallingIdentity();
5347 attachApplicationLocked(thread, callingPid);
5348 Binder.restoreCallingIdentity(origId);
5349 }
5350 }
5351
5352 public final void activityIdle(IBinder token) {
5353 final long origId = Binder.clearCallingIdentity();
5354 activityIdleInternal(token, false);
5355 Binder.restoreCallingIdentity(origId);
5356 }
5357
5358 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5359 boolean remove) {
5360 int N = mStoppingActivities.size();
5361 if (N <= 0) return null;
5362
5363 ArrayList<HistoryRecord> stops = null;
5364
5365 final boolean nowVisible = mResumedActivity != null
5366 && mResumedActivity.nowVisible
5367 && !mResumedActivity.waitingVisible;
5368 for (int i=0; i<N; i++) {
5369 HistoryRecord s = mStoppingActivities.get(i);
5370 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5371 + nowVisible + " waitingVisible=" + s.waitingVisible
5372 + " finishing=" + s.finishing);
5373 if (s.waitingVisible && nowVisible) {
5374 mWaitingVisibleActivities.remove(s);
5375 s.waitingVisible = false;
5376 if (s.finishing) {
5377 // If this activity is finishing, it is sitting on top of
5378 // everyone else but we now know it is no longer needed...
5379 // so get rid of it. Otherwise, we need to go through the
5380 // normal flow and hide it once we determine that it is
5381 // hidden by the activities in front of it.
5382 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5383 mWindowManager.setAppVisibility(s, false);
5384 }
5385 }
5386 if (!s.waitingVisible && remove) {
5387 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5388 if (stops == null) {
5389 stops = new ArrayList<HistoryRecord>();
5390 }
5391 stops.add(s);
5392 mStoppingActivities.remove(i);
5393 N--;
5394 i--;
5395 }
5396 }
5397
5398 return stops;
5399 }
5400
5401 void enableScreenAfterBoot() {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005402 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5403 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005404 mWindowManager.enableScreenAfterBoot();
5405 }
5406
5407 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5408 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5409
5410 ArrayList<HistoryRecord> stops = null;
5411 ArrayList<HistoryRecord> finishes = null;
5412 ArrayList<HistoryRecord> thumbnails = null;
5413 int NS = 0;
5414 int NF = 0;
5415 int NT = 0;
5416 IApplicationThread sendThumbnail = null;
5417 boolean booting = false;
5418 boolean enableScreen = false;
5419
5420 synchronized (this) {
5421 if (token != null) {
5422 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5423 }
5424
5425 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005426 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005427 if (index >= 0) {
5428 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5429
5430 // No longer need to keep the device awake.
5431 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5432 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5433 mLaunchingActivity.release();
5434 }
5435
5436 // We are now idle. If someone is waiting for a thumbnail from
5437 // us, we can now deliver.
5438 r.idle = true;
5439 scheduleAppGcsLocked();
5440 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5441 sendThumbnail = r.app.thread;
5442 r.thumbnailNeeded = false;
5443 }
5444
5445 // If this activity is fullscreen, set up to hide those under it.
5446
5447 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5448 ensureActivitiesVisibleLocked(null, 0);
5449
5450 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5451 if (!mBooted && !fromTimeout) {
5452 mBooted = true;
5453 enableScreen = true;
5454 }
5455 }
5456
5457 // Atomically retrieve all of the other things to do.
5458 stops = processStoppingActivitiesLocked(true);
5459 NS = stops != null ? stops.size() : 0;
5460 if ((NF=mFinishingActivities.size()) > 0) {
5461 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5462 mFinishingActivities.clear();
5463 }
5464 if ((NT=mCancelledThumbnails.size()) > 0) {
5465 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5466 mCancelledThumbnails.clear();
5467 }
5468
5469 booting = mBooting;
5470 mBooting = false;
5471 }
5472
5473 int i;
5474
5475 // Send thumbnail if requested.
5476 if (sendThumbnail != null) {
5477 try {
5478 sendThumbnail.requestThumbnail(token);
5479 } catch (Exception e) {
5480 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5481 sendPendingThumbnail(null, token, null, null, true);
5482 }
5483 }
5484
5485 // Stop any activities that are scheduled to do so but have been
5486 // waiting for the next one to start.
5487 for (i=0; i<NS; i++) {
5488 HistoryRecord r = (HistoryRecord)stops.get(i);
5489 synchronized (this) {
5490 if (r.finishing) {
5491 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5492 } else {
5493 stopActivityLocked(r);
5494 }
5495 }
5496 }
5497
5498 // Finish any activities that are scheduled to do so but have been
5499 // waiting for the next one to start.
5500 for (i=0; i<NF; i++) {
5501 HistoryRecord r = (HistoryRecord)finishes.get(i);
5502 synchronized (this) {
5503 destroyActivityLocked(r, true);
5504 }
5505 }
5506
5507 // Report back to any thumbnail receivers.
5508 for (i=0; i<NT; i++) {
5509 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5510 sendPendingThumbnail(r, null, null, null, true);
5511 }
5512
5513 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005514 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005515 }
5516
5517 trimApplications();
5518 //dump();
5519 //mWindowManager.dump();
5520
5521 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005522 enableScreenAfterBoot();
5523 }
5524 }
5525
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005526 final void finishBooting() {
5527 // Ensure that any processes we had put on hold are now started
5528 // up.
5529 final int NP = mProcessesOnHold.size();
5530 if (NP > 0) {
5531 ArrayList<ProcessRecord> procs =
5532 new ArrayList<ProcessRecord>(mProcessesOnHold);
5533 for (int ip=0; ip<NP; ip++) {
5534 this.startProcessLocked(procs.get(ip), "on-hold", null);
5535 }
5536 }
5537 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5538 // Tell anyone interested that we are done booting!
5539 synchronized (this) {
5540 broadcastIntentLocked(null, null,
5541 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5542 null, null, 0, null, null,
5543 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5544 false, false, MY_PID, Process.SYSTEM_UID);
5545 }
5546 }
5547 }
5548
5549 final void ensureBootCompleted() {
5550 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005551 boolean enableScreen;
5552 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005553 booting = mBooting;
5554 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005555 enableScreen = !mBooted;
5556 mBooted = true;
5557 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005558
5559 if (booting) {
5560 finishBooting();
5561 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005562
5563 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005564 enableScreenAfterBoot();
5565 }
5566 }
5567
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005568 public final void activityPaused(IBinder token, Bundle icicle) {
5569 // Refuse possible leaked file descriptors
5570 if (icicle != null && icicle.hasFileDescriptors()) {
5571 throw new IllegalArgumentException("File descriptors passed in Bundle");
5572 }
5573
5574 final long origId = Binder.clearCallingIdentity();
5575 activityPaused(token, icicle, false);
5576 Binder.restoreCallingIdentity(origId);
5577 }
5578
5579 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5580 if (DEBUG_PAUSE) Log.v(
5581 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5582 + ", timeout=" + timeout);
5583
5584 HistoryRecord r = null;
5585
5586 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005587 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005588 if (index >= 0) {
5589 r = (HistoryRecord)mHistory.get(index);
5590 if (!timeout) {
5591 r.icicle = icicle;
5592 r.haveState = true;
5593 }
5594 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5595 if (mPausingActivity == r) {
5596 r.state = ActivityState.PAUSED;
5597 completePauseLocked();
5598 } else {
5599 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5600 System.identityHashCode(r), r.shortComponentName,
5601 mPausingActivity != null
5602 ? mPausingActivity.shortComponentName : "(none)");
5603 }
5604 }
5605 }
5606 }
5607
5608 public final void activityStopped(IBinder token, Bitmap thumbnail,
5609 CharSequence description) {
5610 if (localLOGV) Log.v(
5611 TAG, "Activity stopped: token=" + token);
5612
5613 HistoryRecord r = null;
5614
5615 final long origId = Binder.clearCallingIdentity();
5616
5617 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005618 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005619 if (index >= 0) {
5620 r = (HistoryRecord)mHistory.get(index);
5621 r.thumbnail = thumbnail;
5622 r.description = description;
5623 r.stopped = true;
5624 r.state = ActivityState.STOPPED;
5625 if (!r.finishing) {
5626 if (r.configDestroy) {
5627 destroyActivityLocked(r, true);
5628 resumeTopActivityLocked(null);
5629 }
5630 }
5631 }
5632 }
5633
5634 if (r != null) {
5635 sendPendingThumbnail(r, null, null, null, false);
5636 }
5637
5638 trimApplications();
5639
5640 Binder.restoreCallingIdentity(origId);
5641 }
5642
5643 public final void activityDestroyed(IBinder token) {
5644 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5645 synchronized (this) {
5646 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5647
Dianne Hackborn75b03852009-06-12 15:43:26 -07005648 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005649 if (index >= 0) {
5650 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5651 if (r.state == ActivityState.DESTROYING) {
5652 final long origId = Binder.clearCallingIdentity();
5653 removeActivityFromHistoryLocked(r);
5654 Binder.restoreCallingIdentity(origId);
5655 }
5656 }
5657 }
5658 }
5659
5660 public String getCallingPackage(IBinder token) {
5661 synchronized (this) {
5662 HistoryRecord r = getCallingRecordLocked(token);
5663 return r != null && r.app != null ? r.app.processName : null;
5664 }
5665 }
5666
5667 public ComponentName getCallingActivity(IBinder token) {
5668 synchronized (this) {
5669 HistoryRecord r = getCallingRecordLocked(token);
5670 return r != null ? r.intent.getComponent() : null;
5671 }
5672 }
5673
5674 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005675 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005676 if (index >= 0) {
5677 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5678 if (r != null) {
5679 return r.resultTo;
5680 }
5681 }
5682 return null;
5683 }
5684
5685 public ComponentName getActivityClassForToken(IBinder token) {
5686 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005687 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005688 if (index >= 0) {
5689 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5690 return r.intent.getComponent();
5691 }
5692 return null;
5693 }
5694 }
5695
5696 public String getPackageForToken(IBinder token) {
5697 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005698 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005699 if (index >= 0) {
5700 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5701 return r.packageName;
5702 }
5703 return null;
5704 }
5705 }
5706
5707 public IIntentSender getIntentSender(int type,
5708 String packageName, IBinder token, String resultWho,
5709 int requestCode, Intent intent, String resolvedType, int flags) {
5710 // Refuse possible leaked file descriptors
5711 if (intent != null && intent.hasFileDescriptors() == true) {
5712 throw new IllegalArgumentException("File descriptors passed in Intent");
5713 }
5714
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005715 if (type == INTENT_SENDER_BROADCAST) {
5716 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5717 throw new IllegalArgumentException(
5718 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5719 }
5720 }
5721
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005722 synchronized(this) {
5723 int callingUid = Binder.getCallingUid();
5724 try {
5725 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5726 Process.supportsProcesses()) {
5727 int uid = ActivityThread.getPackageManager()
5728 .getPackageUid(packageName);
5729 if (uid != Binder.getCallingUid()) {
5730 String msg = "Permission Denial: getIntentSender() from pid="
5731 + Binder.getCallingPid()
5732 + ", uid=" + Binder.getCallingUid()
5733 + ", (need uid=" + uid + ")"
5734 + " is not allowed to send as package " + packageName;
5735 Log.w(TAG, msg);
5736 throw new SecurityException(msg);
5737 }
5738 }
5739 } catch (RemoteException e) {
5740 throw new SecurityException(e);
5741 }
5742 HistoryRecord activity = null;
5743 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005744 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005745 if (index < 0) {
5746 return null;
5747 }
5748 activity = (HistoryRecord)mHistory.get(index);
5749 if (activity.finishing) {
5750 return null;
5751 }
5752 }
5753
5754 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5755 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5756 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5757 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5758 |PendingIntent.FLAG_UPDATE_CURRENT);
5759
5760 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5761 type, packageName, activity, resultWho,
5762 requestCode, intent, resolvedType, flags);
5763 WeakReference<PendingIntentRecord> ref;
5764 ref = mIntentSenderRecords.get(key);
5765 PendingIntentRecord rec = ref != null ? ref.get() : null;
5766 if (rec != null) {
5767 if (!cancelCurrent) {
5768 if (updateCurrent) {
5769 rec.key.requestIntent.replaceExtras(intent);
5770 }
5771 return rec;
5772 }
5773 rec.canceled = true;
5774 mIntentSenderRecords.remove(key);
5775 }
5776 if (noCreate) {
5777 return rec;
5778 }
5779 rec = new PendingIntentRecord(this, key, callingUid);
5780 mIntentSenderRecords.put(key, rec.ref);
5781 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5782 if (activity.pendingResults == null) {
5783 activity.pendingResults
5784 = new HashSet<WeakReference<PendingIntentRecord>>();
5785 }
5786 activity.pendingResults.add(rec.ref);
5787 }
5788 return rec;
5789 }
5790 }
5791
5792 public void cancelIntentSender(IIntentSender sender) {
5793 if (!(sender instanceof PendingIntentRecord)) {
5794 return;
5795 }
5796 synchronized(this) {
5797 PendingIntentRecord rec = (PendingIntentRecord)sender;
5798 try {
5799 int uid = ActivityThread.getPackageManager()
5800 .getPackageUid(rec.key.packageName);
5801 if (uid != Binder.getCallingUid()) {
5802 String msg = "Permission Denial: cancelIntentSender() from pid="
5803 + Binder.getCallingPid()
5804 + ", uid=" + Binder.getCallingUid()
5805 + " is not allowed to cancel packges "
5806 + rec.key.packageName;
5807 Log.w(TAG, msg);
5808 throw new SecurityException(msg);
5809 }
5810 } catch (RemoteException e) {
5811 throw new SecurityException(e);
5812 }
5813 cancelIntentSenderLocked(rec, true);
5814 }
5815 }
5816
5817 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5818 rec.canceled = true;
5819 mIntentSenderRecords.remove(rec.key);
5820 if (cleanActivity && rec.key.activity != null) {
5821 rec.key.activity.pendingResults.remove(rec.ref);
5822 }
5823 }
5824
5825 public String getPackageForIntentSender(IIntentSender pendingResult) {
5826 if (!(pendingResult instanceof PendingIntentRecord)) {
5827 return null;
5828 }
5829 synchronized(this) {
5830 try {
5831 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5832 return res.key.packageName;
5833 } catch (ClassCastException e) {
5834 }
5835 }
5836 return null;
5837 }
5838
5839 public void setProcessLimit(int max) {
5840 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5841 "setProcessLimit()");
5842 mProcessLimit = max;
5843 }
5844
5845 public int getProcessLimit() {
5846 return mProcessLimit;
5847 }
5848
5849 void foregroundTokenDied(ForegroundToken token) {
5850 synchronized (ActivityManagerService.this) {
5851 synchronized (mPidsSelfLocked) {
5852 ForegroundToken cur
5853 = mForegroundProcesses.get(token.pid);
5854 if (cur != token) {
5855 return;
5856 }
5857 mForegroundProcesses.remove(token.pid);
5858 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5859 if (pr == null) {
5860 return;
5861 }
5862 pr.forcingToForeground = null;
5863 pr.foregroundServices = false;
5864 }
5865 updateOomAdjLocked();
5866 }
5867 }
5868
5869 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5870 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5871 "setProcessForeground()");
5872 synchronized(this) {
5873 boolean changed = false;
5874
5875 synchronized (mPidsSelfLocked) {
5876 ProcessRecord pr = mPidsSelfLocked.get(pid);
5877 if (pr == null) {
5878 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5879 return;
5880 }
5881 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5882 if (oldToken != null) {
5883 oldToken.token.unlinkToDeath(oldToken, 0);
5884 mForegroundProcesses.remove(pid);
5885 pr.forcingToForeground = null;
5886 changed = true;
5887 }
5888 if (isForeground && token != null) {
5889 ForegroundToken newToken = new ForegroundToken() {
5890 public void binderDied() {
5891 foregroundTokenDied(this);
5892 }
5893 };
5894 newToken.pid = pid;
5895 newToken.token = token;
5896 try {
5897 token.linkToDeath(newToken, 0);
5898 mForegroundProcesses.put(pid, newToken);
5899 pr.forcingToForeground = token;
5900 changed = true;
5901 } catch (RemoteException e) {
5902 // If the process died while doing this, we will later
5903 // do the cleanup with the process death link.
5904 }
5905 }
5906 }
5907
5908 if (changed) {
5909 updateOomAdjLocked();
5910 }
5911 }
5912 }
5913
5914 // =========================================================
5915 // PERMISSIONS
5916 // =========================================================
5917
5918 static class PermissionController extends IPermissionController.Stub {
5919 ActivityManagerService mActivityManagerService;
5920 PermissionController(ActivityManagerService activityManagerService) {
5921 mActivityManagerService = activityManagerService;
5922 }
5923
5924 public boolean checkPermission(String permission, int pid, int uid) {
5925 return mActivityManagerService.checkPermission(permission, pid,
5926 uid) == PackageManager.PERMISSION_GRANTED;
5927 }
5928 }
5929
5930 /**
5931 * This can be called with or without the global lock held.
5932 */
5933 int checkComponentPermission(String permission, int pid, int uid,
5934 int reqUid) {
5935 // We might be performing an operation on behalf of an indirect binder
5936 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5937 // client identity accordingly before proceeding.
5938 Identity tlsIdentity = sCallerIdentity.get();
5939 if (tlsIdentity != null) {
5940 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5941 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5942 uid = tlsIdentity.uid;
5943 pid = tlsIdentity.pid;
5944 }
5945
5946 // Root, system server and our own process get to do everything.
5947 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5948 !Process.supportsProcesses()) {
5949 return PackageManager.PERMISSION_GRANTED;
5950 }
5951 // If the target requires a specific UID, always fail for others.
5952 if (reqUid >= 0 && uid != reqUid) {
5953 return PackageManager.PERMISSION_DENIED;
5954 }
5955 if (permission == null) {
5956 return PackageManager.PERMISSION_GRANTED;
5957 }
5958 try {
5959 return ActivityThread.getPackageManager()
5960 .checkUidPermission(permission, uid);
5961 } catch (RemoteException e) {
5962 // Should never happen, but if it does... deny!
5963 Log.e(TAG, "PackageManager is dead?!?", e);
5964 }
5965 return PackageManager.PERMISSION_DENIED;
5966 }
5967
5968 /**
5969 * As the only public entry point for permissions checking, this method
5970 * can enforce the semantic that requesting a check on a null global
5971 * permission is automatically denied. (Internally a null permission
5972 * string is used when calling {@link #checkComponentPermission} in cases
5973 * when only uid-based security is needed.)
5974 *
5975 * This can be called with or without the global lock held.
5976 */
5977 public int checkPermission(String permission, int pid, int uid) {
5978 if (permission == null) {
5979 return PackageManager.PERMISSION_DENIED;
5980 }
5981 return checkComponentPermission(permission, pid, uid, -1);
5982 }
5983
5984 /**
5985 * Binder IPC calls go through the public entry point.
5986 * This can be called with or without the global lock held.
5987 */
5988 int checkCallingPermission(String permission) {
5989 return checkPermission(permission,
5990 Binder.getCallingPid(),
5991 Binder.getCallingUid());
5992 }
5993
5994 /**
5995 * This can be called with or without the global lock held.
5996 */
5997 void enforceCallingPermission(String permission, String func) {
5998 if (checkCallingPermission(permission)
5999 == PackageManager.PERMISSION_GRANTED) {
6000 return;
6001 }
6002
6003 String msg = "Permission Denial: " + func + " from pid="
6004 + Binder.getCallingPid()
6005 + ", uid=" + Binder.getCallingUid()
6006 + " requires " + permission;
6007 Log.w(TAG, msg);
6008 throw new SecurityException(msg);
6009 }
6010
6011 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6012 ProviderInfo pi, int uid, int modeFlags) {
6013 try {
6014 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6015 if ((pi.readPermission != null) &&
6016 (pm.checkUidPermission(pi.readPermission, uid)
6017 != PackageManager.PERMISSION_GRANTED)) {
6018 return false;
6019 }
6020 }
6021 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6022 if ((pi.writePermission != null) &&
6023 (pm.checkUidPermission(pi.writePermission, uid)
6024 != PackageManager.PERMISSION_GRANTED)) {
6025 return false;
6026 }
6027 }
6028 return true;
6029 } catch (RemoteException e) {
6030 return false;
6031 }
6032 }
6033
6034 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6035 int modeFlags) {
6036 // Root gets to do everything.
6037 if (uid == 0 || !Process.supportsProcesses()) {
6038 return true;
6039 }
6040 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6041 if (perms == null) return false;
6042 UriPermission perm = perms.get(uri);
6043 if (perm == null) return false;
6044 return (modeFlags&perm.modeFlags) == modeFlags;
6045 }
6046
6047 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6048 // Another redirected-binder-call permissions check as in
6049 // {@link checkComponentPermission}.
6050 Identity tlsIdentity = sCallerIdentity.get();
6051 if (tlsIdentity != null) {
6052 uid = tlsIdentity.uid;
6053 pid = tlsIdentity.pid;
6054 }
6055
6056 // Our own process gets to do everything.
6057 if (pid == MY_PID) {
6058 return PackageManager.PERMISSION_GRANTED;
6059 }
6060 synchronized(this) {
6061 return checkUriPermissionLocked(uri, uid, modeFlags)
6062 ? PackageManager.PERMISSION_GRANTED
6063 : PackageManager.PERMISSION_DENIED;
6064 }
6065 }
6066
6067 private void grantUriPermissionLocked(int callingUid,
6068 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6069 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6070 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6071 if (modeFlags == 0) {
6072 return;
6073 }
6074
6075 final IPackageManager pm = ActivityThread.getPackageManager();
6076
6077 // If this is not a content: uri, we can't do anything with it.
6078 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6079 return;
6080 }
6081
6082 String name = uri.getAuthority();
6083 ProviderInfo pi = null;
6084 ContentProviderRecord cpr
6085 = (ContentProviderRecord)mProvidersByName.get(name);
6086 if (cpr != null) {
6087 pi = cpr.info;
6088 } else {
6089 try {
6090 pi = pm.resolveContentProvider(name,
6091 PackageManager.GET_URI_PERMISSION_PATTERNS);
6092 } catch (RemoteException ex) {
6093 }
6094 }
6095 if (pi == null) {
6096 Log.w(TAG, "No content provider found for: " + name);
6097 return;
6098 }
6099
6100 int targetUid;
6101 try {
6102 targetUid = pm.getPackageUid(targetPkg);
6103 if (targetUid < 0) {
6104 return;
6105 }
6106 } catch (RemoteException ex) {
6107 return;
6108 }
6109
6110 // First... does the target actually need this permission?
6111 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6112 // No need to grant the target this permission.
6113 return;
6114 }
6115
6116 // Second... maybe someone else has already granted the
6117 // permission?
6118 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6119 // No need to grant the target this permission.
6120 return;
6121 }
6122
6123 // Third... is the provider allowing granting of URI permissions?
6124 if (!pi.grantUriPermissions) {
6125 throw new SecurityException("Provider " + pi.packageName
6126 + "/" + pi.name
6127 + " does not allow granting of Uri permissions (uri "
6128 + uri + ")");
6129 }
6130 if (pi.uriPermissionPatterns != null) {
6131 final int N = pi.uriPermissionPatterns.length;
6132 boolean allowed = false;
6133 for (int i=0; i<N; i++) {
6134 if (pi.uriPermissionPatterns[i] != null
6135 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6136 allowed = true;
6137 break;
6138 }
6139 }
6140 if (!allowed) {
6141 throw new SecurityException("Provider " + pi.packageName
6142 + "/" + pi.name
6143 + " does not allow granting of permission to path of Uri "
6144 + uri);
6145 }
6146 }
6147
6148 // Fourth... does the caller itself have permission to access
6149 // this uri?
6150 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6151 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6152 throw new SecurityException("Uid " + callingUid
6153 + " does not have permission to uri " + uri);
6154 }
6155 }
6156
6157 // Okay! So here we are: the caller has the assumed permission
6158 // to the uri, and the target doesn't. Let's now give this to
6159 // the target.
6160
6161 HashMap<Uri, UriPermission> targetUris
6162 = mGrantedUriPermissions.get(targetUid);
6163 if (targetUris == null) {
6164 targetUris = new HashMap<Uri, UriPermission>();
6165 mGrantedUriPermissions.put(targetUid, targetUris);
6166 }
6167
6168 UriPermission perm = targetUris.get(uri);
6169 if (perm == null) {
6170 perm = new UriPermission(targetUid, uri);
6171 targetUris.put(uri, perm);
6172
6173 }
6174 perm.modeFlags |= modeFlags;
6175 if (activity == null) {
6176 perm.globalModeFlags |= modeFlags;
6177 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6178 perm.readActivities.add(activity);
6179 if (activity.readUriPermissions == null) {
6180 activity.readUriPermissions = new HashSet<UriPermission>();
6181 }
6182 activity.readUriPermissions.add(perm);
6183 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6184 perm.writeActivities.add(activity);
6185 if (activity.writeUriPermissions == null) {
6186 activity.writeUriPermissions = new HashSet<UriPermission>();
6187 }
6188 activity.writeUriPermissions.add(perm);
6189 }
6190 }
6191
6192 private void grantUriPermissionFromIntentLocked(int callingUid,
6193 String targetPkg, Intent intent, HistoryRecord activity) {
6194 if (intent == null) {
6195 return;
6196 }
6197 Uri data = intent.getData();
6198 if (data == null) {
6199 return;
6200 }
6201 grantUriPermissionLocked(callingUid, targetPkg, data,
6202 intent.getFlags(), activity);
6203 }
6204
6205 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6206 Uri uri, int modeFlags) {
6207 synchronized(this) {
6208 final ProcessRecord r = getRecordForAppLocked(caller);
6209 if (r == null) {
6210 throw new SecurityException("Unable to find app for caller "
6211 + caller
6212 + " when granting permission to uri " + uri);
6213 }
6214 if (targetPkg == null) {
6215 Log.w(TAG, "grantUriPermission: null target");
6216 return;
6217 }
6218 if (uri == null) {
6219 Log.w(TAG, "grantUriPermission: null uri");
6220 return;
6221 }
6222
6223 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6224 null);
6225 }
6226 }
6227
6228 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6229 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6230 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6231 HashMap<Uri, UriPermission> perms
6232 = mGrantedUriPermissions.get(perm.uid);
6233 if (perms != null) {
6234 perms.remove(perm.uri);
6235 if (perms.size() == 0) {
6236 mGrantedUriPermissions.remove(perm.uid);
6237 }
6238 }
6239 }
6240 }
6241
6242 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6243 if (activity.readUriPermissions != null) {
6244 for (UriPermission perm : activity.readUriPermissions) {
6245 perm.readActivities.remove(activity);
6246 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6247 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6248 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6249 removeUriPermissionIfNeededLocked(perm);
6250 }
6251 }
6252 }
6253 if (activity.writeUriPermissions != null) {
6254 for (UriPermission perm : activity.writeUriPermissions) {
6255 perm.writeActivities.remove(activity);
6256 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6257 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6258 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6259 removeUriPermissionIfNeededLocked(perm);
6260 }
6261 }
6262 }
6263 }
6264
6265 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6266 int modeFlags) {
6267 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6268 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6269 if (modeFlags == 0) {
6270 return;
6271 }
6272
6273 final IPackageManager pm = ActivityThread.getPackageManager();
6274
6275 final String authority = uri.getAuthority();
6276 ProviderInfo pi = null;
6277 ContentProviderRecord cpr
6278 = (ContentProviderRecord)mProvidersByName.get(authority);
6279 if (cpr != null) {
6280 pi = cpr.info;
6281 } else {
6282 try {
6283 pi = pm.resolveContentProvider(authority,
6284 PackageManager.GET_URI_PERMISSION_PATTERNS);
6285 } catch (RemoteException ex) {
6286 }
6287 }
6288 if (pi == null) {
6289 Log.w(TAG, "No content provider found for: " + authority);
6290 return;
6291 }
6292
6293 // Does the caller have this permission on the URI?
6294 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6295 // Right now, if you are not the original owner of the permission,
6296 // you are not allowed to revoke it.
6297 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6298 throw new SecurityException("Uid " + callingUid
6299 + " does not have permission to uri " + uri);
6300 //}
6301 }
6302
6303 // Go through all of the permissions and remove any that match.
6304 final List<String> SEGMENTS = uri.getPathSegments();
6305 if (SEGMENTS != null) {
6306 final int NS = SEGMENTS.size();
6307 int N = mGrantedUriPermissions.size();
6308 for (int i=0; i<N; i++) {
6309 HashMap<Uri, UriPermission> perms
6310 = mGrantedUriPermissions.valueAt(i);
6311 Iterator<UriPermission> it = perms.values().iterator();
6312 toploop:
6313 while (it.hasNext()) {
6314 UriPermission perm = it.next();
6315 Uri targetUri = perm.uri;
6316 if (!authority.equals(targetUri.getAuthority())) {
6317 continue;
6318 }
6319 List<String> targetSegments = targetUri.getPathSegments();
6320 if (targetSegments == null) {
6321 continue;
6322 }
6323 if (targetSegments.size() < NS) {
6324 continue;
6325 }
6326 for (int j=0; j<NS; j++) {
6327 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6328 continue toploop;
6329 }
6330 }
6331 perm.clearModes(modeFlags);
6332 if (perm.modeFlags == 0) {
6333 it.remove();
6334 }
6335 }
6336 if (perms.size() == 0) {
6337 mGrantedUriPermissions.remove(
6338 mGrantedUriPermissions.keyAt(i));
6339 N--;
6340 i--;
6341 }
6342 }
6343 }
6344 }
6345
6346 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6347 int modeFlags) {
6348 synchronized(this) {
6349 final ProcessRecord r = getRecordForAppLocked(caller);
6350 if (r == null) {
6351 throw new SecurityException("Unable to find app for caller "
6352 + caller
6353 + " when revoking permission to uri " + uri);
6354 }
6355 if (uri == null) {
6356 Log.w(TAG, "revokeUriPermission: null uri");
6357 return;
6358 }
6359
6360 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6361 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6362 if (modeFlags == 0) {
6363 return;
6364 }
6365
6366 final IPackageManager pm = ActivityThread.getPackageManager();
6367
6368 final String authority = uri.getAuthority();
6369 ProviderInfo pi = null;
6370 ContentProviderRecord cpr
6371 = (ContentProviderRecord)mProvidersByName.get(authority);
6372 if (cpr != null) {
6373 pi = cpr.info;
6374 } else {
6375 try {
6376 pi = pm.resolveContentProvider(authority,
6377 PackageManager.GET_URI_PERMISSION_PATTERNS);
6378 } catch (RemoteException ex) {
6379 }
6380 }
6381 if (pi == null) {
6382 Log.w(TAG, "No content provider found for: " + authority);
6383 return;
6384 }
6385
6386 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6387 }
6388 }
6389
6390 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6391 synchronized (this) {
6392 ProcessRecord app =
6393 who != null ? getRecordForAppLocked(who) : null;
6394 if (app == null) return;
6395
6396 Message msg = Message.obtain();
6397 msg.what = WAIT_FOR_DEBUGGER_MSG;
6398 msg.obj = app;
6399 msg.arg1 = waiting ? 1 : 0;
6400 mHandler.sendMessage(msg);
6401 }
6402 }
6403
6404 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6405 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006406 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006407 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006408 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006409 }
6410
6411 // =========================================================
6412 // TASK MANAGEMENT
6413 // =========================================================
6414
6415 public List getTasks(int maxNum, int flags,
6416 IThumbnailReceiver receiver) {
6417 ArrayList list = new ArrayList();
6418
6419 PendingThumbnailsRecord pending = null;
6420 IApplicationThread topThumbnail = null;
6421 HistoryRecord topRecord = null;
6422
6423 synchronized(this) {
6424 if (localLOGV) Log.v(
6425 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6426 + ", receiver=" + receiver);
6427
6428 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6429 != PackageManager.PERMISSION_GRANTED) {
6430 if (receiver != null) {
6431 // If the caller wants to wait for pending thumbnails,
6432 // it ain't gonna get them.
6433 try {
6434 receiver.finished();
6435 } catch (RemoteException ex) {
6436 }
6437 }
6438 String msg = "Permission Denial: getTasks() from pid="
6439 + Binder.getCallingPid()
6440 + ", uid=" + Binder.getCallingUid()
6441 + " requires " + android.Manifest.permission.GET_TASKS;
6442 Log.w(TAG, msg);
6443 throw new SecurityException(msg);
6444 }
6445
6446 int pos = mHistory.size()-1;
6447 HistoryRecord next =
6448 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6449 HistoryRecord top = null;
6450 CharSequence topDescription = null;
6451 TaskRecord curTask = null;
6452 int numActivities = 0;
6453 int numRunning = 0;
6454 while (pos >= 0 && maxNum > 0) {
6455 final HistoryRecord r = next;
6456 pos--;
6457 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6458
6459 // Initialize state for next task if needed.
6460 if (top == null ||
6461 (top.state == ActivityState.INITIALIZING
6462 && top.task == r.task)) {
6463 top = r;
6464 topDescription = r.description;
6465 curTask = r.task;
6466 numActivities = numRunning = 0;
6467 }
6468
6469 // Add 'r' into the current task.
6470 numActivities++;
6471 if (r.app != null && r.app.thread != null) {
6472 numRunning++;
6473 }
6474 if (topDescription == null) {
6475 topDescription = r.description;
6476 }
6477
6478 if (localLOGV) Log.v(
6479 TAG, r.intent.getComponent().flattenToShortString()
6480 + ": task=" + r.task);
6481
6482 // If the next one is a different task, generate a new
6483 // TaskInfo entry for what we have.
6484 if (next == null || next.task != curTask) {
6485 ActivityManager.RunningTaskInfo ci
6486 = new ActivityManager.RunningTaskInfo();
6487 ci.id = curTask.taskId;
6488 ci.baseActivity = r.intent.getComponent();
6489 ci.topActivity = top.intent.getComponent();
6490 ci.thumbnail = top.thumbnail;
6491 ci.description = topDescription;
6492 ci.numActivities = numActivities;
6493 ci.numRunning = numRunning;
6494 //System.out.println(
6495 // "#" + maxNum + ": " + " descr=" + ci.description);
6496 if (ci.thumbnail == null && receiver != null) {
6497 if (localLOGV) Log.v(
6498 TAG, "State=" + top.state + "Idle=" + top.idle
6499 + " app=" + top.app
6500 + " thr=" + (top.app != null ? top.app.thread : null));
6501 if (top.state == ActivityState.RESUMED
6502 || top.state == ActivityState.PAUSING) {
6503 if (top.idle && top.app != null
6504 && top.app.thread != null) {
6505 topRecord = top;
6506 topThumbnail = top.app.thread;
6507 } else {
6508 top.thumbnailNeeded = true;
6509 }
6510 }
6511 if (pending == null) {
6512 pending = new PendingThumbnailsRecord(receiver);
6513 }
6514 pending.pendingRecords.add(top);
6515 }
6516 list.add(ci);
6517 maxNum--;
6518 top = null;
6519 }
6520 }
6521
6522 if (pending != null) {
6523 mPendingThumbnails.add(pending);
6524 }
6525 }
6526
6527 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6528
6529 if (topThumbnail != null) {
6530 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6531 try {
6532 topThumbnail.requestThumbnail(topRecord);
6533 } catch (Exception e) {
6534 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6535 sendPendingThumbnail(null, topRecord, null, null, true);
6536 }
6537 }
6538
6539 if (pending == null && receiver != null) {
6540 // In this case all thumbnails were available and the client
6541 // is being asked to be told when the remaining ones come in...
6542 // which is unusually, since the top-most currently running
6543 // activity should never have a canned thumbnail! Oh well.
6544 try {
6545 receiver.finished();
6546 } catch (RemoteException ex) {
6547 }
6548 }
6549
6550 return list;
6551 }
6552
6553 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6554 int flags) {
6555 synchronized (this) {
6556 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6557 "getRecentTasks()");
6558
6559 final int N = mRecentTasks.size();
6560 ArrayList<ActivityManager.RecentTaskInfo> res
6561 = new ArrayList<ActivityManager.RecentTaskInfo>(
6562 maxNum < N ? maxNum : N);
6563 for (int i=0; i<N && maxNum > 0; i++) {
6564 TaskRecord tr = mRecentTasks.get(i);
6565 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6566 || (tr.intent == null)
6567 || ((tr.intent.getFlags()
6568 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6569 ActivityManager.RecentTaskInfo rti
6570 = new ActivityManager.RecentTaskInfo();
6571 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6572 rti.baseIntent = new Intent(
6573 tr.intent != null ? tr.intent : tr.affinityIntent);
6574 rti.origActivity = tr.origActivity;
6575 res.add(rti);
6576 maxNum--;
6577 }
6578 }
6579 return res;
6580 }
6581 }
6582
6583 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6584 int j;
6585 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6586 TaskRecord jt = startTask;
6587
6588 // First look backwards
6589 for (j=startIndex-1; j>=0; j--) {
6590 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6591 if (r.task != jt) {
6592 jt = r.task;
6593 if (affinity.equals(jt.affinity)) {
6594 return j;
6595 }
6596 }
6597 }
6598
6599 // Now look forwards
6600 final int N = mHistory.size();
6601 jt = startTask;
6602 for (j=startIndex+1; j<N; j++) {
6603 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6604 if (r.task != jt) {
6605 if (affinity.equals(jt.affinity)) {
6606 return j;
6607 }
6608 jt = r.task;
6609 }
6610 }
6611
6612 // Might it be at the top?
6613 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6614 return N-1;
6615 }
6616
6617 return -1;
6618 }
6619
6620 /**
6621 * Perform a reset of the given task, if needed as part of launching it.
6622 * Returns the new HistoryRecord at the top of the task.
6623 */
6624 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6625 HistoryRecord newActivity) {
6626 boolean forceReset = (newActivity.info.flags
6627 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6628 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6629 if ((newActivity.info.flags
6630 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6631 forceReset = true;
6632 }
6633 }
6634
6635 final TaskRecord task = taskTop.task;
6636
6637 // We are going to move through the history list so that we can look
6638 // at each activity 'target' with 'below' either the interesting
6639 // activity immediately below it in the stack or null.
6640 HistoryRecord target = null;
6641 int targetI = 0;
6642 int taskTopI = -1;
6643 int replyChainEnd = -1;
6644 int lastReparentPos = -1;
6645 for (int i=mHistory.size()-1; i>=-1; i--) {
6646 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6647
6648 if (below != null && below.finishing) {
6649 continue;
6650 }
6651 if (target == null) {
6652 target = below;
6653 targetI = i;
6654 // If we were in the middle of a reply chain before this
6655 // task, it doesn't appear like the root of the chain wants
6656 // anything interesting, so drop it.
6657 replyChainEnd = -1;
6658 continue;
6659 }
6660
6661 final int flags = target.info.flags;
6662
6663 final boolean finishOnTaskLaunch =
6664 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6665 final boolean allowTaskReparenting =
6666 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6667
6668 if (target.task == task) {
6669 // We are inside of the task being reset... we'll either
6670 // finish this activity, push it out for another task,
6671 // or leave it as-is. We only do this
6672 // for activities that are not the root of the task (since
6673 // if we finish the root, we may no longer have the task!).
6674 if (taskTopI < 0) {
6675 taskTopI = targetI;
6676 }
6677 if (below != null && below.task == task) {
6678 final boolean clearWhenTaskReset =
6679 (target.intent.getFlags()
6680 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006681 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006682 // If this activity is sending a reply to a previous
6683 // activity, we can't do anything with it now until
6684 // we reach the start of the reply chain.
6685 // XXX note that we are assuming the result is always
6686 // to the previous activity, which is almost always
6687 // the case but we really shouldn't count on.
6688 if (replyChainEnd < 0) {
6689 replyChainEnd = targetI;
6690 }
Ed Heyl73798232009-03-24 21:32:21 -07006691 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006692 && target.taskAffinity != null
6693 && !target.taskAffinity.equals(task.affinity)) {
6694 // If this activity has an affinity for another
6695 // task, then we need to move it out of here. We will
6696 // move it as far out of the way as possible, to the
6697 // bottom of the activity stack. This also keeps it
6698 // correctly ordered with any activities we previously
6699 // moved.
6700 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6701 if (target.taskAffinity != null
6702 && target.taskAffinity.equals(p.task.affinity)) {
6703 // If the activity currently at the bottom has the
6704 // same task affinity as the one we are moving,
6705 // then merge it into the same task.
6706 target.task = p.task;
6707 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6708 + " out to bottom task " + p.task);
6709 } else {
6710 mCurTask++;
6711 if (mCurTask <= 0) {
6712 mCurTask = 1;
6713 }
6714 target.task = new TaskRecord(mCurTask, target.info, null,
6715 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6716 target.task.affinityIntent = target.intent;
6717 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6718 + " out to new task " + target.task);
6719 }
6720 mWindowManager.setAppGroupId(target, task.taskId);
6721 if (replyChainEnd < 0) {
6722 replyChainEnd = targetI;
6723 }
6724 int dstPos = 0;
6725 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6726 p = (HistoryRecord)mHistory.get(srcPos);
6727 if (p.finishing) {
6728 continue;
6729 }
6730 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6731 + " out to target's task " + target.task);
6732 task.numActivities--;
6733 p.task = target.task;
6734 target.task.numActivities++;
6735 mHistory.remove(srcPos);
6736 mHistory.add(dstPos, p);
6737 mWindowManager.moveAppToken(dstPos, p);
6738 mWindowManager.setAppGroupId(p, p.task.taskId);
6739 dstPos++;
6740 if (VALIDATE_TOKENS) {
6741 mWindowManager.validateAppTokens(mHistory);
6742 }
6743 i++;
6744 }
6745 if (taskTop == p) {
6746 taskTop = below;
6747 }
6748 if (taskTopI == replyChainEnd) {
6749 taskTopI = -1;
6750 }
6751 replyChainEnd = -1;
6752 addRecentTask(target.task);
6753 } else if (forceReset || finishOnTaskLaunch
6754 || clearWhenTaskReset) {
6755 // If the activity should just be removed -- either
6756 // because it asks for it, or the task should be
6757 // cleared -- then finish it and anything that is
6758 // part of its reply chain.
6759 if (clearWhenTaskReset) {
6760 // In this case, we want to finish this activity
6761 // and everything above it, so be sneaky and pretend
6762 // like these are all in the reply chain.
6763 replyChainEnd = targetI+1;
6764 while (replyChainEnd < mHistory.size() &&
6765 ((HistoryRecord)mHistory.get(
6766 replyChainEnd)).task == task) {
6767 replyChainEnd++;
6768 }
6769 replyChainEnd--;
6770 } else if (replyChainEnd < 0) {
6771 replyChainEnd = targetI;
6772 }
6773 HistoryRecord p = null;
6774 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6775 p = (HistoryRecord)mHistory.get(srcPos);
6776 if (p.finishing) {
6777 continue;
6778 }
6779 if (finishActivityLocked(p, srcPos,
6780 Activity.RESULT_CANCELED, null, "reset")) {
6781 replyChainEnd--;
6782 srcPos--;
6783 }
6784 }
6785 if (taskTop == p) {
6786 taskTop = below;
6787 }
6788 if (taskTopI == replyChainEnd) {
6789 taskTopI = -1;
6790 }
6791 replyChainEnd = -1;
6792 } else {
6793 // If we were in the middle of a chain, well the
6794 // activity that started it all doesn't want anything
6795 // special, so leave it all as-is.
6796 replyChainEnd = -1;
6797 }
6798 } else {
6799 // Reached the bottom of the task -- any reply chain
6800 // should be left as-is.
6801 replyChainEnd = -1;
6802 }
6803
6804 } else if (target.resultTo != null) {
6805 // If this activity is sending a reply to a previous
6806 // activity, we can't do anything with it now until
6807 // we reach the start of the reply chain.
6808 // XXX note that we are assuming the result is always
6809 // to the previous activity, which is almost always
6810 // the case but we really shouldn't count on.
6811 if (replyChainEnd < 0) {
6812 replyChainEnd = targetI;
6813 }
6814
6815 } else if (taskTopI >= 0 && allowTaskReparenting
6816 && task.affinity != null
6817 && task.affinity.equals(target.taskAffinity)) {
6818 // We are inside of another task... if this activity has
6819 // an affinity for our task, then either remove it if we are
6820 // clearing or move it over to our task. Note that
6821 // we currently punt on the case where we are resetting a
6822 // task that is not at the top but who has activities above
6823 // with an affinity to it... this is really not a normal
6824 // case, and we will need to later pull that task to the front
6825 // and usually at that point we will do the reset and pick
6826 // up those remaining activities. (This only happens if
6827 // someone starts an activity in a new task from an activity
6828 // in a task that is not currently on top.)
6829 if (forceReset || finishOnTaskLaunch) {
6830 if (replyChainEnd < 0) {
6831 replyChainEnd = targetI;
6832 }
6833 HistoryRecord p = null;
6834 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6835 p = (HistoryRecord)mHistory.get(srcPos);
6836 if (p.finishing) {
6837 continue;
6838 }
6839 if (finishActivityLocked(p, srcPos,
6840 Activity.RESULT_CANCELED, null, "reset")) {
6841 taskTopI--;
6842 lastReparentPos--;
6843 replyChainEnd--;
6844 srcPos--;
6845 }
6846 }
6847 replyChainEnd = -1;
6848 } else {
6849 if (replyChainEnd < 0) {
6850 replyChainEnd = targetI;
6851 }
6852 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6853 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6854 if (p.finishing) {
6855 continue;
6856 }
6857 if (lastReparentPos < 0) {
6858 lastReparentPos = taskTopI;
6859 taskTop = p;
6860 } else {
6861 lastReparentPos--;
6862 }
6863 mHistory.remove(srcPos);
6864 p.task.numActivities--;
6865 p.task = task;
6866 mHistory.add(lastReparentPos, p);
6867 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6868 + " in to resetting task " + task);
6869 task.numActivities++;
6870 mWindowManager.moveAppToken(lastReparentPos, p);
6871 mWindowManager.setAppGroupId(p, p.task.taskId);
6872 if (VALIDATE_TOKENS) {
6873 mWindowManager.validateAppTokens(mHistory);
6874 }
6875 }
6876 replyChainEnd = -1;
6877
6878 // Now we've moved it in to place... but what if this is
6879 // a singleTop activity and we have put it on top of another
6880 // instance of the same activity? Then we drop the instance
6881 // below so it remains singleTop.
6882 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6883 for (int j=lastReparentPos-1; j>=0; j--) {
6884 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6885 if (p.finishing) {
6886 continue;
6887 }
6888 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6889 if (finishActivityLocked(p, j,
6890 Activity.RESULT_CANCELED, null, "replace")) {
6891 taskTopI--;
6892 lastReparentPos--;
6893 }
6894 }
6895 }
6896 }
6897 }
6898 }
6899
6900 target = below;
6901 targetI = i;
6902 }
6903
6904 return taskTop;
6905 }
6906
6907 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006908 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006909 */
6910 public void moveTaskToFront(int task) {
6911 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6912 "moveTaskToFront()");
6913
6914 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006915 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6916 Binder.getCallingUid(), "Task to front")) {
6917 return;
6918 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006919 final long origId = Binder.clearCallingIdentity();
6920 try {
6921 int N = mRecentTasks.size();
6922 for (int i=0; i<N; i++) {
6923 TaskRecord tr = mRecentTasks.get(i);
6924 if (tr.taskId == task) {
6925 moveTaskToFrontLocked(tr);
6926 return;
6927 }
6928 }
6929 for (int i=mHistory.size()-1; i>=0; i--) {
6930 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6931 if (hr.task.taskId == task) {
6932 moveTaskToFrontLocked(hr.task);
6933 return;
6934 }
6935 }
6936 } finally {
6937 Binder.restoreCallingIdentity(origId);
6938 }
6939 }
6940 }
6941
6942 private final void moveTaskToFrontLocked(TaskRecord tr) {
6943 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6944
6945 final int task = tr.taskId;
6946 int top = mHistory.size()-1;
6947
6948 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6949 // nothing to do!
6950 return;
6951 }
6952
6953 if (DEBUG_TRANSITION) Log.v(TAG,
6954 "Prepare to front transition: task=" + tr);
6955 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6956
6957 ArrayList moved = new ArrayList();
6958
6959 // Applying the affinities may have removed entries from the history,
6960 // so get the size again.
6961 top = mHistory.size()-1;
6962 int pos = top;
6963
6964 // Shift all activities with this task up to the top
6965 // of the stack, keeping them in the same internal order.
6966 while (pos >= 0) {
6967 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6968 if (localLOGV) Log.v(
6969 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6970 boolean first = true;
6971 if (r.task.taskId == task) {
6972 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6973 mHistory.remove(pos);
6974 mHistory.add(top, r);
6975 moved.add(0, r);
6976 top--;
6977 if (first) {
6978 addRecentTask(r.task);
6979 first = false;
6980 }
6981 }
6982 pos--;
6983 }
6984
6985 mWindowManager.moveAppTokensToTop(moved);
6986 if (VALIDATE_TOKENS) {
6987 mWindowManager.validateAppTokens(mHistory);
6988 }
6989
6990 finishTaskMove(task);
6991 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6992 }
6993
6994 private final void finishTaskMove(int task) {
6995 resumeTopActivityLocked(null);
6996 }
6997
6998 public void moveTaskToBack(int task) {
6999 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7000 "moveTaskToBack()");
7001
7002 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007003 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7004 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7005 Binder.getCallingUid(), "Task to back")) {
7006 return;
7007 }
7008 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007009 final long origId = Binder.clearCallingIdentity();
7010 moveTaskToBackLocked(task);
7011 Binder.restoreCallingIdentity(origId);
7012 }
7013 }
7014
7015 /**
7016 * Moves an activity, and all of the other activities within the same task, to the bottom
7017 * of the history stack. The activity's order within the task is unchanged.
7018 *
7019 * @param token A reference to the activity we wish to move
7020 * @param nonRoot If false then this only works if the activity is the root
7021 * of a task; if true it will work for any activity in a task.
7022 * @return Returns true if the move completed, false if not.
7023 */
7024 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7025 synchronized(this) {
7026 final long origId = Binder.clearCallingIdentity();
7027 int taskId = getTaskForActivityLocked(token, !nonRoot);
7028 if (taskId >= 0) {
7029 return moveTaskToBackLocked(taskId);
7030 }
7031 Binder.restoreCallingIdentity(origId);
7032 }
7033 return false;
7034 }
7035
7036 /**
7037 * Worker method for rearranging history stack. Implements the function of moving all
7038 * activities for a specific task (gathering them if disjoint) into a single group at the
7039 * bottom of the stack.
7040 *
7041 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7042 * to premeptively cancel the move.
7043 *
7044 * @param task The taskId to collect and move to the bottom.
7045 * @return Returns true if the move completed, false if not.
7046 */
7047 private final boolean moveTaskToBackLocked(int task) {
7048 Log.i(TAG, "moveTaskToBack: " + task);
7049
7050 // If we have a watcher, preflight the move before committing to it. First check
7051 // for *other* available tasks, but if none are available, then try again allowing the
7052 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007053 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007054 HistoryRecord next = topRunningActivityLocked(null, task);
7055 if (next == null) {
7056 next = topRunningActivityLocked(null, 0);
7057 }
7058 if (next != null) {
7059 // ask watcher if this is allowed
7060 boolean moveOK = true;
7061 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007062 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007063 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007064 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007065 }
7066 if (!moveOK) {
7067 return false;
7068 }
7069 }
7070 }
7071
7072 ArrayList moved = new ArrayList();
7073
7074 if (DEBUG_TRANSITION) Log.v(TAG,
7075 "Prepare to back transition: task=" + task);
7076 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
7077
7078 final int N = mHistory.size();
7079 int bottom = 0;
7080 int pos = 0;
7081
7082 // Shift all activities with this task down to the bottom
7083 // of the stack, keeping them in the same internal order.
7084 while (pos < N) {
7085 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7086 if (localLOGV) Log.v(
7087 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7088 if (r.task.taskId == task) {
7089 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7090 mHistory.remove(pos);
7091 mHistory.add(bottom, r);
7092 moved.add(r);
7093 bottom++;
7094 }
7095 pos++;
7096 }
7097
7098 mWindowManager.moveAppTokensToBottom(moved);
7099 if (VALIDATE_TOKENS) {
7100 mWindowManager.validateAppTokens(mHistory);
7101 }
7102
7103 finishTaskMove(task);
7104 return true;
7105 }
7106
7107 public void moveTaskBackwards(int task) {
7108 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7109 "moveTaskBackwards()");
7110
7111 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007112 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7113 Binder.getCallingUid(), "Task backwards")) {
7114 return;
7115 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007116 final long origId = Binder.clearCallingIdentity();
7117 moveTaskBackwardsLocked(task);
7118 Binder.restoreCallingIdentity(origId);
7119 }
7120 }
7121
7122 private final void moveTaskBackwardsLocked(int task) {
7123 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7124 }
7125
7126 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7127 synchronized(this) {
7128 return getTaskForActivityLocked(token, onlyRoot);
7129 }
7130 }
7131
7132 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7133 final int N = mHistory.size();
7134 TaskRecord lastTask = null;
7135 for (int i=0; i<N; i++) {
7136 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7137 if (r == token) {
7138 if (!onlyRoot || lastTask != r.task) {
7139 return r.task.taskId;
7140 }
7141 return -1;
7142 }
7143 lastTask = r.task;
7144 }
7145
7146 return -1;
7147 }
7148
7149 /**
7150 * Returns the top activity in any existing task matching the given
7151 * Intent. Returns null if no such task is found.
7152 */
7153 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7154 ComponentName cls = intent.getComponent();
7155 if (info.targetActivity != null) {
7156 cls = new ComponentName(info.packageName, info.targetActivity);
7157 }
7158
7159 TaskRecord cp = null;
7160
7161 final int N = mHistory.size();
7162 for (int i=(N-1); i>=0; i--) {
7163 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7164 if (!r.finishing && r.task != cp
7165 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7166 cp = r.task;
7167 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7168 // + "/aff=" + r.task.affinity + " to new cls="
7169 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7170 if (r.task.affinity != null) {
7171 if (r.task.affinity.equals(info.taskAffinity)) {
7172 //Log.i(TAG, "Found matching affinity!");
7173 return r;
7174 }
7175 } else if (r.task.intent != null
7176 && r.task.intent.getComponent().equals(cls)) {
7177 //Log.i(TAG, "Found matching class!");
7178 //dump();
7179 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7180 return r;
7181 } else if (r.task.affinityIntent != null
7182 && r.task.affinityIntent.getComponent().equals(cls)) {
7183 //Log.i(TAG, "Found matching class!");
7184 //dump();
7185 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7186 return r;
7187 }
7188 }
7189 }
7190
7191 return null;
7192 }
7193
7194 /**
7195 * Returns the first activity (starting from the top of the stack) that
7196 * is the same as the given activity. Returns null if no such activity
7197 * is found.
7198 */
7199 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7200 ComponentName cls = intent.getComponent();
7201 if (info.targetActivity != null) {
7202 cls = new ComponentName(info.packageName, info.targetActivity);
7203 }
7204
7205 final int N = mHistory.size();
7206 for (int i=(N-1); i>=0; i--) {
7207 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7208 if (!r.finishing) {
7209 if (r.intent.getComponent().equals(cls)) {
7210 //Log.i(TAG, "Found matching class!");
7211 //dump();
7212 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7213 return r;
7214 }
7215 }
7216 }
7217
7218 return null;
7219 }
7220
7221 public void finishOtherInstances(IBinder token, ComponentName className) {
7222 synchronized(this) {
7223 final long origId = Binder.clearCallingIdentity();
7224
7225 int N = mHistory.size();
7226 TaskRecord lastTask = null;
7227 for (int i=0; i<N; i++) {
7228 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7229 if (r.realActivity.equals(className)
7230 && r != token && lastTask != r.task) {
7231 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7232 null, "others")) {
7233 i--;
7234 N--;
7235 }
7236 }
7237 lastTask = r.task;
7238 }
7239
7240 Binder.restoreCallingIdentity(origId);
7241 }
7242 }
7243
7244 // =========================================================
7245 // THUMBNAILS
7246 // =========================================================
7247
7248 public void reportThumbnail(IBinder token,
7249 Bitmap thumbnail, CharSequence description) {
7250 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7251 final long origId = Binder.clearCallingIdentity();
7252 sendPendingThumbnail(null, token, thumbnail, description, true);
7253 Binder.restoreCallingIdentity(origId);
7254 }
7255
7256 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7257 Bitmap thumbnail, CharSequence description, boolean always) {
7258 TaskRecord task = null;
7259 ArrayList receivers = null;
7260
7261 //System.out.println("Send pending thumbnail: " + r);
7262
7263 synchronized(this) {
7264 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007265 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007266 if (index < 0) {
7267 return;
7268 }
7269 r = (HistoryRecord)mHistory.get(index);
7270 }
7271 if (thumbnail == null) {
7272 thumbnail = r.thumbnail;
7273 description = r.description;
7274 }
7275 if (thumbnail == null && !always) {
7276 // If there is no thumbnail, and this entry is not actually
7277 // going away, then abort for now and pick up the next
7278 // thumbnail we get.
7279 return;
7280 }
7281 task = r.task;
7282
7283 int N = mPendingThumbnails.size();
7284 int i=0;
7285 while (i<N) {
7286 PendingThumbnailsRecord pr =
7287 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7288 //System.out.println("Looking in " + pr.pendingRecords);
7289 if (pr.pendingRecords.remove(r)) {
7290 if (receivers == null) {
7291 receivers = new ArrayList();
7292 }
7293 receivers.add(pr);
7294 if (pr.pendingRecords.size() == 0) {
7295 pr.finished = true;
7296 mPendingThumbnails.remove(i);
7297 N--;
7298 continue;
7299 }
7300 }
7301 i++;
7302 }
7303 }
7304
7305 if (receivers != null) {
7306 final int N = receivers.size();
7307 for (int i=0; i<N; i++) {
7308 try {
7309 PendingThumbnailsRecord pr =
7310 (PendingThumbnailsRecord)receivers.get(i);
7311 pr.receiver.newThumbnail(
7312 task != null ? task.taskId : -1, thumbnail, description);
7313 if (pr.finished) {
7314 pr.receiver.finished();
7315 }
7316 } catch (Exception e) {
7317 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7318 }
7319 }
7320 }
7321 }
7322
7323 // =========================================================
7324 // CONTENT PROVIDERS
7325 // =========================================================
7326
7327 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7328 List providers = null;
7329 try {
7330 providers = ActivityThread.getPackageManager().
7331 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007332 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007333 } catch (RemoteException ex) {
7334 }
7335 if (providers != null) {
7336 final int N = providers.size();
7337 for (int i=0; i<N; i++) {
7338 ProviderInfo cpi =
7339 (ProviderInfo)providers.get(i);
7340 ContentProviderRecord cpr =
7341 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7342 if (cpr == null) {
7343 cpr = new ContentProviderRecord(cpi, app.info);
7344 mProvidersByClass.put(cpi.name, cpr);
7345 }
7346 app.pubProviders.put(cpi.name, cpr);
7347 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007348 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007349 }
7350 }
7351 return providers;
7352 }
7353
7354 private final String checkContentProviderPermissionLocked(
7355 ProviderInfo cpi, ProcessRecord r, int mode) {
7356 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7357 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7358 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7359 cpi.exported ? -1 : cpi.applicationInfo.uid)
7360 == PackageManager.PERMISSION_GRANTED
7361 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7362 return null;
7363 }
7364 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7365 cpi.exported ? -1 : cpi.applicationInfo.uid)
7366 == PackageManager.PERMISSION_GRANTED) {
7367 return null;
7368 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007369
7370 PathPermission[] pps = cpi.pathPermissions;
7371 if (pps != null) {
7372 int i = pps.length;
7373 while (i > 0) {
7374 i--;
7375 PathPermission pp = pps[i];
7376 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7377 cpi.exported ? -1 : cpi.applicationInfo.uid)
7378 == PackageManager.PERMISSION_GRANTED
7379 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7380 return null;
7381 }
7382 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7383 cpi.exported ? -1 : cpi.applicationInfo.uid)
7384 == PackageManager.PERMISSION_GRANTED) {
7385 return null;
7386 }
7387 }
7388 }
7389
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007390 String msg = "Permission Denial: opening provider " + cpi.name
7391 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7392 + ", uid=" + callingUid + ") requires "
7393 + cpi.readPermission + " or " + cpi.writePermission;
7394 Log.w(TAG, msg);
7395 return msg;
7396 }
7397
7398 private final ContentProviderHolder getContentProviderImpl(
7399 IApplicationThread caller, String name) {
7400 ContentProviderRecord cpr;
7401 ProviderInfo cpi = null;
7402
7403 synchronized(this) {
7404 ProcessRecord r = null;
7405 if (caller != null) {
7406 r = getRecordForAppLocked(caller);
7407 if (r == null) {
7408 throw new SecurityException(
7409 "Unable to find app for caller " + caller
7410 + " (pid=" + Binder.getCallingPid()
7411 + ") when getting content provider " + name);
7412 }
7413 }
7414
7415 // First check if this content provider has been published...
7416 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7417 if (cpr != null) {
7418 cpi = cpr.info;
7419 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7420 return new ContentProviderHolder(cpi,
7421 cpi.readPermission != null
7422 ? cpi.readPermission : cpi.writePermission);
7423 }
7424
7425 if (r != null && cpr.canRunHere(r)) {
7426 // This provider has been published or is in the process
7427 // of being published... but it is also allowed to run
7428 // in the caller's process, so don't make a connection
7429 // and just let the caller instantiate its own instance.
7430 if (cpr.provider != null) {
7431 // don't give caller the provider object, it needs
7432 // to make its own.
7433 cpr = new ContentProviderRecord(cpr);
7434 }
7435 return cpr;
7436 }
7437
7438 final long origId = Binder.clearCallingIdentity();
7439
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007440 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007441 // return it right away.
7442 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007443 if (DEBUG_PROVIDER) Log.v(TAG,
7444 "Adding provider requested by "
7445 + r.processName + " from process "
7446 + cpr.info.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007447 r.conProviders.add(cpr);
7448 cpr.clients.add(r);
7449 } else {
7450 cpr.externals++;
7451 }
7452
7453 if (cpr.app != null) {
7454 updateOomAdjLocked(cpr.app);
7455 }
7456
7457 Binder.restoreCallingIdentity(origId);
7458
7459 } else {
7460 try {
7461 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007462 resolveContentProvider(name,
7463 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007464 } catch (RemoteException ex) {
7465 }
7466 if (cpi == null) {
7467 return null;
7468 }
7469
7470 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7471 return new ContentProviderHolder(cpi,
7472 cpi.readPermission != null
7473 ? cpi.readPermission : cpi.writePermission);
7474 }
7475
7476 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7477 final boolean firstClass = cpr == null;
7478 if (firstClass) {
7479 try {
7480 ApplicationInfo ai =
7481 ActivityThread.getPackageManager().
7482 getApplicationInfo(
7483 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007484 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007485 if (ai == null) {
7486 Log.w(TAG, "No package info for content provider "
7487 + cpi.name);
7488 return null;
7489 }
7490 cpr = new ContentProviderRecord(cpi, ai);
7491 } catch (RemoteException ex) {
7492 // pm is in same process, this will never happen.
7493 }
7494 }
7495
7496 if (r != null && cpr.canRunHere(r)) {
7497 // If this is a multiprocess provider, then just return its
7498 // info and allow the caller to instantiate it. Only do
7499 // this if the provider is the same user as the caller's
7500 // process, or can run as root (so can be in any process).
7501 return cpr;
7502 }
7503
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007504 if (DEBUG_PROVIDER) {
7505 RuntimeException e = new RuntimeException("here");
7506 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7507 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007508 }
7509
7510 // This is single process, and our app is now connecting to it.
7511 // See if we are already in the process of launching this
7512 // provider.
7513 final int N = mLaunchingProviders.size();
7514 int i;
7515 for (i=0; i<N; i++) {
7516 if (mLaunchingProviders.get(i) == cpr) {
7517 break;
7518 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007519 }
7520
7521 // If the provider is not already being launched, then get it
7522 // started.
7523 if (i >= N) {
7524 final long origId = Binder.clearCallingIdentity();
7525 ProcessRecord proc = startProcessLocked(cpi.processName,
7526 cpr.appInfo, false, 0, "content provider",
7527 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007528 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007529 if (proc == null) {
7530 Log.w(TAG, "Unable to launch app "
7531 + cpi.applicationInfo.packageName + "/"
7532 + cpi.applicationInfo.uid + " for provider "
7533 + name + ": process is bad");
7534 return null;
7535 }
7536 cpr.launchingApp = proc;
7537 mLaunchingProviders.add(cpr);
7538 Binder.restoreCallingIdentity(origId);
7539 }
7540
7541 // Make sure the provider is published (the same provider class
7542 // may be published under multiple names).
7543 if (firstClass) {
7544 mProvidersByClass.put(cpi.name, cpr);
7545 }
7546 mProvidersByName.put(name, cpr);
7547
7548 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007549 if (DEBUG_PROVIDER) Log.v(TAG,
7550 "Adding provider requested by "
7551 + r.processName + " from process "
7552 + cpr.info.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007553 r.conProviders.add(cpr);
7554 cpr.clients.add(r);
7555 } else {
7556 cpr.externals++;
7557 }
7558 }
7559 }
7560
7561 // Wait for the provider to be published...
7562 synchronized (cpr) {
7563 while (cpr.provider == null) {
7564 if (cpr.launchingApp == null) {
7565 Log.w(TAG, "Unable to launch app "
7566 + cpi.applicationInfo.packageName + "/"
7567 + cpi.applicationInfo.uid + " for provider "
7568 + name + ": launching app became null");
7569 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7570 cpi.applicationInfo.packageName,
7571 cpi.applicationInfo.uid, name);
7572 return null;
7573 }
7574 try {
7575 cpr.wait();
7576 } catch (InterruptedException ex) {
7577 }
7578 }
7579 }
7580 return cpr;
7581 }
7582
7583 public final ContentProviderHolder getContentProvider(
7584 IApplicationThread caller, String name) {
7585 if (caller == null) {
7586 String msg = "null IApplicationThread when getting content provider "
7587 + name;
7588 Log.w(TAG, msg);
7589 throw new SecurityException(msg);
7590 }
7591
7592 return getContentProviderImpl(caller, name);
7593 }
7594
7595 private ContentProviderHolder getContentProviderExternal(String name) {
7596 return getContentProviderImpl(null, name);
7597 }
7598
7599 /**
7600 * Drop a content provider from a ProcessRecord's bookkeeping
7601 * @param cpr
7602 */
7603 public void removeContentProvider(IApplicationThread caller, String name) {
7604 synchronized (this) {
7605 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7606 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007607 // remove from mProvidersByClass
7608 if (DEBUG_PROVIDER) Log.v(TAG, name +
7609 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007610 return;
7611 }
7612 final ProcessRecord r = getRecordForAppLocked(caller);
7613 if (r == null) {
7614 throw new SecurityException(
7615 "Unable to find app for caller " + caller +
7616 " when removing content provider " + name);
7617 }
7618 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007619 ContentProviderRecord localCpr = (ContentProviderRecord)
7620 mProvidersByClass.get(cpr.info.name);
7621 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7622 + r.info.processName + " from process "
7623 + localCpr.appInfo.processName);
7624 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007625 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007626 Log.w(TAG, "removeContentProvider called on local provider: "
7627 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007628 return;
7629 } else {
7630 localCpr.clients.remove(r);
7631 r.conProviders.remove(localCpr);
7632 }
7633 updateOomAdjLocked();
7634 }
7635 }
7636
7637 private void removeContentProviderExternal(String name) {
7638 synchronized (this) {
7639 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7640 if(cpr == null) {
7641 //remove from mProvidersByClass
7642 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7643 return;
7644 }
7645
7646 //update content provider record entry info
7647 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7648 localCpr.externals--;
7649 if (localCpr.externals < 0) {
7650 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7651 }
7652 updateOomAdjLocked();
7653 }
7654 }
7655
7656 public final void publishContentProviders(IApplicationThread caller,
7657 List<ContentProviderHolder> providers) {
7658 if (providers == null) {
7659 return;
7660 }
7661
7662 synchronized(this) {
7663 final ProcessRecord r = getRecordForAppLocked(caller);
7664 if (r == null) {
7665 throw new SecurityException(
7666 "Unable to find app for caller " + caller
7667 + " (pid=" + Binder.getCallingPid()
7668 + ") when publishing content providers");
7669 }
7670
7671 final long origId = Binder.clearCallingIdentity();
7672
7673 final int N = providers.size();
7674 for (int i=0; i<N; i++) {
7675 ContentProviderHolder src = providers.get(i);
7676 if (src == null || src.info == null || src.provider == null) {
7677 continue;
7678 }
7679 ContentProviderRecord dst =
7680 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7681 if (dst != null) {
7682 mProvidersByClass.put(dst.info.name, dst);
7683 String names[] = dst.info.authority.split(";");
7684 for (int j = 0; j < names.length; j++) {
7685 mProvidersByName.put(names[j], dst);
7686 }
7687
7688 int NL = mLaunchingProviders.size();
7689 int j;
7690 for (j=0; j<NL; j++) {
7691 if (mLaunchingProviders.get(j) == dst) {
7692 mLaunchingProviders.remove(j);
7693 j--;
7694 NL--;
7695 }
7696 }
7697 synchronized (dst) {
7698 dst.provider = src.provider;
7699 dst.app = r;
7700 dst.notifyAll();
7701 }
7702 updateOomAdjLocked(r);
7703 }
7704 }
7705
7706 Binder.restoreCallingIdentity(origId);
7707 }
7708 }
7709
7710 public static final void installSystemProviders() {
7711 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7712 List providers = mSelf.generateApplicationProvidersLocked(app);
7713 mSystemThread.installSystemProviders(providers);
7714 }
7715
7716 // =========================================================
7717 // GLOBAL MANAGEMENT
7718 // =========================================================
7719
7720 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7721 ApplicationInfo info, String customProcess) {
7722 String proc = customProcess != null ? customProcess : info.processName;
7723 BatteryStatsImpl.Uid.Proc ps = null;
7724 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7725 synchronized (stats) {
7726 ps = stats.getProcessStatsLocked(info.uid, proc);
7727 }
7728 return new ProcessRecord(ps, thread, info, proc);
7729 }
7730
7731 final ProcessRecord addAppLocked(ApplicationInfo info) {
7732 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7733
7734 if (app == null) {
7735 app = newProcessRecordLocked(null, info, null);
7736 mProcessNames.put(info.processName, info.uid, app);
7737 updateLRUListLocked(app, true);
7738 }
7739
7740 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7741 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7742 app.persistent = true;
7743 app.maxAdj = CORE_SERVER_ADJ;
7744 }
7745 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7746 mPersistentStartingProcesses.add(app);
7747 startProcessLocked(app, "added application", app.processName);
7748 }
7749
7750 return app;
7751 }
7752
7753 public void unhandledBack() {
7754 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7755 "unhandledBack()");
7756
7757 synchronized(this) {
7758 int count = mHistory.size();
7759 if (Config.LOGD) Log.d(
7760 TAG, "Performing unhandledBack(): stack size = " + count);
7761 if (count > 1) {
7762 final long origId = Binder.clearCallingIdentity();
7763 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7764 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7765 Binder.restoreCallingIdentity(origId);
7766 }
7767 }
7768 }
7769
7770 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7771 String name = uri.getAuthority();
7772 ContentProviderHolder cph = getContentProviderExternal(name);
7773 ParcelFileDescriptor pfd = null;
7774 if (cph != null) {
7775 // We record the binder invoker's uid in thread-local storage before
7776 // going to the content provider to open the file. Later, in the code
7777 // that handles all permissions checks, we look for this uid and use
7778 // that rather than the Activity Manager's own uid. The effect is that
7779 // we do the check against the caller's permissions even though it looks
7780 // to the content provider like the Activity Manager itself is making
7781 // the request.
7782 sCallerIdentity.set(new Identity(
7783 Binder.getCallingPid(), Binder.getCallingUid()));
7784 try {
7785 pfd = cph.provider.openFile(uri, "r");
7786 } catch (FileNotFoundException e) {
7787 // do nothing; pfd will be returned null
7788 } finally {
7789 // Ensure that whatever happens, we clean up the identity state
7790 sCallerIdentity.remove();
7791 }
7792
7793 // We've got the fd now, so we're done with the provider.
7794 removeContentProviderExternal(name);
7795 } else {
7796 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7797 }
7798 return pfd;
7799 }
7800
7801 public void goingToSleep() {
7802 synchronized(this) {
7803 mSleeping = true;
7804 mWindowManager.setEventDispatching(false);
7805
7806 if (mResumedActivity != null) {
7807 pauseIfSleepingLocked();
7808 } else {
7809 Log.w(TAG, "goingToSleep with no resumed activity!");
7810 }
7811 }
7812 }
7813
Dianne Hackborn55280a92009-05-07 15:53:46 -07007814 public boolean shutdown(int timeout) {
7815 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7816 != PackageManager.PERMISSION_GRANTED) {
7817 throw new SecurityException("Requires permission "
7818 + android.Manifest.permission.SHUTDOWN);
7819 }
7820
7821 boolean timedout = false;
7822
7823 synchronized(this) {
7824 mShuttingDown = true;
7825 mWindowManager.setEventDispatching(false);
7826
7827 if (mResumedActivity != null) {
7828 pauseIfSleepingLocked();
7829 final long endTime = System.currentTimeMillis() + timeout;
7830 while (mResumedActivity != null || mPausingActivity != null) {
7831 long delay = endTime - System.currentTimeMillis();
7832 if (delay <= 0) {
7833 Log.w(TAG, "Activity manager shutdown timed out");
7834 timedout = true;
7835 break;
7836 }
7837 try {
7838 this.wait();
7839 } catch (InterruptedException e) {
7840 }
7841 }
7842 }
7843 }
7844
7845 mUsageStatsService.shutdown();
7846 mBatteryStatsService.shutdown();
7847
7848 return timedout;
7849 }
7850
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007851 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007852 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007853 if (!mGoingToSleep.isHeld()) {
7854 mGoingToSleep.acquire();
7855 if (mLaunchingActivity.isHeld()) {
7856 mLaunchingActivity.release();
7857 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7858 }
7859 }
7860
7861 // If we are not currently pausing an activity, get the current
7862 // one to pause. If we are pausing one, we will just let that stuff
7863 // run and release the wake lock when all done.
7864 if (mPausingActivity == null) {
7865 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7866 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7867 startPausingLocked(false, true);
7868 }
7869 }
7870 }
7871
7872 public void wakingUp() {
7873 synchronized(this) {
7874 if (mGoingToSleep.isHeld()) {
7875 mGoingToSleep.release();
7876 }
7877 mWindowManager.setEventDispatching(true);
7878 mSleeping = false;
7879 resumeTopActivityLocked(null);
7880 }
7881 }
7882
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007883 public void stopAppSwitches() {
7884 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7885 != PackageManager.PERMISSION_GRANTED) {
7886 throw new SecurityException("Requires permission "
7887 + android.Manifest.permission.STOP_APP_SWITCHES);
7888 }
7889
7890 synchronized(this) {
7891 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7892 + APP_SWITCH_DELAY_TIME;
7893 mDidAppSwitch = false;
7894 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7895 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7896 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7897 }
7898 }
7899
7900 public void resumeAppSwitches() {
7901 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7902 != PackageManager.PERMISSION_GRANTED) {
7903 throw new SecurityException("Requires permission "
7904 + android.Manifest.permission.STOP_APP_SWITCHES);
7905 }
7906
7907 synchronized(this) {
7908 // Note that we don't execute any pending app switches... we will
7909 // let those wait until either the timeout, or the next start
7910 // activity request.
7911 mAppSwitchesAllowedTime = 0;
7912 }
7913 }
7914
7915 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7916 String name) {
7917 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7918 return true;
7919 }
7920
7921 final int perm = checkComponentPermission(
7922 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7923 callingUid, -1);
7924 if (perm == PackageManager.PERMISSION_GRANTED) {
7925 return true;
7926 }
7927
7928 Log.w(TAG, name + " request from " + callingUid + " stopped");
7929 return false;
7930 }
7931
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007932 public void setDebugApp(String packageName, boolean waitForDebugger,
7933 boolean persistent) {
7934 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7935 "setDebugApp()");
7936
7937 // Note that this is not really thread safe if there are multiple
7938 // callers into it at the same time, but that's not a situation we
7939 // care about.
7940 if (persistent) {
7941 final ContentResolver resolver = mContext.getContentResolver();
7942 Settings.System.putString(
7943 resolver, Settings.System.DEBUG_APP,
7944 packageName);
7945 Settings.System.putInt(
7946 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7947 waitForDebugger ? 1 : 0);
7948 }
7949
7950 synchronized (this) {
7951 if (!persistent) {
7952 mOrigDebugApp = mDebugApp;
7953 mOrigWaitForDebugger = mWaitForDebugger;
7954 }
7955 mDebugApp = packageName;
7956 mWaitForDebugger = waitForDebugger;
7957 mDebugTransient = !persistent;
7958 if (packageName != null) {
7959 final long origId = Binder.clearCallingIdentity();
7960 uninstallPackageLocked(packageName, -1, false);
7961 Binder.restoreCallingIdentity(origId);
7962 }
7963 }
7964 }
7965
7966 public void setAlwaysFinish(boolean enabled) {
7967 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7968 "setAlwaysFinish()");
7969
7970 Settings.System.putInt(
7971 mContext.getContentResolver(),
7972 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7973
7974 synchronized (this) {
7975 mAlwaysFinishActivities = enabled;
7976 }
7977 }
7978
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007979 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007980 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007981 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007982 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007983 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007984 }
7985 }
7986
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007987 public void registerActivityWatcher(IActivityWatcher watcher) {
7988 mWatchers.register(watcher);
7989 }
7990
7991 public void unregisterActivityWatcher(IActivityWatcher watcher) {
7992 mWatchers.unregister(watcher);
7993 }
7994
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007995 public final void enterSafeMode() {
7996 synchronized(this) {
7997 // It only makes sense to do this before the system is ready
7998 // and started launching other packages.
7999 if (!mSystemReady) {
8000 try {
8001 ActivityThread.getPackageManager().enterSafeMode();
8002 } catch (RemoteException e) {
8003 }
8004
8005 View v = LayoutInflater.from(mContext).inflate(
8006 com.android.internal.R.layout.safe_mode, null);
8007 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8008 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8009 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8010 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8011 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8012 lp.format = v.getBackground().getOpacity();
8013 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8014 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8015 ((WindowManager)mContext.getSystemService(
8016 Context.WINDOW_SERVICE)).addView(v, lp);
8017 }
8018 }
8019 }
8020
8021 public void noteWakeupAlarm(IIntentSender sender) {
8022 if (!(sender instanceof PendingIntentRecord)) {
8023 return;
8024 }
8025 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8026 synchronized (stats) {
8027 if (mBatteryStatsService.isOnBattery()) {
8028 mBatteryStatsService.enforceCallingPermission();
8029 PendingIntentRecord rec = (PendingIntentRecord)sender;
8030 int MY_UID = Binder.getCallingUid();
8031 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8032 BatteryStatsImpl.Uid.Pkg pkg =
8033 stats.getPackageStatsLocked(uid, rec.key.packageName);
8034 pkg.incWakeupsLocked();
8035 }
8036 }
8037 }
8038
8039 public boolean killPidsForMemory(int[] pids) {
8040 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8041 throw new SecurityException("killPidsForMemory only available to the system");
8042 }
8043
8044 // XXX Note: don't acquire main activity lock here, because the window
8045 // manager calls in with its locks held.
8046
8047 boolean killed = false;
8048 synchronized (mPidsSelfLocked) {
8049 int[] types = new int[pids.length];
8050 int worstType = 0;
8051 for (int i=0; i<pids.length; i++) {
8052 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8053 if (proc != null) {
8054 int type = proc.setAdj;
8055 types[i] = type;
8056 if (type > worstType) {
8057 worstType = type;
8058 }
8059 }
8060 }
8061
8062 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8063 // then constrain it so we will kill all hidden procs.
8064 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8065 worstType = HIDDEN_APP_MIN_ADJ;
8066 }
8067 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8068 for (int i=0; i<pids.length; i++) {
8069 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8070 if (proc == null) {
8071 continue;
8072 }
8073 int adj = proc.setAdj;
8074 if (adj >= worstType) {
8075 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8076 + adj + ")");
8077 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
8078 proc.processName, adj);
8079 killed = true;
8080 Process.killProcess(pids[i]);
8081 }
8082 }
8083 }
8084 return killed;
8085 }
8086
8087 public void reportPss(IApplicationThread caller, int pss) {
8088 Watchdog.PssRequestor req;
8089 String name;
8090 ProcessRecord callerApp;
8091 synchronized (this) {
8092 if (caller == null) {
8093 return;
8094 }
8095 callerApp = getRecordForAppLocked(caller);
8096 if (callerApp == null) {
8097 return;
8098 }
8099 callerApp.lastPss = pss;
8100 req = callerApp;
8101 name = callerApp.processName;
8102 }
8103 Watchdog.getInstance().reportPss(req, name, pss);
8104 if (!callerApp.persistent) {
8105 removeRequestedPss(callerApp);
8106 }
8107 }
8108
8109 public void requestPss(Runnable completeCallback) {
8110 ArrayList<ProcessRecord> procs;
8111 synchronized (this) {
8112 mRequestPssCallback = completeCallback;
8113 mRequestPssList.clear();
8114 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8115 ProcessRecord proc = mLRUProcesses.get(i);
8116 if (!proc.persistent) {
8117 mRequestPssList.add(proc);
8118 }
8119 }
8120 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8121 }
8122
8123 int oldPri = Process.getThreadPriority(Process.myTid());
8124 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8125 for (int i=procs.size()-1; i>=0; i--) {
8126 ProcessRecord proc = procs.get(i);
8127 proc.lastPss = 0;
8128 proc.requestPss();
8129 }
8130 Process.setThreadPriority(oldPri);
8131 }
8132
8133 void removeRequestedPss(ProcessRecord proc) {
8134 Runnable callback = null;
8135 synchronized (this) {
8136 if (mRequestPssList.remove(proc)) {
8137 if (mRequestPssList.size() == 0) {
8138 callback = mRequestPssCallback;
8139 mRequestPssCallback = null;
8140 }
8141 }
8142 }
8143
8144 if (callback != null) {
8145 callback.run();
8146 }
8147 }
8148
8149 public void collectPss(Watchdog.PssStats stats) {
8150 stats.mEmptyPss = 0;
8151 stats.mEmptyCount = 0;
8152 stats.mBackgroundPss = 0;
8153 stats.mBackgroundCount = 0;
8154 stats.mServicePss = 0;
8155 stats.mServiceCount = 0;
8156 stats.mVisiblePss = 0;
8157 stats.mVisibleCount = 0;
8158 stats.mForegroundPss = 0;
8159 stats.mForegroundCount = 0;
8160 stats.mNoPssCount = 0;
8161 synchronized (this) {
8162 int i;
8163 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8164 ? mProcDeaths.length : stats.mProcDeaths.length;
8165 int aggr = 0;
8166 for (i=0; i<NPD; i++) {
8167 aggr += mProcDeaths[i];
8168 stats.mProcDeaths[i] = aggr;
8169 }
8170 while (i<stats.mProcDeaths.length) {
8171 stats.mProcDeaths[i] = 0;
8172 i++;
8173 }
8174
8175 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8176 ProcessRecord proc = mLRUProcesses.get(i);
8177 if (proc.persistent) {
8178 continue;
8179 }
8180 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8181 if (proc.lastPss == 0) {
8182 stats.mNoPssCount++;
8183 continue;
8184 }
8185 if (proc.setAdj == EMPTY_APP_ADJ) {
8186 stats.mEmptyPss += proc.lastPss;
8187 stats.mEmptyCount++;
8188 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8189 stats.mEmptyPss += proc.lastPss;
8190 stats.mEmptyCount++;
8191 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8192 stats.mBackgroundPss += proc.lastPss;
8193 stats.mBackgroundCount++;
8194 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8195 stats.mVisiblePss += proc.lastPss;
8196 stats.mVisibleCount++;
8197 } else {
8198 stats.mForegroundPss += proc.lastPss;
8199 stats.mForegroundCount++;
8200 }
8201 }
8202 }
8203 }
8204
8205 public final void startRunning(String pkg, String cls, String action,
8206 String data) {
8207 synchronized(this) {
8208 if (mStartRunning) {
8209 return;
8210 }
8211 mStartRunning = true;
8212 mTopComponent = pkg != null && cls != null
8213 ? new ComponentName(pkg, cls) : null;
8214 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8215 mTopData = data;
8216 if (!mSystemReady) {
8217 return;
8218 }
8219 }
8220
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008221 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008222 }
8223
8224 private void retrieveSettings() {
8225 final ContentResolver resolver = mContext.getContentResolver();
8226 String debugApp = Settings.System.getString(
8227 resolver, Settings.System.DEBUG_APP);
8228 boolean waitForDebugger = Settings.System.getInt(
8229 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8230 boolean alwaysFinishActivities = Settings.System.getInt(
8231 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8232
8233 Configuration configuration = new Configuration();
8234 Settings.System.getConfiguration(resolver, configuration);
8235
8236 synchronized (this) {
8237 mDebugApp = mOrigDebugApp = debugApp;
8238 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8239 mAlwaysFinishActivities = alwaysFinishActivities;
8240 // This happens before any activities are started, so we can
8241 // change mConfiguration in-place.
8242 mConfiguration.updateFrom(configuration);
8243 }
8244 }
8245
8246 public boolean testIsSystemReady() {
8247 // no need to synchronize(this) just to read & return the value
8248 return mSystemReady;
8249 }
8250
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008251 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008252 // In the simulator, startRunning will never have been called, which
8253 // normally sets a few crucial variables. Do it here instead.
8254 if (!Process.supportsProcesses()) {
8255 mStartRunning = true;
8256 mTopAction = Intent.ACTION_MAIN;
8257 }
8258
8259 synchronized(this) {
8260 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008261 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008262 return;
8263 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008264
8265 // Check to see if there are any update receivers to run.
8266 if (!mDidUpdate) {
8267 if (mWaitingUpdate) {
8268 return;
8269 }
8270 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8271 List<ResolveInfo> ris = null;
8272 try {
8273 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8274 intent, null, 0);
8275 } catch (RemoteException e) {
8276 }
8277 if (ris != null) {
8278 for (int i=ris.size()-1; i>=0; i--) {
8279 if ((ris.get(i).activityInfo.applicationInfo.flags
8280 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8281 ris.remove(i);
8282 }
8283 }
8284 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8285 for (int i=0; i<ris.size(); i++) {
8286 ActivityInfo ai = ris.get(i).activityInfo;
8287 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8288 IIntentReceiver finisher = null;
8289 if (i == 0) {
8290 finisher = new IIntentReceiver.Stub() {
8291 public void performReceive(Intent intent, int resultCode,
8292 String data, Bundle extras, boolean ordered)
8293 throws RemoteException {
8294 synchronized (ActivityManagerService.this) {
8295 mDidUpdate = true;
8296 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008297 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008298 }
8299 };
8300 }
8301 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8302 broadcastIntentLocked(null, null, intent, null, finisher,
8303 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8304 if (i == 0) {
8305 mWaitingUpdate = true;
8306 }
8307 }
8308 }
8309 if (mWaitingUpdate) {
8310 return;
8311 }
8312 mDidUpdate = true;
8313 }
8314
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008315 mSystemReady = true;
8316 if (!mStartRunning) {
8317 return;
8318 }
8319 }
8320
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008321 ArrayList<ProcessRecord> procsToKill = null;
8322 synchronized(mPidsSelfLocked) {
8323 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8324 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8325 if (!isAllowedWhileBooting(proc.info)){
8326 if (procsToKill == null) {
8327 procsToKill = new ArrayList<ProcessRecord>();
8328 }
8329 procsToKill.add(proc);
8330 }
8331 }
8332 }
8333
8334 if (procsToKill != null) {
8335 synchronized(this) {
8336 for (int i=procsToKill.size()-1; i>=0; i--) {
8337 ProcessRecord proc = procsToKill.get(i);
8338 Log.i(TAG, "Removing system update proc: " + proc);
8339 removeProcessLocked(proc, true);
8340 }
8341 }
8342 }
8343
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008344 Log.i(TAG, "System now ready");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008345 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8346 SystemClock.uptimeMillis());
8347
8348 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008349 // Make sure we have no pre-ready processes sitting around.
8350
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008351 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8352 ResolveInfo ri = mContext.getPackageManager()
8353 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008354 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008355 CharSequence errorMsg = null;
8356 if (ri != null) {
8357 ActivityInfo ai = ri.activityInfo;
8358 ApplicationInfo app = ai.applicationInfo;
8359 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8360 mTopAction = Intent.ACTION_FACTORY_TEST;
8361 mTopData = null;
8362 mTopComponent = new ComponentName(app.packageName,
8363 ai.name);
8364 } else {
8365 errorMsg = mContext.getResources().getText(
8366 com.android.internal.R.string.factorytest_not_system);
8367 }
8368 } else {
8369 errorMsg = mContext.getResources().getText(
8370 com.android.internal.R.string.factorytest_no_action);
8371 }
8372 if (errorMsg != null) {
8373 mTopAction = null;
8374 mTopData = null;
8375 mTopComponent = null;
8376 Message msg = Message.obtain();
8377 msg.what = SHOW_FACTORY_ERROR_MSG;
8378 msg.getData().putCharSequence("msg", errorMsg);
8379 mHandler.sendMessage(msg);
8380 }
8381 }
8382 }
8383
8384 retrieveSettings();
8385
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008386 if (goingCallback != null) goingCallback.run();
8387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008388 synchronized (this) {
8389 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8390 try {
8391 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008392 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008393 if (apps != null) {
8394 int N = apps.size();
8395 int i;
8396 for (i=0; i<N; i++) {
8397 ApplicationInfo info
8398 = (ApplicationInfo)apps.get(i);
8399 if (info != null &&
8400 !info.packageName.equals("android")) {
8401 addAppLocked(info);
8402 }
8403 }
8404 }
8405 } catch (RemoteException ex) {
8406 // pm is in same process, this will never happen.
8407 }
8408 }
8409
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008410 // Start up initial activity.
8411 mBooting = true;
8412
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008413 try {
8414 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8415 Message msg = Message.obtain();
8416 msg.what = SHOW_UID_ERROR_MSG;
8417 mHandler.sendMessage(msg);
8418 }
8419 } catch (RemoteException e) {
8420 }
8421
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008422 resumeTopActivityLocked(null);
8423 }
8424 }
8425
8426 boolean makeAppCrashingLocked(ProcessRecord app,
8427 String tag, String shortMsg, String longMsg, byte[] crashData) {
8428 app.crashing = true;
8429 app.crashingReport = generateProcessError(app,
8430 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8431 startAppProblemLocked(app);
8432 app.stopFreezingAllLocked();
8433 return handleAppCrashLocked(app);
8434 }
8435
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008436 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Jacek Surazskia2339432009-09-18 15:01:26 +02008437 // check if error reporting is enabled in Gservices
8438 int enabled = Settings.Gservices.getInt(mContext.getContentResolver(),
8439 Settings.Gservices.SEND_ACTION_APP_ERROR, 0);
8440 if (enabled == 0) {
8441 return null;
8442 }
8443
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008444 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008445
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008446 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008447 // look for receiver in the installer package
8448 String candidate = pm.getInstallerPackageName(app.info.packageName);
8449 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8450 if (result != null) {
8451 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008452 }
8453
Jacek Surazski82a73df2009-06-17 14:33:18 +02008454 // if the error app is on the system image, look for system apps
8455 // error receiver
8456 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8457 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8458 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8459 if (result != null) {
8460 return result;
8461 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008462 }
8463
Jacek Surazski82a73df2009-06-17 14:33:18 +02008464 // if there is a default receiver, try that
8465 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8466 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008467 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008468 // should not happen
8469 Log.e(TAG, "error talking to PackageManager", e);
8470 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008471 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008472 }
8473
8474 /**
8475 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8476 *
8477 * @param pm PackageManager isntance
8478 * @param errorPackage package which caused the error
8479 * @param receiverPackage candidate package to receive the error
8480 * @return activity component within receiverPackage which handles
8481 * ACTION_APP_ERROR, or null if not found
8482 */
8483 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8484 String receiverPackage) throws RemoteException {
8485 if (receiverPackage == null || receiverPackage.length() == 0) {
8486 return null;
8487 }
8488
8489 // break the loop if it's the error report receiver package that crashed
8490 if (receiverPackage.equals(errorPackage)) {
8491 return null;
8492 }
8493
8494 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8495 intent.setPackage(receiverPackage);
8496 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8497 if (info == null || info.activityInfo == null) {
8498 return null;
8499 }
8500 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008501 }
8502
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008503 void makeAppNotRespondingLocked(ProcessRecord app,
8504 String tag, String shortMsg, String longMsg, byte[] crashData) {
8505 app.notResponding = true;
8506 app.notRespondingReport = generateProcessError(app,
8507 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8508 crashData);
8509 startAppProblemLocked(app);
8510 app.stopFreezingAllLocked();
8511 }
8512
8513 /**
8514 * Generate a process error record, suitable for attachment to a ProcessRecord.
8515 *
8516 * @param app The ProcessRecord in which the error occurred.
8517 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8518 * ActivityManager.AppErrorStateInfo
8519 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8520 * @param shortMsg Short message describing the crash.
8521 * @param longMsg Long message describing the crash.
8522 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8523 *
8524 * @return Returns a fully-formed AppErrorStateInfo record.
8525 */
8526 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8527 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8528 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8529
8530 report.condition = condition;
8531 report.processName = app.processName;
8532 report.pid = app.pid;
8533 report.uid = app.info.uid;
8534 report.tag = tag;
8535 report.shortMsg = shortMsg;
8536 report.longMsg = longMsg;
8537 report.crashData = crashData;
8538
8539 return report;
8540 }
8541
8542 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8543 boolean crashed) {
8544 synchronized (this) {
8545 app.crashing = false;
8546 app.crashingReport = null;
8547 app.notResponding = false;
8548 app.notRespondingReport = null;
8549 if (app.anrDialog == fromDialog) {
8550 app.anrDialog = null;
8551 }
8552 if (app.waitDialog == fromDialog) {
8553 app.waitDialog = null;
8554 }
8555 if (app.pid > 0 && app.pid != MY_PID) {
8556 if (crashed) {
8557 handleAppCrashLocked(app);
8558 }
8559 Log.i(ActivityManagerService.TAG, "Killing process "
8560 + app.processName
8561 + " (pid=" + app.pid + ") at user's request");
8562 Process.killProcess(app.pid);
8563 }
8564
8565 }
8566 }
8567
8568 boolean handleAppCrashLocked(ProcessRecord app) {
8569 long now = SystemClock.uptimeMillis();
8570
8571 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8572 app.info.uid);
8573 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8574 // This process loses!
8575 Log.w(TAG, "Process " + app.info.processName
8576 + " has crashed too many times: killing!");
8577 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8578 app.info.processName, app.info.uid);
8579 killServicesLocked(app, false);
8580 for (int i=mHistory.size()-1; i>=0; i--) {
8581 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8582 if (r.app == app) {
8583 if (Config.LOGD) Log.d(
8584 TAG, " Force finishing activity "
8585 + r.intent.getComponent().flattenToShortString());
8586 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8587 }
8588 }
8589 if (!app.persistent) {
8590 // We don't want to start this process again until the user
8591 // explicitly does so... but for persistent process, we really
8592 // need to keep it running. If a persistent process is actually
8593 // repeatedly crashing, then badness for everyone.
8594 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8595 app.info.processName);
8596 mBadProcesses.put(app.info.processName, app.info.uid, now);
8597 app.bad = true;
8598 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8599 app.removed = true;
8600 removeProcessLocked(app, false);
8601 return false;
8602 }
8603 }
8604
8605 // Bump up the crash count of any services currently running in the proc.
8606 if (app.services.size() != 0) {
8607 // Any services running in the application need to be placed
8608 // back in the pending list.
8609 Iterator it = app.services.iterator();
8610 while (it.hasNext()) {
8611 ServiceRecord sr = (ServiceRecord)it.next();
8612 sr.crashCount++;
8613 }
8614 }
8615
8616 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8617 return true;
8618 }
8619
8620 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008621 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008622 skipCurrentReceiverLocked(app);
8623 }
8624
8625 void skipCurrentReceiverLocked(ProcessRecord app) {
8626 boolean reschedule = false;
8627 BroadcastRecord r = app.curReceiver;
8628 if (r != null) {
8629 // The current broadcast is waiting for this app's receiver
8630 // to be finished. Looks like that's not going to happen, so
8631 // let the broadcast continue.
8632 logBroadcastReceiverDiscard(r);
8633 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8634 r.resultExtras, r.resultAbort, true);
8635 reschedule = true;
8636 }
8637 r = mPendingBroadcast;
8638 if (r != null && r.curApp == app) {
8639 if (DEBUG_BROADCAST) Log.v(TAG,
8640 "skip & discard pending app " + r);
8641 logBroadcastReceiverDiscard(r);
8642 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8643 r.resultExtras, r.resultAbort, true);
8644 reschedule = true;
8645 }
8646 if (reschedule) {
8647 scheduleBroadcastsLocked();
8648 }
8649 }
8650
8651 public int handleApplicationError(IBinder app, int flags,
8652 String tag, String shortMsg, String longMsg, byte[] crashData) {
8653 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008654 ProcessRecord r = null;
8655 synchronized (this) {
8656 if (app != null) {
8657 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8658 final int NA = apps.size();
8659 for (int ia=0; ia<NA; ia++) {
8660 ProcessRecord p = apps.valueAt(ia);
8661 if (p.thread != null && p.thread.asBinder() == app) {
8662 r = p;
8663 break;
8664 }
8665 }
8666 }
8667 }
8668
8669 if (r != null) {
8670 // The application has crashed. Send the SIGQUIT to the process so
8671 // that it can dump its state.
8672 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8673 //Log.i(TAG, "Current system threads:");
8674 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8675 }
8676
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008677 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008678 try {
8679 String name = r != null ? r.processName : null;
8680 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008681 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008682 shortMsg, longMsg, crashData)) {
8683 Log.w(TAG, "Force-killing crashed app " + name
8684 + " at watcher's request");
8685 Process.killProcess(pid);
8686 return 0;
8687 }
8688 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008689 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008690 }
8691 }
8692
8693 final long origId = Binder.clearCallingIdentity();
8694
8695 // If this process is running instrumentation, finish it.
8696 if (r != null && r.instrumentationClass != null) {
8697 Log.w(TAG, "Error in app " + r.processName
8698 + " running instrumentation " + r.instrumentationClass + ":");
8699 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8700 if (longMsg != null) Log.w(TAG, " " + longMsg);
8701 Bundle info = new Bundle();
8702 info.putString("shortMsg", shortMsg);
8703 info.putString("longMsg", longMsg);
8704 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8705 Binder.restoreCallingIdentity(origId);
8706 return 0;
8707 }
8708
8709 if (r != null) {
8710 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8711 return 0;
8712 }
8713 } else {
8714 Log.w(TAG, "Some application object " + app + " tag " + tag
8715 + " has crashed, but I don't know who it is.");
8716 Log.w(TAG, "ShortMsg:" + shortMsg);
8717 Log.w(TAG, "LongMsg:" + longMsg);
8718 Binder.restoreCallingIdentity(origId);
8719 return 0;
8720 }
8721
8722 Message msg = Message.obtain();
8723 msg.what = SHOW_ERROR_MSG;
8724 HashMap data = new HashMap();
8725 data.put("result", result);
8726 data.put("app", r);
8727 data.put("flags", flags);
8728 data.put("shortMsg", shortMsg);
8729 data.put("longMsg", longMsg);
8730 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8731 // For system processes, submit crash data to the server.
8732 data.put("crashData", crashData);
8733 }
8734 msg.obj = data;
8735 mHandler.sendMessage(msg);
8736
8737 Binder.restoreCallingIdentity(origId);
8738 }
8739
8740 int res = result.get();
8741
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008742 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008743 synchronized (this) {
8744 if (r != null) {
8745 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8746 SystemClock.uptimeMillis());
8747 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008748 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8749 appErrorIntent = createAppErrorIntentLocked(r);
8750 res = AppErrorDialog.FORCE_QUIT;
8751 }
8752 }
8753
8754 if (appErrorIntent != null) {
8755 try {
8756 mContext.startActivity(appErrorIntent);
8757 } catch (ActivityNotFoundException e) {
8758 Log.w(TAG, "bug report receiver dissappeared", e);
8759 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008760 }
8761
8762 return res;
8763 }
8764
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008765 Intent createAppErrorIntentLocked(ProcessRecord r) {
8766 ApplicationErrorReport report = createAppErrorReportLocked(r);
8767 if (report == null) {
8768 return null;
8769 }
8770 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8771 result.setComponent(r.errorReportReceiver);
8772 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8773 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8774 return result;
8775 }
8776
8777 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8778 if (r.errorReportReceiver == null) {
8779 return null;
8780 }
8781
8782 if (!r.crashing && !r.notResponding) {
8783 return null;
8784 }
8785
8786 try {
8787 ApplicationErrorReport report = new ApplicationErrorReport();
8788 report.packageName = r.info.packageName;
8789 report.installerPackageName = r.errorReportReceiver.getPackageName();
8790 report.processName = r.processName;
8791
8792 if (r.crashing) {
8793 report.type = ApplicationErrorReport.TYPE_CRASH;
8794 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8795
8796 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8797 r.crashingReport.crashData);
8798 DataInputStream dataStream = new DataInputStream(byteStream);
8799 CrashData crashData = new CrashData(dataStream);
8800 ThrowableData throwData = crashData.getThrowableData();
8801
8802 report.time = crashData.getTime();
8803 report.crashInfo.stackTrace = throwData.toString();
8804
Jacek Surazskif829a782009-06-11 22:47:02 +02008805 // Extract the source of the exception, useful for report
8806 // clustering. Also extract the "deepest" non-null exception
8807 // message.
8808 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008809 while (throwData.getCause() != null) {
8810 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008811 String msg = throwData.getMessage();
8812 if (msg != null && msg.length() > 0) {
8813 exceptionMessage = msg;
8814 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008815 }
8816 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008817 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008818 report.crashInfo.exceptionClassName = throwData.getType();
8819 report.crashInfo.throwFileName = trace.getFileName();
8820 report.crashInfo.throwClassName = trace.getClassName();
8821 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008822 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008823 } else if (r.notResponding) {
8824 report.type = ApplicationErrorReport.TYPE_ANR;
8825 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8826
8827 report.anrInfo.activity = r.notRespondingReport.tag;
8828 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8829 report.anrInfo.info = r.notRespondingReport.longMsg;
8830 }
8831
8832 return report;
8833 } catch (IOException e) {
8834 // we don't send it
8835 }
8836
8837 return null;
8838 }
8839
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008840 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8841 // assume our apps are happy - lazy create the list
8842 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8843
8844 synchronized (this) {
8845
8846 // iterate across all processes
8847 final int N = mLRUProcesses.size();
8848 for (int i = 0; i < N; i++) {
8849 ProcessRecord app = mLRUProcesses.get(i);
8850 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8851 // This one's in trouble, so we'll generate a report for it
8852 // crashes are higher priority (in case there's a crash *and* an anr)
8853 ActivityManager.ProcessErrorStateInfo report = null;
8854 if (app.crashing) {
8855 report = app.crashingReport;
8856 } else if (app.notResponding) {
8857 report = app.notRespondingReport;
8858 }
8859
8860 if (report != null) {
8861 if (errList == null) {
8862 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8863 }
8864 errList.add(report);
8865 } else {
8866 Log.w(TAG, "Missing app error report, app = " + app.processName +
8867 " crashing = " + app.crashing +
8868 " notResponding = " + app.notResponding);
8869 }
8870 }
8871 }
8872 }
8873
8874 return errList;
8875 }
8876
8877 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8878 // Lazy instantiation of list
8879 List<ActivityManager.RunningAppProcessInfo> runList = null;
8880 synchronized (this) {
8881 // Iterate across all processes
8882 final int N = mLRUProcesses.size();
8883 for (int i = 0; i < N; i++) {
8884 ProcessRecord app = mLRUProcesses.get(i);
8885 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8886 // Generate process state info for running application
8887 ActivityManager.RunningAppProcessInfo currApp =
8888 new ActivityManager.RunningAppProcessInfo(app.processName,
8889 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07008890 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008891 int adj = app.curAdj;
8892 if (adj >= CONTENT_PROVIDER_ADJ) {
8893 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8894 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8895 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008896 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8897 } else if (adj >= HOME_APP_ADJ) {
8898 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8899 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008900 } else if (adj >= SECONDARY_SERVER_ADJ) {
8901 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8902 } else if (adj >= VISIBLE_APP_ADJ) {
8903 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8904 } else {
8905 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8906 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07008907 currApp.importanceReasonCode = app.adjTypeCode;
8908 if (app.adjSource instanceof ProcessRecord) {
8909 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
8910 } else if (app.adjSource instanceof HistoryRecord) {
8911 HistoryRecord r = (HistoryRecord)app.adjSource;
8912 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
8913 }
8914 if (app.adjTarget instanceof ComponentName) {
8915 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
8916 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008917 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8918 // + " lru=" + currApp.lru);
8919 if (runList == null) {
8920 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8921 }
8922 runList.add(currApp);
8923 }
8924 }
8925 }
8926 return runList;
8927 }
8928
8929 @Override
8930 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8931 synchronized (this) {
8932 if (checkCallingPermission(android.Manifest.permission.DUMP)
8933 != PackageManager.PERMISSION_GRANTED) {
8934 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8935 + Binder.getCallingPid()
8936 + ", uid=" + Binder.getCallingUid()
8937 + " without permission "
8938 + android.Manifest.permission.DUMP);
8939 return;
8940 }
8941 if (args.length != 0 && "service".equals(args[0])) {
8942 dumpService(fd, pw, args);
8943 return;
8944 }
8945 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008946 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008947 pw.println(" ");
8948 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008949 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008950 if (mWaitingVisibleActivities.size() > 0) {
8951 pw.println(" ");
8952 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008953 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008954 }
8955 if (mStoppingActivities.size() > 0) {
8956 pw.println(" ");
8957 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008958 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008959 }
8960 if (mFinishingActivities.size() > 0) {
8961 pw.println(" ");
8962 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008963 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008964 }
8965
8966 pw.println(" ");
8967 pw.println(" mPausingActivity: " + mPausingActivity);
8968 pw.println(" mResumedActivity: " + mResumedActivity);
8969 pw.println(" mFocusedActivity: " + mFocusedActivity);
8970 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8971
8972 if (mRecentTasks.size() > 0) {
8973 pw.println(" ");
8974 pw.println("Recent tasks in Current Activity Manager State:");
8975
8976 final int N = mRecentTasks.size();
8977 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008978 TaskRecord tr = mRecentTasks.get(i);
8979 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8980 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008981 mRecentTasks.get(i).dump(pw, " ");
8982 }
8983 }
8984
8985 pw.println(" ");
8986 pw.println(" mCurTask: " + mCurTask);
8987
8988 pw.println(" ");
8989 pw.println("Processes in Current Activity Manager State:");
8990
8991 boolean needSep = false;
8992 int numPers = 0;
8993
8994 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8995 final int NA = procs.size();
8996 for (int ia=0; ia<NA; ia++) {
8997 if (!needSep) {
8998 pw.println(" All known processes:");
8999 needSep = true;
9000 }
9001 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009002 pw.print(r.persistent ? " *PERS*" : " *APP*");
9003 pw.print(" UID "); pw.print(procs.keyAt(ia));
9004 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009005 r.dump(pw, " ");
9006 if (r.persistent) {
9007 numPers++;
9008 }
9009 }
9010 }
9011
9012 if (mLRUProcesses.size() > 0) {
9013 if (needSep) pw.println(" ");
9014 needSep = true;
9015 pw.println(" Running processes (most recent first):");
9016 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009017 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009018 needSep = true;
9019 }
9020
9021 synchronized (mPidsSelfLocked) {
9022 if (mPidsSelfLocked.size() > 0) {
9023 if (needSep) pw.println(" ");
9024 needSep = true;
9025 pw.println(" PID mappings:");
9026 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009027 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9028 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009029 }
9030 }
9031 }
9032
9033 if (mForegroundProcesses.size() > 0) {
9034 if (needSep) pw.println(" ");
9035 needSep = true;
9036 pw.println(" Foreground Processes:");
9037 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009038 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9039 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009040 }
9041 }
9042
9043 if (mPersistentStartingProcesses.size() > 0) {
9044 if (needSep) pw.println(" ");
9045 needSep = true;
9046 pw.println(" Persisent processes that are starting:");
9047 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009048 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009049 }
9050
9051 if (mStartingProcesses.size() > 0) {
9052 if (needSep) pw.println(" ");
9053 needSep = true;
9054 pw.println(" Processes that are starting:");
9055 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009056 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009057 }
9058
9059 if (mRemovedProcesses.size() > 0) {
9060 if (needSep) pw.println(" ");
9061 needSep = true;
9062 pw.println(" Processes that are being removed:");
9063 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009064 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009065 }
9066
9067 if (mProcessesOnHold.size() > 0) {
9068 if (needSep) pw.println(" ");
9069 needSep = true;
9070 pw.println(" Processes that are on old until the system is ready:");
9071 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009072 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009073 }
9074
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009075 if (mProcessesToGc.size() > 0) {
9076 if (needSep) pw.println(" ");
9077 needSep = true;
9078 pw.println(" Processes that are waiting to GC:");
9079 long now = SystemClock.uptimeMillis();
9080 for (int i=0; i<mProcessesToGc.size(); i++) {
9081 ProcessRecord proc = mProcessesToGc.get(i);
9082 pw.print(" Process "); pw.println(proc);
9083 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9084 pw.print(", last gced=");
9085 pw.print(now-proc.lastRequestedGc);
9086 pw.print(" ms ago, last lowMwm=");
9087 pw.print(now-proc.lastLowMemory);
9088 pw.println(" ms ago");
9089
9090 }
9091 }
9092
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009093 if (mProcessCrashTimes.getMap().size() > 0) {
9094 if (needSep) pw.println(" ");
9095 needSep = true;
9096 pw.println(" Time since processes crashed:");
9097 long now = SystemClock.uptimeMillis();
9098 for (Map.Entry<String, SparseArray<Long>> procs
9099 : mProcessCrashTimes.getMap().entrySet()) {
9100 SparseArray<Long> uids = procs.getValue();
9101 final int N = uids.size();
9102 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009103 pw.print(" Process "); pw.print(procs.getKey());
9104 pw.print(" uid "); pw.print(uids.keyAt(i));
9105 pw.print(": last crashed ");
9106 pw.print((now-uids.valueAt(i)));
9107 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009108 }
9109 }
9110 }
9111
9112 if (mBadProcesses.getMap().size() > 0) {
9113 if (needSep) pw.println(" ");
9114 needSep = true;
9115 pw.println(" Bad processes:");
9116 for (Map.Entry<String, SparseArray<Long>> procs
9117 : mBadProcesses.getMap().entrySet()) {
9118 SparseArray<Long> uids = procs.getValue();
9119 final int N = uids.size();
9120 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009121 pw.print(" Bad process "); pw.print(procs.getKey());
9122 pw.print(" uid "); pw.print(uids.keyAt(i));
9123 pw.print(": crashed at time ");
9124 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009125 }
9126 }
9127 }
9128
9129 pw.println(" ");
9130 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009131 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009132 pw.println(" mConfiguration: " + mConfiguration);
9133 pw.println(" mStartRunning=" + mStartRunning
9134 + " mSystemReady=" + mSystemReady
9135 + " mBooting=" + mBooting
9136 + " mBooted=" + mBooted
9137 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009138 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009139 pw.println(" mGoingToSleep=" + mGoingToSleep);
9140 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9141 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9142 + " mDebugTransient=" + mDebugTransient
9143 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9144 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009145 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009146 }
9147 }
9148
9149 /**
9150 * There are three ways to call this:
9151 * - no service specified: dump all the services
9152 * - a flattened component name that matched an existing service was specified as the
9153 * first arg: dump that one service
9154 * - the first arg isn't the flattened component name of an existing service:
9155 * dump all services whose component contains the first arg as a substring
9156 */
9157 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9158 String[] newArgs;
9159 String componentNameString;
9160 ServiceRecord r;
9161 if (args.length == 1) {
9162 componentNameString = null;
9163 newArgs = EMPTY_STRING_ARRAY;
9164 r = null;
9165 } else {
9166 componentNameString = args[1];
9167 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9168 r = componentName != null ? mServices.get(componentName) : null;
9169 newArgs = new String[args.length - 2];
9170 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9171 }
9172
9173 if (r != null) {
9174 dumpService(fd, pw, r, newArgs);
9175 } else {
9176 for (ServiceRecord r1 : mServices.values()) {
9177 if (componentNameString == null
9178 || r1.name.flattenToString().contains(componentNameString)) {
9179 dumpService(fd, pw, r1, newArgs);
9180 }
9181 }
9182 }
9183 }
9184
9185 /**
9186 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9187 * there is a thread associated with the service.
9188 */
9189 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9190 pw.println(" Service " + r.name.flattenToString());
9191 if (r.app != null && r.app.thread != null) {
9192 try {
9193 // flush anything that is already in the PrintWriter since the thread is going
9194 // to write to the file descriptor directly
9195 pw.flush();
9196 r.app.thread.dumpService(fd, r, args);
9197 pw.print("\n");
9198 } catch (RemoteException e) {
9199 pw.println("got a RemoteException while dumping the service");
9200 }
9201 }
9202 }
9203
9204 void dumpBroadcasts(PrintWriter pw) {
9205 synchronized (this) {
9206 if (checkCallingPermission(android.Manifest.permission.DUMP)
9207 != PackageManager.PERMISSION_GRANTED) {
9208 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9209 + Binder.getCallingPid()
9210 + ", uid=" + Binder.getCallingUid()
9211 + " without permission "
9212 + android.Manifest.permission.DUMP);
9213 return;
9214 }
9215 pw.println("Broadcasts in Current Activity Manager State:");
9216
9217 if (mRegisteredReceivers.size() > 0) {
9218 pw.println(" ");
9219 pw.println(" Registered Receivers:");
9220 Iterator it = mRegisteredReceivers.values().iterator();
9221 while (it.hasNext()) {
9222 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009223 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009224 r.dump(pw, " ");
9225 }
9226 }
9227
9228 pw.println(" ");
9229 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009230 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009231
9232 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9233 || mPendingBroadcast != null) {
9234 if (mParallelBroadcasts.size() > 0) {
9235 pw.println(" ");
9236 pw.println(" Active broadcasts:");
9237 }
9238 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9239 pw.println(" Broadcast #" + i + ":");
9240 mParallelBroadcasts.get(i).dump(pw, " ");
9241 }
9242 if (mOrderedBroadcasts.size() > 0) {
9243 pw.println(" ");
9244 pw.println(" Active serialized broadcasts:");
9245 }
9246 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9247 pw.println(" Serialized Broadcast #" + i + ":");
9248 mOrderedBroadcasts.get(i).dump(pw, " ");
9249 }
9250 pw.println(" ");
9251 pw.println(" Pending broadcast:");
9252 if (mPendingBroadcast != null) {
9253 mPendingBroadcast.dump(pw, " ");
9254 } else {
9255 pw.println(" (null)");
9256 }
9257 }
9258
9259 pw.println(" ");
9260 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9261 if (mStickyBroadcasts != null) {
9262 pw.println(" ");
9263 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009264 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009265 for (Map.Entry<String, ArrayList<Intent>> ent
9266 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009267 pw.print(" * Sticky action "); pw.print(ent.getKey());
9268 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009269 ArrayList<Intent> intents = ent.getValue();
9270 final int N = intents.size();
9271 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009272 sb.setLength(0);
9273 sb.append(" Intent: ");
9274 intents.get(i).toShortString(sb, true, false);
9275 pw.println(sb.toString());
9276 Bundle bundle = intents.get(i).getExtras();
9277 if (bundle != null) {
9278 pw.print(" ");
9279 pw.println(bundle.toString());
9280 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009281 }
9282 }
9283 }
9284
9285 pw.println(" ");
9286 pw.println(" mHandler:");
9287 mHandler.dump(new PrintWriterPrinter(pw), " ");
9288 }
9289 }
9290
9291 void dumpServices(PrintWriter pw) {
9292 synchronized (this) {
9293 if (checkCallingPermission(android.Manifest.permission.DUMP)
9294 != PackageManager.PERMISSION_GRANTED) {
9295 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9296 + Binder.getCallingPid()
9297 + ", uid=" + Binder.getCallingUid()
9298 + " without permission "
9299 + android.Manifest.permission.DUMP);
9300 return;
9301 }
9302 pw.println("Services in Current Activity Manager State:");
9303
9304 boolean needSep = false;
9305
9306 if (mServices.size() > 0) {
9307 pw.println(" Active services:");
9308 Iterator<ServiceRecord> it = mServices.values().iterator();
9309 while (it.hasNext()) {
9310 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009311 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009312 r.dump(pw, " ");
9313 }
9314 needSep = true;
9315 }
9316
9317 if (mPendingServices.size() > 0) {
9318 if (needSep) pw.println(" ");
9319 pw.println(" Pending services:");
9320 for (int i=0; i<mPendingServices.size(); i++) {
9321 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009322 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009323 r.dump(pw, " ");
9324 }
9325 needSep = true;
9326 }
9327
9328 if (mRestartingServices.size() > 0) {
9329 if (needSep) pw.println(" ");
9330 pw.println(" Restarting services:");
9331 for (int i=0; i<mRestartingServices.size(); i++) {
9332 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009333 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009334 r.dump(pw, " ");
9335 }
9336 needSep = true;
9337 }
9338
9339 if (mStoppingServices.size() > 0) {
9340 if (needSep) pw.println(" ");
9341 pw.println(" Stopping services:");
9342 for (int i=0; i<mStoppingServices.size(); i++) {
9343 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009344 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009345 r.dump(pw, " ");
9346 }
9347 needSep = true;
9348 }
9349
9350 if (mServiceConnections.size() > 0) {
9351 if (needSep) pw.println(" ");
9352 pw.println(" Connection bindings to services:");
9353 Iterator<ConnectionRecord> it
9354 = mServiceConnections.values().iterator();
9355 while (it.hasNext()) {
9356 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009357 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009358 r.dump(pw, " ");
9359 }
9360 }
9361 }
9362 }
9363
9364 void dumpProviders(PrintWriter pw) {
9365 synchronized (this) {
9366 if (checkCallingPermission(android.Manifest.permission.DUMP)
9367 != PackageManager.PERMISSION_GRANTED) {
9368 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9369 + Binder.getCallingPid()
9370 + ", uid=" + Binder.getCallingUid()
9371 + " without permission "
9372 + android.Manifest.permission.DUMP);
9373 return;
9374 }
9375
9376 pw.println("Content Providers in Current Activity Manager State:");
9377
9378 boolean needSep = false;
9379
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009380 if (mProvidersByClass.size() > 0) {
9381 if (needSep) pw.println(" ");
9382 pw.println(" Published content providers (by class):");
9383 Iterator it = mProvidersByClass.entrySet().iterator();
9384 while (it.hasNext()) {
9385 Map.Entry e = (Map.Entry)it.next();
9386 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009387 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009388 r.dump(pw, " ");
9389 }
9390 needSep = true;
9391 }
9392
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009393 if (mProvidersByName.size() > 0) {
9394 pw.println(" ");
9395 pw.println(" Authority to provider mappings:");
9396 Iterator it = mProvidersByName.entrySet().iterator();
9397 while (it.hasNext()) {
9398 Map.Entry e = (Map.Entry)it.next();
9399 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9400 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9401 pw.println(r);
9402 }
9403 needSep = true;
9404 }
9405
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009406 if (mLaunchingProviders.size() > 0) {
9407 if (needSep) pw.println(" ");
9408 pw.println(" Launching content providers:");
9409 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009410 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9411 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009412 }
9413 needSep = true;
9414 }
9415
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009416 if (mGrantedUriPermissions.size() > 0) {
9417 pw.println();
9418 pw.println("Granted Uri Permissions:");
9419 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9420 int uid = mGrantedUriPermissions.keyAt(i);
9421 HashMap<Uri, UriPermission> perms
9422 = mGrantedUriPermissions.valueAt(i);
9423 pw.print(" * UID "); pw.print(uid);
9424 pw.println(" holds:");
9425 for (UriPermission perm : perms.values()) {
9426 pw.print(" "); pw.println(perm);
9427 perm.dump(pw, " ");
9428 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009429 }
9430 }
9431 }
9432 }
9433
9434 void dumpSenders(PrintWriter pw) {
9435 synchronized (this) {
9436 if (checkCallingPermission(android.Manifest.permission.DUMP)
9437 != PackageManager.PERMISSION_GRANTED) {
9438 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9439 + Binder.getCallingPid()
9440 + ", uid=" + Binder.getCallingUid()
9441 + " without permission "
9442 + android.Manifest.permission.DUMP);
9443 return;
9444 }
9445
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009446 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009447
9448 if (this.mIntentSenderRecords.size() > 0) {
9449 Iterator<WeakReference<PendingIntentRecord>> it
9450 = mIntentSenderRecords.values().iterator();
9451 while (it.hasNext()) {
9452 WeakReference<PendingIntentRecord> ref = it.next();
9453 PendingIntentRecord rec = ref != null ? ref.get(): null;
9454 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009455 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009456 rec.dump(pw, " ");
9457 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009458 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009459 }
9460 }
9461 }
9462 }
9463 }
9464
9465 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009466 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009467 TaskRecord lastTask = null;
9468 for (int i=list.size()-1; i>=0; i--) {
9469 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009470 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009471 if (lastTask != r.task) {
9472 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009473 pw.print(prefix);
9474 pw.print(full ? "* " : " ");
9475 pw.println(lastTask);
9476 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009477 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009478 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009479 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009480 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9481 pw.print(" #"); pw.print(i); pw.print(": ");
9482 pw.println(r);
9483 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009484 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009485 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009486 }
9487 }
9488
9489 private static final int dumpProcessList(PrintWriter pw, List list,
9490 String prefix, String normalLabel, String persistentLabel,
9491 boolean inclOomAdj) {
9492 int numPers = 0;
9493 for (int i=list.size()-1; i>=0; i--) {
9494 ProcessRecord r = (ProcessRecord)list.get(i);
9495 if (false) {
9496 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9497 + " #" + i + ":");
9498 r.dump(pw, prefix + " ");
9499 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009500 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009501 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009502 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9503 if (r.adjSource != null || r.adjTarget != null) {
9504 pw.println(prefix + " " + r.adjTarget
9505 + " used by " + r.adjSource);
9506 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009507 } else {
9508 pw.println(String.format("%s%s #%2d: %s",
9509 prefix, (r.persistent ? persistentLabel : normalLabel),
9510 i, r.toString()));
9511 }
9512 if (r.persistent) {
9513 numPers++;
9514 }
9515 }
9516 return numPers;
9517 }
9518
9519 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9520 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009521 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009522 long uptime = SystemClock.uptimeMillis();
9523 long realtime = SystemClock.elapsedRealtime();
9524
9525 if (isCheckinRequest) {
9526 // short checkin version
9527 pw.println(uptime + "," + realtime);
9528 pw.flush();
9529 } else {
9530 pw.println("Applications Memory Usage (kB):");
9531 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9532 }
9533 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9534 ProcessRecord r = (ProcessRecord)list.get(i);
9535 if (r.thread != null) {
9536 if (!isCheckinRequest) {
9537 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9538 pw.flush();
9539 }
9540 try {
9541 r.thread.asBinder().dump(fd, args);
9542 } catch (RemoteException e) {
9543 if (!isCheckinRequest) {
9544 pw.println("Got RemoteException!");
9545 pw.flush();
9546 }
9547 }
9548 }
9549 }
9550 }
9551
9552 /**
9553 * Searches array of arguments for the specified string
9554 * @param args array of argument strings
9555 * @param value value to search for
9556 * @return true if the value is contained in the array
9557 */
9558 private static boolean scanArgs(String[] args, String value) {
9559 if (args != null) {
9560 for (String arg : args) {
9561 if (value.equals(arg)) {
9562 return true;
9563 }
9564 }
9565 }
9566 return false;
9567 }
9568
Dianne Hackborn75b03852009-06-12 15:43:26 -07009569 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009570 int count = mHistory.size();
9571
9572 // convert the token to an entry in the history.
9573 HistoryRecord r = null;
9574 int index = -1;
9575 for (int i=count-1; i>=0; i--) {
9576 Object o = mHistory.get(i);
9577 if (o == token) {
9578 r = (HistoryRecord)o;
9579 index = i;
9580 break;
9581 }
9582 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009583
9584 return index;
9585 }
9586
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009587 private final void killServicesLocked(ProcessRecord app,
9588 boolean allowRestart) {
9589 // Report disconnected services.
9590 if (false) {
9591 // XXX we are letting the client link to the service for
9592 // death notifications.
9593 if (app.services.size() > 0) {
9594 Iterator it = app.services.iterator();
9595 while (it.hasNext()) {
9596 ServiceRecord r = (ServiceRecord)it.next();
9597 if (r.connections.size() > 0) {
9598 Iterator<ConnectionRecord> jt
9599 = r.connections.values().iterator();
9600 while (jt.hasNext()) {
9601 ConnectionRecord c = jt.next();
9602 if (c.binding.client != app) {
9603 try {
9604 //c.conn.connected(r.className, null);
9605 } catch (Exception e) {
9606 // todo: this should be asynchronous!
9607 Log.w(TAG, "Exception thrown disconnected servce "
9608 + r.shortName
9609 + " from app " + app.processName, e);
9610 }
9611 }
9612 }
9613 }
9614 }
9615 }
9616 }
9617
9618 // Clean up any connections this application has to other services.
9619 if (app.connections.size() > 0) {
9620 Iterator<ConnectionRecord> it = app.connections.iterator();
9621 while (it.hasNext()) {
9622 ConnectionRecord r = it.next();
9623 removeConnectionLocked(r, app, null);
9624 }
9625 }
9626 app.connections.clear();
9627
9628 if (app.services.size() != 0) {
9629 // Any services running in the application need to be placed
9630 // back in the pending list.
9631 Iterator it = app.services.iterator();
9632 while (it.hasNext()) {
9633 ServiceRecord sr = (ServiceRecord)it.next();
9634 synchronized (sr.stats.getBatteryStats()) {
9635 sr.stats.stopLaunchedLocked();
9636 }
9637 sr.app = null;
9638 sr.executeNesting = 0;
9639 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009640
9641 boolean hasClients = sr.bindings.size() > 0;
9642 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009643 Iterator<IntentBindRecord> bindings
9644 = sr.bindings.values().iterator();
9645 while (bindings.hasNext()) {
9646 IntentBindRecord b = bindings.next();
9647 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9648 + ": shouldUnbind=" + b.hasBound);
9649 b.binder = null;
9650 b.requested = b.received = b.hasBound = false;
9651 }
9652 }
9653
9654 if (sr.crashCount >= 2) {
9655 Log.w(TAG, "Service crashed " + sr.crashCount
9656 + " times, stopping: " + sr);
9657 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9658 sr.crashCount, sr.shortName, app.pid);
9659 bringDownServiceLocked(sr, true);
9660 } else if (!allowRestart) {
9661 bringDownServiceLocked(sr, true);
9662 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009663 boolean canceled = scheduleServiceRestartLocked(sr, true);
9664
9665 // Should the service remain running? Note that in the
9666 // extreme case of so many attempts to deliver a command
9667 // that it failed, that we also will stop it here.
9668 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9669 if (sr.pendingStarts.size() == 0) {
9670 sr.startRequested = false;
9671 if (!hasClients) {
9672 // Whoops, no reason to restart!
9673 bringDownServiceLocked(sr, true);
9674 }
9675 }
9676 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009677 }
9678 }
9679
9680 if (!allowRestart) {
9681 app.services.clear();
9682 }
9683 }
9684
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009685 // Make sure we have no more records on the stopping list.
9686 int i = mStoppingServices.size();
9687 while (i > 0) {
9688 i--;
9689 ServiceRecord sr = mStoppingServices.get(i);
9690 if (sr.app == app) {
9691 mStoppingServices.remove(i);
9692 }
9693 }
9694
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009695 app.executingServices.clear();
9696 }
9697
9698 private final void removeDyingProviderLocked(ProcessRecord proc,
9699 ContentProviderRecord cpr) {
9700 synchronized (cpr) {
9701 cpr.launchingApp = null;
9702 cpr.notifyAll();
9703 }
9704
9705 mProvidersByClass.remove(cpr.info.name);
9706 String names[] = cpr.info.authority.split(";");
9707 for (int j = 0; j < names.length; j++) {
9708 mProvidersByName.remove(names[j]);
9709 }
9710
9711 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9712 while (cit.hasNext()) {
9713 ProcessRecord capp = cit.next();
9714 if (!capp.persistent && capp.thread != null
9715 && capp.pid != 0
9716 && capp.pid != MY_PID) {
9717 Log.i(TAG, "Killing app " + capp.processName
9718 + " (pid " + capp.pid
9719 + ") because provider " + cpr.info.name
9720 + " is in dying process " + proc.processName);
9721 Process.killProcess(capp.pid);
9722 }
9723 }
9724
9725 mLaunchingProviders.remove(cpr);
9726 }
9727
9728 /**
9729 * Main code for cleaning up a process when it has gone away. This is
9730 * called both as a result of the process dying, or directly when stopping
9731 * a process when running in single process mode.
9732 */
9733 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9734 boolean restarting, int index) {
9735 if (index >= 0) {
9736 mLRUProcesses.remove(index);
9737 }
9738
9739 // Dismiss any open dialogs.
9740 if (app.crashDialog != null) {
9741 app.crashDialog.dismiss();
9742 app.crashDialog = null;
9743 }
9744 if (app.anrDialog != null) {
9745 app.anrDialog.dismiss();
9746 app.anrDialog = null;
9747 }
9748 if (app.waitDialog != null) {
9749 app.waitDialog.dismiss();
9750 app.waitDialog = null;
9751 }
9752
9753 app.crashing = false;
9754 app.notResponding = false;
9755
9756 app.resetPackageList();
9757 app.thread = null;
9758 app.forcingToForeground = null;
9759 app.foregroundServices = false;
9760
9761 killServicesLocked(app, true);
9762
9763 boolean restart = false;
9764
9765 int NL = mLaunchingProviders.size();
9766
9767 // Remove published content providers.
9768 if (!app.pubProviders.isEmpty()) {
9769 Iterator it = app.pubProviders.values().iterator();
9770 while (it.hasNext()) {
9771 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9772 cpr.provider = null;
9773 cpr.app = null;
9774
9775 // See if someone is waiting for this provider... in which
9776 // case we don't remove it, but just let it restart.
9777 int i = 0;
9778 if (!app.bad) {
9779 for (; i<NL; i++) {
9780 if (mLaunchingProviders.get(i) == cpr) {
9781 restart = true;
9782 break;
9783 }
9784 }
9785 } else {
9786 i = NL;
9787 }
9788
9789 if (i >= NL) {
9790 removeDyingProviderLocked(app, cpr);
9791 NL = mLaunchingProviders.size();
9792 }
9793 }
9794 app.pubProviders.clear();
9795 }
9796
9797 // Look through the content providers we are waiting to have launched,
9798 // and if any run in this process then either schedule a restart of
9799 // the process or kill the client waiting for it if this process has
9800 // gone bad.
9801 for (int i=0; i<NL; i++) {
9802 ContentProviderRecord cpr = (ContentProviderRecord)
9803 mLaunchingProviders.get(i);
9804 if (cpr.launchingApp == app) {
9805 if (!app.bad) {
9806 restart = true;
9807 } else {
9808 removeDyingProviderLocked(app, cpr);
9809 NL = mLaunchingProviders.size();
9810 }
9811 }
9812 }
9813
9814 // Unregister from connected content providers.
9815 if (!app.conProviders.isEmpty()) {
9816 Iterator it = app.conProviders.iterator();
9817 while (it.hasNext()) {
9818 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9819 cpr.clients.remove(app);
9820 }
9821 app.conProviders.clear();
9822 }
9823
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009824 // At this point there may be remaining entries in mLaunchingProviders
9825 // where we were the only one waiting, so they are no longer of use.
9826 // Look for these and clean up if found.
9827 // XXX Commented out for now. Trying to figure out a way to reproduce
9828 // the actual situation to identify what is actually going on.
9829 if (false) {
9830 for (int i=0; i<NL; i++) {
9831 ContentProviderRecord cpr = (ContentProviderRecord)
9832 mLaunchingProviders.get(i);
9833 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9834 synchronized (cpr) {
9835 cpr.launchingApp = null;
9836 cpr.notifyAll();
9837 }
9838 }
9839 }
9840 }
9841
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009842 skipCurrentReceiverLocked(app);
9843
9844 // Unregister any receivers.
9845 if (app.receivers.size() > 0) {
9846 Iterator<ReceiverList> it = app.receivers.iterator();
9847 while (it.hasNext()) {
9848 removeReceiverLocked(it.next());
9849 }
9850 app.receivers.clear();
9851 }
9852
Christopher Tate181fafa2009-05-14 11:12:14 -07009853 // If the app is undergoing backup, tell the backup manager about it
9854 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9855 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9856 try {
9857 IBackupManager bm = IBackupManager.Stub.asInterface(
9858 ServiceManager.getService(Context.BACKUP_SERVICE));
9859 bm.agentDisconnected(app.info.packageName);
9860 } catch (RemoteException e) {
9861 // can't happen; backup manager is local
9862 }
9863 }
9864
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009865 // If the caller is restarting this app, then leave it in its
9866 // current lists and let the caller take care of it.
9867 if (restarting) {
9868 return;
9869 }
9870
9871 if (!app.persistent) {
9872 if (DEBUG_PROCESSES) Log.v(TAG,
9873 "Removing non-persistent process during cleanup: " + app);
9874 mProcessNames.remove(app.processName, app.info.uid);
9875 } else if (!app.removed) {
9876 // This app is persistent, so we need to keep its record around.
9877 // If it is not already on the pending app list, add it there
9878 // and start a new process for it.
9879 app.thread = null;
9880 app.forcingToForeground = null;
9881 app.foregroundServices = false;
9882 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9883 mPersistentStartingProcesses.add(app);
9884 restart = true;
9885 }
9886 }
9887 mProcessesOnHold.remove(app);
9888
The Android Open Source Project4df24232009-03-05 14:34:35 -08009889 if (app == mHomeProcess) {
9890 mHomeProcess = null;
9891 }
9892
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009893 if (restart) {
9894 // We have components that still need to be running in the
9895 // process, so re-launch it.
9896 mProcessNames.put(app.processName, app.info.uid, app);
9897 startProcessLocked(app, "restart", app.processName);
9898 } else if (app.pid > 0 && app.pid != MY_PID) {
9899 // Goodbye!
9900 synchronized (mPidsSelfLocked) {
9901 mPidsSelfLocked.remove(app.pid);
9902 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9903 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009904 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009905 }
9906 }
9907
9908 // =========================================================
9909 // SERVICES
9910 // =========================================================
9911
9912 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9913 ActivityManager.RunningServiceInfo info =
9914 new ActivityManager.RunningServiceInfo();
9915 info.service = r.name;
9916 if (r.app != null) {
9917 info.pid = r.app.pid;
9918 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -07009919 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009920 info.process = r.processName;
9921 info.foreground = r.isForeground;
9922 info.activeSince = r.createTime;
9923 info.started = r.startRequested;
9924 info.clientCount = r.connections.size();
9925 info.crashCount = r.crashCount;
9926 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07009927 if (r.isForeground) {
9928 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
9929 }
9930 if (r.startRequested) {
9931 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
9932 }
9933 if (r.app != null && r.app.pid == Process.myPid()) {
9934 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
9935 }
9936 if (r.app != null && r.app.persistent) {
9937 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
9938 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009939 for (ConnectionRecord conn : r.connections.values()) {
9940 if (conn.clientLabel != 0) {
9941 info.clientPackage = conn.binding.client.info.packageName;
9942 info.clientLabel = conn.clientLabel;
9943 break;
9944 }
9945 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009946 return info;
9947 }
9948
9949 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9950 int flags) {
9951 synchronized (this) {
9952 ArrayList<ActivityManager.RunningServiceInfo> res
9953 = new ArrayList<ActivityManager.RunningServiceInfo>();
9954
9955 if (mServices.size() > 0) {
9956 Iterator<ServiceRecord> it = mServices.values().iterator();
9957 while (it.hasNext() && res.size() < maxNum) {
9958 res.add(makeRunningServiceInfoLocked(it.next()));
9959 }
9960 }
9961
9962 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9963 ServiceRecord r = mRestartingServices.get(i);
9964 ActivityManager.RunningServiceInfo info =
9965 makeRunningServiceInfoLocked(r);
9966 info.restarting = r.nextRestartTime;
9967 res.add(info);
9968 }
9969
9970 return res;
9971 }
9972 }
9973
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009974 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
9975 synchronized (this) {
9976 ServiceRecord r = mServices.get(name);
9977 if (r != null) {
9978 for (ConnectionRecord conn : r.connections.values()) {
9979 if (conn.clientIntent != null) {
9980 return conn.clientIntent;
9981 }
9982 }
9983 }
9984 }
9985 return null;
9986 }
9987
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009988 private final ServiceRecord findServiceLocked(ComponentName name,
9989 IBinder token) {
9990 ServiceRecord r = mServices.get(name);
9991 return r == token ? r : null;
9992 }
9993
9994 private final class ServiceLookupResult {
9995 final ServiceRecord record;
9996 final String permission;
9997
9998 ServiceLookupResult(ServiceRecord _record, String _permission) {
9999 record = _record;
10000 permission = _permission;
10001 }
10002 };
10003
10004 private ServiceLookupResult findServiceLocked(Intent service,
10005 String resolvedType) {
10006 ServiceRecord r = null;
10007 if (service.getComponent() != null) {
10008 r = mServices.get(service.getComponent());
10009 }
10010 if (r == null) {
10011 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10012 r = mServicesByIntent.get(filter);
10013 }
10014
10015 if (r == null) {
10016 try {
10017 ResolveInfo rInfo =
10018 ActivityThread.getPackageManager().resolveService(
10019 service, resolvedType, 0);
10020 ServiceInfo sInfo =
10021 rInfo != null ? rInfo.serviceInfo : null;
10022 if (sInfo == null) {
10023 return null;
10024 }
10025
10026 ComponentName name = new ComponentName(
10027 sInfo.applicationInfo.packageName, sInfo.name);
10028 r = mServices.get(name);
10029 } catch (RemoteException ex) {
10030 // pm is in same process, this will never happen.
10031 }
10032 }
10033 if (r != null) {
10034 int callingPid = Binder.getCallingPid();
10035 int callingUid = Binder.getCallingUid();
10036 if (checkComponentPermission(r.permission,
10037 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10038 != PackageManager.PERMISSION_GRANTED) {
10039 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10040 + " from pid=" + callingPid
10041 + ", uid=" + callingUid
10042 + " requires " + r.permission);
10043 return new ServiceLookupResult(null, r.permission);
10044 }
10045 return new ServiceLookupResult(r, null);
10046 }
10047 return null;
10048 }
10049
10050 private class ServiceRestarter implements Runnable {
10051 private ServiceRecord mService;
10052
10053 void setService(ServiceRecord service) {
10054 mService = service;
10055 }
10056
10057 public void run() {
10058 synchronized(ActivityManagerService.this) {
10059 performServiceRestartLocked(mService);
10060 }
10061 }
10062 }
10063
10064 private ServiceLookupResult retrieveServiceLocked(Intent service,
10065 String resolvedType, int callingPid, int callingUid) {
10066 ServiceRecord r = null;
10067 if (service.getComponent() != null) {
10068 r = mServices.get(service.getComponent());
10069 }
10070 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10071 r = mServicesByIntent.get(filter);
10072 if (r == null) {
10073 try {
10074 ResolveInfo rInfo =
10075 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010076 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010077 ServiceInfo sInfo =
10078 rInfo != null ? rInfo.serviceInfo : null;
10079 if (sInfo == null) {
10080 Log.w(TAG, "Unable to start service " + service +
10081 ": not found");
10082 return null;
10083 }
10084
10085 ComponentName name = new ComponentName(
10086 sInfo.applicationInfo.packageName, sInfo.name);
10087 r = mServices.get(name);
10088 if (r == null) {
10089 filter = new Intent.FilterComparison(service.cloneFilter());
10090 ServiceRestarter res = new ServiceRestarter();
10091 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10092 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10093 synchronized (stats) {
10094 ss = stats.getServiceStatsLocked(
10095 sInfo.applicationInfo.uid, sInfo.packageName,
10096 sInfo.name);
10097 }
10098 r = new ServiceRecord(ss, name, filter, sInfo, res);
10099 res.setService(r);
10100 mServices.put(name, r);
10101 mServicesByIntent.put(filter, r);
10102
10103 // Make sure this component isn't in the pending list.
10104 int N = mPendingServices.size();
10105 for (int i=0; i<N; i++) {
10106 ServiceRecord pr = mPendingServices.get(i);
10107 if (pr.name.equals(name)) {
10108 mPendingServices.remove(i);
10109 i--;
10110 N--;
10111 }
10112 }
10113 }
10114 } catch (RemoteException ex) {
10115 // pm is in same process, this will never happen.
10116 }
10117 }
10118 if (r != null) {
10119 if (checkComponentPermission(r.permission,
10120 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10121 != PackageManager.PERMISSION_GRANTED) {
10122 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10123 + " from pid=" + Binder.getCallingPid()
10124 + ", uid=" + Binder.getCallingUid()
10125 + " requires " + r.permission);
10126 return new ServiceLookupResult(null, r.permission);
10127 }
10128 return new ServiceLookupResult(r, null);
10129 }
10130 return null;
10131 }
10132
10133 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10134 long now = SystemClock.uptimeMillis();
10135 if (r.executeNesting == 0 && r.app != null) {
10136 if (r.app.executingServices.size() == 0) {
10137 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10138 msg.obj = r.app;
10139 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10140 }
10141 r.app.executingServices.add(r);
10142 }
10143 r.executeNesting++;
10144 r.executingStart = now;
10145 }
10146
10147 private final void sendServiceArgsLocked(ServiceRecord r,
10148 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010149 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010150 if (N == 0) {
10151 return;
10152 }
10153
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010154 int i = 0;
10155 while (i < N) {
10156 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010157 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010158 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010159 + r.name + " " + r.intent + " args=" + si.intent);
10160 if (si.intent == null && N > 0) {
10161 // If somehow we got a dummy start at the front, then
10162 // just drop it here.
10163 i++;
10164 continue;
10165 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010166 bumpServiceExecutingLocked(r);
10167 if (!oomAdjusted) {
10168 oomAdjusted = true;
10169 updateOomAdjLocked(r.app);
10170 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010171 int flags = 0;
10172 if (si.deliveryCount > 0) {
10173 flags |= Service.START_FLAG_RETRY;
10174 }
10175 if (si.doneExecutingCount > 0) {
10176 flags |= Service.START_FLAG_REDELIVERY;
10177 }
10178 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10179 si.deliveredTime = SystemClock.uptimeMillis();
10180 r.deliveredStarts.add(si);
10181 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010182 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010183 } catch (RemoteException e) {
10184 // Remote process gone... we'll let the normal cleanup take
10185 // care of this.
10186 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010187 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010188 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010189 break;
10190 }
10191 }
10192 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010193 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010194 } else {
10195 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010196 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010197 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010198 }
10199 }
10200 }
10201
10202 private final boolean requestServiceBindingLocked(ServiceRecord r,
10203 IntentBindRecord i, boolean rebind) {
10204 if (r.app == null || r.app.thread == null) {
10205 // If service is not currently running, can't yet bind.
10206 return false;
10207 }
10208 if ((!i.requested || rebind) && i.apps.size() > 0) {
10209 try {
10210 bumpServiceExecutingLocked(r);
10211 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10212 + ": shouldUnbind=" + i.hasBound);
10213 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10214 if (!rebind) {
10215 i.requested = true;
10216 }
10217 i.hasBound = true;
10218 i.doRebind = false;
10219 } catch (RemoteException e) {
10220 return false;
10221 }
10222 }
10223 return true;
10224 }
10225
10226 private final void requestServiceBindingsLocked(ServiceRecord r) {
10227 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10228 while (bindings.hasNext()) {
10229 IntentBindRecord i = bindings.next();
10230 if (!requestServiceBindingLocked(r, i, false)) {
10231 break;
10232 }
10233 }
10234 }
10235
10236 private final void realStartServiceLocked(ServiceRecord r,
10237 ProcessRecord app) throws RemoteException {
10238 if (app.thread == null) {
10239 throw new RemoteException();
10240 }
10241
10242 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010243 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010244
10245 app.services.add(r);
10246 bumpServiceExecutingLocked(r);
10247 updateLRUListLocked(app, true);
10248
10249 boolean created = false;
10250 try {
10251 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10252 + r.name + " " + r.intent);
10253 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
10254 System.identityHashCode(r), r.shortName,
10255 r.intent.getIntent().toString(), r.app.pid);
10256 synchronized (r.stats.getBatteryStats()) {
10257 r.stats.startLaunchedLocked();
10258 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010259 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010260 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010261 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010262 created = true;
10263 } finally {
10264 if (!created) {
10265 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010266 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010267 }
10268 }
10269
10270 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010271
10272 // If the service is in the started state, and there are no
10273 // pending arguments, then fake up one so its onStartCommand() will
10274 // be called.
10275 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10276 r.lastStartId++;
10277 if (r.lastStartId < 1) {
10278 r.lastStartId = 1;
10279 }
10280 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10281 }
10282
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010283 sendServiceArgsLocked(r, true);
10284 }
10285
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010286 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10287 boolean allowCancel) {
10288 boolean canceled = false;
10289
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010290 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010291 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010292 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010293
10294 // Any delivered but not yet finished starts should be put back
10295 // on the pending list.
10296 final int N = r.deliveredStarts.size();
10297 if (N > 0) {
10298 for (int i=N-1; i>=0; i--) {
10299 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10300 if (si.intent == null) {
10301 // We'll generate this again if needed.
10302 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10303 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10304 r.pendingStarts.add(0, si);
10305 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10306 dur *= 2;
10307 if (minDuration < dur) minDuration = dur;
10308 if (resetTime < dur) resetTime = dur;
10309 } else {
10310 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10311 + r.name);
10312 canceled = true;
10313 }
10314 }
10315 r.deliveredStarts.clear();
10316 }
10317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010318 r.totalRestartCount++;
10319 if (r.restartDelay == 0) {
10320 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010321 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010322 } else {
10323 // If it has been a "reasonably long time" since the service
10324 // was started, then reset our restart duration back to
10325 // the beginning, so we don't infinitely increase the duration
10326 // on a service that just occasionally gets killed (which is
10327 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010328 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010329 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010330 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010331 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010332 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010333 if (r.restartDelay < minDuration) {
10334 r.restartDelay = minDuration;
10335 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010336 }
10337 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010338
10339 r.nextRestartTime = now + r.restartDelay;
10340
10341 // Make sure that we don't end up restarting a bunch of services
10342 // all at the same time.
10343 boolean repeat;
10344 do {
10345 repeat = false;
10346 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10347 ServiceRecord r2 = mRestartingServices.get(i);
10348 if (r2 != r && r.nextRestartTime
10349 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10350 && r.nextRestartTime
10351 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10352 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10353 r.restartDelay = r.nextRestartTime - now;
10354 repeat = true;
10355 break;
10356 }
10357 }
10358 } while (repeat);
10359
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010360 if (!mRestartingServices.contains(r)) {
10361 mRestartingServices.add(r);
10362 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010363
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010364 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010365
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010366 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010367 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010368 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10369 Log.w(TAG, "Scheduling restart of crashed service "
10370 + r.shortName + " in " + r.restartDelay + "ms");
10371 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10372 r.shortName, r.restartDelay);
10373
10374 Message msg = Message.obtain();
10375 msg.what = SERVICE_ERROR_MSG;
10376 msg.obj = r;
10377 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010378
10379 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010380 }
10381
10382 final void performServiceRestartLocked(ServiceRecord r) {
10383 if (!mRestartingServices.contains(r)) {
10384 return;
10385 }
10386 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10387 }
10388
10389 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10390 if (r.restartDelay == 0) {
10391 return false;
10392 }
10393 r.resetRestartCounter();
10394 mRestartingServices.remove(r);
10395 mHandler.removeCallbacks(r.restarter);
10396 return true;
10397 }
10398
10399 private final boolean bringUpServiceLocked(ServiceRecord r,
10400 int intentFlags, boolean whileRestarting) {
10401 //Log.i(TAG, "Bring up service:");
10402 //r.dump(" ");
10403
10404 if (r.app != null) {
10405 sendServiceArgsLocked(r, false);
10406 return true;
10407 }
10408
10409 if (!whileRestarting && r.restartDelay > 0) {
10410 // If waiting for a restart, then do nothing.
10411 return true;
10412 }
10413
10414 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10415 + " " + r.intent);
10416
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010417 // We are now bringing the service up, so no longer in the
10418 // restarting state.
10419 mRestartingServices.remove(r);
10420
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010421 final String appName = r.processName;
10422 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10423 if (app != null && app.thread != null) {
10424 try {
10425 realStartServiceLocked(r, app);
10426 return true;
10427 } catch (RemoteException e) {
10428 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10429 }
10430
10431 // If a dead object exception was thrown -- fall through to
10432 // restart the application.
10433 }
10434
10435 if (!mPendingServices.contains(r)) {
10436 // Not running -- get it started, and enqueue this service record
10437 // to be executed when the app comes up.
10438 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070010439 "service", r.name, false) == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010440 Log.w(TAG, "Unable to launch app "
10441 + r.appInfo.packageName + "/"
10442 + r.appInfo.uid + " for service "
10443 + r.intent.getIntent() + ": process is bad");
10444 bringDownServiceLocked(r, true);
10445 return false;
10446 }
10447 mPendingServices.add(r);
10448 }
10449 return true;
10450 }
10451
10452 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10453 //Log.i(TAG, "Bring down service:");
10454 //r.dump(" ");
10455
10456 // Does it still need to run?
10457 if (!force && r.startRequested) {
10458 return;
10459 }
10460 if (r.connections.size() > 0) {
10461 if (!force) {
10462 // XXX should probably keep a count of the number of auto-create
10463 // connections directly in the service.
10464 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10465 while (it.hasNext()) {
10466 ConnectionRecord cr = it.next();
10467 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10468 return;
10469 }
10470 }
10471 }
10472
10473 // Report to all of the connections that the service is no longer
10474 // available.
10475 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10476 while (it.hasNext()) {
10477 ConnectionRecord c = it.next();
10478 try {
10479 // todo: shouldn't be a synchronous call!
10480 c.conn.connected(r.name, null);
10481 } catch (Exception e) {
10482 Log.w(TAG, "Failure disconnecting service " + r.name +
10483 " to connection " + c.conn.asBinder() +
10484 " (in " + c.binding.client.processName + ")", e);
10485 }
10486 }
10487 }
10488
10489 // Tell the service that it has been unbound.
10490 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10491 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10492 while (it.hasNext()) {
10493 IntentBindRecord ibr = it.next();
10494 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10495 + ": hasBound=" + ibr.hasBound);
10496 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10497 try {
10498 bumpServiceExecutingLocked(r);
10499 updateOomAdjLocked(r.app);
10500 ibr.hasBound = false;
10501 r.app.thread.scheduleUnbindService(r,
10502 ibr.intent.getIntent());
10503 } catch (Exception e) {
10504 Log.w(TAG, "Exception when unbinding service "
10505 + r.shortName, e);
10506 serviceDoneExecutingLocked(r, true);
10507 }
10508 }
10509 }
10510 }
10511
10512 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10513 + " " + r.intent);
10514 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10515 System.identityHashCode(r), r.shortName,
10516 (r.app != null) ? r.app.pid : -1);
10517
10518 mServices.remove(r.name);
10519 mServicesByIntent.remove(r.intent);
10520 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10521 r.totalRestartCount = 0;
10522 unscheduleServiceRestartLocked(r);
10523
10524 // Also make sure it is not on the pending list.
10525 int N = mPendingServices.size();
10526 for (int i=0; i<N; i++) {
10527 if (mPendingServices.get(i) == r) {
10528 mPendingServices.remove(i);
10529 if (DEBUG_SERVICE) Log.v(
10530 TAG, "Removed pending service: " + r.shortName);
10531 i--;
10532 N--;
10533 }
10534 }
10535
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010536 r.cancelNotification();
10537 r.isForeground = false;
10538 r.foregroundId = 0;
10539 r.foregroundNoti = null;
10540
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010541 // Clear start entries.
10542 r.deliveredStarts.clear();
10543 r.pendingStarts.clear();
10544
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010545 if (r.app != null) {
10546 synchronized (r.stats.getBatteryStats()) {
10547 r.stats.stopLaunchedLocked();
10548 }
10549 r.app.services.remove(r);
10550 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010551 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010552 if (DEBUG_SERVICE) Log.v(TAG,
10553 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010554 bumpServiceExecutingLocked(r);
10555 mStoppingServices.add(r);
10556 updateOomAdjLocked(r.app);
10557 r.app.thread.scheduleStopService(r);
10558 } catch (Exception e) {
10559 Log.w(TAG, "Exception when stopping service "
10560 + r.shortName, e);
10561 serviceDoneExecutingLocked(r, true);
10562 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010563 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010564 } else {
10565 if (DEBUG_SERVICE) Log.v(
10566 TAG, "Removed service that has no process: " + r.shortName);
10567 }
10568 } else {
10569 if (DEBUG_SERVICE) Log.v(
10570 TAG, "Removed service that is not running: " + r.shortName);
10571 }
10572 }
10573
10574 ComponentName startServiceLocked(IApplicationThread caller,
10575 Intent service, String resolvedType,
10576 int callingPid, int callingUid) {
10577 synchronized(this) {
10578 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10579 + " type=" + resolvedType + " args=" + service.getExtras());
10580
10581 if (caller != null) {
10582 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10583 if (callerApp == null) {
10584 throw new SecurityException(
10585 "Unable to find app for caller " + caller
10586 + " (pid=" + Binder.getCallingPid()
10587 + ") when starting service " + service);
10588 }
10589 }
10590
10591 ServiceLookupResult res =
10592 retrieveServiceLocked(service, resolvedType,
10593 callingPid, callingUid);
10594 if (res == null) {
10595 return null;
10596 }
10597 if (res.record == null) {
10598 return new ComponentName("!", res.permission != null
10599 ? res.permission : "private to package");
10600 }
10601 ServiceRecord r = res.record;
10602 if (unscheduleServiceRestartLocked(r)) {
10603 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10604 + r.shortName);
10605 }
10606 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010607 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010608 r.lastStartId++;
10609 if (r.lastStartId < 1) {
10610 r.lastStartId = 1;
10611 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010612 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010613 r.lastActivity = SystemClock.uptimeMillis();
10614 synchronized (r.stats.getBatteryStats()) {
10615 r.stats.startRunningLocked();
10616 }
10617 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10618 return new ComponentName("!", "Service process is bad");
10619 }
10620 return r.name;
10621 }
10622 }
10623
10624 public ComponentName startService(IApplicationThread caller, Intent service,
10625 String resolvedType) {
10626 // Refuse possible leaked file descriptors
10627 if (service != null && service.hasFileDescriptors() == true) {
10628 throw new IllegalArgumentException("File descriptors passed in Intent");
10629 }
10630
10631 synchronized(this) {
10632 final int callingPid = Binder.getCallingPid();
10633 final int callingUid = Binder.getCallingUid();
10634 final long origId = Binder.clearCallingIdentity();
10635 ComponentName res = startServiceLocked(caller, service,
10636 resolvedType, callingPid, callingUid);
10637 Binder.restoreCallingIdentity(origId);
10638 return res;
10639 }
10640 }
10641
10642 ComponentName startServiceInPackage(int uid,
10643 Intent service, String resolvedType) {
10644 synchronized(this) {
10645 final long origId = Binder.clearCallingIdentity();
10646 ComponentName res = startServiceLocked(null, service,
10647 resolvedType, -1, uid);
10648 Binder.restoreCallingIdentity(origId);
10649 return res;
10650 }
10651 }
10652
10653 public int stopService(IApplicationThread caller, Intent service,
10654 String resolvedType) {
10655 // Refuse possible leaked file descriptors
10656 if (service != null && service.hasFileDescriptors() == true) {
10657 throw new IllegalArgumentException("File descriptors passed in Intent");
10658 }
10659
10660 synchronized(this) {
10661 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10662 + " type=" + resolvedType);
10663
10664 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10665 if (caller != null && callerApp == null) {
10666 throw new SecurityException(
10667 "Unable to find app for caller " + caller
10668 + " (pid=" + Binder.getCallingPid()
10669 + ") when stopping service " + service);
10670 }
10671
10672 // If this service is active, make sure it is stopped.
10673 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10674 if (r != null) {
10675 if (r.record != null) {
10676 synchronized (r.record.stats.getBatteryStats()) {
10677 r.record.stats.stopRunningLocked();
10678 }
10679 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010680 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010681 final long origId = Binder.clearCallingIdentity();
10682 bringDownServiceLocked(r.record, false);
10683 Binder.restoreCallingIdentity(origId);
10684 return 1;
10685 }
10686 return -1;
10687 }
10688 }
10689
10690 return 0;
10691 }
10692
10693 public IBinder peekService(Intent service, String resolvedType) {
10694 // Refuse possible leaked file descriptors
10695 if (service != null && service.hasFileDescriptors() == true) {
10696 throw new IllegalArgumentException("File descriptors passed in Intent");
10697 }
10698
10699 IBinder ret = null;
10700
10701 synchronized(this) {
10702 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10703
10704 if (r != null) {
10705 // r.record is null if findServiceLocked() failed the caller permission check
10706 if (r.record == null) {
10707 throw new SecurityException(
10708 "Permission Denial: Accessing service " + r.record.name
10709 + " from pid=" + Binder.getCallingPid()
10710 + ", uid=" + Binder.getCallingUid()
10711 + " requires " + r.permission);
10712 }
10713 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10714 if (ib != null) {
10715 ret = ib.binder;
10716 }
10717 }
10718 }
10719
10720 return ret;
10721 }
10722
10723 public boolean stopServiceToken(ComponentName className, IBinder token,
10724 int startId) {
10725 synchronized(this) {
10726 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10727 + " " + token + " startId=" + startId);
10728 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010729 if (r != null) {
10730 if (startId >= 0) {
10731 // Asked to only stop if done with all work. Note that
10732 // to avoid leaks, we will take this as dropping all
10733 // start items up to and including this one.
10734 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10735 if (si != null) {
10736 while (r.deliveredStarts.size() > 0) {
10737 if (r.deliveredStarts.remove(0) == si) {
10738 break;
10739 }
10740 }
10741 }
10742
10743 if (r.lastStartId != startId) {
10744 return false;
10745 }
10746
10747 if (r.deliveredStarts.size() > 0) {
10748 Log.w(TAG, "stopServiceToken startId " + startId
10749 + " is last, but have " + r.deliveredStarts.size()
10750 + " remaining args");
10751 }
10752 }
10753
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010754 synchronized (r.stats.getBatteryStats()) {
10755 r.stats.stopRunningLocked();
10756 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010757 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010758 }
10759 final long origId = Binder.clearCallingIdentity();
10760 bringDownServiceLocked(r, false);
10761 Binder.restoreCallingIdentity(origId);
10762 return true;
10763 }
10764 }
10765 return false;
10766 }
10767
10768 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010769 int id, Notification notification, boolean removeNotification) {
10770 final long origId = Binder.clearCallingIdentity();
10771 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010772 synchronized(this) {
10773 ServiceRecord r = findServiceLocked(className, token);
10774 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010775 if (id != 0) {
10776 if (notification == null) {
10777 throw new IllegalArgumentException("null notification");
10778 }
10779 if (r.foregroundId != id) {
10780 r.cancelNotification();
10781 r.foregroundId = id;
10782 }
10783 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10784 r.foregroundNoti = notification;
10785 r.isForeground = true;
10786 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010787 if (r.app != null) {
10788 updateServiceForegroundLocked(r.app, true);
10789 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010790 } else {
10791 if (r.isForeground) {
10792 r.isForeground = false;
10793 if (r.app != null) {
10794 updateServiceForegroundLocked(r.app, true);
10795 }
10796 }
10797 if (removeNotification) {
10798 r.cancelNotification();
10799 r.foregroundId = 0;
10800 r.foregroundNoti = null;
10801 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010802 }
10803 }
10804 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010805 } finally {
10806 Binder.restoreCallingIdentity(origId);
10807 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010808 }
10809
10810 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10811 boolean anyForeground = false;
10812 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10813 if (sr.isForeground) {
10814 anyForeground = true;
10815 break;
10816 }
10817 }
10818 if (anyForeground != proc.foregroundServices) {
10819 proc.foregroundServices = anyForeground;
10820 if (oomAdj) {
10821 updateOomAdjLocked();
10822 }
10823 }
10824 }
10825
10826 public int bindService(IApplicationThread caller, IBinder token,
10827 Intent service, String resolvedType,
10828 IServiceConnection connection, int flags) {
10829 // Refuse possible leaked file descriptors
10830 if (service != null && service.hasFileDescriptors() == true) {
10831 throw new IllegalArgumentException("File descriptors passed in Intent");
10832 }
10833
10834 synchronized(this) {
10835 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10836 + " type=" + resolvedType + " conn=" + connection.asBinder()
10837 + " flags=0x" + Integer.toHexString(flags));
10838 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10839 if (callerApp == null) {
10840 throw new SecurityException(
10841 "Unable to find app for caller " + caller
10842 + " (pid=" + Binder.getCallingPid()
10843 + ") when binding service " + service);
10844 }
10845
10846 HistoryRecord activity = null;
10847 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010848 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010849 if (aindex < 0) {
10850 Log.w(TAG, "Binding with unknown activity: " + token);
10851 return 0;
10852 }
10853 activity = (HistoryRecord)mHistory.get(aindex);
10854 }
10855
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010856 int clientLabel = 0;
10857 PendingIntent clientIntent = null;
10858
10859 if (callerApp.info.uid == Process.SYSTEM_UID) {
10860 // Hacky kind of thing -- allow system stuff to tell us
10861 // what they are, so we can report this elsewhere for
10862 // others to know why certain services are running.
10863 try {
10864 clientIntent = (PendingIntent)service.getParcelableExtra(
10865 Intent.EXTRA_CLIENT_INTENT);
10866 } catch (RuntimeException e) {
10867 }
10868 if (clientIntent != null) {
10869 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
10870 if (clientLabel != 0) {
10871 // There are no useful extras in the intent, trash them.
10872 // System code calling with this stuff just needs to know
10873 // this will happen.
10874 service = service.cloneFilter();
10875 }
10876 }
10877 }
10878
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010879 ServiceLookupResult res =
10880 retrieveServiceLocked(service, resolvedType,
10881 Binder.getCallingPid(), Binder.getCallingUid());
10882 if (res == null) {
10883 return 0;
10884 }
10885 if (res.record == null) {
10886 return -1;
10887 }
10888 ServiceRecord s = res.record;
10889
10890 final long origId = Binder.clearCallingIdentity();
10891
10892 if (unscheduleServiceRestartLocked(s)) {
10893 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10894 + s.shortName);
10895 }
10896
10897 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10898 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010899 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010900
10901 IBinder binder = connection.asBinder();
10902 s.connections.put(binder, c);
10903 b.connections.add(c);
10904 if (activity != null) {
10905 if (activity.connections == null) {
10906 activity.connections = new HashSet<ConnectionRecord>();
10907 }
10908 activity.connections.add(c);
10909 }
10910 b.client.connections.add(c);
10911 mServiceConnections.put(binder, c);
10912
10913 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10914 s.lastActivity = SystemClock.uptimeMillis();
10915 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10916 return 0;
10917 }
10918 }
10919
10920 if (s.app != null) {
10921 // This could have made the service more important.
10922 updateOomAdjLocked(s.app);
10923 }
10924
10925 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10926 + ": received=" + b.intent.received
10927 + " apps=" + b.intent.apps.size()
10928 + " doRebind=" + b.intent.doRebind);
10929
10930 if (s.app != null && b.intent.received) {
10931 // Service is already running, so we can immediately
10932 // publish the connection.
10933 try {
10934 c.conn.connected(s.name, b.intent.binder);
10935 } catch (Exception e) {
10936 Log.w(TAG, "Failure sending service " + s.shortName
10937 + " to connection " + c.conn.asBinder()
10938 + " (in " + c.binding.client.processName + ")", e);
10939 }
10940
10941 // If this is the first app connected back to this binding,
10942 // and the service had previously asked to be told when
10943 // rebound, then do so.
10944 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10945 requestServiceBindingLocked(s, b.intent, true);
10946 }
10947 } else if (!b.intent.requested) {
10948 requestServiceBindingLocked(s, b.intent, false);
10949 }
10950
10951 Binder.restoreCallingIdentity(origId);
10952 }
10953
10954 return 1;
10955 }
10956
10957 private void removeConnectionLocked(
10958 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10959 IBinder binder = c.conn.asBinder();
10960 AppBindRecord b = c.binding;
10961 ServiceRecord s = b.service;
10962 s.connections.remove(binder);
10963 b.connections.remove(c);
10964 if (c.activity != null && c.activity != skipAct) {
10965 if (c.activity.connections != null) {
10966 c.activity.connections.remove(c);
10967 }
10968 }
10969 if (b.client != skipApp) {
10970 b.client.connections.remove(c);
10971 }
10972 mServiceConnections.remove(binder);
10973
10974 if (b.connections.size() == 0) {
10975 b.intent.apps.remove(b.client);
10976 }
10977
10978 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10979 + ": shouldUnbind=" + b.intent.hasBound);
10980 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10981 && b.intent.hasBound) {
10982 try {
10983 bumpServiceExecutingLocked(s);
10984 updateOomAdjLocked(s.app);
10985 b.intent.hasBound = false;
10986 // Assume the client doesn't want to know about a rebind;
10987 // we will deal with that later if it asks for one.
10988 b.intent.doRebind = false;
10989 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10990 } catch (Exception e) {
10991 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10992 serviceDoneExecutingLocked(s, true);
10993 }
10994 }
10995
10996 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10997 bringDownServiceLocked(s, false);
10998 }
10999 }
11000
11001 public boolean unbindService(IServiceConnection connection) {
11002 synchronized (this) {
11003 IBinder binder = connection.asBinder();
11004 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11005 ConnectionRecord r = mServiceConnections.get(binder);
11006 if (r == null) {
11007 Log.w(TAG, "Unbind failed: could not find connection for "
11008 + connection.asBinder());
11009 return false;
11010 }
11011
11012 final long origId = Binder.clearCallingIdentity();
11013
11014 removeConnectionLocked(r, null, null);
11015
11016 if (r.binding.service.app != null) {
11017 // This could have made the service less important.
11018 updateOomAdjLocked(r.binding.service.app);
11019 }
11020
11021 Binder.restoreCallingIdentity(origId);
11022 }
11023
11024 return true;
11025 }
11026
11027 public void publishService(IBinder token, Intent intent, IBinder service) {
11028 // Refuse possible leaked file descriptors
11029 if (intent != null && intent.hasFileDescriptors() == true) {
11030 throw new IllegalArgumentException("File descriptors passed in Intent");
11031 }
11032
11033 synchronized(this) {
11034 if (!(token instanceof ServiceRecord)) {
11035 throw new IllegalArgumentException("Invalid service token");
11036 }
11037 ServiceRecord r = (ServiceRecord)token;
11038
11039 final long origId = Binder.clearCallingIdentity();
11040
11041 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11042 + " " + intent + ": " + service);
11043 if (r != null) {
11044 Intent.FilterComparison filter
11045 = new Intent.FilterComparison(intent);
11046 IntentBindRecord b = r.bindings.get(filter);
11047 if (b != null && !b.received) {
11048 b.binder = service;
11049 b.requested = true;
11050 b.received = true;
11051 if (r.connections.size() > 0) {
11052 Iterator<ConnectionRecord> it
11053 = r.connections.values().iterator();
11054 while (it.hasNext()) {
11055 ConnectionRecord c = it.next();
11056 if (!filter.equals(c.binding.intent.intent)) {
11057 if (DEBUG_SERVICE) Log.v(
11058 TAG, "Not publishing to: " + c);
11059 if (DEBUG_SERVICE) Log.v(
11060 TAG, "Bound intent: " + c.binding.intent.intent);
11061 if (DEBUG_SERVICE) Log.v(
11062 TAG, "Published intent: " + intent);
11063 continue;
11064 }
11065 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11066 try {
11067 c.conn.connected(r.name, service);
11068 } catch (Exception e) {
11069 Log.w(TAG, "Failure sending service " + r.name +
11070 " to connection " + c.conn.asBinder() +
11071 " (in " + c.binding.client.processName + ")", e);
11072 }
11073 }
11074 }
11075 }
11076
11077 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11078
11079 Binder.restoreCallingIdentity(origId);
11080 }
11081 }
11082 }
11083
11084 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11085 // Refuse possible leaked file descriptors
11086 if (intent != null && intent.hasFileDescriptors() == true) {
11087 throw new IllegalArgumentException("File descriptors passed in Intent");
11088 }
11089
11090 synchronized(this) {
11091 if (!(token instanceof ServiceRecord)) {
11092 throw new IllegalArgumentException("Invalid service token");
11093 }
11094 ServiceRecord r = (ServiceRecord)token;
11095
11096 final long origId = Binder.clearCallingIdentity();
11097
11098 if (r != null) {
11099 Intent.FilterComparison filter
11100 = new Intent.FilterComparison(intent);
11101 IntentBindRecord b = r.bindings.get(filter);
11102 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11103 + " at " + b + ": apps="
11104 + (b != null ? b.apps.size() : 0));
11105 if (b != null) {
11106 if (b.apps.size() > 0) {
11107 // Applications have already bound since the last
11108 // unbind, so just rebind right here.
11109 requestServiceBindingLocked(r, b, true);
11110 } else {
11111 // Note to tell the service the next time there is
11112 // a new client.
11113 b.doRebind = true;
11114 }
11115 }
11116
11117 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11118
11119 Binder.restoreCallingIdentity(origId);
11120 }
11121 }
11122 }
11123
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011124 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011125 synchronized(this) {
11126 if (!(token instanceof ServiceRecord)) {
11127 throw new IllegalArgumentException("Invalid service token");
11128 }
11129 ServiceRecord r = (ServiceRecord)token;
11130 boolean inStopping = mStoppingServices.contains(token);
11131 if (r != null) {
11132 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11133 + ": nesting=" + r.executeNesting
11134 + ", inStopping=" + inStopping);
11135 if (r != token) {
11136 Log.w(TAG, "Done executing service " + r.name
11137 + " with incorrect token: given " + token
11138 + ", expected " + r);
11139 return;
11140 }
11141
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011142 if (type == 1) {
11143 // This is a call from a service start... take care of
11144 // book-keeping.
11145 r.callStart = true;
11146 switch (res) {
11147 case Service.START_STICKY_COMPATIBILITY:
11148 case Service.START_STICKY: {
11149 // We are done with the associated start arguments.
11150 r.findDeliveredStart(startId, true);
11151 // Don't stop if killed.
11152 r.stopIfKilled = false;
11153 break;
11154 }
11155 case Service.START_NOT_STICKY: {
11156 // We are done with the associated start arguments.
11157 r.findDeliveredStart(startId, true);
11158 if (r.lastStartId == startId) {
11159 // There is no more work, and this service
11160 // doesn't want to hang around if killed.
11161 r.stopIfKilled = true;
11162 }
11163 break;
11164 }
11165 case Service.START_REDELIVER_INTENT: {
11166 // We'll keep this item until they explicitly
11167 // call stop for it, but keep track of the fact
11168 // that it was delivered.
11169 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11170 if (si != null) {
11171 si.deliveryCount = 0;
11172 si.doneExecutingCount++;
11173 // Don't stop if killed.
11174 r.stopIfKilled = true;
11175 }
11176 break;
11177 }
11178 default:
11179 throw new IllegalArgumentException(
11180 "Unknown service start result: " + res);
11181 }
11182 if (res == Service.START_STICKY_COMPATIBILITY) {
11183 r.callStart = false;
11184 }
11185 }
11186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011187 final long origId = Binder.clearCallingIdentity();
11188 serviceDoneExecutingLocked(r, inStopping);
11189 Binder.restoreCallingIdentity(origId);
11190 } else {
11191 Log.w(TAG, "Done executing unknown service " + r.name
11192 + " with token " + token);
11193 }
11194 }
11195 }
11196
11197 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11198 r.executeNesting--;
11199 if (r.executeNesting <= 0 && r.app != null) {
11200 r.app.executingServices.remove(r);
11201 if (r.app.executingServices.size() == 0) {
11202 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11203 }
11204 if (inStopping) {
11205 mStoppingServices.remove(r);
11206 }
11207 updateOomAdjLocked(r.app);
11208 }
11209 }
11210
11211 void serviceTimeout(ProcessRecord proc) {
11212 synchronized(this) {
11213 if (proc.executingServices.size() == 0 || proc.thread == null) {
11214 return;
11215 }
11216 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11217 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11218 ServiceRecord timeout = null;
11219 long nextTime = 0;
11220 while (it.hasNext()) {
11221 ServiceRecord sr = it.next();
11222 if (sr.executingStart < maxTime) {
11223 timeout = sr;
11224 break;
11225 }
11226 if (sr.executingStart > nextTime) {
11227 nextTime = sr.executingStart;
11228 }
11229 }
11230 if (timeout != null && mLRUProcesses.contains(proc)) {
11231 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011232 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011233 + timeout.name);
11234 } else {
11235 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11236 msg.obj = proc;
11237 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11238 }
11239 }
11240 }
11241
11242 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011243 // BACKUP AND RESTORE
11244 // =========================================================
11245
11246 // Cause the target app to be launched if necessary and its backup agent
11247 // instantiated. The backup agent will invoke backupAgentCreated() on the
11248 // activity manager to announce its creation.
11249 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11250 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11251 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11252
11253 synchronized(this) {
11254 // !!! TODO: currently no check here that we're already bound
11255 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11256 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11257 synchronized (stats) {
11258 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11259 }
11260
11261 BackupRecord r = new BackupRecord(ss, app, backupMode);
11262 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11263 // startProcessLocked() returns existing proc's record if it's already running
11264 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011265 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011266 if (proc == null) {
11267 Log.e(TAG, "Unable to start backup agent process " + r);
11268 return false;
11269 }
11270
11271 r.app = proc;
11272 mBackupTarget = r;
11273 mBackupAppName = app.packageName;
11274
Christopher Tate6fa95972009-06-05 18:43:55 -070011275 // Try not to kill the process during backup
11276 updateOomAdjLocked(proc);
11277
Christopher Tate181fafa2009-05-14 11:12:14 -070011278 // If the process is already attached, schedule the creation of the backup agent now.
11279 // If it is not yet live, this will be done when it attaches to the framework.
11280 if (proc.thread != null) {
11281 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11282 try {
11283 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11284 } catch (RemoteException e) {
11285 // !!! TODO: notify the backup manager that we crashed, or rely on
11286 // death notices, or...?
11287 }
11288 } else {
11289 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11290 }
11291 // Invariants: at this point, the target app process exists and the application
11292 // is either already running or in the process of coming up. mBackupTarget and
11293 // mBackupAppName describe the app, so that when it binds back to the AM we
11294 // know that it's scheduled for a backup-agent operation.
11295 }
11296
11297 return true;
11298 }
11299
11300 // A backup agent has just come up
11301 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11302 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11303 + " = " + agent);
11304
11305 synchronized(this) {
11306 if (!agentPackageName.equals(mBackupAppName)) {
11307 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11308 return;
11309 }
11310
Christopher Tate043dadc2009-06-02 16:11:00 -070011311 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011312 try {
11313 IBackupManager bm = IBackupManager.Stub.asInterface(
11314 ServiceManager.getService(Context.BACKUP_SERVICE));
11315 bm.agentConnected(agentPackageName, agent);
11316 } catch (RemoteException e) {
11317 // can't happen; the backup manager service is local
11318 } catch (Exception e) {
11319 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11320 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011321 } finally {
11322 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011323 }
11324 }
11325 }
11326
11327 // done with this agent
11328 public void unbindBackupAgent(ApplicationInfo appInfo) {
11329 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011330 if (appInfo == null) {
11331 Log.w(TAG, "unbind backup agent for null app");
11332 return;
11333 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011334
11335 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011336 if (mBackupAppName == null) {
11337 Log.w(TAG, "Unbinding backup agent with no active backup");
11338 return;
11339 }
11340
Christopher Tate181fafa2009-05-14 11:12:14 -070011341 if (!mBackupAppName.equals(appInfo.packageName)) {
11342 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11343 return;
11344 }
11345
Christopher Tate6fa95972009-06-05 18:43:55 -070011346 ProcessRecord proc = mBackupTarget.app;
11347 mBackupTarget = null;
11348 mBackupAppName = null;
11349
11350 // Not backing this app up any more; reset its OOM adjustment
11351 updateOomAdjLocked(proc);
11352
Christopher Tatec7b31e32009-06-10 15:49:30 -070011353 // If the app crashed during backup, 'thread' will be null here
11354 if (proc.thread != null) {
11355 try {
11356 proc.thread.scheduleDestroyBackupAgent(appInfo);
11357 } catch (Exception e) {
11358 Log.e(TAG, "Exception when unbinding backup agent:");
11359 e.printStackTrace();
11360 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011361 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011362 }
11363 }
11364 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011365 // BROADCASTS
11366 // =========================================================
11367
11368 private final List getStickies(String action, IntentFilter filter,
11369 List cur) {
11370 final ContentResolver resolver = mContext.getContentResolver();
11371 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11372 if (list == null) {
11373 return cur;
11374 }
11375 int N = list.size();
11376 for (int i=0; i<N; i++) {
11377 Intent intent = list.get(i);
11378 if (filter.match(resolver, intent, true, TAG) >= 0) {
11379 if (cur == null) {
11380 cur = new ArrayList<Intent>();
11381 }
11382 cur.add(intent);
11383 }
11384 }
11385 return cur;
11386 }
11387
11388 private final void scheduleBroadcastsLocked() {
11389 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11390 + mBroadcastsScheduled);
11391
11392 if (mBroadcastsScheduled) {
11393 return;
11394 }
11395 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11396 mBroadcastsScheduled = true;
11397 }
11398
11399 public Intent registerReceiver(IApplicationThread caller,
11400 IIntentReceiver receiver, IntentFilter filter, String permission) {
11401 synchronized(this) {
11402 ProcessRecord callerApp = null;
11403 if (caller != null) {
11404 callerApp = getRecordForAppLocked(caller);
11405 if (callerApp == null) {
11406 throw new SecurityException(
11407 "Unable to find app for caller " + caller
11408 + " (pid=" + Binder.getCallingPid()
11409 + ") when registering receiver " + receiver);
11410 }
11411 }
11412
11413 List allSticky = null;
11414
11415 // Look for any matching sticky broadcasts...
11416 Iterator actions = filter.actionsIterator();
11417 if (actions != null) {
11418 while (actions.hasNext()) {
11419 String action = (String)actions.next();
11420 allSticky = getStickies(action, filter, allSticky);
11421 }
11422 } else {
11423 allSticky = getStickies(null, filter, allSticky);
11424 }
11425
11426 // The first sticky in the list is returned directly back to
11427 // the client.
11428 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11429
11430 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11431 + ": " + sticky);
11432
11433 if (receiver == null) {
11434 return sticky;
11435 }
11436
11437 ReceiverList rl
11438 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11439 if (rl == null) {
11440 rl = new ReceiverList(this, callerApp,
11441 Binder.getCallingPid(),
11442 Binder.getCallingUid(), receiver);
11443 if (rl.app != null) {
11444 rl.app.receivers.add(rl);
11445 } else {
11446 try {
11447 receiver.asBinder().linkToDeath(rl, 0);
11448 } catch (RemoteException e) {
11449 return sticky;
11450 }
11451 rl.linkedToDeath = true;
11452 }
11453 mRegisteredReceivers.put(receiver.asBinder(), rl);
11454 }
11455 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11456 rl.add(bf);
11457 if (!bf.debugCheck()) {
11458 Log.w(TAG, "==> For Dynamic broadast");
11459 }
11460 mReceiverResolver.addFilter(bf);
11461
11462 // Enqueue broadcasts for all existing stickies that match
11463 // this filter.
11464 if (allSticky != null) {
11465 ArrayList receivers = new ArrayList();
11466 receivers.add(bf);
11467
11468 int N = allSticky.size();
11469 for (int i=0; i<N; i++) {
11470 Intent intent = (Intent)allSticky.get(i);
11471 BroadcastRecord r = new BroadcastRecord(intent, null,
11472 null, -1, -1, null, receivers, null, 0, null, null,
11473 false);
11474 if (mParallelBroadcasts.size() == 0) {
11475 scheduleBroadcastsLocked();
11476 }
11477 mParallelBroadcasts.add(r);
11478 }
11479 }
11480
11481 return sticky;
11482 }
11483 }
11484
11485 public void unregisterReceiver(IIntentReceiver receiver) {
11486 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11487
11488 boolean doNext = false;
11489
11490 synchronized(this) {
11491 ReceiverList rl
11492 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11493 if (rl != null) {
11494 if (rl.curBroadcast != null) {
11495 BroadcastRecord r = rl.curBroadcast;
11496 doNext = finishReceiverLocked(
11497 receiver.asBinder(), r.resultCode, r.resultData,
11498 r.resultExtras, r.resultAbort, true);
11499 }
11500
11501 if (rl.app != null) {
11502 rl.app.receivers.remove(rl);
11503 }
11504 removeReceiverLocked(rl);
11505 if (rl.linkedToDeath) {
11506 rl.linkedToDeath = false;
11507 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11508 }
11509 }
11510 }
11511
11512 if (!doNext) {
11513 return;
11514 }
11515
11516 final long origId = Binder.clearCallingIdentity();
11517 processNextBroadcast(false);
11518 trimApplications();
11519 Binder.restoreCallingIdentity(origId);
11520 }
11521
11522 void removeReceiverLocked(ReceiverList rl) {
11523 mRegisteredReceivers.remove(rl.receiver.asBinder());
11524 int N = rl.size();
11525 for (int i=0; i<N; i++) {
11526 mReceiverResolver.removeFilter(rl.get(i));
11527 }
11528 }
11529
11530 private final int broadcastIntentLocked(ProcessRecord callerApp,
11531 String callerPackage, Intent intent, String resolvedType,
11532 IIntentReceiver resultTo, int resultCode, String resultData,
11533 Bundle map, String requiredPermission,
11534 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11535 intent = new Intent(intent);
11536
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011537 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011538 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11539 + " ordered=" + ordered);
11540 if ((resultTo != null) && !ordered) {
11541 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11542 }
11543
11544 // Handle special intents: if this broadcast is from the package
11545 // manager about a package being removed, we need to remove all of
11546 // its activities from the history stack.
11547 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11548 intent.getAction());
11549 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11550 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11551 || uidRemoved) {
11552 if (checkComponentPermission(
11553 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11554 callingPid, callingUid, -1)
11555 == PackageManager.PERMISSION_GRANTED) {
11556 if (uidRemoved) {
11557 final Bundle intentExtras = intent.getExtras();
11558 final int uid = intentExtras != null
11559 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11560 if (uid >= 0) {
11561 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11562 synchronized (bs) {
11563 bs.removeUidStatsLocked(uid);
11564 }
11565 }
11566 } else {
11567 Uri data = intent.getData();
11568 String ssp;
11569 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11570 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11571 uninstallPackageLocked(ssp,
11572 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011573 AttributeCache ac = AttributeCache.instance();
11574 if (ac != null) {
11575 ac.removePackage(ssp);
11576 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011577 }
11578 }
11579 }
11580 } else {
11581 String msg = "Permission Denial: " + intent.getAction()
11582 + " broadcast from " + callerPackage + " (pid=" + callingPid
11583 + ", uid=" + callingUid + ")"
11584 + " requires "
11585 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11586 Log.w(TAG, msg);
11587 throw new SecurityException(msg);
11588 }
11589 }
11590
11591 /*
11592 * If this is the time zone changed action, queue up a message that will reset the timezone
11593 * of all currently running processes. This message will get queued up before the broadcast
11594 * happens.
11595 */
11596 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11597 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11598 }
11599
Dianne Hackborn854060af2009-07-09 18:14:31 -070011600 /*
11601 * Prevent non-system code (defined here to be non-persistent
11602 * processes) from sending protected broadcasts.
11603 */
11604 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11605 || callingUid == Process.SHELL_UID || callingUid == 0) {
11606 // Always okay.
11607 } else if (callerApp == null || !callerApp.persistent) {
11608 try {
11609 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11610 intent.getAction())) {
11611 String msg = "Permission Denial: not allowed to send broadcast "
11612 + intent.getAction() + " from pid="
11613 + callingPid + ", uid=" + callingUid;
11614 Log.w(TAG, msg);
11615 throw new SecurityException(msg);
11616 }
11617 } catch (RemoteException e) {
11618 Log.w(TAG, "Remote exception", e);
11619 return BROADCAST_SUCCESS;
11620 }
11621 }
11622
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011623 // Add to the sticky list if requested.
11624 if (sticky) {
11625 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11626 callingPid, callingUid)
11627 != PackageManager.PERMISSION_GRANTED) {
11628 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11629 + callingPid + ", uid=" + callingUid
11630 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11631 Log.w(TAG, msg);
11632 throw new SecurityException(msg);
11633 }
11634 if (requiredPermission != null) {
11635 Log.w(TAG, "Can't broadcast sticky intent " + intent
11636 + " and enforce permission " + requiredPermission);
11637 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11638 }
11639 if (intent.getComponent() != null) {
11640 throw new SecurityException(
11641 "Sticky broadcasts can't target a specific component");
11642 }
11643 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11644 if (list == null) {
11645 list = new ArrayList<Intent>();
11646 mStickyBroadcasts.put(intent.getAction(), list);
11647 }
11648 int N = list.size();
11649 int i;
11650 for (i=0; i<N; i++) {
11651 if (intent.filterEquals(list.get(i))) {
11652 // This sticky already exists, replace it.
11653 list.set(i, new Intent(intent));
11654 break;
11655 }
11656 }
11657 if (i >= N) {
11658 list.add(new Intent(intent));
11659 }
11660 }
11661
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011662 // Figure out who all will receive this broadcast.
11663 List receivers = null;
11664 List<BroadcastFilter> registeredReceivers = null;
11665 try {
11666 if (intent.getComponent() != null) {
11667 // Broadcast is going to one specific receiver class...
11668 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011669 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011670 if (ai != null) {
11671 receivers = new ArrayList();
11672 ResolveInfo ri = new ResolveInfo();
11673 ri.activityInfo = ai;
11674 receivers.add(ri);
11675 }
11676 } else {
11677 // Need to resolve the intent to interested receivers...
11678 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11679 == 0) {
11680 receivers =
11681 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011682 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011683 }
Mihai Preda074edef2009-05-18 17:13:31 +020011684 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011685 }
11686 } catch (RemoteException ex) {
11687 // pm is in same process, this will never happen.
11688 }
11689
11690 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11691 if (!ordered && NR > 0) {
11692 // If we are not serializing this broadcast, then send the
11693 // registered receivers separately so they don't wait for the
11694 // components to be launched.
11695 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11696 callerPackage, callingPid, callingUid, requiredPermission,
11697 registeredReceivers, resultTo, resultCode, resultData, map,
11698 ordered);
11699 if (DEBUG_BROADCAST) Log.v(
11700 TAG, "Enqueueing parallel broadcast " + r
11701 + ": prev had " + mParallelBroadcasts.size());
11702 mParallelBroadcasts.add(r);
11703 scheduleBroadcastsLocked();
11704 registeredReceivers = null;
11705 NR = 0;
11706 }
11707
11708 // Merge into one list.
11709 int ir = 0;
11710 if (receivers != null) {
11711 // A special case for PACKAGE_ADDED: do not allow the package
11712 // being added to see this broadcast. This prevents them from
11713 // using this as a back door to get run as soon as they are
11714 // installed. Maybe in the future we want to have a special install
11715 // broadcast or such for apps, but we'd like to deliberately make
11716 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011717 boolean skip = false;
11718 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011719 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011720 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11721 skip = true;
11722 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11723 skip = true;
11724 }
11725 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011726 ? intent.getData().getSchemeSpecificPart()
11727 : null;
11728 if (skipPackage != null && receivers != null) {
11729 int NT = receivers.size();
11730 for (int it=0; it<NT; it++) {
11731 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11732 if (curt.activityInfo.packageName.equals(skipPackage)) {
11733 receivers.remove(it);
11734 it--;
11735 NT--;
11736 }
11737 }
11738 }
11739
11740 int NT = receivers != null ? receivers.size() : 0;
11741 int it = 0;
11742 ResolveInfo curt = null;
11743 BroadcastFilter curr = null;
11744 while (it < NT && ir < NR) {
11745 if (curt == null) {
11746 curt = (ResolveInfo)receivers.get(it);
11747 }
11748 if (curr == null) {
11749 curr = registeredReceivers.get(ir);
11750 }
11751 if (curr.getPriority() >= curt.priority) {
11752 // Insert this broadcast record into the final list.
11753 receivers.add(it, curr);
11754 ir++;
11755 curr = null;
11756 it++;
11757 NT++;
11758 } else {
11759 // Skip to the next ResolveInfo in the final list.
11760 it++;
11761 curt = null;
11762 }
11763 }
11764 }
11765 while (ir < NR) {
11766 if (receivers == null) {
11767 receivers = new ArrayList();
11768 }
11769 receivers.add(registeredReceivers.get(ir));
11770 ir++;
11771 }
11772
11773 if ((receivers != null && receivers.size() > 0)
11774 || resultTo != null) {
11775 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11776 callerPackage, callingPid, callingUid, requiredPermission,
11777 receivers, resultTo, resultCode, resultData, map, ordered);
11778 if (DEBUG_BROADCAST) Log.v(
11779 TAG, "Enqueueing ordered broadcast " + r
11780 + ": prev had " + mOrderedBroadcasts.size());
11781 if (DEBUG_BROADCAST) {
11782 int seq = r.intent.getIntExtra("seq", -1);
11783 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11784 }
11785 mOrderedBroadcasts.add(r);
11786 scheduleBroadcastsLocked();
11787 }
11788
11789 return BROADCAST_SUCCESS;
11790 }
11791
11792 public final int broadcastIntent(IApplicationThread caller,
11793 Intent intent, String resolvedType, IIntentReceiver resultTo,
11794 int resultCode, String resultData, Bundle map,
11795 String requiredPermission, boolean serialized, boolean sticky) {
11796 // Refuse possible leaked file descriptors
11797 if (intent != null && intent.hasFileDescriptors() == true) {
11798 throw new IllegalArgumentException("File descriptors passed in Intent");
11799 }
11800
11801 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011802 int flags = intent.getFlags();
11803
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011804 if (!mSystemReady) {
11805 // if the caller really truly claims to know what they're doing, go
11806 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011807 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11808 intent = new Intent(intent);
11809 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11810 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11811 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11812 + " before boot completion");
11813 throw new IllegalStateException("Cannot broadcast before boot completed");
11814 }
11815 }
11816
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011817 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
11818 throw new IllegalArgumentException(
11819 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
11820 }
11821
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011822 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11823 final int callingPid = Binder.getCallingPid();
11824 final int callingUid = Binder.getCallingUid();
11825 final long origId = Binder.clearCallingIdentity();
11826 int res = broadcastIntentLocked(callerApp,
11827 callerApp != null ? callerApp.info.packageName : null,
11828 intent, resolvedType, resultTo,
11829 resultCode, resultData, map, requiredPermission, serialized,
11830 sticky, callingPid, callingUid);
11831 Binder.restoreCallingIdentity(origId);
11832 return res;
11833 }
11834 }
11835
11836 int broadcastIntentInPackage(String packageName, int uid,
11837 Intent intent, String resolvedType, IIntentReceiver resultTo,
11838 int resultCode, String resultData, Bundle map,
11839 String requiredPermission, boolean serialized, boolean sticky) {
11840 synchronized(this) {
11841 final long origId = Binder.clearCallingIdentity();
11842 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11843 resultTo, resultCode, resultData, map, requiredPermission,
11844 serialized, sticky, -1, uid);
11845 Binder.restoreCallingIdentity(origId);
11846 return res;
11847 }
11848 }
11849
11850 public final void unbroadcastIntent(IApplicationThread caller,
11851 Intent intent) {
11852 // Refuse possible leaked file descriptors
11853 if (intent != null && intent.hasFileDescriptors() == true) {
11854 throw new IllegalArgumentException("File descriptors passed in Intent");
11855 }
11856
11857 synchronized(this) {
11858 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11859 != PackageManager.PERMISSION_GRANTED) {
11860 String msg = "Permission Denial: unbroadcastIntent() from pid="
11861 + Binder.getCallingPid()
11862 + ", uid=" + Binder.getCallingUid()
11863 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11864 Log.w(TAG, msg);
11865 throw new SecurityException(msg);
11866 }
11867 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11868 if (list != null) {
11869 int N = list.size();
11870 int i;
11871 for (i=0; i<N; i++) {
11872 if (intent.filterEquals(list.get(i))) {
11873 list.remove(i);
11874 break;
11875 }
11876 }
11877 }
11878 }
11879 }
11880
11881 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11882 String resultData, Bundle resultExtras, boolean resultAbort,
11883 boolean explicit) {
11884 if (mOrderedBroadcasts.size() == 0) {
11885 if (explicit) {
11886 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11887 }
11888 return false;
11889 }
11890 BroadcastRecord r = mOrderedBroadcasts.get(0);
11891 if (r.receiver == null) {
11892 if (explicit) {
11893 Log.w(TAG, "finishReceiver called but none active");
11894 }
11895 return false;
11896 }
11897 if (r.receiver != receiver) {
11898 Log.w(TAG, "finishReceiver called but active receiver is different");
11899 return false;
11900 }
11901 int state = r.state;
11902 r.state = r.IDLE;
11903 if (state == r.IDLE) {
11904 if (explicit) {
11905 Log.w(TAG, "finishReceiver called but state is IDLE");
11906 }
11907 }
11908 r.receiver = null;
11909 r.intent.setComponent(null);
11910 if (r.curApp != null) {
11911 r.curApp.curReceiver = null;
11912 }
11913 if (r.curFilter != null) {
11914 r.curFilter.receiverList.curBroadcast = null;
11915 }
11916 r.curFilter = null;
11917 r.curApp = null;
11918 r.curComponent = null;
11919 r.curReceiver = null;
11920 mPendingBroadcast = null;
11921
11922 r.resultCode = resultCode;
11923 r.resultData = resultData;
11924 r.resultExtras = resultExtras;
11925 r.resultAbort = resultAbort;
11926
11927 // We will process the next receiver right now if this is finishing
11928 // an app receiver (which is always asynchronous) or after we have
11929 // come back from calling a receiver.
11930 return state == BroadcastRecord.APP_RECEIVE
11931 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11932 }
11933
11934 public void finishReceiver(IBinder who, int resultCode, String resultData,
11935 Bundle resultExtras, boolean resultAbort) {
11936 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11937
11938 // Refuse possible leaked file descriptors
11939 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11940 throw new IllegalArgumentException("File descriptors passed in Bundle");
11941 }
11942
11943 boolean doNext;
11944
11945 final long origId = Binder.clearCallingIdentity();
11946
11947 synchronized(this) {
11948 doNext = finishReceiverLocked(
11949 who, resultCode, resultData, resultExtras, resultAbort, true);
11950 }
11951
11952 if (doNext) {
11953 processNextBroadcast(false);
11954 }
11955 trimApplications();
11956
11957 Binder.restoreCallingIdentity(origId);
11958 }
11959
11960 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11961 if (r.nextReceiver > 0) {
11962 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11963 if (curReceiver instanceof BroadcastFilter) {
11964 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11965 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11966 System.identityHashCode(r),
11967 r.intent.getAction(),
11968 r.nextReceiver - 1,
11969 System.identityHashCode(bf));
11970 } else {
11971 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11972 System.identityHashCode(r),
11973 r.intent.getAction(),
11974 r.nextReceiver - 1,
11975 ((ResolveInfo)curReceiver).toString());
11976 }
11977 } else {
11978 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11979 + r);
11980 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11981 System.identityHashCode(r),
11982 r.intent.getAction(),
11983 r.nextReceiver,
11984 "NONE");
11985 }
11986 }
11987
11988 private final void broadcastTimeout() {
11989 synchronized (this) {
11990 if (mOrderedBroadcasts.size() == 0) {
11991 return;
11992 }
11993 long now = SystemClock.uptimeMillis();
11994 BroadcastRecord r = mOrderedBroadcasts.get(0);
11995 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11996 if (DEBUG_BROADCAST) Log.v(TAG,
11997 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11998 + (r.startTime + BROADCAST_TIMEOUT));
11999 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12000 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12001 return;
12002 }
12003
12004 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
12005 r.startTime = now;
12006 r.anrCount++;
12007
12008 // Current receiver has passed its expiration date.
12009 if (r.nextReceiver <= 0) {
12010 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12011 return;
12012 }
12013
12014 ProcessRecord app = null;
12015
12016 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12017 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12018 logBroadcastReceiverDiscard(r);
12019 if (curReceiver instanceof BroadcastFilter) {
12020 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12021 if (bf.receiverList.pid != 0
12022 && bf.receiverList.pid != MY_PID) {
12023 synchronized (this.mPidsSelfLocked) {
12024 app = this.mPidsSelfLocked.get(
12025 bf.receiverList.pid);
12026 }
12027 }
12028 } else {
12029 app = r.curApp;
12030 }
12031
12032 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070012033 appNotRespondingLocked(app, null, null,
12034 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012035 }
12036
12037 if (mPendingBroadcast == r) {
12038 mPendingBroadcast = null;
12039 }
12040
12041 // Move on to the next receiver.
12042 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12043 r.resultExtras, r.resultAbort, true);
12044 scheduleBroadcastsLocked();
12045 }
12046 }
12047
12048 private final void processCurBroadcastLocked(BroadcastRecord r,
12049 ProcessRecord app) throws RemoteException {
12050 if (app.thread == null) {
12051 throw new RemoteException();
12052 }
12053 r.receiver = app.thread.asBinder();
12054 r.curApp = app;
12055 app.curReceiver = r;
12056 updateLRUListLocked(app, true);
12057
12058 // Tell the application to launch this receiver.
12059 r.intent.setComponent(r.curComponent);
12060
12061 boolean started = false;
12062 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012063 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012064 "Delivering to component " + r.curComponent
12065 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012066 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012067 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12068 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12069 started = true;
12070 } finally {
12071 if (!started) {
12072 r.receiver = null;
12073 r.curApp = null;
12074 app.curReceiver = null;
12075 }
12076 }
12077
12078 }
12079
12080 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
12081 Intent intent, int resultCode, String data,
12082 Bundle extras, boolean ordered) throws RemoteException {
12083 if (app != null && app.thread != null) {
12084 // If we have an app thread, do the call through that so it is
12085 // correctly ordered with other one-way calls.
12086 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
12087 data, extras, ordered);
12088 } else {
12089 receiver.performReceive(intent, resultCode, data, extras, ordered);
12090 }
12091 }
12092
12093 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12094 BroadcastFilter filter, boolean ordered) {
12095 boolean skip = false;
12096 if (filter.requiredPermission != null) {
12097 int perm = checkComponentPermission(filter.requiredPermission,
12098 r.callingPid, r.callingUid, -1);
12099 if (perm != PackageManager.PERMISSION_GRANTED) {
12100 Log.w(TAG, "Permission Denial: broadcasting "
12101 + r.intent.toString()
12102 + " from " + r.callerPackage + " (pid="
12103 + r.callingPid + ", uid=" + r.callingUid + ")"
12104 + " requires " + filter.requiredPermission
12105 + " due to registered receiver " + filter);
12106 skip = true;
12107 }
12108 }
12109 if (r.requiredPermission != null) {
12110 int perm = checkComponentPermission(r.requiredPermission,
12111 filter.receiverList.pid, filter.receiverList.uid, -1);
12112 if (perm != PackageManager.PERMISSION_GRANTED) {
12113 Log.w(TAG, "Permission Denial: receiving "
12114 + r.intent.toString()
12115 + " to " + filter.receiverList.app
12116 + " (pid=" + filter.receiverList.pid
12117 + ", uid=" + filter.receiverList.uid + ")"
12118 + " requires " + r.requiredPermission
12119 + " due to sender " + r.callerPackage
12120 + " (uid " + r.callingUid + ")");
12121 skip = true;
12122 }
12123 }
12124
12125 if (!skip) {
12126 // If this is not being sent as an ordered broadcast, then we
12127 // don't want to touch the fields that keep track of the current
12128 // state of ordered broadcasts.
12129 if (ordered) {
12130 r.receiver = filter.receiverList.receiver.asBinder();
12131 r.curFilter = filter;
12132 filter.receiverList.curBroadcast = r;
12133 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012134 if (filter.receiverList.app != null) {
12135 // Bump hosting application to no longer be in background
12136 // scheduling class. Note that we can't do that if there
12137 // isn't an app... but we can only be in that case for
12138 // things that directly call the IActivityManager API, which
12139 // are already core system stuff so don't matter for this.
12140 r.curApp = filter.receiverList.app;
12141 filter.receiverList.app.curReceiver = r;
12142 updateOomAdjLocked();
12143 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012144 }
12145 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012146 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012147 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012148 Log.i(TAG, "Delivering to " + filter.receiverList.app
12149 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012150 }
12151 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12152 new Intent(r.intent), r.resultCode,
12153 r.resultData, r.resultExtras, r.ordered);
12154 if (ordered) {
12155 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12156 }
12157 } catch (RemoteException e) {
12158 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12159 if (ordered) {
12160 r.receiver = null;
12161 r.curFilter = null;
12162 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012163 if (filter.receiverList.app != null) {
12164 filter.receiverList.app.curReceiver = null;
12165 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012166 }
12167 }
12168 }
12169 }
12170
12171 private final void processNextBroadcast(boolean fromMsg) {
12172 synchronized(this) {
12173 BroadcastRecord r;
12174
12175 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12176 + mParallelBroadcasts.size() + " broadcasts, "
12177 + mOrderedBroadcasts.size() + " serialized broadcasts");
12178
12179 updateCpuStats();
12180
12181 if (fromMsg) {
12182 mBroadcastsScheduled = false;
12183 }
12184
12185 // First, deliver any non-serialized broadcasts right away.
12186 while (mParallelBroadcasts.size() > 0) {
12187 r = mParallelBroadcasts.remove(0);
12188 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012189 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12190 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012191 for (int i=0; i<N; i++) {
12192 Object target = r.receivers.get(i);
12193 if (DEBUG_BROADCAST) Log.v(TAG,
12194 "Delivering non-serialized to registered "
12195 + target + ": " + r);
12196 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12197 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012198 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12199 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012200 }
12201
12202 // Now take care of the next serialized one...
12203
12204 // If we are waiting for a process to come up to handle the next
12205 // broadcast, then do nothing at this point. Just in case, we
12206 // check that the process we're waiting for still exists.
12207 if (mPendingBroadcast != null) {
12208 Log.i(TAG, "processNextBroadcast: waiting for "
12209 + mPendingBroadcast.curApp);
12210
12211 boolean isDead;
12212 synchronized (mPidsSelfLocked) {
12213 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12214 }
12215 if (!isDead) {
12216 // It's still alive, so keep waiting
12217 return;
12218 } else {
12219 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12220 + " died before responding to broadcast");
12221 mPendingBroadcast = null;
12222 }
12223 }
12224
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012225 boolean looped = false;
12226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012227 do {
12228 if (mOrderedBroadcasts.size() == 0) {
12229 // No more broadcasts pending, so all done!
12230 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012231 if (looped) {
12232 // If we had finished the last ordered broadcast, then
12233 // make sure all processes have correct oom and sched
12234 // adjustments.
12235 updateOomAdjLocked();
12236 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012237 return;
12238 }
12239 r = mOrderedBroadcasts.get(0);
12240 boolean forceReceive = false;
12241
12242 // Ensure that even if something goes awry with the timeout
12243 // detection, we catch "hung" broadcasts here, discard them,
12244 // and continue to make progress.
12245 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12246 long now = SystemClock.uptimeMillis();
12247 if (r.dispatchTime > 0) {
12248 if ((numReceivers > 0) &&
12249 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12250 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12251 + " now=" + now
12252 + " dispatchTime=" + r.dispatchTime
12253 + " startTime=" + r.startTime
12254 + " intent=" + r.intent
12255 + " numReceivers=" + numReceivers
12256 + " nextReceiver=" + r.nextReceiver
12257 + " state=" + r.state);
12258 broadcastTimeout(); // forcibly finish this broadcast
12259 forceReceive = true;
12260 r.state = BroadcastRecord.IDLE;
12261 }
12262 }
12263
12264 if (r.state != BroadcastRecord.IDLE) {
12265 if (DEBUG_BROADCAST) Log.d(TAG,
12266 "processNextBroadcast() called when not idle (state="
12267 + r.state + ")");
12268 return;
12269 }
12270
12271 if (r.receivers == null || r.nextReceiver >= numReceivers
12272 || r.resultAbort || forceReceive) {
12273 // No more receivers for this broadcast! Send the final
12274 // result if requested...
12275 if (r.resultTo != null) {
12276 try {
12277 if (DEBUG_BROADCAST) {
12278 int seq = r.intent.getIntExtra("seq", -1);
12279 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12280 + " seq=" + seq + " app=" + r.callerApp);
12281 }
12282 performReceive(r.callerApp, r.resultTo,
12283 new Intent(r.intent), r.resultCode,
12284 r.resultData, r.resultExtras, false);
12285 } catch (RemoteException e) {
12286 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12287 }
12288 }
12289
12290 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12291 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12292
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012293 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12294 + r);
12295
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012296 // ... and on to the next...
12297 mOrderedBroadcasts.remove(0);
12298 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012299 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012300 continue;
12301 }
12302 } while (r == null);
12303
12304 // Get the next receiver...
12305 int recIdx = r.nextReceiver++;
12306
12307 // Keep track of when this receiver started, and make sure there
12308 // is a timeout message pending to kill it if need be.
12309 r.startTime = SystemClock.uptimeMillis();
12310 if (recIdx == 0) {
12311 r.dispatchTime = r.startTime;
12312
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012313 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12314 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012315 if (DEBUG_BROADCAST) Log.v(TAG,
12316 "Submitting BROADCAST_TIMEOUT_MSG for "
12317 + (r.startTime + BROADCAST_TIMEOUT));
12318 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12319 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12320 }
12321
12322 Object nextReceiver = r.receivers.get(recIdx);
12323 if (nextReceiver instanceof BroadcastFilter) {
12324 // Simple case: this is a registered receiver who gets
12325 // a direct call.
12326 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12327 if (DEBUG_BROADCAST) Log.v(TAG,
12328 "Delivering serialized to registered "
12329 + filter + ": " + r);
12330 deliverToRegisteredReceiver(r, filter, r.ordered);
12331 if (r.receiver == null || !r.ordered) {
12332 // The receiver has already finished, so schedule to
12333 // process the next one.
12334 r.state = BroadcastRecord.IDLE;
12335 scheduleBroadcastsLocked();
12336 }
12337 return;
12338 }
12339
12340 // Hard case: need to instantiate the receiver, possibly
12341 // starting its application process to host it.
12342
12343 ResolveInfo info =
12344 (ResolveInfo)nextReceiver;
12345
12346 boolean skip = false;
12347 int perm = checkComponentPermission(info.activityInfo.permission,
12348 r.callingPid, r.callingUid,
12349 info.activityInfo.exported
12350 ? -1 : info.activityInfo.applicationInfo.uid);
12351 if (perm != PackageManager.PERMISSION_GRANTED) {
12352 Log.w(TAG, "Permission Denial: broadcasting "
12353 + r.intent.toString()
12354 + " from " + r.callerPackage + " (pid=" + r.callingPid
12355 + ", uid=" + r.callingUid + ")"
12356 + " requires " + info.activityInfo.permission
12357 + " due to receiver " + info.activityInfo.packageName
12358 + "/" + info.activityInfo.name);
12359 skip = true;
12360 }
12361 if (r.callingUid != Process.SYSTEM_UID &&
12362 r.requiredPermission != null) {
12363 try {
12364 perm = ActivityThread.getPackageManager().
12365 checkPermission(r.requiredPermission,
12366 info.activityInfo.applicationInfo.packageName);
12367 } catch (RemoteException e) {
12368 perm = PackageManager.PERMISSION_DENIED;
12369 }
12370 if (perm != PackageManager.PERMISSION_GRANTED) {
12371 Log.w(TAG, "Permission Denial: receiving "
12372 + r.intent + " to "
12373 + info.activityInfo.applicationInfo.packageName
12374 + " requires " + r.requiredPermission
12375 + " due to sender " + r.callerPackage
12376 + " (uid " + r.callingUid + ")");
12377 skip = true;
12378 }
12379 }
12380 if (r.curApp != null && r.curApp.crashing) {
12381 // If the target process is crashing, just skip it.
12382 skip = true;
12383 }
12384
12385 if (skip) {
12386 r.receiver = null;
12387 r.curFilter = null;
12388 r.state = BroadcastRecord.IDLE;
12389 scheduleBroadcastsLocked();
12390 return;
12391 }
12392
12393 r.state = BroadcastRecord.APP_RECEIVE;
12394 String targetProcess = info.activityInfo.processName;
12395 r.curComponent = new ComponentName(
12396 info.activityInfo.applicationInfo.packageName,
12397 info.activityInfo.name);
12398 r.curReceiver = info.activityInfo;
12399
12400 // Is this receiver's application already running?
12401 ProcessRecord app = getProcessRecordLocked(targetProcess,
12402 info.activityInfo.applicationInfo.uid);
12403 if (app != null && app.thread != null) {
12404 try {
12405 processCurBroadcastLocked(r, app);
12406 return;
12407 } catch (RemoteException e) {
12408 Log.w(TAG, "Exception when sending broadcast to "
12409 + r.curComponent, e);
12410 }
12411
12412 // If a dead object exception was thrown -- fall through to
12413 // restart the application.
12414 }
12415
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012416 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012417 if ((r.curApp=startProcessLocked(targetProcess,
12418 info.activityInfo.applicationInfo, true,
12419 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012420 "broadcast", r.curComponent,
12421 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12422 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012423 // Ah, this recipient is unavailable. Finish it if necessary,
12424 // and mark the broadcast record as ready for the next.
12425 Log.w(TAG, "Unable to launch app "
12426 + info.activityInfo.applicationInfo.packageName + "/"
12427 + info.activityInfo.applicationInfo.uid + " for broadcast "
12428 + r.intent + ": process is bad");
12429 logBroadcastReceiverDiscard(r);
12430 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12431 r.resultExtras, r.resultAbort, true);
12432 scheduleBroadcastsLocked();
12433 r.state = BroadcastRecord.IDLE;
12434 return;
12435 }
12436
12437 mPendingBroadcast = r;
12438 }
12439 }
12440
12441 // =========================================================
12442 // INSTRUMENTATION
12443 // =========================================================
12444
12445 public boolean startInstrumentation(ComponentName className,
12446 String profileFile, int flags, Bundle arguments,
12447 IInstrumentationWatcher watcher) {
12448 // Refuse possible leaked file descriptors
12449 if (arguments != null && arguments.hasFileDescriptors()) {
12450 throw new IllegalArgumentException("File descriptors passed in Bundle");
12451 }
12452
12453 synchronized(this) {
12454 InstrumentationInfo ii = null;
12455 ApplicationInfo ai = null;
12456 try {
12457 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012458 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012459 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012460 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012461 } catch (PackageManager.NameNotFoundException e) {
12462 }
12463 if (ii == null) {
12464 reportStartInstrumentationFailure(watcher, className,
12465 "Unable to find instrumentation info for: " + className);
12466 return false;
12467 }
12468 if (ai == null) {
12469 reportStartInstrumentationFailure(watcher, className,
12470 "Unable to find instrumentation target package: " + ii.targetPackage);
12471 return false;
12472 }
12473
12474 int match = mContext.getPackageManager().checkSignatures(
12475 ii.targetPackage, ii.packageName);
12476 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12477 String msg = "Permission Denial: starting instrumentation "
12478 + className + " from pid="
12479 + Binder.getCallingPid()
12480 + ", uid=" + Binder.getCallingPid()
12481 + " not allowed because package " + ii.packageName
12482 + " does not have a signature matching the target "
12483 + ii.targetPackage;
12484 reportStartInstrumentationFailure(watcher, className, msg);
12485 throw new SecurityException(msg);
12486 }
12487
12488 final long origId = Binder.clearCallingIdentity();
12489 uninstallPackageLocked(ii.targetPackage, -1, true);
12490 ProcessRecord app = addAppLocked(ai);
12491 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012492 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012493 app.instrumentationProfileFile = profileFile;
12494 app.instrumentationArguments = arguments;
12495 app.instrumentationWatcher = watcher;
12496 app.instrumentationResultClass = className;
12497 Binder.restoreCallingIdentity(origId);
12498 }
12499
12500 return true;
12501 }
12502
12503 /**
12504 * Report errors that occur while attempting to start Instrumentation. Always writes the
12505 * error to the logs, but if somebody is watching, send the report there too. This enables
12506 * the "am" command to report errors with more information.
12507 *
12508 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12509 * @param cn The component name of the instrumentation.
12510 * @param report The error report.
12511 */
12512 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12513 ComponentName cn, String report) {
12514 Log.w(TAG, report);
12515 try {
12516 if (watcher != null) {
12517 Bundle results = new Bundle();
12518 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12519 results.putString("Error", report);
12520 watcher.instrumentationStatus(cn, -1, results);
12521 }
12522 } catch (RemoteException e) {
12523 Log.w(TAG, e);
12524 }
12525 }
12526
12527 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12528 if (app.instrumentationWatcher != null) {
12529 try {
12530 // NOTE: IInstrumentationWatcher *must* be oneway here
12531 app.instrumentationWatcher.instrumentationFinished(
12532 app.instrumentationClass,
12533 resultCode,
12534 results);
12535 } catch (RemoteException e) {
12536 }
12537 }
12538 app.instrumentationWatcher = null;
12539 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012540 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012541 app.instrumentationProfileFile = null;
12542 app.instrumentationArguments = null;
12543
12544 uninstallPackageLocked(app.processName, -1, false);
12545 }
12546
12547 public void finishInstrumentation(IApplicationThread target,
12548 int resultCode, Bundle results) {
12549 // Refuse possible leaked file descriptors
12550 if (results != null && results.hasFileDescriptors()) {
12551 throw new IllegalArgumentException("File descriptors passed in Intent");
12552 }
12553
12554 synchronized(this) {
12555 ProcessRecord app = getRecordForAppLocked(target);
12556 if (app == null) {
12557 Log.w(TAG, "finishInstrumentation: no app for " + target);
12558 return;
12559 }
12560 final long origId = Binder.clearCallingIdentity();
12561 finishInstrumentationLocked(app, resultCode, results);
12562 Binder.restoreCallingIdentity(origId);
12563 }
12564 }
12565
12566 // =========================================================
12567 // CONFIGURATION
12568 // =========================================================
12569
12570 public ConfigurationInfo getDeviceConfigurationInfo() {
12571 ConfigurationInfo config = new ConfigurationInfo();
12572 synchronized (this) {
12573 config.reqTouchScreen = mConfiguration.touchscreen;
12574 config.reqKeyboardType = mConfiguration.keyboard;
12575 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012576 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12577 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012578 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12579 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012580 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12581 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012582 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12583 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012584 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012585 }
12586 return config;
12587 }
12588
12589 public Configuration getConfiguration() {
12590 Configuration ci;
12591 synchronized(this) {
12592 ci = new Configuration(mConfiguration);
12593 }
12594 return ci;
12595 }
12596
12597 public void updateConfiguration(Configuration values) {
12598 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12599 "updateConfiguration()");
12600
12601 synchronized(this) {
12602 if (values == null && mWindowManager != null) {
12603 // sentinel: fetch the current configuration from the window manager
12604 values = mWindowManager.computeNewConfiguration();
12605 }
12606
12607 final long origId = Binder.clearCallingIdentity();
12608 updateConfigurationLocked(values, null);
12609 Binder.restoreCallingIdentity(origId);
12610 }
12611 }
12612
12613 /**
12614 * Do either or both things: (1) change the current configuration, and (2)
12615 * make sure the given activity is running with the (now) current
12616 * configuration. Returns true if the activity has been left running, or
12617 * false if <var>starting</var> is being destroyed to match the new
12618 * configuration.
12619 */
12620 public boolean updateConfigurationLocked(Configuration values,
12621 HistoryRecord starting) {
12622 int changes = 0;
12623
12624 boolean kept = true;
12625
12626 if (values != null) {
12627 Configuration newConfig = new Configuration(mConfiguration);
12628 changes = newConfig.updateFrom(values);
12629 if (changes != 0) {
12630 if (DEBUG_SWITCH) {
12631 Log.i(TAG, "Updating configuration to: " + values);
12632 }
12633
12634 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12635
12636 if (values.locale != null) {
12637 saveLocaleLocked(values.locale,
12638 !values.locale.equals(mConfiguration.locale),
12639 values.userSetLocale);
12640 }
12641
12642 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012643 Log.i(TAG, "Config changed: " + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012644
12645 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12646 msg.obj = new Configuration(mConfiguration);
12647 mHandler.sendMessage(msg);
12648
12649 final int N = mLRUProcesses.size();
12650 for (int i=0; i<N; i++) {
12651 ProcessRecord app = mLRUProcesses.get(i);
12652 try {
12653 if (app.thread != null) {
12654 app.thread.scheduleConfigurationChanged(mConfiguration);
12655 }
12656 } catch (Exception e) {
12657 }
12658 }
12659 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12660 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12661 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012662
12663 AttributeCache ac = AttributeCache.instance();
12664 if (ac != null) {
12665 ac.updateConfiguration(mConfiguration);
12666 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012667 }
12668 }
12669
12670 if (changes != 0 && starting == null) {
12671 // If the configuration changed, and the caller is not already
12672 // in the process of starting an activity, then find the top
12673 // activity to check if its configuration needs to change.
12674 starting = topRunningActivityLocked(null);
12675 }
12676
12677 if (starting != null) {
12678 kept = ensureActivityConfigurationLocked(starting, changes);
12679 if (kept) {
12680 // If this didn't result in the starting activity being
12681 // destroyed, then we need to make sure at this point that all
12682 // other activities are made visible.
12683 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12684 + ", ensuring others are correct.");
12685 ensureActivitiesVisibleLocked(starting, changes);
12686 }
12687 }
12688
12689 return kept;
12690 }
12691
12692 private final boolean relaunchActivityLocked(HistoryRecord r,
12693 int changes, boolean andResume) {
12694 List<ResultInfo> results = null;
12695 List<Intent> newIntents = null;
12696 if (andResume) {
12697 results = r.results;
12698 newIntents = r.newIntents;
12699 }
12700 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12701 + " with results=" + results + " newIntents=" + newIntents
12702 + " andResume=" + andResume);
12703 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12704 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12705 r.task.taskId, r.shortComponentName);
12706
12707 r.startFreezingScreenLocked(r.app, 0);
12708
12709 try {
12710 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12711 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12712 changes, !andResume);
12713 // Note: don't need to call pauseIfSleepingLocked() here, because
12714 // the caller will only pass in 'andResume' if this activity is
12715 // currently resumed, which implies we aren't sleeping.
12716 } catch (RemoteException e) {
12717 return false;
12718 }
12719
12720 if (andResume) {
12721 r.results = null;
12722 r.newIntents = null;
12723 }
12724
12725 return true;
12726 }
12727
12728 /**
12729 * Make sure the given activity matches the current configuration. Returns
12730 * false if the activity had to be destroyed. Returns true if the
12731 * configuration is the same, or the activity will remain running as-is
12732 * for whatever reason. Ensures the HistoryRecord is updated with the
12733 * correct configuration and all other bookkeeping is handled.
12734 */
12735 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12736 int globalChanges) {
12737 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12738
12739 // Short circuit: if the two configurations are the exact same
12740 // object (the common case), then there is nothing to do.
12741 Configuration newConfig = mConfiguration;
12742 if (r.configuration == newConfig) {
12743 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12744 return true;
12745 }
12746
12747 // We don't worry about activities that are finishing.
12748 if (r.finishing) {
12749 if (DEBUG_SWITCH) Log.i(TAG,
12750 "Configuration doesn't matter in finishing " + r);
12751 r.stopFreezingScreenLocked(false);
12752 return true;
12753 }
12754
12755 // Okay we now are going to make this activity have the new config.
12756 // But then we need to figure out how it needs to deal with that.
12757 Configuration oldConfig = r.configuration;
12758 r.configuration = newConfig;
12759
12760 // If the activity isn't currently running, just leave the new
12761 // configuration and it will pick that up next time it starts.
12762 if (r.app == null || r.app.thread == null) {
12763 if (DEBUG_SWITCH) Log.i(TAG,
12764 "Configuration doesn't matter not running " + r);
12765 r.stopFreezingScreenLocked(false);
12766 return true;
12767 }
12768
12769 // If the activity isn't persistent, there is a chance we will
12770 // need to restart it.
12771 if (!r.persistent) {
12772
12773 // Figure out what has changed between the two configurations.
12774 int changes = oldConfig.diff(newConfig);
12775 if (DEBUG_SWITCH) {
12776 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12777 + Integer.toHexString(changes) + ", handles=0x"
12778 + Integer.toHexString(r.info.configChanges));
12779 }
12780 if ((changes&(~r.info.configChanges)) != 0) {
12781 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12782 r.configChangeFlags |= changes;
12783 r.startFreezingScreenLocked(r.app, globalChanges);
12784 if (r.app == null || r.app.thread == null) {
12785 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12786 destroyActivityLocked(r, true);
12787 } else if (r.state == ActivityState.PAUSING) {
12788 // A little annoying: we are waiting for this activity to
12789 // finish pausing. Let's not do anything now, but just
12790 // flag that it needs to be restarted when done pausing.
12791 r.configDestroy = true;
12792 return true;
12793 } else if (r.state == ActivityState.RESUMED) {
12794 // Try to optimize this case: the configuration is changing
12795 // and we need to restart the top, resumed activity.
12796 // Instead of doing the normal handshaking, just say
12797 // "restart!".
12798 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12799 relaunchActivityLocked(r, r.configChangeFlags, true);
12800 r.configChangeFlags = 0;
12801 } else {
12802 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12803 relaunchActivityLocked(r, r.configChangeFlags, false);
12804 r.configChangeFlags = 0;
12805 }
12806
12807 // All done... tell the caller we weren't able to keep this
12808 // activity around.
12809 return false;
12810 }
12811 }
12812
12813 // Default case: the activity can handle this new configuration, so
12814 // hand it over. Note that we don't need to give it the new
12815 // configuration, since we always send configuration changes to all
12816 // process when they happen so it can just use whatever configuration
12817 // it last got.
12818 if (r.app != null && r.app.thread != null) {
12819 try {
12820 r.app.thread.scheduleActivityConfigurationChanged(r);
12821 } catch (RemoteException e) {
12822 // If process died, whatever.
12823 }
12824 }
12825 r.stopFreezingScreenLocked(false);
12826
12827 return true;
12828 }
12829
12830 /**
12831 * Save the locale. You must be inside a synchronized (this) block.
12832 */
12833 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12834 if(isDiff) {
12835 SystemProperties.set("user.language", l.getLanguage());
12836 SystemProperties.set("user.region", l.getCountry());
12837 }
12838
12839 if(isPersist) {
12840 SystemProperties.set("persist.sys.language", l.getLanguage());
12841 SystemProperties.set("persist.sys.country", l.getCountry());
12842 SystemProperties.set("persist.sys.localevar", l.getVariant());
12843 }
12844 }
12845
12846 // =========================================================
12847 // LIFETIME MANAGEMENT
12848 // =========================================================
12849
12850 private final int computeOomAdjLocked(
12851 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12852 if (mAdjSeq == app.adjSeq) {
12853 // This adjustment has already been computed.
12854 return app.curAdj;
12855 }
12856
12857 if (app.thread == null) {
12858 app.adjSeq = mAdjSeq;
12859 return (app.curAdj=EMPTY_APP_ADJ);
12860 }
12861
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012862 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
12863 // The max adjustment doesn't allow this app to be anything
12864 // below foreground, so it is not worth doing work for it.
12865 app.adjType = "fixed";
12866 app.adjSeq = mAdjSeq;
12867 app.curRawAdj = app.maxAdj;
12868 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
12869 return (app.curAdj=app.maxAdj);
12870 }
12871
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070012872 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012873 app.adjSource = null;
12874 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012875
The Android Open Source Project4df24232009-03-05 14:34:35 -080012876 // Determine the importance of the process, starting with most
12877 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012878 int adj;
12879 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012880 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012881 // The last app on the list is the foreground app.
12882 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012883 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012884 } else if (app.instrumentationClass != null) {
12885 // Don't want to kill running instrumentation.
12886 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012887 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012888 } else if (app.persistentActivities > 0) {
12889 // Special persistent activities... shouldn't be used these days.
12890 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012891 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012892 } else if (app.curReceiver != null ||
12893 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12894 // An app that is currently receiving a broadcast also
12895 // counts as being in the foreground.
12896 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012897 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012898 } else if (app.executingServices.size() > 0) {
12899 // An app that is currently executing a service callback also
12900 // counts as being in the foreground.
12901 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012902 app.adjType = "exec-service";
12903 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012904 // The user is aware of this app, so make it visible.
12905 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012906 app.adjType = "foreground-service";
12907 } else if (app.forcingToForeground != null) {
12908 // The user is aware of this app, so make it visible.
12909 adj = VISIBLE_APP_ADJ;
12910 app.adjType = "force-foreground";
12911 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012912 } else if (app == mHomeProcess) {
12913 // This process is hosting what we currently consider to be the
12914 // home app, so we don't want to let it go into the background.
12915 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012916 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012917 } else if ((N=app.activities.size()) != 0) {
12918 // This app is in the background with paused activities.
12919 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012920 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012921 for (int j=0; j<N; j++) {
12922 if (((HistoryRecord)app.activities.get(j)).visible) {
12923 // This app has a visible activity!
12924 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012925 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012926 break;
12927 }
12928 }
12929 } else {
12930 // A very not-needed process.
12931 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012932 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012933 }
12934
The Android Open Source Project4df24232009-03-05 14:34:35 -080012935 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012936 // there are applications dependent on our services or providers, but
12937 // this gives us a baseline and makes sure we don't get into an
12938 // infinite recursion.
12939 app.adjSeq = mAdjSeq;
12940 app.curRawAdj = adj;
12941 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12942
Christopher Tate6fa95972009-06-05 18:43:55 -070012943 if (mBackupTarget != null && app == mBackupTarget.app) {
12944 // If possible we want to avoid killing apps while they're being backed up
12945 if (adj > BACKUP_APP_ADJ) {
12946 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12947 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012948 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070012949 }
12950 }
12951
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012952 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012953 final long now = SystemClock.uptimeMillis();
12954 // This process is more important if the top activity is
12955 // bound to the service.
12956 Iterator jt = app.services.iterator();
12957 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12958 ServiceRecord s = (ServiceRecord)jt.next();
12959 if (s.startRequested) {
12960 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12961 // This service has seen some activity within
12962 // recent memory, so we will keep its process ahead
12963 // of the background processes.
12964 if (adj > SECONDARY_SERVER_ADJ) {
12965 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012966 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012967 }
12968 }
12969 }
12970 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12971 Iterator<ConnectionRecord> kt
12972 = s.connections.values().iterator();
12973 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12974 // XXX should compute this based on the max of
12975 // all connected clients.
12976 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012977 if (cr.binding.client == app) {
12978 // Binding to ourself is not interesting.
12979 continue;
12980 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012981 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12982 ProcessRecord client = cr.binding.client;
12983 int myHiddenAdj = hiddenAdj;
12984 if (myHiddenAdj > client.hiddenAdj) {
12985 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12986 myHiddenAdj = client.hiddenAdj;
12987 } else {
12988 myHiddenAdj = VISIBLE_APP_ADJ;
12989 }
12990 }
12991 int clientAdj = computeOomAdjLocked(
12992 client, myHiddenAdj, TOP_APP);
12993 if (adj > clientAdj) {
12994 adj = clientAdj > VISIBLE_APP_ADJ
12995 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012996 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070012997 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
12998 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012999 app.adjSource = cr.binding.client;
13000 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013001 }
13002 }
13003 HistoryRecord a = cr.activity;
13004 //if (a != null) {
13005 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13006 //}
13007 if (a != null && adj > FOREGROUND_APP_ADJ &&
13008 (a.state == ActivityState.RESUMED
13009 || a.state == ActivityState.PAUSING)) {
13010 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013011 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013012 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13013 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013014 app.adjSource = a;
13015 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013016 }
13017 }
13018 }
13019 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013020
13021 // Finally, f this process has active services running in it, we
13022 // would like to avoid killing it unless it would prevent the current
13023 // application from running. By default we put the process in
13024 // with the rest of the background processes; as we scan through
13025 // its services we may bump it up from there.
13026 if (adj > hiddenAdj) {
13027 adj = hiddenAdj;
13028 app.adjType = "bg-services";
13029 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013030 }
13031
13032 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013033 Iterator jt = app.pubProviders.values().iterator();
13034 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13035 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13036 if (cpr.clients.size() != 0) {
13037 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13038 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13039 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013040 if (client == app) {
13041 // Being our own client is not interesting.
13042 continue;
13043 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013044 int myHiddenAdj = hiddenAdj;
13045 if (myHiddenAdj > client.hiddenAdj) {
13046 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13047 myHiddenAdj = client.hiddenAdj;
13048 } else {
13049 myHiddenAdj = FOREGROUND_APP_ADJ;
13050 }
13051 }
13052 int clientAdj = computeOomAdjLocked(
13053 client, myHiddenAdj, TOP_APP);
13054 if (adj > clientAdj) {
13055 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013056 ? clientAdj : FOREGROUND_APP_ADJ;
13057 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013058 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13059 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013060 app.adjSource = client;
13061 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013062 }
13063 }
13064 }
13065 // If the provider has external (non-framework) process
13066 // dependencies, ensure that its adjustment is at least
13067 // FOREGROUND_APP_ADJ.
13068 if (cpr.externals != 0) {
13069 if (adj > FOREGROUND_APP_ADJ) {
13070 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013071 app.adjType = "provider";
13072 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013073 }
13074 }
13075 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013076
13077 // Finally, if this process has published any content providers,
13078 // then its adjustment makes it at least as important as any of the
13079 // processes using those providers, and no less important than
13080 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
13081 if (adj > CONTENT_PROVIDER_ADJ) {
13082 adj = CONTENT_PROVIDER_ADJ;
13083 app.adjType = "pub-providers";
13084 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013085 }
13086
13087 app.curRawAdj = adj;
13088
13089 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13090 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13091 if (adj > app.maxAdj) {
13092 adj = app.maxAdj;
13093 }
13094
13095 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013096 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013097 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
13098 : Process.THREAD_GROUP_DEFAULT;
13099
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013100 return adj;
13101 }
13102
13103 /**
13104 * Ask a given process to GC right now.
13105 */
13106 final void performAppGcLocked(ProcessRecord app) {
13107 try {
13108 app.lastRequestedGc = SystemClock.uptimeMillis();
13109 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013110 if (app.reportLowMemory) {
13111 app.reportLowMemory = false;
13112 app.thread.scheduleLowMemory();
13113 } else {
13114 app.thread.processInBackground();
13115 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013116 }
13117 } catch (Exception e) {
13118 // whatever.
13119 }
13120 }
13121
13122 /**
13123 * Returns true if things are idle enough to perform GCs.
13124 */
13125 private final boolean canGcNow() {
13126 return mParallelBroadcasts.size() == 0
13127 && mOrderedBroadcasts.size() == 0
13128 && (mSleeping || (mResumedActivity != null &&
13129 mResumedActivity.idle));
13130 }
13131
13132 /**
13133 * Perform GCs on all processes that are waiting for it, but only
13134 * if things are idle.
13135 */
13136 final void performAppGcsLocked() {
13137 final int N = mProcessesToGc.size();
13138 if (N <= 0) {
13139 return;
13140 }
13141 if (canGcNow()) {
13142 while (mProcessesToGc.size() > 0) {
13143 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013144 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13145 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13146 <= SystemClock.uptimeMillis()) {
13147 // To avoid spamming the system, we will GC processes one
13148 // at a time, waiting a few seconds between each.
13149 performAppGcLocked(proc);
13150 scheduleAppGcsLocked();
13151 return;
13152 } else {
13153 // It hasn't been long enough since we last GCed this
13154 // process... put it in the list to wait for its time.
13155 addProcessToGcListLocked(proc);
13156 break;
13157 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013158 }
13159 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013160
13161 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013162 }
13163 }
13164
13165 /**
13166 * If all looks good, perform GCs on all processes waiting for them.
13167 */
13168 final void performAppGcsIfAppropriateLocked() {
13169 if (canGcNow()) {
13170 performAppGcsLocked();
13171 return;
13172 }
13173 // Still not idle, wait some more.
13174 scheduleAppGcsLocked();
13175 }
13176
13177 /**
13178 * Schedule the execution of all pending app GCs.
13179 */
13180 final void scheduleAppGcsLocked() {
13181 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013182
13183 if (mProcessesToGc.size() > 0) {
13184 // Schedule a GC for the time to the next process.
13185 ProcessRecord proc = mProcessesToGc.get(0);
13186 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13187
13188 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13189 long now = SystemClock.uptimeMillis();
13190 if (when < (now+GC_TIMEOUT)) {
13191 when = now + GC_TIMEOUT;
13192 }
13193 mHandler.sendMessageAtTime(msg, when);
13194 }
13195 }
13196
13197 /**
13198 * Add a process to the array of processes waiting to be GCed. Keeps the
13199 * list in sorted order by the last GC time. The process can't already be
13200 * on the list.
13201 */
13202 final void addProcessToGcListLocked(ProcessRecord proc) {
13203 boolean added = false;
13204 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13205 if (mProcessesToGc.get(i).lastRequestedGc <
13206 proc.lastRequestedGc) {
13207 added = true;
13208 mProcessesToGc.add(i+1, proc);
13209 break;
13210 }
13211 }
13212 if (!added) {
13213 mProcessesToGc.add(0, proc);
13214 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013215 }
13216
13217 /**
13218 * Set up to ask a process to GC itself. This will either do it
13219 * immediately, or put it on the list of processes to gc the next
13220 * time things are idle.
13221 */
13222 final void scheduleAppGcLocked(ProcessRecord app) {
13223 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013224 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013225 return;
13226 }
13227 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013228 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013229 scheduleAppGcsLocked();
13230 }
13231 }
13232
13233 private final boolean updateOomAdjLocked(
13234 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13235 app.hiddenAdj = hiddenAdj;
13236
13237 if (app.thread == null) {
13238 return true;
13239 }
13240
13241 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
13242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013243 if (app.pid != 0 && app.pid != MY_PID) {
13244 if (app.curRawAdj != app.setRawAdj) {
13245 if (app.curRawAdj > FOREGROUND_APP_ADJ
13246 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13247 // If this app is transitioning from foreground to
13248 // non-foreground, have it do a gc.
13249 scheduleAppGcLocked(app);
13250 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13251 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13252 // Likewise do a gc when an app is moving in to the
13253 // background (such as a service stopping).
13254 scheduleAppGcLocked(app);
13255 }
13256 app.setRawAdj = app.curRawAdj;
13257 }
13258 if (adj != app.setAdj) {
13259 if (Process.setOomAdj(app.pid, adj)) {
13260 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13261 TAG, "Set app " + app.processName +
13262 " oom adj to " + adj);
13263 app.setAdj = adj;
13264 } else {
13265 return false;
13266 }
13267 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013268 if (app.setSchedGroup != app.curSchedGroup) {
13269 app.setSchedGroup = app.curSchedGroup;
13270 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13271 "Setting process group of " + app.processName
13272 + " to " + app.curSchedGroup);
13273 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013274 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013275 try {
13276 Process.setProcessGroup(app.pid, app.curSchedGroup);
13277 } catch (Exception e) {
13278 Log.w(TAG, "Failed setting process group of " + app.pid
13279 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013280 e.printStackTrace();
13281 } finally {
13282 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013283 }
13284 }
13285 if (false) {
13286 if (app.thread != null) {
13287 try {
13288 app.thread.setSchedulingGroup(app.curSchedGroup);
13289 } catch (RemoteException e) {
13290 }
13291 }
13292 }
13293 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013294 }
13295
13296 return true;
13297 }
13298
13299 private final HistoryRecord resumedAppLocked() {
13300 HistoryRecord resumedActivity = mResumedActivity;
13301 if (resumedActivity == null || resumedActivity.app == null) {
13302 resumedActivity = mPausingActivity;
13303 if (resumedActivity == null || resumedActivity.app == null) {
13304 resumedActivity = topRunningActivityLocked(null);
13305 }
13306 }
13307 return resumedActivity;
13308 }
13309
13310 private final boolean updateOomAdjLocked(ProcessRecord app) {
13311 final HistoryRecord TOP_ACT = resumedAppLocked();
13312 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13313 int curAdj = app.curAdj;
13314 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13315 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13316
13317 mAdjSeq++;
13318
13319 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13320 if (res) {
13321 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13322 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13323 if (nowHidden != wasHidden) {
13324 // Changed to/from hidden state, so apps after it in the LRU
13325 // list may also be changed.
13326 updateOomAdjLocked();
13327 }
13328 }
13329 return res;
13330 }
13331
13332 private final boolean updateOomAdjLocked() {
13333 boolean didOomAdj = true;
13334 final HistoryRecord TOP_ACT = resumedAppLocked();
13335 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13336
13337 if (false) {
13338 RuntimeException e = new RuntimeException();
13339 e.fillInStackTrace();
13340 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13341 }
13342
13343 mAdjSeq++;
13344
13345 // First try updating the OOM adjustment for each of the
13346 // application processes based on their current state.
13347 int i = mLRUProcesses.size();
13348 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13349 while (i > 0) {
13350 i--;
13351 ProcessRecord app = mLRUProcesses.get(i);
13352 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13353 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13354 && app.curAdj == curHiddenAdj) {
13355 curHiddenAdj++;
13356 }
13357 } else {
13358 didOomAdj = false;
13359 }
13360 }
13361
13362 // todo: for now pretend like OOM ADJ didn't work, because things
13363 // aren't behaving as expected on Linux -- it's not killing processes.
13364 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13365 }
13366
13367 private final void trimApplications() {
13368 synchronized (this) {
13369 int i;
13370
13371 // First remove any unused application processes whose package
13372 // has been removed.
13373 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13374 final ProcessRecord app = mRemovedProcesses.get(i);
13375 if (app.activities.size() == 0
13376 && app.curReceiver == null && app.services.size() == 0) {
13377 Log.i(
13378 TAG, "Exiting empty application process "
13379 + app.processName + " ("
13380 + (app.thread != null ? app.thread.asBinder() : null)
13381 + ")\n");
13382 if (app.pid > 0 && app.pid != MY_PID) {
13383 Process.killProcess(app.pid);
13384 } else {
13385 try {
13386 app.thread.scheduleExit();
13387 } catch (Exception e) {
13388 // Ignore exceptions.
13389 }
13390 }
13391 cleanUpApplicationRecordLocked(app, false, -1);
13392 mRemovedProcesses.remove(i);
13393
13394 if (app.persistent) {
13395 if (app.persistent) {
13396 addAppLocked(app.info);
13397 }
13398 }
13399 }
13400 }
13401
13402 // Now try updating the OOM adjustment for each of the
13403 // application processes based on their current state.
13404 // If the setOomAdj() API is not supported, then go with our
13405 // back-up plan...
13406 if (!updateOomAdjLocked()) {
13407
13408 // Count how many processes are running services.
13409 int numServiceProcs = 0;
13410 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13411 final ProcessRecord app = mLRUProcesses.get(i);
13412
13413 if (app.persistent || app.services.size() != 0
13414 || app.curReceiver != null
13415 || app.persistentActivities > 0) {
13416 // Don't count processes holding services against our
13417 // maximum process count.
13418 if (localLOGV) Log.v(
13419 TAG, "Not trimming app " + app + " with services: "
13420 + app.services);
13421 numServiceProcs++;
13422 }
13423 }
13424
13425 int curMaxProcs = mProcessLimit;
13426 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13427 if (mAlwaysFinishActivities) {
13428 curMaxProcs = 1;
13429 }
13430 curMaxProcs += numServiceProcs;
13431
13432 // Quit as many processes as we can to get down to the desired
13433 // process count. First remove any processes that no longer
13434 // have activites running in them.
13435 for ( i=0;
13436 i<mLRUProcesses.size()
13437 && mLRUProcesses.size() > curMaxProcs;
13438 i++) {
13439 final ProcessRecord app = mLRUProcesses.get(i);
13440 // Quit an application only if it is not currently
13441 // running any activities.
13442 if (!app.persistent && app.activities.size() == 0
13443 && app.curReceiver == null && app.services.size() == 0) {
13444 Log.i(
13445 TAG, "Exiting empty application process "
13446 + app.processName + " ("
13447 + (app.thread != null ? app.thread.asBinder() : null)
13448 + ")\n");
13449 if (app.pid > 0 && app.pid != MY_PID) {
13450 Process.killProcess(app.pid);
13451 } else {
13452 try {
13453 app.thread.scheduleExit();
13454 } catch (Exception e) {
13455 // Ignore exceptions.
13456 }
13457 }
13458 // todo: For now we assume the application is not buggy
13459 // or evil, and will quit as a result of our request.
13460 // Eventually we need to drive this off of the death
13461 // notification, and kill the process if it takes too long.
13462 cleanUpApplicationRecordLocked(app, false, i);
13463 i--;
13464 }
13465 }
13466
13467 // If we still have too many processes, now from the least
13468 // recently used process we start finishing activities.
13469 if (Config.LOGV) Log.v(
13470 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13471 " of " + curMaxProcs + " processes");
13472 for ( i=0;
13473 i<mLRUProcesses.size()
13474 && mLRUProcesses.size() > curMaxProcs;
13475 i++) {
13476 final ProcessRecord app = mLRUProcesses.get(i);
13477 // Quit the application only if we have a state saved for
13478 // all of its activities.
13479 boolean canQuit = !app.persistent && app.curReceiver == null
13480 && app.services.size() == 0
13481 && app.persistentActivities == 0;
13482 int NUMA = app.activities.size();
13483 int j;
13484 if (Config.LOGV) Log.v(
13485 TAG, "Looking to quit " + app.processName);
13486 for (j=0; j<NUMA && canQuit; j++) {
13487 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13488 if (Config.LOGV) Log.v(
13489 TAG, " " + r.intent.getComponent().flattenToShortString()
13490 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13491 canQuit = (r.haveState || !r.stateNotNeeded)
13492 && !r.visible && r.stopped;
13493 }
13494 if (canQuit) {
13495 // Finish all of the activities, and then the app itself.
13496 for (j=0; j<NUMA; j++) {
13497 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13498 if (!r.finishing) {
13499 destroyActivityLocked(r, false);
13500 }
13501 r.resultTo = null;
13502 }
13503 Log.i(TAG, "Exiting application process "
13504 + app.processName + " ("
13505 + (app.thread != null ? app.thread.asBinder() : null)
13506 + ")\n");
13507 if (app.pid > 0 && app.pid != MY_PID) {
13508 Process.killProcess(app.pid);
13509 } else {
13510 try {
13511 app.thread.scheduleExit();
13512 } catch (Exception e) {
13513 // Ignore exceptions.
13514 }
13515 }
13516 // todo: For now we assume the application is not buggy
13517 // or evil, and will quit as a result of our request.
13518 // Eventually we need to drive this off of the death
13519 // notification, and kill the process if it takes too long.
13520 cleanUpApplicationRecordLocked(app, false, i);
13521 i--;
13522 //dump();
13523 }
13524 }
13525
13526 }
13527
13528 int curMaxActivities = MAX_ACTIVITIES;
13529 if (mAlwaysFinishActivities) {
13530 curMaxActivities = 1;
13531 }
13532
13533 // Finally, if there are too many activities now running, try to
13534 // finish as many as we can to get back down to the limit.
13535 for ( i=0;
13536 i<mLRUActivities.size()
13537 && mLRUActivities.size() > curMaxActivities;
13538 i++) {
13539 final HistoryRecord r
13540 = (HistoryRecord)mLRUActivities.get(i);
13541
13542 // We can finish this one if we have its icicle saved and
13543 // it is not persistent.
13544 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13545 && r.stopped && !r.persistent && !r.finishing) {
13546 final int origSize = mLRUActivities.size();
13547 destroyActivityLocked(r, true);
13548
13549 // This will remove it from the LRU list, so keep
13550 // our index at the same value. Note that this check to
13551 // see if the size changes is just paranoia -- if
13552 // something unexpected happens, we don't want to end up
13553 // in an infinite loop.
13554 if (origSize > mLRUActivities.size()) {
13555 i--;
13556 }
13557 }
13558 }
13559 }
13560 }
13561
13562 /** This method sends the specified signal to each of the persistent apps */
13563 public void signalPersistentProcesses(int sig) throws RemoteException {
13564 if (sig != Process.SIGNAL_USR1) {
13565 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13566 }
13567
13568 synchronized (this) {
13569 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13570 != PackageManager.PERMISSION_GRANTED) {
13571 throw new SecurityException("Requires permission "
13572 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13573 }
13574
13575 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13576 ProcessRecord r = mLRUProcesses.get(i);
13577 if (r.thread != null && r.persistent) {
13578 Process.sendSignal(r.pid, sig);
13579 }
13580 }
13581 }
13582 }
13583
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013584 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013585 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013586
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013587 try {
13588 synchronized (this) {
13589 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13590 // its own permission.
13591 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13592 != PackageManager.PERMISSION_GRANTED) {
13593 throw new SecurityException("Requires permission "
13594 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013595 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013596
13597 if (start && fd == null) {
13598 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013599 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013600
13601 ProcessRecord proc = null;
13602 try {
13603 int pid = Integer.parseInt(process);
13604 synchronized (mPidsSelfLocked) {
13605 proc = mPidsSelfLocked.get(pid);
13606 }
13607 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013608 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013609
13610 if (proc == null) {
13611 HashMap<String, SparseArray<ProcessRecord>> all
13612 = mProcessNames.getMap();
13613 SparseArray<ProcessRecord> procs = all.get(process);
13614 if (procs != null && procs.size() > 0) {
13615 proc = procs.valueAt(0);
13616 }
13617 }
13618
13619 if (proc == null || proc.thread == null) {
13620 throw new IllegalArgumentException("Unknown process: " + process);
13621 }
13622
13623 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13624 if (isSecure) {
13625 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13626 throw new SecurityException("Process not debuggable: " + proc);
13627 }
13628 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013629
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013630 proc.thread.profilerControl(start, path, fd);
13631 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013632 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013633 }
13634 } catch (RemoteException e) {
13635 throw new IllegalStateException("Process disappeared");
13636 } finally {
13637 if (fd != null) {
13638 try {
13639 fd.close();
13640 } catch (IOException e) {
13641 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013642 }
13643 }
13644 }
13645
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013646 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13647 public void monitor() {
13648 synchronized (this) { }
13649 }
13650}