blob: c62444de6d51ac85b35337286118a364e43d6f8f [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 Tate436344a2009-09-30 16:17:37 -0700143 static final boolean DEBUG_BACKUP = localLOGV || false;
Dianne Hackborndc6b6352009-09-30 14:20:09 -0700144 static final boolean DEBUG_CONFIGURATION = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 static final boolean VALIDATE_TOKENS = false;
146 static final boolean SHOW_ACTIVITY_START_TIME = true;
147
148 // Control over CPU and battery monitoring.
149 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
150 static final boolean MONITOR_CPU_USAGE = true;
151 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
152 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
153 static final boolean MONITOR_THREAD_CPU_USAGE = false;
154
155 // Event log tags
156 static final int LOG_CONFIGURATION_CHANGED = 2719;
157 static final int LOG_CPU = 2721;
158 static final int LOG_AM_FINISH_ACTIVITY = 30001;
159 static final int LOG_TASK_TO_FRONT = 30002;
160 static final int LOG_AM_NEW_INTENT = 30003;
161 static final int LOG_AM_CREATE_TASK = 30004;
162 static final int LOG_AM_CREATE_ACTIVITY = 30005;
163 static final int LOG_AM_RESTART_ACTIVITY = 30006;
164 static final int LOG_AM_RESUME_ACTIVITY = 30007;
165 static final int LOG_ANR = 30008;
166 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
167 static final int LOG_AM_PROCESS_BOUND = 30010;
168 static final int LOG_AM_PROCESS_DIED = 30011;
169 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
170 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
171 static final int LOG_AM_PROCESS_START = 30014;
172 static final int LOG_AM_PROCESS_BAD = 30015;
173 static final int LOG_AM_PROCESS_GOOD = 30016;
174 static final int LOG_AM_LOW_MEMORY = 30017;
175 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
176 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
177 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
178 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
179 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
180 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
181 static final int LOG_AM_CREATE_SERVICE = 30030;
182 static final int LOG_AM_DESTROY_SERVICE = 30031;
183 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
184 static final int LOG_AM_DROP_PROCESS = 30033;
185 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
186 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
187 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
188
189 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
190 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
191
Dianne Hackborn1655be42009-05-08 14:29:01 -0700192 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700193 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 private static final String SYSTEM_SECURE = "ro.secure";
196
197 // This is the maximum number of application processes we would like
198 // to have running. Due to the asynchronous nature of things, we can
199 // temporarily go beyond this limit.
200 static final int MAX_PROCESSES = 2;
201
202 // Set to false to leave processes running indefinitely, relying on
203 // the kernel killing them as resources are required.
204 static final boolean ENFORCE_PROCESS_LIMIT = false;
205
206 // This is the maximum number of activities that we would like to have
207 // running at a given time.
208 static final int MAX_ACTIVITIES = 20;
209
210 // Maximum number of recent tasks that we can remember.
211 static final int MAX_RECENT_TASKS = 20;
212
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700213 // Amount of time after a call to stopAppSwitches() during which we will
214 // prevent further untrusted switches from happening.
215 static final long APP_SWITCH_DELAY_TIME = 5*1000;
216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 // How long until we reset a task when the user returns to it. Currently
218 // 30 minutes.
219 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
220
221 // Set to true to disable the icon that is shown while a new activity
222 // is being started.
223 static final boolean SHOW_APP_STARTING_ICON = true;
224
225 // How long we wait until giving up on the last activity to pause. This
226 // is short because it directly impacts the responsiveness of starting the
227 // next activity.
228 static final int PAUSE_TIMEOUT = 500;
229
230 /**
231 * How long we can hold the launch wake lock before giving up.
232 */
233 static final int LAUNCH_TIMEOUT = 10*1000;
234
235 // How long we wait for a launched process to attach to the activity manager
236 // before we decide it's never going to come up for real.
237 static final int PROC_START_TIMEOUT = 10*1000;
238
239 // How long we wait until giving up on the last activity telling us it
240 // is idle.
241 static final int IDLE_TIMEOUT = 10*1000;
242
243 // How long to wait after going idle before forcing apps to GC.
244 static final int GC_TIMEOUT = 5*1000;
245
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700246 // The minimum amount of time between successive GC requests for a process.
247 static final int GC_MIN_INTERVAL = 60*1000;
248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 // How long we wait until giving up on an activity telling us it has
250 // finished destroying itself.
251 static final int DESTROY_TIMEOUT = 10*1000;
252
253 // How long we allow a receiver to run before giving up on it.
254 static final int BROADCAST_TIMEOUT = 10*1000;
255
256 // How long we wait for a service to finish executing.
257 static final int SERVICE_TIMEOUT = 20*1000;
258
259 // How long a service needs to be running until restarting its process
260 // is no longer considered to be a relaunch of the service.
261 static final int SERVICE_RESTART_DURATION = 5*1000;
262
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700263 // How long a service needs to be running until it will start back at
264 // SERVICE_RESTART_DURATION after being killed.
265 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
266
267 // Multiplying factor to increase restart duration time by, for each time
268 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
269 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
270
271 // The minimum amount of time between restarting services that we allow.
272 // That is, when multiple services are restarting, we won't allow each
273 // to restart less than this amount of time from the last one.
274 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 // Maximum amount of time for there to be no activity on a service before
277 // we consider it non-essential and allow its process to go on the
278 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700279 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280
281 // How long we wait until we timeout on key dispatching.
282 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
283
284 // The minimum time we allow between crashes, for us to consider this
285 // application to be bad and stop and its services and reject broadcasts.
286 static final int MIN_CRASH_INTERVAL = 60*1000;
287
288 // How long we wait until we timeout on key dispatching during instrumentation.
289 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
290
291 // OOM adjustments for processes in various states:
292
293 // This is a process without anything currently running in it. Definitely
294 // the first to go! Value set in system/rootdir/init.rc on startup.
295 // This value is initalized in the constructor, careful when refering to
296 // this static variable externally.
297 static int EMPTY_APP_ADJ;
298
299 // This is a process with a content provider that does not have any clients
300 // attached to it. If it did have any clients, its adjustment would be the
301 // one for the highest-priority of those processes.
302 static int CONTENT_PROVIDER_ADJ;
303
304 // This is a process only hosting activities that are not visible,
305 // so it can be killed without any disruption. Value set in
306 // system/rootdir/init.rc on startup.
307 final int HIDDEN_APP_MAX_ADJ;
308 static int HIDDEN_APP_MIN_ADJ;
309
The Android Open Source Project4df24232009-03-05 14:34:35 -0800310 // This is a process holding the home application -- we want to try
311 // avoiding killing it, even if it would normally be in the background,
312 // because the user interacts with it so much.
313 final int HOME_APP_ADJ;
314
Christopher Tate6fa95972009-06-05 18:43:55 -0700315 // This is a process currently hosting a backup operation. Killing it
316 // is not entirely fatal but is generally a bad idea.
317 final int BACKUP_APP_ADJ;
318
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 // This is a process holding a secondary server -- killing it will not
320 // have much of an impact as far as the user is concerned. Value set in
321 // system/rootdir/init.rc on startup.
322 final int SECONDARY_SERVER_ADJ;
323
324 // This is a process only hosting activities that are visible to the
325 // user, so we'd prefer they don't disappear. Value set in
326 // system/rootdir/init.rc on startup.
327 final int VISIBLE_APP_ADJ;
328
329 // This is the process running the current foreground app. We'd really
330 // rather not kill it! Value set in system/rootdir/init.rc on startup.
331 final int FOREGROUND_APP_ADJ;
332
333 // This is a process running a core server, such as telephony. Definitely
334 // don't want to kill it, but doing so is not completely fatal.
335 static final int CORE_SERVER_ADJ = -12;
336
337 // The system process runs at the default adjustment.
338 static final int SYSTEM_ADJ = -16;
339
340 // Memory pages are 4K.
341 static final int PAGE_SIZE = 4*1024;
342
Jacek Surazski82a73df2009-06-17 14:33:18 +0200343 // System property defining error report receiver for system apps
344 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
345
346 // System property defining default error report receiver
347 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 // Corresponding memory levels for above adjustments.
350 final int EMPTY_APP_MEM;
351 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800352 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700353 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 final int SECONDARY_SERVER_MEM;
355 final int VISIBLE_APP_MEM;
356 final int FOREGROUND_APP_MEM;
357
358 final int MY_PID;
359
360 static final String[] EMPTY_STRING_ARRAY = new String[0];
361
362 enum ActivityState {
363 INITIALIZING,
364 RESUMED,
365 PAUSING,
366 PAUSED,
367 STOPPING,
368 STOPPED,
369 FINISHING,
370 DESTROYING,
371 DESTROYED
372 }
373
374 /**
375 * The back history of all previous (and possibly still
376 * running) activities. It contains HistoryRecord objects.
377 */
378 final ArrayList mHistory = new ArrayList();
379
380 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700381 * Description of a request to start a new activity, which has been held
382 * due to app switches being disabled.
383 */
384 class PendingActivityLaunch {
385 HistoryRecord r;
386 HistoryRecord sourceRecord;
387 Uri[] grantedUriPermissions;
388 int grantedMode;
389 boolean onlyIfNeeded;
390 }
391
392 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
393 = new ArrayList<PendingActivityLaunch>();
394
395 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 * List of all active broadcasts that are to be executed immediately
397 * (without waiting for another broadcast to finish). Currently this only
398 * contains broadcasts to registered receivers, to avoid spinning up
399 * a bunch of processes to execute IntentReceiver components.
400 */
401 final ArrayList<BroadcastRecord> mParallelBroadcasts
402 = new ArrayList<BroadcastRecord>();
403
404 /**
405 * List of all active broadcasts that are to be executed one at a time.
406 * The object at the top of the list is the currently activity broadcasts;
407 * those after it are waiting for the top to finish..
408 */
409 final ArrayList<BroadcastRecord> mOrderedBroadcasts
410 = new ArrayList<BroadcastRecord>();
411
412 /**
413 * Set when we current have a BROADCAST_INTENT_MSG in flight.
414 */
415 boolean mBroadcastsScheduled = false;
416
417 /**
418 * Set to indicate whether to issue an onUserLeaving callback when a
419 * newly launched activity is being brought in front of us.
420 */
421 boolean mUserLeaving = false;
422
423 /**
424 * When we are in the process of pausing an activity, before starting the
425 * next one, this variable holds the activity that is currently being paused.
426 */
427 HistoryRecord mPausingActivity = null;
428
429 /**
430 * Current activity that is resumed, or null if there is none.
431 */
432 HistoryRecord mResumedActivity = null;
433
434 /**
435 * Activity we have told the window manager to have key focus.
436 */
437 HistoryRecord mFocusedActivity = null;
438
439 /**
440 * This is the last activity that we put into the paused state. This is
441 * used to determine if we need to do an activity transition while sleeping,
442 * when we normally hold the top activity paused.
443 */
444 HistoryRecord mLastPausedActivity = null;
445
446 /**
447 * List of activities that are waiting for a new activity
448 * to become visible before completing whatever operation they are
449 * supposed to do.
450 */
451 final ArrayList mWaitingVisibleActivities = new ArrayList();
452
453 /**
454 * List of activities that are ready to be stopped, but waiting
455 * for the next activity to settle down before doing so. It contains
456 * HistoryRecord objects.
457 */
458 final ArrayList<HistoryRecord> mStoppingActivities
459 = new ArrayList<HistoryRecord>();
460
461 /**
Dianne Hackbornbfe319e2009-09-21 00:34:05 -0700462 * Animations that for the current transition have requested not to
463 * be considered for the transition animation.
464 */
465 final ArrayList<HistoryRecord> mNoAnimActivities
466 = new ArrayList<HistoryRecord>();
467
468 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 * List of intents that were used to start the most recent tasks.
470 */
471 final ArrayList<TaskRecord> mRecentTasks
472 = new ArrayList<TaskRecord>();
473
474 /**
475 * List of activities that are ready to be finished, but waiting
476 * for the previous activity to settle down before doing so. It contains
477 * HistoryRecord objects.
478 */
479 final ArrayList mFinishingActivities = new ArrayList();
480
481 /**
482 * All of the applications we currently have running organized by name.
483 * The keys are strings of the application package name (as
484 * returned by the package manager), and the keys are ApplicationRecord
485 * objects.
486 */
487 final ProcessMap<ProcessRecord> mProcessNames
488 = new ProcessMap<ProcessRecord>();
489
490 /**
491 * The last time that various processes have crashed.
492 */
493 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
494
495 /**
496 * Set of applications that we consider to be bad, and will reject
497 * incoming broadcasts from (which the user has no control over).
498 * Processes are added to this set when they have crashed twice within
499 * a minimum amount of time; they are removed from it when they are
500 * later restarted (hopefully due to some user action). The value is the
501 * time it was added to the list.
502 */
503 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
504
505 /**
506 * All of the processes we currently have running organized by pid.
507 * The keys are the pid running the application.
508 *
509 * <p>NOTE: This object is protected by its own lock, NOT the global
510 * activity manager lock!
511 */
512 final SparseArray<ProcessRecord> mPidsSelfLocked
513 = new SparseArray<ProcessRecord>();
514
515 /**
516 * All of the processes that have been forced to be foreground. The key
517 * is the pid of the caller who requested it (we hold a death
518 * link on it).
519 */
520 abstract class ForegroundToken implements IBinder.DeathRecipient {
521 int pid;
522 IBinder token;
523 }
524 final SparseArray<ForegroundToken> mForegroundProcesses
525 = new SparseArray<ForegroundToken>();
526
527 /**
528 * List of records for processes that someone had tried to start before the
529 * system was ready. We don't start them at that point, but ensure they
530 * are started by the time booting is complete.
531 */
532 final ArrayList<ProcessRecord> mProcessesOnHold
533 = new ArrayList<ProcessRecord>();
534
535 /**
536 * List of records for processes that we have started and are waiting
537 * for them to call back. This is really only needed when running in
538 * single processes mode, in which case we do not have a unique pid for
539 * each process.
540 */
541 final ArrayList<ProcessRecord> mStartingProcesses
542 = new ArrayList<ProcessRecord>();
543
544 /**
545 * List of persistent applications that are in the process
546 * of being started.
547 */
548 final ArrayList<ProcessRecord> mPersistentStartingProcesses
549 = new ArrayList<ProcessRecord>();
550
551 /**
552 * Processes that are being forcibly torn down.
553 */
554 final ArrayList<ProcessRecord> mRemovedProcesses
555 = new ArrayList<ProcessRecord>();
556
557 /**
558 * List of running applications, sorted by recent usage.
559 * The first entry in the list is the least recently used.
560 * It contains ApplicationRecord objects. This list does NOT include
561 * any persistent application records (since we never want to exit them).
562 */
563 final ArrayList<ProcessRecord> mLRUProcesses
564 = new ArrayList<ProcessRecord>();
565
566 /**
567 * List of processes that should gc as soon as things are idle.
568 */
569 final ArrayList<ProcessRecord> mProcessesToGc
570 = new ArrayList<ProcessRecord>();
571
572 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800573 * This is the process holding what we currently consider to be
574 * the "home" activity.
575 */
576 private ProcessRecord mHomeProcess;
577
578 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 * List of running activities, sorted by recent usage.
580 * The first entry in the list is the least recently used.
581 * It contains HistoryRecord objects.
582 */
583 private final ArrayList mLRUActivities = new ArrayList();
584
585 /**
586 * Set of PendingResultRecord objects that are currently active.
587 */
588 final HashSet mPendingResultRecords = new HashSet();
589
590 /**
591 * Set of IntentSenderRecord objects that are currently active.
592 */
593 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
594 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
595
596 /**
597 * Intent broadcast that we have tried to start, but are
598 * waiting for its application's process to be created. We only
599 * need one (instead of a list) because we always process broadcasts
600 * one at a time, so no others can be started while waiting for this
601 * one.
602 */
603 BroadcastRecord mPendingBroadcast = null;
604
605 /**
606 * Keeps track of all IIntentReceivers that have been registered for
607 * broadcasts. Hash keys are the receiver IBinder, hash value is
608 * a ReceiverList.
609 */
610 final HashMap mRegisteredReceivers = new HashMap();
611
612 /**
613 * Resolver for broadcast intents to registered receivers.
614 * Holds BroadcastFilter (subclass of IntentFilter).
615 */
616 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
617 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
618 @Override
619 protected boolean allowFilterResult(
620 BroadcastFilter filter, List<BroadcastFilter> dest) {
621 IBinder target = filter.receiverList.receiver.asBinder();
622 for (int i=dest.size()-1; i>=0; i--) {
623 if (dest.get(i).receiverList.receiver.asBinder() == target) {
624 return false;
625 }
626 }
627 return true;
628 }
629 };
630
631 /**
632 * State of all active sticky broadcasts. Keys are the action of the
633 * sticky Intent, values are an ArrayList of all broadcasted intents with
634 * that action (which should usually be one).
635 */
636 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
637 new HashMap<String, ArrayList<Intent>>();
638
639 /**
640 * All currently running services.
641 */
642 final HashMap<ComponentName, ServiceRecord> mServices =
643 new HashMap<ComponentName, ServiceRecord>();
644
645 /**
646 * All currently running services indexed by the Intent used to start them.
647 */
648 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
649 new HashMap<Intent.FilterComparison, ServiceRecord>();
650
651 /**
652 * All currently bound service connections. Keys are the IBinder of
653 * the client's IServiceConnection.
654 */
655 final HashMap<IBinder, ConnectionRecord> mServiceConnections
656 = new HashMap<IBinder, ConnectionRecord>();
657
658 /**
659 * List of services that we have been asked to start,
660 * but haven't yet been able to. It is used to hold start requests
661 * while waiting for their corresponding application thread to get
662 * going.
663 */
664 final ArrayList<ServiceRecord> mPendingServices
665 = new ArrayList<ServiceRecord>();
666
667 /**
668 * List of services that are scheduled to restart following a crash.
669 */
670 final ArrayList<ServiceRecord> mRestartingServices
671 = new ArrayList<ServiceRecord>();
672
673 /**
674 * List of services that are in the process of being stopped.
675 */
676 final ArrayList<ServiceRecord> mStoppingServices
677 = new ArrayList<ServiceRecord>();
678
679 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700680 * Backup/restore process management
681 */
682 String mBackupAppName = null;
683 BackupRecord mBackupTarget = null;
684
685 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 * List of PendingThumbnailsRecord objects of clients who are still
687 * waiting to receive all of the thumbnails for a task.
688 */
689 final ArrayList mPendingThumbnails = new ArrayList();
690
691 /**
692 * List of HistoryRecord objects that have been finished and must
693 * still report back to a pending thumbnail receiver.
694 */
695 final ArrayList mCancelledThumbnails = new ArrayList();
696
697 /**
698 * All of the currently running global content providers. Keys are a
699 * string containing the provider name and values are a
700 * ContentProviderRecord object containing the data about it. Note
701 * that a single provider may be published under multiple names, so
702 * there may be multiple entries here for a single one in mProvidersByClass.
703 */
704 final HashMap mProvidersByName = new HashMap();
705
706 /**
707 * All of the currently running global content providers. Keys are a
708 * string containing the provider's implementation class and values are a
709 * ContentProviderRecord object containing the data about it.
710 */
711 final HashMap mProvidersByClass = new HashMap();
712
713 /**
714 * List of content providers who have clients waiting for them. The
715 * application is currently being launched and the provider will be
716 * removed from this list once it is published.
717 */
718 final ArrayList mLaunchingProviders = new ArrayList();
719
720 /**
721 * Global set of specific Uri permissions that have been granted.
722 */
723 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
724 = new SparseArray<HashMap<Uri, UriPermission>>();
725
726 /**
727 * Thread-local storage used to carry caller permissions over through
728 * indirect content-provider access.
729 * @see #ActivityManagerService.openContentUri()
730 */
731 private class Identity {
732 public int pid;
733 public int uid;
734
735 Identity(int _pid, int _uid) {
736 pid = _pid;
737 uid = _uid;
738 }
739 }
740 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
741
742 /**
743 * All information we have collected about the runtime performance of
744 * any user id that can impact battery performance.
745 */
746 final BatteryStatsService mBatteryStatsService;
747
748 /**
749 * information about component usage
750 */
751 final UsageStatsService mUsageStatsService;
752
753 /**
754 * Current configuration information. HistoryRecord objects are given
755 * a reference to this object to indicate which configuration they are
756 * currently running in, so this object must be kept immutable.
757 */
758 Configuration mConfiguration = new Configuration();
759
760 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700761 * Hardware-reported OpenGLES version.
762 */
763 final int GL_ES_VERSION;
764
765 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 * List of initialization arguments to pass to all processes when binding applications to them.
767 * For example, references to the commonly used services.
768 */
769 HashMap<String, IBinder> mAppBindArgs;
770
771 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700772 * Temporary to avoid allocations. Protected by main lock.
773 */
774 final StringBuilder mStringBuilder = new StringBuilder(256);
775
776 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 * Used to control how we initialize the service.
778 */
779 boolean mStartRunning = false;
780 ComponentName mTopComponent;
781 String mTopAction;
782 String mTopData;
783 boolean mSystemReady = false;
784 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700785 boolean mWaitingUpdate = false;
786 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787
788 Context mContext;
789
790 int mFactoryTest;
791
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700792 boolean mCheckedForSetup;
793
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700795 * The time at which we will allow normal application switches again,
796 * after a call to {@link #stopAppSwitches()}.
797 */
798 long mAppSwitchesAllowedTime;
799
800 /**
801 * This is set to true after the first switch after mAppSwitchesAllowedTime
802 * is set; any switches after that will clear the time.
803 */
804 boolean mDidAppSwitch;
805
806 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 * Set while we are wanting to sleep, to prevent any
808 * activities from being started/resumed.
809 */
810 boolean mSleeping = false;
811
812 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700813 * Set if we are shutting down the system, similar to sleeping.
814 */
815 boolean mShuttingDown = false;
816
817 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 * Set when the system is going to sleep, until we have
819 * successfully paused the current activity and released our wake lock.
820 * At that point the system is allowed to actually sleep.
821 */
822 PowerManager.WakeLock mGoingToSleep;
823
824 /**
825 * We don't want to allow the device to go to sleep while in the process
826 * of launching an activity. This is primarily to allow alarm intent
827 * receivers to launch an activity and get that to run before the device
828 * goes back to sleep.
829 */
830 PowerManager.WakeLock mLaunchingActivity;
831
832 /**
833 * Task identifier that activities are currently being started
834 * in. Incremented each time a new task is created.
835 * todo: Replace this with a TokenSpace class that generates non-repeating
836 * integers that won't wrap.
837 */
838 int mCurTask = 1;
839
840 /**
841 * Current sequence id for oom_adj computation traversal.
842 */
843 int mAdjSeq = 0;
844
845 /**
846 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
847 * is set, indicating the user wants processes started in such a way
848 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
849 * running in each process (thus no pre-initialized process, etc).
850 */
851 boolean mSimpleProcessManagement = false;
852
853 /**
854 * System monitoring: number of processes that died since the last
855 * N procs were started.
856 */
857 int[] mProcDeaths = new int[20];
858
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700859 /**
860 * This is set if we had to do a delayed dexopt of an app before launching
861 * it, to increasing the ANR timeouts in that case.
862 */
863 boolean mDidDexOpt;
864
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800865 String mDebugApp = null;
866 boolean mWaitForDebugger = false;
867 boolean mDebugTransient = false;
868 String mOrigDebugApp = null;
869 boolean mOrigWaitForDebugger = false;
870 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700871 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800872
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700873 final RemoteCallbackList<IActivityWatcher> mWatchers
874 = new RemoteCallbackList<IActivityWatcher>();
875
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 /**
877 * Callback of last caller to {@link #requestPss}.
878 */
879 Runnable mRequestPssCallback;
880
881 /**
882 * Remaining processes for which we are waiting results from the last
883 * call to {@link #requestPss}.
884 */
885 final ArrayList<ProcessRecord> mRequestPssList
886 = new ArrayList<ProcessRecord>();
887
888 /**
889 * Runtime statistics collection thread. This object's lock is used to
890 * protect all related state.
891 */
892 final Thread mProcessStatsThread;
893
894 /**
895 * Used to collect process stats when showing not responding dialog.
896 * Protected by mProcessStatsThread.
897 */
898 final ProcessStats mProcessStats = new ProcessStats(
899 MONITOR_THREAD_CPU_USAGE);
900 long mLastCpuTime = 0;
901 long mLastWriteTime = 0;
902
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700903 long mInitialStartTime = 0;
904
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 /**
906 * Set to true after the system has finished booting.
907 */
908 boolean mBooted = false;
909
910 int mProcessLimit = 0;
911
912 WindowManagerService mWindowManager;
913
914 static ActivityManagerService mSelf;
915 static ActivityThread mSystemThread;
916
917 private final class AppDeathRecipient implements IBinder.DeathRecipient {
918 final ProcessRecord mApp;
919 final int mPid;
920 final IApplicationThread mAppThread;
921
922 AppDeathRecipient(ProcessRecord app, int pid,
923 IApplicationThread thread) {
924 if (localLOGV) Log.v(
925 TAG, "New death recipient " + this
926 + " for thread " + thread.asBinder());
927 mApp = app;
928 mPid = pid;
929 mAppThread = thread;
930 }
931
932 public void binderDied() {
933 if (localLOGV) Log.v(
934 TAG, "Death received in " + this
935 + " for thread " + mAppThread.asBinder());
936 removeRequestedPss(mApp);
937 synchronized(ActivityManagerService.this) {
938 appDiedLocked(mApp, mPid, mAppThread);
939 }
940 }
941 }
942
943 static final int SHOW_ERROR_MSG = 1;
944 static final int SHOW_NOT_RESPONDING_MSG = 2;
945 static final int SHOW_FACTORY_ERROR_MSG = 3;
946 static final int UPDATE_CONFIGURATION_MSG = 4;
947 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
948 static final int WAIT_FOR_DEBUGGER_MSG = 6;
949 static final int BROADCAST_INTENT_MSG = 7;
950 static final int BROADCAST_TIMEOUT_MSG = 8;
951 static final int PAUSE_TIMEOUT_MSG = 9;
952 static final int IDLE_TIMEOUT_MSG = 10;
953 static final int IDLE_NOW_MSG = 11;
954 static final int SERVICE_TIMEOUT_MSG = 12;
955 static final int UPDATE_TIME_ZONE = 13;
956 static final int SHOW_UID_ERROR_MSG = 14;
957 static final int IM_FEELING_LUCKY_MSG = 15;
958 static final int LAUNCH_TIMEOUT_MSG = 16;
959 static final int DESTROY_TIMEOUT_MSG = 17;
960 static final int SERVICE_ERROR_MSG = 18;
961 static final int RESUME_TOP_ACTIVITY_MSG = 19;
962 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700963 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700964 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965
966 AlertDialog mUidAlert;
967
968 final Handler mHandler = new Handler() {
969 //public Handler() {
970 // if (localLOGV) Log.v(TAG, "Handler started!");
971 //}
972
973 public void handleMessage(Message msg) {
974 switch (msg.what) {
975 case SHOW_ERROR_MSG: {
976 HashMap data = (HashMap) msg.obj;
977 byte[] crashData = (byte[])data.get("crashData");
978 if (crashData != null) {
979 // This needs to be *un*synchronized to avoid deadlock.
980 ContentResolver resolver = mContext.getContentResolver();
981 Checkin.reportCrash(resolver, crashData);
982 }
983 synchronized (ActivityManagerService.this) {
984 ProcessRecord proc = (ProcessRecord)data.get("app");
985 if (proc != null && proc.crashDialog != null) {
986 Log.e(TAG, "App already has crash dialog: " + proc);
987 return;
988 }
989 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700990 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991 Dialog d = new AppErrorDialog(
992 mContext, res, proc,
993 (Integer)data.get("flags"),
994 (String)data.get("shortMsg"),
995 (String)data.get("longMsg"));
996 d.show();
997 proc.crashDialog = d;
998 } else {
999 // The device is asleep, so just pretend that the user
1000 // saw a crash dialog and hit "force quit".
1001 res.set(0);
1002 }
1003 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001004
1005 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001006 } break;
1007 case SHOW_NOT_RESPONDING_MSG: {
1008 synchronized (ActivityManagerService.this) {
1009 HashMap data = (HashMap) msg.obj;
1010 ProcessRecord proc = (ProcessRecord)data.get("app");
1011 if (proc != null && proc.anrDialog != null) {
1012 Log.e(TAG, "App already has anr dialog: " + proc);
1013 return;
1014 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001015
1016 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1017 null, null, 0, null, null, null,
1018 false, false, MY_PID, Process.SYSTEM_UID);
1019
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1021 mContext, proc, (HistoryRecord)data.get("activity"));
1022 d.show();
1023 proc.anrDialog = d;
1024 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001025
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001026 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001027 } break;
1028 case SHOW_FACTORY_ERROR_MSG: {
1029 Dialog d = new FactoryErrorDialog(
1030 mContext, msg.getData().getCharSequence("msg"));
1031 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001032 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033 } break;
1034 case UPDATE_CONFIGURATION_MSG: {
1035 final ContentResolver resolver = mContext.getContentResolver();
1036 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1037 } break;
1038 case GC_BACKGROUND_PROCESSES_MSG: {
1039 synchronized (ActivityManagerService.this) {
1040 performAppGcsIfAppropriateLocked();
1041 }
1042 } break;
1043 case WAIT_FOR_DEBUGGER_MSG: {
1044 synchronized (ActivityManagerService.this) {
1045 ProcessRecord app = (ProcessRecord)msg.obj;
1046 if (msg.arg1 != 0) {
1047 if (!app.waitedForDebugger) {
1048 Dialog d = new AppWaitingForDebuggerDialog(
1049 ActivityManagerService.this,
1050 mContext, app);
1051 app.waitDialog = d;
1052 app.waitedForDebugger = true;
1053 d.show();
1054 }
1055 } else {
1056 if (app.waitDialog != null) {
1057 app.waitDialog.dismiss();
1058 app.waitDialog = null;
1059 }
1060 }
1061 }
1062 } break;
1063 case BROADCAST_INTENT_MSG: {
1064 if (DEBUG_BROADCAST) Log.v(
1065 TAG, "Received BROADCAST_INTENT_MSG");
1066 processNextBroadcast(true);
1067 } break;
1068 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001069 if (mDidDexOpt) {
1070 mDidDexOpt = false;
1071 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1072 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1073 return;
1074 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001075 broadcastTimeout();
1076 } break;
1077 case PAUSE_TIMEOUT_MSG: {
1078 IBinder token = (IBinder)msg.obj;
1079 // We don't at this point know if the activity is fullscreen,
1080 // so we need to be conservative and assume it isn't.
1081 Log.w(TAG, "Activity pause timeout for " + token);
1082 activityPaused(token, null, true);
1083 } break;
1084 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001085 if (mDidDexOpt) {
1086 mDidDexOpt = false;
1087 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1088 nmsg.obj = msg.obj;
1089 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1090 return;
1091 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001092 // We don't at this point know if the activity is fullscreen,
1093 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001094 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001095 Log.w(TAG, "Activity idle timeout for " + token);
1096 activityIdleInternal(token, true);
1097 } break;
1098 case DESTROY_TIMEOUT_MSG: {
1099 IBinder token = (IBinder)msg.obj;
1100 // We don't at this point know if the activity is fullscreen,
1101 // so we need to be conservative and assume it isn't.
1102 Log.w(TAG, "Activity destroy timeout for " + token);
1103 activityDestroyed(token);
1104 } break;
1105 case IDLE_NOW_MSG: {
1106 IBinder token = (IBinder)msg.obj;
1107 activityIdle(token);
1108 } break;
1109 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001110 if (mDidDexOpt) {
1111 mDidDexOpt = false;
1112 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1113 nmsg.obj = msg.obj;
1114 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1115 return;
1116 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117 serviceTimeout((ProcessRecord)msg.obj);
1118 } break;
1119 case UPDATE_TIME_ZONE: {
1120 synchronized (ActivityManagerService.this) {
1121 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1122 ProcessRecord r = mLRUProcesses.get(i);
1123 if (r.thread != null) {
1124 try {
1125 r.thread.updateTimeZone();
1126 } catch (RemoteException ex) {
1127 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1128 }
1129 }
1130 }
1131 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001132 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001133 case SHOW_UID_ERROR_MSG: {
1134 // XXX This is a temporary dialog, no need to localize.
1135 AlertDialog d = new BaseErrorDialog(mContext);
1136 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1137 d.setCancelable(false);
1138 d.setTitle("System UIDs Inconsistent");
1139 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1140 d.setButton("I'm Feeling Lucky",
1141 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1142 mUidAlert = d;
1143 d.show();
1144 } break;
1145 case IM_FEELING_LUCKY_MSG: {
1146 if (mUidAlert != null) {
1147 mUidAlert.dismiss();
1148 mUidAlert = null;
1149 }
1150 } break;
1151 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001152 if (mDidDexOpt) {
1153 mDidDexOpt = false;
1154 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1155 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1156 return;
1157 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001158 synchronized (ActivityManagerService.this) {
1159 if (mLaunchingActivity.isHeld()) {
1160 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1161 mLaunchingActivity.release();
1162 }
1163 }
1164 } break;
1165 case SERVICE_ERROR_MSG: {
1166 ServiceRecord srv = (ServiceRecord)msg.obj;
1167 // This needs to be *un*synchronized to avoid deadlock.
1168 Checkin.logEvent(mContext.getContentResolver(),
1169 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1170 srv.name.toShortString());
1171 } break;
1172 case RESUME_TOP_ACTIVITY_MSG: {
1173 synchronized (ActivityManagerService.this) {
1174 resumeTopActivityLocked(null);
1175 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001176 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001178 if (mDidDexOpt) {
1179 mDidDexOpt = false;
1180 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1181 nmsg.obj = msg.obj;
1182 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1183 return;
1184 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001185 ProcessRecord app = (ProcessRecord)msg.obj;
1186 synchronized (ActivityManagerService.this) {
1187 processStartTimedOutLocked(app);
1188 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001189 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001190 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1191 synchronized (ActivityManagerService.this) {
1192 doPendingActivityLaunchesLocked(true);
1193 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001194 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001195 case KILL_APPLICATION_MSG: {
1196 synchronized (ActivityManagerService.this) {
1197 int uid = msg.arg1;
1198 boolean restart = (msg.arg2 == 1);
1199 String pkg = (String) msg.obj;
1200 uninstallPackageLocked(pkg, uid, restart);
1201 }
1202 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001203 }
1204 }
1205 };
1206
1207 public static void setSystemProcess() {
1208 try {
1209 ActivityManagerService m = mSelf;
1210
1211 ServiceManager.addService("activity", m);
1212 ServiceManager.addService("meminfo", new MemBinder(m));
1213 if (MONITOR_CPU_USAGE) {
1214 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1215 }
1216 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1217 ServiceManager.addService("activity.services", new ServicesBinder(m));
1218 ServiceManager.addService("activity.senders", new SendersBinder(m));
1219 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1220 ServiceManager.addService("permission", new PermissionController(m));
1221
1222 ApplicationInfo info =
1223 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001224 "android", STOCK_PM_FLAGS);
Mike Cleron432b7132009-09-24 15:28:29 -07001225 mSystemThread.installSystemApplicationInfo(info);
1226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001227 synchronized (mSelf) {
1228 ProcessRecord app = mSelf.newProcessRecordLocked(
1229 mSystemThread.getApplicationThread(), info,
1230 info.processName);
1231 app.persistent = true;
1232 app.pid = Process.myPid();
1233 app.maxAdj = SYSTEM_ADJ;
1234 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1235 synchronized (mSelf.mPidsSelfLocked) {
1236 mSelf.mPidsSelfLocked.put(app.pid, app);
1237 }
1238 mSelf.updateLRUListLocked(app, true);
1239 }
1240 } catch (PackageManager.NameNotFoundException e) {
1241 throw new RuntimeException(
1242 "Unable to find android system package", e);
1243 }
1244 }
1245
1246 public void setWindowManager(WindowManagerService wm) {
1247 mWindowManager = wm;
1248 }
1249
1250 public static final Context main(int factoryTest) {
1251 AThread thr = new AThread();
1252 thr.start();
1253
1254 synchronized (thr) {
1255 while (thr.mService == null) {
1256 try {
1257 thr.wait();
1258 } catch (InterruptedException e) {
1259 }
1260 }
1261 }
1262
1263 ActivityManagerService m = thr.mService;
1264 mSelf = m;
1265 ActivityThread at = ActivityThread.systemMain();
1266 mSystemThread = at;
1267 Context context = at.getSystemContext();
1268 m.mContext = context;
1269 m.mFactoryTest = factoryTest;
1270 PowerManager pm =
1271 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1272 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1273 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1274 m.mLaunchingActivity.setReferenceCounted(false);
1275
1276 m.mBatteryStatsService.publish(context);
1277 m.mUsageStatsService.publish(context);
1278
1279 synchronized (thr) {
1280 thr.mReady = true;
1281 thr.notifyAll();
1282 }
1283
1284 m.startRunning(null, null, null, null);
1285
1286 return context;
1287 }
1288
1289 public static ActivityManagerService self() {
1290 return mSelf;
1291 }
1292
1293 static class AThread extends Thread {
1294 ActivityManagerService mService;
1295 boolean mReady = false;
1296
1297 public AThread() {
1298 super("ActivityManager");
1299 }
1300
1301 public void run() {
1302 Looper.prepare();
1303
1304 android.os.Process.setThreadPriority(
1305 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1306
1307 ActivityManagerService m = new ActivityManagerService();
1308
1309 synchronized (this) {
1310 mService = m;
1311 notifyAll();
1312 }
1313
1314 synchronized (this) {
1315 while (!mReady) {
1316 try {
1317 wait();
1318 } catch (InterruptedException e) {
1319 }
1320 }
1321 }
1322
1323 Looper.loop();
1324 }
1325 }
1326
1327 static class BroadcastsBinder extends Binder {
1328 ActivityManagerService mActivityManagerService;
1329 BroadcastsBinder(ActivityManagerService activityManagerService) {
1330 mActivityManagerService = activityManagerService;
1331 }
1332
1333 @Override
1334 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1335 mActivityManagerService.dumpBroadcasts(pw);
1336 }
1337 }
1338
1339 static class ServicesBinder extends Binder {
1340 ActivityManagerService mActivityManagerService;
1341 ServicesBinder(ActivityManagerService activityManagerService) {
1342 mActivityManagerService = activityManagerService;
1343 }
1344
1345 @Override
1346 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1347 mActivityManagerService.dumpServices(pw);
1348 }
1349 }
1350
1351 static class SendersBinder extends Binder {
1352 ActivityManagerService mActivityManagerService;
1353 SendersBinder(ActivityManagerService activityManagerService) {
1354 mActivityManagerService = activityManagerService;
1355 }
1356
1357 @Override
1358 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1359 mActivityManagerService.dumpSenders(pw);
1360 }
1361 }
1362
1363 static class ProvidersBinder extends Binder {
1364 ActivityManagerService mActivityManagerService;
1365 ProvidersBinder(ActivityManagerService activityManagerService) {
1366 mActivityManagerService = activityManagerService;
1367 }
1368
1369 @Override
1370 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1371 mActivityManagerService.dumpProviders(pw);
1372 }
1373 }
1374
1375 static class MemBinder extends Binder {
1376 ActivityManagerService mActivityManagerService;
1377 MemBinder(ActivityManagerService activityManagerService) {
1378 mActivityManagerService = activityManagerService;
1379 }
1380
1381 @Override
1382 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1383 ActivityManagerService service = mActivityManagerService;
1384 ArrayList<ProcessRecord> procs;
1385 synchronized (mActivityManagerService) {
1386 if (args != null && args.length > 0
1387 && args[0].charAt(0) != '-') {
1388 procs = new ArrayList<ProcessRecord>();
1389 int pid = -1;
1390 try {
1391 pid = Integer.parseInt(args[0]);
1392 } catch (NumberFormatException e) {
1393
1394 }
1395 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1396 ProcessRecord proc = service.mLRUProcesses.get(i);
1397 if (proc.pid == pid) {
1398 procs.add(proc);
1399 } else if (proc.processName.equals(args[0])) {
1400 procs.add(proc);
1401 }
1402 }
1403 if (procs.size() <= 0) {
1404 pw.println("No process found for: " + args[0]);
1405 return;
1406 }
1407 } else {
1408 procs = service.mLRUProcesses;
1409 }
1410 }
1411 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1412 }
1413 }
1414
1415 static class CpuBinder extends Binder {
1416 ActivityManagerService mActivityManagerService;
1417 CpuBinder(ActivityManagerService activityManagerService) {
1418 mActivityManagerService = activityManagerService;
1419 }
1420
1421 @Override
1422 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1423 synchronized (mActivityManagerService.mProcessStatsThread) {
1424 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1425 }
1426 }
1427 }
1428
1429 private ActivityManagerService() {
1430 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1431 if (v != null && Integer.getInteger(v) != 0) {
1432 mSimpleProcessManagement = true;
1433 }
1434 v = System.getenv("ANDROID_DEBUG_APP");
1435 if (v != null) {
1436 mSimpleProcessManagement = true;
1437 }
1438
1439 MY_PID = Process.myPid();
1440
1441 File dataDir = Environment.getDataDirectory();
1442 File systemDir = new File(dataDir, "system");
1443 systemDir.mkdirs();
1444 mBatteryStatsService = new BatteryStatsService(new File(
1445 systemDir, "batterystats.bin").toString());
1446 mBatteryStatsService.getActiveStatistics().readLocked();
1447 mBatteryStatsService.getActiveStatistics().writeLocked();
1448
1449 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001450 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451
Jack Palevichb90d28c2009-07-22 15:35:24 -07001452 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1453 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1454
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001455 mConfiguration.makeDefault();
1456 mProcessStats.init();
1457
1458 // Add ourself to the Watchdog monitors.
1459 Watchdog.getInstance().addMonitor(this);
1460
1461 // These values are set in system/rootdir/init.rc on startup.
1462 FOREGROUND_APP_ADJ =
1463 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1464 VISIBLE_APP_ADJ =
1465 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1466 SECONDARY_SERVER_ADJ =
1467 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001468 BACKUP_APP_ADJ =
1469 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001470 HOME_APP_ADJ =
1471 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472 HIDDEN_APP_MIN_ADJ =
1473 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1474 CONTENT_PROVIDER_ADJ =
1475 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1476 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1477 EMPTY_APP_ADJ =
1478 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1479 FOREGROUND_APP_MEM =
1480 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1481 VISIBLE_APP_MEM =
1482 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1483 SECONDARY_SERVER_MEM =
1484 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001485 BACKUP_APP_MEM =
1486 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001487 HOME_APP_MEM =
1488 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 HIDDEN_APP_MEM =
1490 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1491 EMPTY_APP_MEM =
1492 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1493
1494 mProcessStatsThread = new Thread("ProcessStats") {
1495 public void run() {
1496 while (true) {
1497 try {
1498 try {
1499 synchronized(this) {
1500 final long now = SystemClock.uptimeMillis();
1501 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1502 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1503 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1504 // + ", write delay=" + nextWriteDelay);
1505 if (nextWriteDelay < nextCpuDelay) {
1506 nextCpuDelay = nextWriteDelay;
1507 }
1508 if (nextCpuDelay > 0) {
1509 this.wait(nextCpuDelay);
1510 }
1511 }
1512 } catch (InterruptedException e) {
1513 }
1514
1515 updateCpuStatsNow();
1516 } catch (Exception e) {
1517 Log.e(TAG, "Unexpected exception collecting process stats", e);
1518 }
1519 }
1520 }
1521 };
1522 mProcessStatsThread.start();
1523 }
1524
1525 @Override
1526 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1527 throws RemoteException {
1528 try {
1529 return super.onTransact(code, data, reply, flags);
1530 } catch (RuntimeException e) {
1531 // The activity manager only throws security exceptions, so let's
1532 // log all others.
1533 if (!(e instanceof SecurityException)) {
1534 Log.e(TAG, "Activity Manager Crash", e);
1535 }
1536 throw e;
1537 }
1538 }
1539
1540 void updateCpuStats() {
1541 synchronized (mProcessStatsThread) {
1542 final long now = SystemClock.uptimeMillis();
1543 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1544 mProcessStatsThread.notify();
1545 }
1546 }
1547 }
1548
1549 void updateCpuStatsNow() {
1550 synchronized (mProcessStatsThread) {
1551 final long now = SystemClock.uptimeMillis();
1552 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 if (MONITOR_CPU_USAGE &&
1555 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1556 mLastCpuTime = now;
1557 haveNewCpuStats = true;
1558 mProcessStats.update();
1559 //Log.i(TAG, mProcessStats.printCurrentState());
1560 //Log.i(TAG, "Total CPU usage: "
1561 // + mProcessStats.getTotalCpuPercent() + "%");
1562
1563 // Log the cpu usage if the property is set.
1564 if ("true".equals(SystemProperties.get("events.cpu"))) {
1565 int user = mProcessStats.getLastUserTime();
1566 int system = mProcessStats.getLastSystemTime();
1567 int iowait = mProcessStats.getLastIoWaitTime();
1568 int irq = mProcessStats.getLastIrqTime();
1569 int softIrq = mProcessStats.getLastSoftIrqTime();
1570 int idle = mProcessStats.getLastIdleTime();
1571
1572 int total = user + system + iowait + irq + softIrq + idle;
1573 if (total == 0) total = 1;
1574
1575 EventLog.writeEvent(LOG_CPU,
1576 ((user+system+iowait+irq+softIrq) * 100) / total,
1577 (user * 100) / total,
1578 (system * 100) / total,
1579 (iowait * 100) / total,
1580 (irq * 100) / total,
1581 (softIrq * 100) / total);
1582 }
1583 }
1584
Amith Yamasanie43530a2009-08-21 13:11:37 -07001585 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001586 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001587 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001588 synchronized(mPidsSelfLocked) {
1589 if (haveNewCpuStats) {
1590 if (mBatteryStatsService.isOnBattery()) {
1591 final int N = mProcessStats.countWorkingStats();
1592 for (int i=0; i<N; i++) {
1593 ProcessStats.Stats st
1594 = mProcessStats.getWorkingStats(i);
1595 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1596 if (pr != null) {
1597 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1598 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001599 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001600 } else {
1601 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001602 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001603 if (ps != null) {
1604 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001605 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001606 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607 }
1608 }
1609 }
1610 }
1611 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001612
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001613 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1614 mLastWriteTime = now;
1615 mBatteryStatsService.getActiveStatistics().writeLocked();
1616 }
1617 }
1618 }
1619 }
1620
1621 /**
1622 * Initialize the application bind args. These are passed to each
1623 * process when the bindApplication() IPC is sent to the process. They're
1624 * lazily setup to make sure the services are running when they're asked for.
1625 */
1626 private HashMap<String, IBinder> getCommonServicesLocked() {
1627 if (mAppBindArgs == null) {
1628 mAppBindArgs = new HashMap<String, IBinder>();
1629
1630 // Setup the application init args
1631 mAppBindArgs.put("package", ServiceManager.getService("package"));
1632 mAppBindArgs.put("window", ServiceManager.getService("window"));
1633 mAppBindArgs.put(Context.ALARM_SERVICE,
1634 ServiceManager.getService(Context.ALARM_SERVICE));
1635 }
1636 return mAppBindArgs;
1637 }
1638
1639 private final void setFocusedActivityLocked(HistoryRecord r) {
1640 if (mFocusedActivity != r) {
1641 mFocusedActivity = r;
1642 mWindowManager.setFocusedApp(r, true);
1643 }
1644 }
1645
1646 private final void updateLRUListLocked(ProcessRecord app,
1647 boolean oomAdj) {
1648 // put it on the LRU to keep track of when it should be exited.
1649 int lrui = mLRUProcesses.indexOf(app);
1650 if (lrui >= 0) mLRUProcesses.remove(lrui);
1651 mLRUProcesses.add(app);
1652 //Log.i(TAG, "Putting proc to front: " + app.processName);
1653 if (oomAdj) {
1654 updateOomAdjLocked();
1655 }
1656 }
1657
1658 private final boolean updateLRUListLocked(HistoryRecord r) {
1659 final boolean hadit = mLRUActivities.remove(r);
1660 mLRUActivities.add(r);
1661 return hadit;
1662 }
1663
1664 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1665 int i = mHistory.size()-1;
1666 while (i >= 0) {
1667 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1668 if (!r.finishing && r != notTop) {
1669 return r;
1670 }
1671 i--;
1672 }
1673 return null;
1674 }
1675
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001676 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1677 int i = mHistory.size()-1;
1678 while (i >= 0) {
1679 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1680 if (!r.finishing && !r.delayedResume && r != notTop) {
1681 return r;
1682 }
1683 i--;
1684 }
1685 return null;
1686 }
1687
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001688 /**
1689 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001690 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 *
1692 * @param token If non-null, any history records matching this token will be skipped.
1693 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1694 *
1695 * @return Returns the HistoryRecord of the next activity on the stack.
1696 */
1697 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1698 int i = mHistory.size()-1;
1699 while (i >= 0) {
1700 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1701 // Note: the taskId check depends on real taskId fields being non-zero
1702 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1703 return r;
1704 }
1705 i--;
1706 }
1707 return null;
1708 }
1709
1710 private final ProcessRecord getProcessRecordLocked(
1711 String processName, int uid) {
1712 if (uid == Process.SYSTEM_UID) {
1713 // The system gets to run in any process. If there are multiple
1714 // processes with the same uid, just pick the first (this
1715 // should never happen).
1716 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1717 processName);
1718 return procs != null ? procs.valueAt(0) : null;
1719 }
1720 ProcessRecord proc = mProcessNames.get(processName, uid);
1721 return proc;
1722 }
1723
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001724 private void ensurePackageDexOpt(String packageName) {
1725 IPackageManager pm = ActivityThread.getPackageManager();
1726 try {
1727 if (pm.performDexOpt(packageName)) {
1728 mDidDexOpt = true;
1729 }
1730 } catch (RemoteException e) {
1731 }
1732 }
1733
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 private boolean isNextTransitionForward() {
1735 int transit = mWindowManager.getPendingAppTransition();
1736 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1737 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1738 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1739 }
1740
1741 private final boolean realStartActivityLocked(HistoryRecord r,
1742 ProcessRecord app, boolean andResume, boolean checkConfig)
1743 throws RemoteException {
1744
1745 r.startFreezingScreenLocked(app, 0);
1746 mWindowManager.setAppVisibility(r, true);
1747
1748 // Have the window manager re-evaluate the orientation of
1749 // the screen based on the new activity order. Note that
1750 // as a result of this, it can call back into the activity
1751 // manager with a new orientation. We don't care about that,
1752 // because the activity is not currently running so we are
1753 // just restarting it anyway.
1754 if (checkConfig) {
1755 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001756 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001757 r.mayFreezeScreenLocked(app) ? r : null);
1758 updateConfigurationLocked(config, r);
1759 }
1760
1761 r.app = app;
1762
1763 if (localLOGV) Log.v(TAG, "Launching: " + r);
1764
1765 int idx = app.activities.indexOf(r);
1766 if (idx < 0) {
1767 app.activities.add(r);
1768 }
1769 updateLRUListLocked(app, true);
1770
1771 try {
1772 if (app.thread == null) {
1773 throw new RemoteException();
1774 }
1775 List<ResultInfo> results = null;
1776 List<Intent> newIntents = null;
1777 if (andResume) {
1778 results = r.results;
1779 newIntents = r.newIntents;
1780 }
1781 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1782 + " icicle=" + r.icicle
1783 + " with results=" + results + " newIntents=" + newIntents
1784 + " andResume=" + andResume);
1785 if (andResume) {
1786 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1787 System.identityHashCode(r),
1788 r.task.taskId, r.shortComponentName);
1789 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001790 if (r.isHomeActivity) {
1791 mHomeProcess = app;
1792 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001793 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001794 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001795 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001796 r.info, r.icicle, results, newIntents, !andResume,
1797 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001798 } catch (RemoteException e) {
1799 if (r.launchFailed) {
1800 // This is the second time we failed -- finish activity
1801 // and give up.
1802 Log.e(TAG, "Second failure launching "
1803 + r.intent.getComponent().flattenToShortString()
1804 + ", giving up", e);
1805 appDiedLocked(app, app.pid, app.thread);
1806 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1807 "2nd-crash");
1808 return false;
1809 }
1810
1811 // This is the first time we failed -- restart process and
1812 // retry.
1813 app.activities.remove(r);
1814 throw e;
1815 }
1816
1817 r.launchFailed = false;
1818 if (updateLRUListLocked(r)) {
1819 Log.w(TAG, "Activity " + r
1820 + " being launched, but already in LRU list");
1821 }
1822
1823 if (andResume) {
1824 // As part of the process of launching, ActivityThread also performs
1825 // a resume.
1826 r.state = ActivityState.RESUMED;
1827 r.icicle = null;
1828 r.haveState = false;
1829 r.stopped = false;
1830 mResumedActivity = r;
1831 r.task.touchActiveTime();
1832 completeResumeLocked(r);
1833 pauseIfSleepingLocked();
1834 } else {
1835 // This activity is not starting in the resumed state... which
1836 // should look like we asked it to pause+stop (but remain visible),
1837 // and it has done so and reported back the current icicle and
1838 // other state.
1839 r.state = ActivityState.STOPPED;
1840 r.stopped = true;
1841 }
1842
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001843 // Launch the new version setup screen if needed. We do this -after-
1844 // launching the initial activity (that is, home), so that it can have
1845 // a chance to initialize itself while in the background, making the
1846 // switch back to it faster and look better.
1847 startSetupActivityLocked();
1848
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001849 return true;
1850 }
1851
1852 private final void startSpecificActivityLocked(HistoryRecord r,
1853 boolean andResume, boolean checkConfig) {
1854 // Is this activity's application already running?
1855 ProcessRecord app = getProcessRecordLocked(r.processName,
1856 r.info.applicationInfo.uid);
1857
1858 if (r.startTime == 0) {
1859 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001860 if (mInitialStartTime == 0) {
1861 mInitialStartTime = r.startTime;
1862 }
1863 } else if (mInitialStartTime == 0) {
1864 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001865 }
1866
1867 if (app != null && app.thread != null) {
1868 try {
1869 realStartActivityLocked(r, app, andResume, checkConfig);
1870 return;
1871 } catch (RemoteException e) {
1872 Log.w(TAG, "Exception when starting activity "
1873 + r.intent.getComponent().flattenToShortString(), e);
1874 }
1875
1876 // If a dead object exception was thrown -- fall through to
1877 // restart the application.
1878 }
1879
1880 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001881 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001882 }
1883
1884 private final ProcessRecord startProcessLocked(String processName,
1885 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001886 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001887 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1888 // We don't have to do anything more if:
1889 // (1) There is an existing application record; and
1890 // (2) The caller doesn't think it is dead, OR there is no thread
1891 // object attached to it so we know it couldn't have crashed; and
1892 // (3) There is a pid assigned to it, so it is either starting or
1893 // already running.
1894 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1895 + " app=" + app + " knownToBeDead=" + knownToBeDead
1896 + " thread=" + (app != null ? app.thread : null)
1897 + " pid=" + (app != null ? app.pid : -1));
1898 if (app != null &&
1899 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1900 return app;
1901 }
1902
1903 String hostingNameStr = hostingName != null
1904 ? hostingName.flattenToShortString() : null;
1905
1906 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1907 // If we are in the background, then check to see if this process
1908 // is bad. If so, we will just silently fail.
1909 if (mBadProcesses.get(info.processName, info.uid) != null) {
1910 return null;
1911 }
1912 } else {
1913 // When the user is explicitly starting a process, then clear its
1914 // crash count so that we won't make it bad until they see at
1915 // least one crash dialog again, and make the process good again
1916 // if it had been bad.
1917 mProcessCrashTimes.remove(info.processName, info.uid);
1918 if (mBadProcesses.get(info.processName, info.uid) != null) {
1919 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1920 info.processName);
1921 mBadProcesses.remove(info.processName, info.uid);
1922 if (app != null) {
1923 app.bad = false;
1924 }
1925 }
1926 }
1927
1928 if (app == null) {
1929 app = newProcessRecordLocked(null, info, processName);
1930 mProcessNames.put(processName, info.uid, app);
1931 } else {
1932 // If this is a new package in the process, add the package to the list
1933 app.addPackage(info.packageName);
1934 }
1935
1936 // If the system is not ready yet, then hold off on starting this
1937 // process until it is.
1938 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001939 && !isAllowedWhileBooting(info)
1940 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001941 if (!mProcessesOnHold.contains(app)) {
1942 mProcessesOnHold.add(app);
1943 }
1944 return app;
1945 }
1946
1947 startProcessLocked(app, hostingType, hostingNameStr);
1948 return (app.pid != 0) ? app : null;
1949 }
1950
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001951 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1952 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1953 }
1954
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001955 private final void startProcessLocked(ProcessRecord app,
1956 String hostingType, String hostingNameStr) {
1957 if (app.pid > 0 && app.pid != MY_PID) {
1958 synchronized (mPidsSelfLocked) {
1959 mPidsSelfLocked.remove(app.pid);
1960 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1961 }
1962 app.pid = 0;
1963 }
1964
1965 mProcessesOnHold.remove(app);
1966
1967 updateCpuStats();
1968
1969 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1970 mProcDeaths[0] = 0;
1971
1972 try {
1973 int uid = app.info.uid;
1974 int[] gids = null;
1975 try {
1976 gids = mContext.getPackageManager().getPackageGids(
1977 app.info.packageName);
1978 } catch (PackageManager.NameNotFoundException e) {
1979 Log.w(TAG, "Unable to retrieve gids", e);
1980 }
1981 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1982 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1983 && mTopComponent != null
1984 && app.processName.equals(mTopComponent.getPackageName())) {
1985 uid = 0;
1986 }
1987 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1988 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1989 uid = 0;
1990 }
1991 }
1992 int debugFlags = 0;
1993 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1994 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1995 }
1996 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1997 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1998 }
1999 if ("1".equals(SystemProperties.get("debug.assert"))) {
2000 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
2001 }
2002 int pid = Process.start("android.app.ActivityThread",
2003 mSimpleProcessManagement ? app.processName : null, uid, uid,
2004 gids, debugFlags, null);
2005 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
2006 synchronized (bs) {
2007 if (bs.isOnBattery()) {
2008 app.batteryStats.incStartsLocked();
2009 }
2010 }
2011
2012 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
2013 app.processName, hostingType,
2014 hostingNameStr != null ? hostingNameStr : "");
2015
2016 if (app.persistent) {
2017 Watchdog.getInstance().processStarted(app, app.processName, pid);
2018 }
2019
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07002020 StringBuilder buf = mStringBuilder;
2021 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002022 buf.append("Start proc ");
2023 buf.append(app.processName);
2024 buf.append(" for ");
2025 buf.append(hostingType);
2026 if (hostingNameStr != null) {
2027 buf.append(" ");
2028 buf.append(hostingNameStr);
2029 }
2030 buf.append(": pid=");
2031 buf.append(pid);
2032 buf.append(" uid=");
2033 buf.append(uid);
2034 buf.append(" gids={");
2035 if (gids != null) {
2036 for (int gi=0; gi<gids.length; gi++) {
2037 if (gi != 0) buf.append(", ");
2038 buf.append(gids[gi]);
2039
2040 }
2041 }
2042 buf.append("}");
2043 Log.i(TAG, buf.toString());
2044 if (pid == 0 || pid == MY_PID) {
2045 // Processes are being emulated with threads.
2046 app.pid = MY_PID;
2047 app.removed = false;
2048 mStartingProcesses.add(app);
2049 } else if (pid > 0) {
2050 app.pid = pid;
2051 app.removed = false;
2052 synchronized (mPidsSelfLocked) {
2053 this.mPidsSelfLocked.put(pid, app);
2054 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2055 msg.obj = app;
2056 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2057 }
2058 } else {
2059 app.pid = 0;
2060 RuntimeException e = new RuntimeException(
2061 "Failure starting process " + app.processName
2062 + ": returned pid=" + pid);
2063 Log.e(TAG, e.getMessage(), e);
2064 }
2065 } catch (RuntimeException e) {
2066 // XXX do better error recovery.
2067 app.pid = 0;
2068 Log.e(TAG, "Failure starting process " + app.processName, e);
2069 }
2070 }
2071
2072 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2073 if (mPausingActivity != null) {
2074 RuntimeException e = new RuntimeException();
2075 Log.e(TAG, "Trying to pause when pause is already pending for "
2076 + mPausingActivity, e);
2077 }
2078 HistoryRecord prev = mResumedActivity;
2079 if (prev == null) {
2080 RuntimeException e = new RuntimeException();
2081 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2082 resumeTopActivityLocked(null);
2083 return;
2084 }
2085 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2086 mResumedActivity = null;
2087 mPausingActivity = prev;
2088 mLastPausedActivity = prev;
2089 prev.state = ActivityState.PAUSING;
2090 prev.task.touchActiveTime();
2091
2092 updateCpuStats();
2093
2094 if (prev.app != null && prev.app.thread != null) {
2095 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2096 try {
2097 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2098 System.identityHashCode(prev),
2099 prev.shortComponentName);
2100 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2101 prev.configChangeFlags);
2102 updateUsageStats(prev, false);
2103 } catch (Exception e) {
2104 // Ignore exception, if process died other code will cleanup.
2105 Log.w(TAG, "Exception thrown during pause", e);
2106 mPausingActivity = null;
2107 mLastPausedActivity = null;
2108 }
2109 } else {
2110 mPausingActivity = null;
2111 mLastPausedActivity = null;
2112 }
2113
2114 // If we are not going to sleep, we want to ensure the device is
2115 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002116 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002117 mLaunchingActivity.acquire();
2118 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2119 // To be safe, don't allow the wake lock to be held for too long.
2120 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2121 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2122 }
2123 }
2124
2125
2126 if (mPausingActivity != null) {
2127 // Have the window manager pause its key dispatching until the new
2128 // activity has started. If we're pausing the activity just because
2129 // the screen is being turned off and the UI is sleeping, don't interrupt
2130 // key dispatch; the same activity will pick it up again on wakeup.
2131 if (!uiSleeping) {
2132 prev.pauseKeyDispatchingLocked();
2133 } else {
2134 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2135 }
2136
2137 // Schedule a pause timeout in case the app doesn't respond.
2138 // We don't give it much time because this directly impacts the
2139 // responsiveness seen by the user.
2140 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2141 msg.obj = prev;
2142 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2143 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2144 } else {
2145 // This activity failed to schedule the
2146 // pause, so just treat it as being paused now.
2147 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2148 resumeTopActivityLocked(null);
2149 }
2150 }
2151
2152 private final void completePauseLocked() {
2153 HistoryRecord prev = mPausingActivity;
2154 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2155
2156 if (prev != null) {
2157 if (prev.finishing) {
2158 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2159 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2160 } else if (prev.app != null) {
2161 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2162 if (prev.waitingVisible) {
2163 prev.waitingVisible = false;
2164 mWaitingVisibleActivities.remove(prev);
2165 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2166 TAG, "Complete pause, no longer waiting: " + prev);
2167 }
2168 if (prev.configDestroy) {
2169 // The previous is being paused because the configuration
2170 // is changing, which means it is actually stopping...
2171 // To juggle the fact that we are also starting a new
2172 // instance right now, we need to first completely stop
2173 // the current instance before starting the new one.
2174 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2175 destroyActivityLocked(prev, true);
2176 } else {
2177 mStoppingActivities.add(prev);
2178 if (mStoppingActivities.size() > 3) {
2179 // If we already have a few activities waiting to stop,
2180 // then give up on things going idle and start clearing
2181 // them out.
2182 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2183 Message msg = Message.obtain();
2184 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2185 mHandler.sendMessage(msg);
2186 }
2187 }
2188 } else {
2189 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2190 prev = null;
2191 }
2192 mPausingActivity = null;
2193 }
2194
Dianne Hackborn55280a92009-05-07 15:53:46 -07002195 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002196 resumeTopActivityLocked(prev);
2197 } else {
2198 if (mGoingToSleep.isHeld()) {
2199 mGoingToSleep.release();
2200 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002201 if (mShuttingDown) {
2202 notifyAll();
2203 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002204 }
2205
2206 if (prev != null) {
2207 prev.resumeKeyDispatchingLocked();
2208 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002209
2210 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2211 long diff = 0;
2212 synchronized (mProcessStatsThread) {
2213 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2214 }
2215 if (diff > 0) {
2216 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2217 synchronized (bsi) {
2218 BatteryStatsImpl.Uid.Proc ps =
2219 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2220 prev.info.packageName);
2221 if (ps != null) {
2222 ps.addForegroundTimeLocked(diff);
2223 }
2224 }
2225 }
2226 }
2227 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002228 }
2229
2230 /**
2231 * Once we know that we have asked an application to put an activity in
2232 * the resumed state (either by launching it or explicitly telling it),
2233 * this function updates the rest of our state to match that fact.
2234 */
2235 private final void completeResumeLocked(HistoryRecord next) {
2236 next.idle = false;
2237 next.results = null;
2238 next.newIntents = null;
2239
2240 // schedule an idle timeout in case the app doesn't do it for us.
2241 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2242 msg.obj = next;
2243 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2244
2245 if (false) {
2246 // The activity was never told to pause, so just keep
2247 // things going as-is. To maintain our own state,
2248 // we need to emulate it coming back and saying it is
2249 // idle.
2250 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2251 msg.obj = next;
2252 mHandler.sendMessage(msg);
2253 }
2254
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002255 reportResumedActivityLocked(next);
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002256
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002257 next.thumbnail = null;
2258 setFocusedActivityLocked(next);
2259 next.resumeKeyDispatchingLocked();
2260 ensureActivitiesVisibleLocked(null, 0);
2261 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002262 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002263
2264 // Mark the point when the activity is resuming
2265 // TODO: To be more accurate, the mark should be before the onCreate,
2266 // not after the onResume. But for subsequent starts, onResume is fine.
2267 if (next.app != null) {
2268 synchronized (mProcessStatsThread) {
2269 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2270 }
2271 } else {
2272 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2273 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002274 }
2275
2276 /**
2277 * Make sure that all activities that need to be visible (that is, they
2278 * currently can be seen by the user) actually are.
2279 */
2280 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2281 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2282 if (DEBUG_VISBILITY) Log.v(
2283 TAG, "ensureActivitiesVisible behind " + top
2284 + " configChanges=0x" + Integer.toHexString(configChanges));
2285
2286 // If the top activity is not fullscreen, then we need to
2287 // make sure any activities under it are now visible.
2288 final int count = mHistory.size();
2289 int i = count-1;
2290 while (mHistory.get(i) != top) {
2291 i--;
2292 }
2293 HistoryRecord r;
2294 boolean behindFullscreen = false;
2295 for (; i>=0; i--) {
2296 r = (HistoryRecord)mHistory.get(i);
2297 if (DEBUG_VISBILITY) Log.v(
2298 TAG, "Make visible? " + r + " finishing=" + r.finishing
2299 + " state=" + r.state);
2300 if (r.finishing) {
2301 continue;
2302 }
2303
2304 final boolean doThisProcess = onlyThisProcess == null
2305 || onlyThisProcess.equals(r.processName);
2306
2307 // First: if this is not the current activity being started, make
2308 // sure it matches the current configuration.
2309 if (r != starting && doThisProcess) {
2310 ensureActivityConfigurationLocked(r, 0);
2311 }
2312
2313 if (r.app == null || r.app.thread == null) {
2314 if (onlyThisProcess == null
2315 || onlyThisProcess.equals(r.processName)) {
2316 // This activity needs to be visible, but isn't even
2317 // running... get it started, but don't resume it
2318 // at this point.
2319 if (DEBUG_VISBILITY) Log.v(
2320 TAG, "Start and freeze screen for " + r);
2321 if (r != starting) {
2322 r.startFreezingScreenLocked(r.app, configChanges);
2323 }
2324 if (!r.visible) {
2325 if (DEBUG_VISBILITY) Log.v(
2326 TAG, "Starting and making visible: " + r);
2327 mWindowManager.setAppVisibility(r, true);
2328 }
2329 if (r != starting) {
2330 startSpecificActivityLocked(r, false, false);
2331 }
2332 }
2333
2334 } else if (r.visible) {
2335 // If this activity is already visible, then there is nothing
2336 // else to do here.
2337 if (DEBUG_VISBILITY) Log.v(
2338 TAG, "Skipping: already visible at " + r);
2339 r.stopFreezingScreenLocked(false);
2340
2341 } else if (onlyThisProcess == null) {
2342 // This activity is not currently visible, but is running.
2343 // Tell it to become visible.
2344 r.visible = true;
2345 if (r.state != ActivityState.RESUMED && r != starting) {
2346 // If this activity is paused, tell it
2347 // to now show its window.
2348 if (DEBUG_VISBILITY) Log.v(
2349 TAG, "Making visible and scheduling visibility: " + r);
2350 try {
2351 mWindowManager.setAppVisibility(r, true);
2352 r.app.thread.scheduleWindowVisibility(r, true);
2353 r.stopFreezingScreenLocked(false);
2354 } catch (Exception e) {
2355 // Just skip on any failure; we'll make it
2356 // visible when it next restarts.
2357 Log.w(TAG, "Exception thrown making visibile: "
2358 + r.intent.getComponent(), e);
2359 }
2360 }
2361 }
2362
2363 // Aggregate current change flags.
2364 configChanges |= r.configChangeFlags;
2365
2366 if (r.fullscreen) {
2367 // At this point, nothing else needs to be shown
2368 if (DEBUG_VISBILITY) Log.v(
2369 TAG, "Stopping: fullscreen at " + r);
2370 behindFullscreen = true;
2371 i--;
2372 break;
2373 }
2374 }
2375
2376 // Now for any activities that aren't visible to the user, make
2377 // sure they no longer are keeping the screen frozen.
2378 while (i >= 0) {
2379 r = (HistoryRecord)mHistory.get(i);
2380 if (DEBUG_VISBILITY) Log.v(
2381 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2382 + " state=" + r.state
2383 + " behindFullscreen=" + behindFullscreen);
2384 if (!r.finishing) {
2385 if (behindFullscreen) {
2386 if (r.visible) {
2387 if (DEBUG_VISBILITY) Log.v(
2388 TAG, "Making invisible: " + r);
2389 r.visible = false;
2390 try {
2391 mWindowManager.setAppVisibility(r, false);
2392 if ((r.state == ActivityState.STOPPING
2393 || r.state == ActivityState.STOPPED)
2394 && r.app != null && r.app.thread != null) {
2395 if (DEBUG_VISBILITY) Log.v(
2396 TAG, "Scheduling invisibility: " + r);
2397 r.app.thread.scheduleWindowVisibility(r, false);
2398 }
2399 } catch (Exception e) {
2400 // Just skip on any failure; we'll make it
2401 // visible when it next restarts.
2402 Log.w(TAG, "Exception thrown making hidden: "
2403 + r.intent.getComponent(), e);
2404 }
2405 } else {
2406 if (DEBUG_VISBILITY) Log.v(
2407 TAG, "Already invisible: " + r);
2408 }
2409 } else if (r.fullscreen) {
2410 if (DEBUG_VISBILITY) Log.v(
2411 TAG, "Now behindFullscreen: " + r);
2412 behindFullscreen = true;
2413 }
2414 }
2415 i--;
2416 }
2417 }
2418
2419 /**
2420 * Version of ensureActivitiesVisible that can easily be called anywhere.
2421 */
2422 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2423 int configChanges) {
2424 HistoryRecord r = topRunningActivityLocked(null);
2425 if (r != null) {
2426 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2427 }
2428 }
2429
2430 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2431 if (resumed) {
2432 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2433 } else {
2434 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2435 }
2436 }
2437
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002438 private boolean startHomeActivityLocked() {
2439 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2440 && mTopAction == null) {
2441 // We are running in factory test mode, but unable to find
2442 // the factory test app, so just sit around displaying the
2443 // error message and don't try to start anything.
2444 return false;
2445 }
2446 Intent intent = new Intent(
2447 mTopAction,
2448 mTopData != null ? Uri.parse(mTopData) : null);
2449 intent.setComponent(mTopComponent);
2450 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2451 intent.addCategory(Intent.CATEGORY_HOME);
2452 }
2453 ActivityInfo aInfo =
2454 intent.resolveActivityInfo(mContext.getPackageManager(),
2455 STOCK_PM_FLAGS);
2456 if (aInfo != null) {
2457 intent.setComponent(new ComponentName(
2458 aInfo.applicationInfo.packageName, aInfo.name));
2459 // Don't do this if the home app is currently being
2460 // instrumented.
2461 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2462 aInfo.applicationInfo.uid);
2463 if (app == null || app.instrumentationClass == null) {
2464 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2465 startActivityLocked(null, intent, null, null, 0, aInfo,
2466 null, null, 0, 0, 0, false, false);
2467 }
2468 }
2469
2470
2471 return true;
2472 }
2473
2474 /**
2475 * Starts the "new version setup screen" if appropriate.
2476 */
2477 private void startSetupActivityLocked() {
2478 // Only do this once per boot.
2479 if (mCheckedForSetup) {
2480 return;
2481 }
2482
2483 // We will show this screen if the current one is a different
2484 // version than the last one shown, and we are not running in
2485 // low-level factory test mode.
2486 final ContentResolver resolver = mContext.getContentResolver();
2487 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2488 Settings.Secure.getInt(resolver,
2489 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2490 mCheckedForSetup = true;
2491
2492 // See if we should be showing the platform update setup UI.
2493 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2494 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2495 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2496
2497 // We don't allow third party apps to replace this.
2498 ResolveInfo ri = null;
2499 for (int i=0; ris != null && i<ris.size(); i++) {
2500 if ((ris.get(i).activityInfo.applicationInfo.flags
2501 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2502 ri = ris.get(i);
2503 break;
2504 }
2505 }
2506
2507 if (ri != null) {
2508 String vers = ri.activityInfo.metaData != null
2509 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2510 : null;
2511 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2512 vers = ri.activityInfo.applicationInfo.metaData.getString(
2513 Intent.METADATA_SETUP_VERSION);
2514 }
2515 String lastVers = Settings.Secure.getString(
2516 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2517 if (vers != null && !vers.equals(lastVers)) {
2518 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2519 intent.setComponent(new ComponentName(
2520 ri.activityInfo.packageName, ri.activityInfo.name));
2521 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2522 null, null, 0, 0, 0, false, false);
2523 }
2524 }
2525 }
2526 }
2527
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002528 private void reportResumedActivityLocked(HistoryRecord r) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002529 //Log.i(TAG, "**** REPORT RESUME: " + r);
2530
2531 final int identHash = System.identityHashCode(r);
2532 updateUsageStats(r, true);
2533
2534 int i = mWatchers.beginBroadcast();
2535 while (i > 0) {
2536 i--;
2537 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2538 if (w != null) {
2539 try {
2540 w.activityResuming(identHash);
2541 } catch (RemoteException e) {
2542 }
2543 }
2544 }
2545 mWatchers.finishBroadcast();
2546 }
2547
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002548 /**
2549 * Ensure that the top activity in the stack is resumed.
2550 *
2551 * @param prev The previously resumed activity, for when in the process
2552 * of pausing; can be null to call from elsewhere.
2553 *
2554 * @return Returns true if something is being resumed, or false if
2555 * nothing happened.
2556 */
2557 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2558 // Find the first activity that is not finishing.
2559 HistoryRecord next = topRunningActivityLocked(null);
2560
2561 // Remember how we'll process this pause/resume situation, and ensure
2562 // that the state is reset however we wind up proceeding.
2563 final boolean userLeaving = mUserLeaving;
2564 mUserLeaving = false;
2565
2566 if (next == null) {
2567 // There are no more activities! Let's just start up the
2568 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002569 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002570 }
2571
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002572 next.delayedResume = false;
2573
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002574 // If the top activity is the resumed one, nothing to do.
2575 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2576 // Make sure we have executed any pending transitions, since there
2577 // should be nothing left to do at this point.
2578 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002579 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002580 return false;
2581 }
2582
2583 // If we are sleeping, and there is no resumed activity, and the top
2584 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002585 if ((mSleeping || mShuttingDown)
2586 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002587 // Make sure we have executed any pending transitions, since there
2588 // should be nothing left to do at this point.
2589 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002590 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002591 return false;
2592 }
2593
2594 // The activity may be waiting for stop, but that is no longer
2595 // appropriate for it.
2596 mStoppingActivities.remove(next);
2597 mWaitingVisibleActivities.remove(next);
2598
2599 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2600
2601 // If we are currently pausing an activity, then don't do anything
2602 // until that is done.
2603 if (mPausingActivity != null) {
2604 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2605 return false;
2606 }
2607
2608 // We need to start pausing the current activity so the top one
2609 // can be resumed...
2610 if (mResumedActivity != null) {
2611 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2612 startPausingLocked(userLeaving, false);
2613 return true;
2614 }
2615
2616 if (prev != null && prev != next) {
2617 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2618 prev.waitingVisible = true;
2619 mWaitingVisibleActivities.add(prev);
2620 if (DEBUG_SWITCH) Log.v(
2621 TAG, "Resuming top, waiting visible to hide: " + prev);
2622 } else {
2623 // The next activity is already visible, so hide the previous
2624 // activity's windows right now so we can show the new one ASAP.
2625 // We only do this if the previous is finishing, which should mean
2626 // it is on top of the one being resumed so hiding it quickly
2627 // is good. Otherwise, we want to do the normal route of allowing
2628 // the resumed activity to be shown so we can decide if the
2629 // previous should actually be hidden depending on whether the
2630 // new one is found to be full-screen or not.
2631 if (prev.finishing) {
2632 mWindowManager.setAppVisibility(prev, false);
2633 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2634 + prev + ", waitingVisible="
2635 + (prev != null ? prev.waitingVisible : null)
2636 + ", nowVisible=" + next.nowVisible);
2637 } else {
2638 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2639 + prev + ", waitingVisible="
2640 + (prev != null ? prev.waitingVisible : null)
2641 + ", nowVisible=" + next.nowVisible);
2642 }
2643 }
2644 }
2645
2646 // We are starting up the next activity, so tell the window manager
2647 // that the previous one will be hidden soon. This way it can know
2648 // to ignore it when computing the desired screen orientation.
2649 if (prev != null) {
2650 if (prev.finishing) {
2651 if (DEBUG_TRANSITION) Log.v(TAG,
2652 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002653 if (mNoAnimActivities.contains(prev)) {
2654 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2655 } else {
2656 mWindowManager.prepareAppTransition(prev.task == next.task
2657 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2658 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2659 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002660 mWindowManager.setAppWillBeHidden(prev);
2661 mWindowManager.setAppVisibility(prev, false);
2662 } else {
2663 if (DEBUG_TRANSITION) Log.v(TAG,
2664 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002665 if (mNoAnimActivities.contains(next)) {
2666 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2667 } else {
2668 mWindowManager.prepareAppTransition(prev.task == next.task
2669 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2670 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2671 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002672 }
2673 if (false) {
2674 mWindowManager.setAppWillBeHidden(prev);
2675 mWindowManager.setAppVisibility(prev, false);
2676 }
2677 } else if (mHistory.size() > 1) {
2678 if (DEBUG_TRANSITION) Log.v(TAG,
2679 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002680 if (mNoAnimActivities.contains(next)) {
2681 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2682 } else {
2683 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2684 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002685 }
2686
2687 if (next.app != null && next.app.thread != null) {
2688 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2689
2690 // This activity is now becoming visible.
2691 mWindowManager.setAppVisibility(next, true);
2692
2693 HistoryRecord lastResumedActivity = mResumedActivity;
2694 ActivityState lastState = next.state;
2695
2696 updateCpuStats();
2697
2698 next.state = ActivityState.RESUMED;
2699 mResumedActivity = next;
2700 next.task.touchActiveTime();
2701 updateLRUListLocked(next.app, true);
2702 updateLRUListLocked(next);
2703
2704 // Have the window manager re-evaluate the orientation of
2705 // the screen based on the new activity order.
2706 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002707 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002708 next.mayFreezeScreenLocked(next.app) ? next : null);
2709 if (config != null) {
2710 next.frozenBeforeDestroy = true;
2711 }
2712 if (!updateConfigurationLocked(config, next)) {
2713 // The configuration update wasn't able to keep the existing
2714 // instance of the activity, and instead started a new one.
2715 // We should be all done, but let's just make sure our activity
2716 // is still at the top and schedule another run if something
2717 // weird happened.
2718 HistoryRecord nextNext = topRunningActivityLocked(null);
2719 if (DEBUG_SWITCH) Log.i(TAG,
2720 "Activity config changed during resume: " + next
2721 + ", new next: " + nextNext);
2722 if (nextNext != next) {
2723 // Do over!
2724 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2725 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002726 setFocusedActivityLocked(next);
2727 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002728 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002729 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002730 return true;
2731 }
2732
2733 try {
2734 // Deliver all pending results.
2735 ArrayList a = next.results;
2736 if (a != null) {
2737 final int N = a.size();
2738 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002739 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002740 TAG, "Delivering results to " + next
2741 + ": " + a);
2742 next.app.thread.scheduleSendResult(next, a);
2743 }
2744 }
2745
2746 if (next.newIntents != null) {
2747 next.app.thread.scheduleNewIntent(next.newIntents, next);
2748 }
2749
2750 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2751 System.identityHashCode(next),
2752 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002753
2754 next.app.thread.scheduleResumeActivity(next,
2755 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002756
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002757 pauseIfSleepingLocked();
2758
2759 } catch (Exception e) {
2760 // Whoops, need to restart this activity!
2761 next.state = lastState;
2762 mResumedActivity = lastResumedActivity;
2763 if (Config.LOGD) Log.d(TAG,
2764 "Restarting because process died: " + next);
2765 if (!next.hasBeenLaunched) {
2766 next.hasBeenLaunched = true;
2767 } else {
2768 if (SHOW_APP_STARTING_ICON) {
2769 mWindowManager.setAppStartingWindow(
2770 next, next.packageName, next.theme,
2771 next.nonLocalizedLabel,
2772 next.labelRes, next.icon, null, true);
2773 }
2774 }
2775 startSpecificActivityLocked(next, true, false);
2776 return true;
2777 }
2778
2779 // From this point on, if something goes wrong there is no way
2780 // to recover the activity.
2781 try {
2782 next.visible = true;
2783 completeResumeLocked(next);
2784 } catch (Exception e) {
2785 // If any exception gets thrown, toss away this
2786 // activity and try the next one.
2787 Log.w(TAG, "Exception thrown during resume of " + next, e);
2788 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2789 "resume-exception");
2790 return true;
2791 }
2792
2793 // Didn't need to use the icicle, and it is now out of date.
2794 next.icicle = null;
2795 next.haveState = false;
2796 next.stopped = false;
2797
2798 } else {
2799 // Whoops, need to restart this activity!
2800 if (!next.hasBeenLaunched) {
2801 next.hasBeenLaunched = true;
2802 } else {
2803 if (SHOW_APP_STARTING_ICON) {
2804 mWindowManager.setAppStartingWindow(
2805 next, next.packageName, next.theme,
2806 next.nonLocalizedLabel,
2807 next.labelRes, next.icon, null, true);
2808 }
2809 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2810 }
2811 startSpecificActivityLocked(next, true, true);
2812 }
2813
2814 return true;
2815 }
2816
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002817 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2818 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002819 final int NH = mHistory.size();
2820
2821 int addPos = -1;
2822
2823 if (!newTask) {
2824 // If starting in an existing task, find where that is...
2825 HistoryRecord next = null;
2826 boolean startIt = true;
2827 for (int i = NH-1; i >= 0; i--) {
2828 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2829 if (p.finishing) {
2830 continue;
2831 }
2832 if (p.task == r.task) {
2833 // Here it is! Now, if this is not yet visible to the
2834 // user, then just add it without starting; it will
2835 // get started when the user navigates back to it.
2836 addPos = i+1;
2837 if (!startIt) {
2838 mHistory.add(addPos, r);
2839 r.inHistory = true;
2840 r.task.numActivities++;
2841 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2842 r.info.screenOrientation, r.fullscreen);
2843 if (VALIDATE_TOKENS) {
2844 mWindowManager.validateAppTokens(mHistory);
2845 }
2846 return;
2847 }
2848 break;
2849 }
2850 if (p.fullscreen) {
2851 startIt = false;
2852 }
2853 next = p;
2854 }
2855 }
2856
2857 // Place a new activity at top of stack, so it is next to interact
2858 // with the user.
2859 if (addPos < 0) {
2860 addPos = mHistory.size();
2861 }
2862
2863 // If we are not placing the new activity frontmost, we do not want
2864 // to deliver the onUserLeaving callback to the actual frontmost
2865 // activity
2866 if (addPos < NH) {
2867 mUserLeaving = false;
2868 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2869 }
2870
2871 // Slot the activity into the history stack and proceed
2872 mHistory.add(addPos, r);
2873 r.inHistory = true;
2874 r.frontOfTask = newTask;
2875 r.task.numActivities++;
2876 if (NH > 0) {
2877 // We want to show the starting preview window if we are
2878 // switching to a new task, or the next activity's process is
2879 // not currently running.
2880 boolean showStartingIcon = newTask;
2881 ProcessRecord proc = r.app;
2882 if (proc == null) {
2883 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2884 }
2885 if (proc == null || proc.thread == null) {
2886 showStartingIcon = true;
2887 }
2888 if (DEBUG_TRANSITION) Log.v(TAG,
2889 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002890 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2891 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2892 mNoAnimActivities.add(r);
2893 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2894 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2895 mNoAnimActivities.remove(r);
2896 } else {
2897 mWindowManager.prepareAppTransition(newTask
2898 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2899 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2900 mNoAnimActivities.remove(r);
2901 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002902 mWindowManager.addAppToken(
2903 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2904 boolean doShow = true;
2905 if (newTask) {
2906 // Even though this activity is starting fresh, we still need
2907 // to reset it to make sure we apply affinities to move any
2908 // existing activities from other tasks in to it.
2909 // If the caller has requested that the target task be
2910 // reset, then do so.
2911 if ((r.intent.getFlags()
2912 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2913 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002914 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002915 }
2916 }
2917 if (SHOW_APP_STARTING_ICON && doShow) {
2918 // Figure out if we are transitioning from another activity that is
2919 // "has the same starting icon" as the next one. This allows the
2920 // window manager to keep the previous window it had previously
2921 // created, if it still had one.
2922 HistoryRecord prev = mResumedActivity;
2923 if (prev != null) {
2924 // We don't want to reuse the previous starting preview if:
2925 // (1) The current activity is in a different task.
2926 if (prev.task != r.task) prev = null;
2927 // (2) The current activity is already displayed.
2928 else if (prev.nowVisible) prev = null;
2929 }
2930 mWindowManager.setAppStartingWindow(
2931 r, r.packageName, r.theme, r.nonLocalizedLabel,
2932 r.labelRes, r.icon, prev, showStartingIcon);
2933 }
2934 } else {
2935 // If this is the first activity, don't do any fancy animations,
2936 // because there is nothing for it to animate on top of.
2937 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2938 r.info.screenOrientation, r.fullscreen);
2939 }
2940 if (VALIDATE_TOKENS) {
2941 mWindowManager.validateAppTokens(mHistory);
2942 }
2943
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002944 if (doResume) {
2945 resumeTopActivityLocked(null);
2946 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002947 }
2948
2949 /**
2950 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002951 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2952 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002953 * an instance of that activity in the stack and, if found, finish all
2954 * activities on top of it and return the instance.
2955 *
2956 * @param newR Description of the new activity being started.
2957 * @return Returns the old activity that should be continue to be used,
2958 * or null if none was found.
2959 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002960 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002961 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002962 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002963
2964 // First find the requested task.
2965 while (i > 0) {
2966 i--;
2967 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2968 if (r.task.taskId == taskId) {
2969 i++;
2970 break;
2971 }
2972 }
2973
2974 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002975 while (i > 0) {
2976 i--;
2977 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2978 if (r.finishing) {
2979 continue;
2980 }
2981 if (r.task.taskId != taskId) {
2982 return null;
2983 }
2984 if (r.realActivity.equals(newR.realActivity)) {
2985 // Here it is! Now finish everything in front...
2986 HistoryRecord ret = r;
2987 if (doClear) {
2988 while (i < (mHistory.size()-1)) {
2989 i++;
2990 r = (HistoryRecord)mHistory.get(i);
2991 if (r.finishing) {
2992 continue;
2993 }
2994 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2995 null, "clear")) {
2996 i--;
2997 }
2998 }
2999 }
3000
3001 // Finally, if this is a normal launch mode (that is, not
3002 // expecting onNewIntent()), then we will finish the current
3003 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003004 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
3005 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003006 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003007 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003008 if (index >= 0) {
3009 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
3010 null, "clear");
3011 }
3012 return null;
3013 }
3014 }
3015
3016 return ret;
3017 }
3018 }
3019
3020 return null;
3021 }
3022
3023 /**
3024 * Find the activity in the history stack within the given task. Returns
3025 * the index within the history at which it's found, or < 0 if not found.
3026 */
3027 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3028 int i = mHistory.size();
3029 while (i > 0) {
3030 i--;
3031 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3032 if (candidate.task.taskId != task) {
3033 break;
3034 }
3035 if (candidate.realActivity.equals(r.realActivity)) {
3036 return i;
3037 }
3038 }
3039
3040 return -1;
3041 }
3042
3043 /**
3044 * Reorder the history stack so that the activity at the given index is
3045 * brought to the front.
3046 */
3047 private final HistoryRecord moveActivityToFrontLocked(int where) {
3048 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3049 int top = mHistory.size();
3050 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3051 mHistory.add(top, newTop);
3052 oldTop.frontOfTask = false;
3053 newTop.frontOfTask = true;
3054 return newTop;
3055 }
3056
3057 /**
3058 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3059 * method will be called at the proper time.
3060 */
3061 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3062 boolean sent = false;
3063 if (r.state == ActivityState.RESUMED
3064 && r.app != null && r.app.thread != null) {
3065 try {
3066 ArrayList<Intent> ar = new ArrayList<Intent>();
3067 ar.add(new Intent(intent));
3068 r.app.thread.scheduleNewIntent(ar, r);
3069 sent = true;
3070 } catch (Exception e) {
3071 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3072 }
3073 }
3074 if (!sent) {
3075 r.addNewIntentLocked(new Intent(intent));
3076 }
3077 }
3078
3079 private final void logStartActivity(int tag, HistoryRecord r,
3080 TaskRecord task) {
3081 EventLog.writeEvent(tag,
3082 System.identityHashCode(r), task.taskId,
3083 r.shortComponentName, r.intent.getAction(),
3084 r.intent.getType(), r.intent.getDataString(),
3085 r.intent.getFlags());
3086 }
3087
3088 private final int startActivityLocked(IApplicationThread caller,
3089 Intent intent, String resolvedType,
3090 Uri[] grantedUriPermissions,
3091 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3092 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003093 int callingPid, int callingUid, boolean onlyIfNeeded,
3094 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003095 Log.i(TAG, "Starting activity: " + intent);
3096
3097 HistoryRecord sourceRecord = null;
3098 HistoryRecord resultRecord = null;
3099 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003100 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003101 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003102 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3103 if (index >= 0) {
3104 sourceRecord = (HistoryRecord)mHistory.get(index);
3105 if (requestCode >= 0 && !sourceRecord.finishing) {
3106 resultRecord = sourceRecord;
3107 }
3108 }
3109 }
3110
3111 int launchFlags = intent.getFlags();
3112
3113 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3114 && sourceRecord != null) {
3115 // Transfer the result target from the source activity to the new
3116 // one being started, including any failures.
3117 if (requestCode >= 0) {
3118 return START_FORWARD_AND_REQUEST_CONFLICT;
3119 }
3120 resultRecord = sourceRecord.resultTo;
3121 resultWho = sourceRecord.resultWho;
3122 requestCode = sourceRecord.requestCode;
3123 sourceRecord.resultTo = null;
3124 if (resultRecord != null) {
3125 resultRecord.removeResultsLocked(
3126 sourceRecord, resultWho, requestCode);
3127 }
3128 }
3129
3130 int err = START_SUCCESS;
3131
3132 if (intent.getComponent() == null) {
3133 // We couldn't find a class that can handle the given Intent.
3134 // That's the end of that!
3135 err = START_INTENT_NOT_RESOLVED;
3136 }
3137
3138 if (err == START_SUCCESS && aInfo == null) {
3139 // We couldn't find the specific class specified in the Intent.
3140 // Also the end of the line.
3141 err = START_CLASS_NOT_FOUND;
3142 }
3143
3144 ProcessRecord callerApp = null;
3145 if (err == START_SUCCESS && caller != null) {
3146 callerApp = getRecordForAppLocked(caller);
3147 if (callerApp != null) {
3148 callingPid = callerApp.pid;
3149 callingUid = callerApp.info.uid;
3150 } else {
3151 Log.w(TAG, "Unable to find app for caller " + caller
3152 + " (pid=" + callingPid + ") when starting: "
3153 + intent.toString());
3154 err = START_PERMISSION_DENIED;
3155 }
3156 }
3157
3158 if (err != START_SUCCESS) {
3159 if (resultRecord != null) {
3160 sendActivityResultLocked(-1,
3161 resultRecord, resultWho, requestCode,
3162 Activity.RESULT_CANCELED, null);
3163 }
3164 return err;
3165 }
3166
3167 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3168 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3169 if (perm != PackageManager.PERMISSION_GRANTED) {
3170 if (resultRecord != null) {
3171 sendActivityResultLocked(-1,
3172 resultRecord, resultWho, requestCode,
3173 Activity.RESULT_CANCELED, null);
3174 }
3175 String msg = "Permission Denial: starting " + intent.toString()
3176 + " from " + callerApp + " (pid=" + callingPid
3177 + ", uid=" + callingUid + ")"
3178 + " requires " + aInfo.permission;
3179 Log.w(TAG, msg);
3180 throw new SecurityException(msg);
3181 }
3182
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003183 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003184 boolean abort = false;
3185 try {
3186 // The Intent we give to the watcher has the extra data
3187 // stripped off, since it can contain private information.
3188 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003189 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003190 aInfo.applicationInfo.packageName);
3191 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003192 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003193 }
3194
3195 if (abort) {
3196 if (resultRecord != null) {
3197 sendActivityResultLocked(-1,
3198 resultRecord, resultWho, requestCode,
3199 Activity.RESULT_CANCELED, null);
3200 }
3201 // We pretend to the caller that it was really started, but
3202 // they will just get a cancel result.
3203 return START_SUCCESS;
3204 }
3205 }
3206
3207 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3208 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003209 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003210
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003211 if (mResumedActivity == null
3212 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3213 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3214 PendingActivityLaunch pal = new PendingActivityLaunch();
3215 pal.r = r;
3216 pal.sourceRecord = sourceRecord;
3217 pal.grantedUriPermissions = grantedUriPermissions;
3218 pal.grantedMode = grantedMode;
3219 pal.onlyIfNeeded = onlyIfNeeded;
3220 mPendingActivityLaunches.add(pal);
3221 return START_SWITCHES_CANCELED;
3222 }
3223 }
3224
3225 if (mDidAppSwitch) {
3226 // This is the second allowed switch since we stopped switches,
3227 // so now just generally allow switches. Use case: user presses
3228 // home (switches disabled, switch to home, mDidAppSwitch now true);
3229 // user taps a home icon (coming from home so allowed, we hit here
3230 // and now allow anyone to switch again).
3231 mAppSwitchesAllowedTime = 0;
3232 } else {
3233 mDidAppSwitch = true;
3234 }
3235
3236 doPendingActivityLaunchesLocked(false);
3237
3238 return startActivityUncheckedLocked(r, sourceRecord,
3239 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3240 }
3241
3242 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3243 final int N = mPendingActivityLaunches.size();
3244 if (N <= 0) {
3245 return;
3246 }
3247 for (int i=0; i<N; i++) {
3248 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3249 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3250 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3251 doResume && i == (N-1));
3252 }
3253 mPendingActivityLaunches.clear();
3254 }
3255
3256 private final int startActivityUncheckedLocked(HistoryRecord r,
3257 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3258 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3259 final Intent intent = r.intent;
3260 final int callingUid = r.launchedFromUid;
3261
3262 int launchFlags = intent.getFlags();
3263
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003264 // We'll invoke onUserLeaving before onPause only if the launching
3265 // activity did not explicitly state that this is an automated launch.
3266 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3267 if (DEBUG_USER_LEAVING) Log.v(TAG,
3268 "startActivity() => mUserLeaving=" + mUserLeaving);
3269
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003270 // If the caller has asked not to resume at this point, we make note
3271 // of this in the record so that we can skip it when trying to find
3272 // the top running activity.
3273 if (!doResume) {
3274 r.delayedResume = true;
3275 }
3276
3277 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3278 != 0 ? r : null;
3279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003280 // If the onlyIfNeeded flag is set, then we can do this if the activity
3281 // being launched is the same as the one making the call... or, as
3282 // a special case, if we do not know the caller then we count the
3283 // current top activity as the caller.
3284 if (onlyIfNeeded) {
3285 HistoryRecord checkedCaller = sourceRecord;
3286 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003287 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003288 }
3289 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3290 // Caller is not the same as launcher, so always needed.
3291 onlyIfNeeded = false;
3292 }
3293 }
3294
3295 if (grantedUriPermissions != null && callingUid > 0) {
3296 for (int i=0; i<grantedUriPermissions.length; i++) {
3297 grantUriPermissionLocked(callingUid, r.packageName,
3298 grantedUriPermissions[i], grantedMode, r);
3299 }
3300 }
3301
3302 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3303 intent, r);
3304
3305 if (sourceRecord == null) {
3306 // This activity is not being started from another... in this
3307 // case we -always- start a new task.
3308 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3309 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3310 + intent);
3311 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3312 }
3313 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3314 // The original activity who is starting us is running as a single
3315 // instance... this new activity it is starting must go on its
3316 // own task.
3317 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3318 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3319 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3320 // The activity being started is a single instance... it always
3321 // gets launched into its own task.
3322 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3323 }
3324
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003325 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003326 // For whatever reason this activity is being launched into a new
3327 // task... yet the caller has requested a result back. Well, that
3328 // is pretty messed up, so instead immediately send back a cancel
3329 // and let the new task continue launched as normal without a
3330 // dependency on its originator.
3331 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3332 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003333 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003334 Activity.RESULT_CANCELED, null);
3335 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003336 }
3337
3338 boolean addingToTask = false;
3339 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3340 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3341 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3342 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3343 // If bring to front is requested, and no result is requested, and
3344 // we can find a task that was started with this same
3345 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003346 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003347 // See if there is a task to bring to the front. If this is
3348 // a SINGLE_INSTANCE activity, there can be one and only one
3349 // instance of it in the history, and it is always in its own
3350 // unique task, so we do a special search.
3351 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3352 ? findTaskLocked(intent, r.info)
3353 : findActivityLocked(intent, r.info);
3354 if (taskTop != null) {
3355 if (taskTop.task.intent == null) {
3356 // This task was started because of movement of
3357 // the activity based on affinity... now that we
3358 // are actually launching it, we can assign the
3359 // base intent.
3360 taskTop.task.setIntent(intent, r.info);
3361 }
3362 // If the target task is not in the front, then we need
3363 // to bring it to the front... except... well, with
3364 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3365 // to have the same behavior as if a new instance was
3366 // being started, which means not bringing it to the front
3367 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003368 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003369 if (curTop.task != taskTop.task) {
3370 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3371 boolean callerAtFront = sourceRecord == null
3372 || curTop.task == sourceRecord.task;
3373 if (callerAtFront) {
3374 // We really do want to push this one into the
3375 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003376 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003377 }
3378 }
3379 // If the caller has requested that the target task be
3380 // reset, then do so.
3381 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3382 taskTop = resetTaskIfNeededLocked(taskTop, r);
3383 }
3384 if (onlyIfNeeded) {
3385 // We don't need to start a new activity, and
3386 // the client said not to do anything if that
3387 // is the case, so this is it! And for paranoia, make
3388 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003389 if (doResume) {
3390 resumeTopActivityLocked(null);
3391 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003392 return START_RETURN_INTENT_TO_CALLER;
3393 }
3394 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3395 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3396 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3397 // In this situation we want to remove all activities
3398 // from the task up to the one being started. In most
3399 // cases this means we are resetting the task to its
3400 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003401 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003402 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003403 if (top != null) {
3404 if (top.frontOfTask) {
3405 // Activity aliases may mean we use different
3406 // intents for the top activity, so make sure
3407 // the task now has the identity of the new
3408 // intent.
3409 top.task.setIntent(r.intent, r.info);
3410 }
3411 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3412 deliverNewIntentLocked(top, r.intent);
3413 } else {
3414 // A special case: we need to
3415 // start the activity because it is not currently
3416 // running, and the caller has asked to clear the
3417 // current task to have this activity at the top.
3418 addingToTask = true;
3419 // Now pretend like this activity is being started
3420 // by the top of its task, so it is put in the
3421 // right place.
3422 sourceRecord = taskTop;
3423 }
3424 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3425 // In this case the top activity on the task is the
3426 // same as the one being launched, so we take that
3427 // as a request to bring the task to the foreground.
3428 // If the top activity in the task is the root
3429 // activity, deliver this new intent to it if it
3430 // desires.
3431 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3432 && taskTop.realActivity.equals(r.realActivity)) {
3433 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3434 if (taskTop.frontOfTask) {
3435 taskTop.task.setIntent(r.intent, r.info);
3436 }
3437 deliverNewIntentLocked(taskTop, r.intent);
3438 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3439 // In this case we are launching the root activity
3440 // of the task, but with a different intent. We
3441 // should start a new instance on top.
3442 addingToTask = true;
3443 sourceRecord = taskTop;
3444 }
3445 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3446 // In this case an activity is being launched in to an
3447 // existing task, without resetting that task. This
3448 // is typically the situation of launching an activity
3449 // from a notification or shortcut. We want to place
3450 // the new activity on top of the current task.
3451 addingToTask = true;
3452 sourceRecord = taskTop;
3453 } else if (!taskTop.task.rootWasReset) {
3454 // In this case we are launching in to an existing task
3455 // that has not yet been started from its front door.
3456 // The current task has been brought to the front.
3457 // Ideally, we'd probably like to place this new task
3458 // at the bottom of its stack, but that's a little hard
3459 // to do with the current organization of the code so
3460 // for now we'll just drop it.
3461 taskTop.task.setIntent(r.intent, r.info);
3462 }
3463 if (!addingToTask) {
3464 // We didn't do anything... but it was needed (a.k.a., client
3465 // don't use that intent!) And for paranoia, make
3466 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003467 if (doResume) {
3468 resumeTopActivityLocked(null);
3469 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003470 return START_TASK_TO_FRONT;
3471 }
3472 }
3473 }
3474 }
3475
3476 //String uri = r.intent.toURI();
3477 //Intent intent2 = new Intent(uri);
3478 //Log.i(TAG, "Given intent: " + r.intent);
3479 //Log.i(TAG, "URI is: " + uri);
3480 //Log.i(TAG, "To intent: " + intent2);
3481
3482 if (r.packageName != null) {
3483 // If the activity being launched is the same as the one currently
3484 // at the top, then we need to check if it should only be launched
3485 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003486 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3487 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003488 if (top.realActivity.equals(r.realActivity)) {
3489 if (top.app != null && top.app.thread != null) {
3490 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3491 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3492 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3493 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3494 // For paranoia, make sure we have correctly
3495 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003496 if (doResume) {
3497 resumeTopActivityLocked(null);
3498 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003499 if (onlyIfNeeded) {
3500 // We don't need to start a new activity, and
3501 // the client said not to do anything if that
3502 // is the case, so this is it!
3503 return START_RETURN_INTENT_TO_CALLER;
3504 }
3505 deliverNewIntentLocked(top, r.intent);
3506 return START_DELIVERED_TO_TOP;
3507 }
3508 }
3509 }
3510 }
3511
3512 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003513 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003514 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003515 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003516 Activity.RESULT_CANCELED, null);
3517 }
3518 return START_CLASS_NOT_FOUND;
3519 }
3520
3521 boolean newTask = false;
3522
3523 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003524 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003525 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3526 // todo: should do better management of integers.
3527 mCurTask++;
3528 if (mCurTask <= 0) {
3529 mCurTask = 1;
3530 }
3531 r.task = new TaskRecord(mCurTask, r.info, intent,
3532 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3533 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3534 + " in new task " + r.task);
3535 newTask = true;
3536 addRecentTask(r.task);
3537
3538 } else if (sourceRecord != null) {
3539 if (!addingToTask &&
3540 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3541 // In this case, we are adding the activity to an existing
3542 // task, but the caller has asked to clear that task if the
3543 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003544 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003545 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003546 if (top != null) {
3547 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3548 deliverNewIntentLocked(top, r.intent);
3549 // For paranoia, make sure we have correctly
3550 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003551 if (doResume) {
3552 resumeTopActivityLocked(null);
3553 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003554 return START_DELIVERED_TO_TOP;
3555 }
3556 } else if (!addingToTask &&
3557 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3558 // In this case, we are launching an activity in our own task
3559 // that may already be running somewhere in the history, and
3560 // we want to shuffle it to the front of the stack if so.
3561 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3562 if (where >= 0) {
3563 HistoryRecord top = moveActivityToFrontLocked(where);
3564 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3565 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003566 if (doResume) {
3567 resumeTopActivityLocked(null);
3568 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003569 return START_DELIVERED_TO_TOP;
3570 }
3571 }
3572 // An existing activity is starting this new activity, so we want
3573 // to keep the new one in the same task as the one that is starting
3574 // it.
3575 r.task = sourceRecord.task;
3576 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3577 + " in existing task " + r.task);
3578
3579 } else {
3580 // This not being started from an existing activity, and not part
3581 // of a new task... just put it in the top task, though these days
3582 // this case should never happen.
3583 final int N = mHistory.size();
3584 HistoryRecord prev =
3585 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3586 r.task = prev != null
3587 ? prev.task
3588 : new TaskRecord(mCurTask, r.info, intent,
3589 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3590 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3591 + " in new guessed " + r.task);
3592 }
3593 if (newTask) {
3594 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3595 }
3596 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003597 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003598 return START_SUCCESS;
3599 }
3600
3601 public final int startActivity(IApplicationThread caller,
3602 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3603 int grantedMode, IBinder resultTo,
3604 String resultWho, int requestCode, boolean onlyIfNeeded,
3605 boolean debug) {
3606 // Refuse possible leaked file descriptors
3607 if (intent != null && intent.hasFileDescriptors()) {
3608 throw new IllegalArgumentException("File descriptors passed in Intent");
3609 }
3610
The Android Open Source Project4df24232009-03-05 14:34:35 -08003611 final boolean componentSpecified = intent.getComponent() != null;
3612
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003613 // Don't modify the client's object!
3614 intent = new Intent(intent);
3615
3616 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003617 ActivityInfo aInfo;
3618 try {
3619 ResolveInfo rInfo =
3620 ActivityThread.getPackageManager().resolveIntent(
3621 intent, resolvedType,
3622 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003623 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003624 aInfo = rInfo != null ? rInfo.activityInfo : null;
3625 } catch (RemoteException e) {
3626 aInfo = null;
3627 }
3628
3629 if (aInfo != null) {
3630 // Store the found target back into the intent, because now that
3631 // we have it we never want to do this again. For example, if the
3632 // user navigates back to this point in the history, we should
3633 // always restart the exact same activity.
3634 intent.setComponent(new ComponentName(
3635 aInfo.applicationInfo.packageName, aInfo.name));
3636
3637 // Don't debug things in the system process
3638 if (debug) {
3639 if (!aInfo.processName.equals("system")) {
3640 setDebugApp(aInfo.processName, true, false);
3641 }
3642 }
3643 }
3644
3645 synchronized(this) {
3646 final long origId = Binder.clearCallingIdentity();
3647 int res = startActivityLocked(caller, intent, resolvedType,
3648 grantedUriPermissions, grantedMode, aInfo,
3649 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003650 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003651 Binder.restoreCallingIdentity(origId);
3652 return res;
3653 }
3654 }
3655
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003656 public int startActivityIntentSender(IApplicationThread caller,
3657 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003658 IBinder resultTo, String resultWho, int requestCode,
3659 int flagsMask, int flagsValues) {
3660 // Refuse possible leaked file descriptors
3661 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3662 throw new IllegalArgumentException("File descriptors passed in Intent");
3663 }
3664
3665 IIntentSender sender = intent.getTarget();
3666 if (!(sender instanceof PendingIntentRecord)) {
3667 throw new IllegalArgumentException("Bad PendingIntent object");
3668 }
3669
3670 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003671
3672 synchronized (this) {
3673 // If this is coming from the currently resumed activity, it is
3674 // effectively saying that app switches are allowed at this point.
3675 if (mResumedActivity != null
3676 && mResumedActivity.info.applicationInfo.uid ==
3677 Binder.getCallingUid()) {
3678 mAppSwitchesAllowedTime = 0;
3679 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003680 }
3681
3682 return pir.sendInner(0, fillInIntent, resolvedType,
3683 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3684 }
3685
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003686 public boolean startNextMatchingActivity(IBinder callingActivity,
3687 Intent intent) {
3688 // Refuse possible leaked file descriptors
3689 if (intent != null && intent.hasFileDescriptors() == true) {
3690 throw new IllegalArgumentException("File descriptors passed in Intent");
3691 }
3692
3693 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003694 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003695 if (index < 0) {
3696 return false;
3697 }
3698 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3699 if (r.app == null || r.app.thread == null) {
3700 // The caller is not running... d'oh!
3701 return false;
3702 }
3703 intent = new Intent(intent);
3704 // The caller is not allowed to change the data.
3705 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3706 // And we are resetting to find the next component...
3707 intent.setComponent(null);
3708
3709 ActivityInfo aInfo = null;
3710 try {
3711 List<ResolveInfo> resolves =
3712 ActivityThread.getPackageManager().queryIntentActivities(
3713 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003714 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003715
3716 // Look for the original activity in the list...
3717 final int N = resolves != null ? resolves.size() : 0;
3718 for (int i=0; i<N; i++) {
3719 ResolveInfo rInfo = resolves.get(i);
3720 if (rInfo.activityInfo.packageName.equals(r.packageName)
3721 && rInfo.activityInfo.name.equals(r.info.name)) {
3722 // We found the current one... the next matching is
3723 // after it.
3724 i++;
3725 if (i<N) {
3726 aInfo = resolves.get(i).activityInfo;
3727 }
3728 break;
3729 }
3730 }
3731 } catch (RemoteException e) {
3732 }
3733
3734 if (aInfo == null) {
3735 // Nobody who is next!
3736 return false;
3737 }
3738
3739 intent.setComponent(new ComponentName(
3740 aInfo.applicationInfo.packageName, aInfo.name));
3741 intent.setFlags(intent.getFlags()&~(
3742 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3743 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3744 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3745 Intent.FLAG_ACTIVITY_NEW_TASK));
3746
3747 // Okay now we need to start the new activity, replacing the
3748 // currently running activity. This is a little tricky because
3749 // we want to start the new one as if the current one is finished,
3750 // but not finish the current one first so that there is no flicker.
3751 // And thus...
3752 final boolean wasFinishing = r.finishing;
3753 r.finishing = true;
3754
3755 // Propagate reply information over to the new activity.
3756 final HistoryRecord resultTo = r.resultTo;
3757 final String resultWho = r.resultWho;
3758 final int requestCode = r.requestCode;
3759 r.resultTo = null;
3760 if (resultTo != null) {
3761 resultTo.removeResultsLocked(r, resultWho, requestCode);
3762 }
3763
3764 final long origId = Binder.clearCallingIdentity();
3765 // XXX we are not dealing with propagating grantedUriPermissions...
3766 // those are not yet exposed to user code, so there is no need.
3767 int res = startActivityLocked(r.app.thread, intent,
3768 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003769 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003770 Binder.restoreCallingIdentity(origId);
3771
3772 r.finishing = wasFinishing;
3773 if (res != START_SUCCESS) {
3774 return false;
3775 }
3776 return true;
3777 }
3778 }
3779
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003780 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003781 Intent intent, String resolvedType, IBinder resultTo,
3782 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003783
3784 // This is so super not safe, that only the system (or okay root)
3785 // can do it.
3786 final int callingUid = Binder.getCallingUid();
3787 if (callingUid != 0 && callingUid != Process.myUid()) {
3788 throw new SecurityException(
3789 "startActivityInPackage only available to the system");
3790 }
3791
The Android Open Source Project4df24232009-03-05 14:34:35 -08003792 final boolean componentSpecified = intent.getComponent() != null;
3793
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003794 // Don't modify the client's object!
3795 intent = new Intent(intent);
3796
3797 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003798 ActivityInfo aInfo;
3799 try {
3800 ResolveInfo rInfo =
3801 ActivityThread.getPackageManager().resolveIntent(
3802 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003803 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003804 aInfo = rInfo != null ? rInfo.activityInfo : null;
3805 } catch (RemoteException e) {
3806 aInfo = null;
3807 }
3808
3809 if (aInfo != null) {
3810 // Store the found target back into the intent, because now that
3811 // we have it we never want to do this again. For example, if the
3812 // user navigates back to this point in the history, we should
3813 // always restart the exact same activity.
3814 intent.setComponent(new ComponentName(
3815 aInfo.applicationInfo.packageName, aInfo.name));
3816 }
3817
3818 synchronized(this) {
3819 return startActivityLocked(null, intent, resolvedType,
3820 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003821 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003822 }
3823 }
3824
3825 private final void addRecentTask(TaskRecord task) {
3826 // Remove any existing entries that are the same kind of task.
3827 int N = mRecentTasks.size();
3828 for (int i=0; i<N; i++) {
3829 TaskRecord tr = mRecentTasks.get(i);
3830 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3831 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3832 mRecentTasks.remove(i);
3833 i--;
3834 N--;
3835 if (task.intent == null) {
3836 // If the new recent task we are adding is not fully
3837 // specified, then replace it with the existing recent task.
3838 task = tr;
3839 }
3840 }
3841 }
3842 if (N >= MAX_RECENT_TASKS) {
3843 mRecentTasks.remove(N-1);
3844 }
3845 mRecentTasks.add(0, task);
3846 }
3847
3848 public void setRequestedOrientation(IBinder token,
3849 int requestedOrientation) {
3850 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003851 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003852 if (index < 0) {
3853 return;
3854 }
3855 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3856 final long origId = Binder.clearCallingIdentity();
3857 mWindowManager.setAppOrientation(r, requestedOrientation);
3858 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003859 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003860 r.mayFreezeScreenLocked(r.app) ? r : null);
3861 if (config != null) {
3862 r.frozenBeforeDestroy = true;
3863 if (!updateConfigurationLocked(config, r)) {
3864 resumeTopActivityLocked(null);
3865 }
3866 }
3867 Binder.restoreCallingIdentity(origId);
3868 }
3869 }
3870
3871 public int getRequestedOrientation(IBinder token) {
3872 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003873 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003874 if (index < 0) {
3875 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3876 }
3877 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3878 return mWindowManager.getAppOrientation(r);
3879 }
3880 }
3881
3882 private final void stopActivityLocked(HistoryRecord r) {
3883 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3884 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3885 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3886 if (!r.finishing) {
3887 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3888 "no-history");
3889 }
3890 } else if (r.app != null && r.app.thread != null) {
3891 if (mFocusedActivity == r) {
3892 setFocusedActivityLocked(topRunningActivityLocked(null));
3893 }
3894 r.resumeKeyDispatchingLocked();
3895 try {
3896 r.stopped = false;
3897 r.state = ActivityState.STOPPING;
3898 if (DEBUG_VISBILITY) Log.v(
3899 TAG, "Stopping visible=" + r.visible + " for " + r);
3900 if (!r.visible) {
3901 mWindowManager.setAppVisibility(r, false);
3902 }
3903 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3904 } catch (Exception e) {
3905 // Maybe just ignore exceptions here... if the process
3906 // has crashed, our death notification will clean things
3907 // up.
3908 Log.w(TAG, "Exception thrown during pause", e);
3909 // Just in case, assume it to be stopped.
3910 r.stopped = true;
3911 r.state = ActivityState.STOPPED;
3912 if (r.configDestroy) {
3913 destroyActivityLocked(r, true);
3914 }
3915 }
3916 }
3917 }
3918
3919 /**
3920 * @return Returns true if the activity is being finished, false if for
3921 * some reason it is being left as-is.
3922 */
3923 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3924 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003925 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003926 TAG, "Finishing activity: token=" + token
3927 + ", result=" + resultCode + ", data=" + resultData);
3928
Dianne Hackborn75b03852009-06-12 15:43:26 -07003929 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003930 if (index < 0) {
3931 return false;
3932 }
3933 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3934
3935 // Is this the last activity left?
3936 boolean lastActivity = true;
3937 for (int i=mHistory.size()-1; i>=0; i--) {
3938 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3939 if (!p.finishing && p != r) {
3940 lastActivity = false;
3941 break;
3942 }
3943 }
3944
3945 // If this is the last activity, but it is the home activity, then
3946 // just don't finish it.
3947 if (lastActivity) {
3948 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3949 return false;
3950 }
3951 }
3952
3953 finishActivityLocked(r, index, resultCode, resultData, reason);
3954 return true;
3955 }
3956
3957 /**
3958 * @return Returns true if this activity has been removed from the history
3959 * list, or false if it is still in the list and will be removed later.
3960 */
3961 private final boolean finishActivityLocked(HistoryRecord r, int index,
3962 int resultCode, Intent resultData, String reason) {
3963 if (r.finishing) {
3964 Log.w(TAG, "Duplicate finish request for " + r);
3965 return false;
3966 }
3967
3968 r.finishing = true;
3969 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3970 System.identityHashCode(r),
3971 r.task.taskId, r.shortComponentName, reason);
3972 r.task.numActivities--;
3973 if (r.frontOfTask && index < (mHistory.size()-1)) {
3974 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3975 if (next.task == r.task) {
3976 next.frontOfTask = true;
3977 }
3978 }
3979
3980 r.pauseKeyDispatchingLocked();
3981 if (mFocusedActivity == r) {
3982 setFocusedActivityLocked(topRunningActivityLocked(null));
3983 }
3984
3985 // send the result
3986 HistoryRecord resultTo = r.resultTo;
3987 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003988 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3989 + " who=" + r.resultWho + " req=" + r.requestCode
3990 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003991 if (r.info.applicationInfo.uid > 0) {
3992 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3993 r.packageName, resultData, r);
3994 }
3995 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3996 resultData);
3997 r.resultTo = null;
3998 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003999 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004000
4001 // Make sure this HistoryRecord is not holding on to other resources,
4002 // because clients have remote IPC references to this object so we
4003 // can't assume that will go away and want to avoid circular IPC refs.
4004 r.results = null;
4005 r.pendingResults = null;
4006 r.newIntents = null;
4007 r.icicle = null;
4008
4009 if (mPendingThumbnails.size() > 0) {
4010 // There are clients waiting to receive thumbnails so, in case
4011 // this is an activity that someone is waiting for, add it
4012 // to the pending list so we can correctly update the clients.
4013 mCancelledThumbnails.add(r);
4014 }
4015
4016 if (mResumedActivity == r) {
4017 boolean endTask = index <= 0
4018 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
4019 if (DEBUG_TRANSITION) Log.v(TAG,
4020 "Prepare close transition: finishing " + r);
4021 mWindowManager.prepareAppTransition(endTask
4022 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
4023 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
4024
4025 // Tell window manager to prepare for this one to be removed.
4026 mWindowManager.setAppVisibility(r, false);
4027
4028 if (mPausingActivity == null) {
4029 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4030 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4031 startPausingLocked(false, false);
4032 }
4033
4034 } else if (r.state != ActivityState.PAUSING) {
4035 // If the activity is PAUSING, we will complete the finish once
4036 // it is done pausing; else we can just directly finish it here.
4037 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4038 return finishCurrentActivityLocked(r, index,
4039 FINISH_AFTER_PAUSE) == null;
4040 } else {
4041 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4042 }
4043
4044 return false;
4045 }
4046
4047 private static final int FINISH_IMMEDIATELY = 0;
4048 private static final int FINISH_AFTER_PAUSE = 1;
4049 private static final int FINISH_AFTER_VISIBLE = 2;
4050
4051 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4052 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004053 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004054 if (index < 0) {
4055 return null;
4056 }
4057
4058 return finishCurrentActivityLocked(r, index, mode);
4059 }
4060
4061 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4062 int index, int mode) {
4063 // First things first: if this activity is currently visible,
4064 // and the resumed activity is not yet visible, then hold off on
4065 // finishing until the resumed one becomes visible.
4066 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4067 if (!mStoppingActivities.contains(r)) {
4068 mStoppingActivities.add(r);
4069 if (mStoppingActivities.size() > 3) {
4070 // If we already have a few activities waiting to stop,
4071 // then give up on things going idle and start clearing
4072 // them out.
4073 Message msg = Message.obtain();
4074 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4075 mHandler.sendMessage(msg);
4076 }
4077 }
4078 r.state = ActivityState.STOPPING;
4079 updateOomAdjLocked();
4080 return r;
4081 }
4082
4083 // make sure the record is cleaned out of other places.
4084 mStoppingActivities.remove(r);
4085 mWaitingVisibleActivities.remove(r);
4086 if (mResumedActivity == r) {
4087 mResumedActivity = null;
4088 }
4089 final ActivityState prevState = r.state;
4090 r.state = ActivityState.FINISHING;
4091
4092 if (mode == FINISH_IMMEDIATELY
4093 || prevState == ActivityState.STOPPED
4094 || prevState == ActivityState.INITIALIZING) {
4095 // If this activity is already stopped, we can just finish
4096 // it right now.
4097 return destroyActivityLocked(r, true) ? null : r;
4098 } else {
4099 // Need to go through the full pause cycle to get this
4100 // activity into the stopped state and then finish it.
4101 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4102 mFinishingActivities.add(r);
4103 resumeTopActivityLocked(null);
4104 }
4105 return r;
4106 }
4107
4108 /**
4109 * This is the internal entry point for handling Activity.finish().
4110 *
4111 * @param token The Binder token referencing the Activity we want to finish.
4112 * @param resultCode Result code, if any, from this Activity.
4113 * @param resultData Result data (Intent), if any, from this Activity.
4114 *
4115 * @result Returns true if the activity successfully finished, or false if it is still running.
4116 */
4117 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4118 // Refuse possible leaked file descriptors
4119 if (resultData != null && resultData.hasFileDescriptors() == true) {
4120 throw new IllegalArgumentException("File descriptors passed in Intent");
4121 }
4122
4123 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004124 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004125 // Find the first activity that is not finishing.
4126 HistoryRecord next = topRunningActivityLocked(token, 0);
4127 if (next != null) {
4128 // ask watcher if this is allowed
4129 boolean resumeOK = true;
4130 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004131 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004132 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004133 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004134 }
4135
4136 if (!resumeOK) {
4137 return false;
4138 }
4139 }
4140 }
4141 final long origId = Binder.clearCallingIdentity();
4142 boolean res = requestFinishActivityLocked(token, resultCode,
4143 resultData, "app-request");
4144 Binder.restoreCallingIdentity(origId);
4145 return res;
4146 }
4147 }
4148
4149 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4150 String resultWho, int requestCode, int resultCode, Intent data) {
4151
4152 if (callingUid > 0) {
4153 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4154 data, r);
4155 }
4156
The Android Open Source Project10592532009-03-18 17:39:46 -07004157 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4158 + " : who=" + resultWho + " req=" + requestCode
4159 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004160 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4161 try {
4162 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4163 list.add(new ResultInfo(resultWho, requestCode,
4164 resultCode, data));
4165 r.app.thread.scheduleSendResult(r, list);
4166 return;
4167 } catch (Exception e) {
4168 Log.w(TAG, "Exception thrown sending result to " + r, e);
4169 }
4170 }
4171
4172 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4173 }
4174
4175 public final void finishSubActivity(IBinder token, String resultWho,
4176 int requestCode) {
4177 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004178 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004179 if (index < 0) {
4180 return;
4181 }
4182 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4183
4184 final long origId = Binder.clearCallingIdentity();
4185
4186 int i;
4187 for (i=mHistory.size()-1; i>=0; i--) {
4188 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4189 if (r.resultTo == self && r.requestCode == requestCode) {
4190 if ((r.resultWho == null && resultWho == null) ||
4191 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4192 finishActivityLocked(r, i,
4193 Activity.RESULT_CANCELED, null, "request-sub");
4194 }
4195 }
4196 }
4197
4198 Binder.restoreCallingIdentity(origId);
4199 }
4200 }
4201
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004202 public void overridePendingTransition(IBinder token, String packageName,
4203 int enterAnim, int exitAnim) {
4204 synchronized(this) {
4205 int index = indexOfTokenLocked(token);
4206 if (index < 0) {
4207 return;
4208 }
4209 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4210
4211 final long origId = Binder.clearCallingIdentity();
4212
4213 if (self.state == ActivityState.RESUMED
4214 || self.state == ActivityState.PAUSING) {
4215 mWindowManager.overridePendingAppTransition(packageName,
4216 enterAnim, exitAnim);
4217 }
4218
4219 Binder.restoreCallingIdentity(origId);
4220 }
4221 }
4222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004223 /**
4224 * Perform clean-up of service connections in an activity record.
4225 */
4226 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4227 // Throw away any services that have been bound by this activity.
4228 if (r.connections != null) {
4229 Iterator<ConnectionRecord> it = r.connections.iterator();
4230 while (it.hasNext()) {
4231 ConnectionRecord c = it.next();
4232 removeConnectionLocked(c, null, r);
4233 }
4234 r.connections = null;
4235 }
4236 }
4237
4238 /**
4239 * Perform the common clean-up of an activity record. This is called both
4240 * as part of destroyActivityLocked() (when destroying the client-side
4241 * representation) and cleaning things up as a result of its hosting
4242 * processing going away, in which case there is no remaining client-side
4243 * state to destroy so only the cleanup here is needed.
4244 */
4245 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4246 if (mResumedActivity == r) {
4247 mResumedActivity = null;
4248 }
4249 if (mFocusedActivity == r) {
4250 mFocusedActivity = null;
4251 }
4252
4253 r.configDestroy = false;
4254 r.frozenBeforeDestroy = false;
4255
4256 // Make sure this record is no longer in the pending finishes list.
4257 // This could happen, for example, if we are trimming activities
4258 // down to the max limit while they are still waiting to finish.
4259 mFinishingActivities.remove(r);
4260 mWaitingVisibleActivities.remove(r);
4261
4262 // Remove any pending results.
4263 if (r.finishing && r.pendingResults != null) {
4264 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4265 PendingIntentRecord rec = apr.get();
4266 if (rec != null) {
4267 cancelIntentSenderLocked(rec, false);
4268 }
4269 }
4270 r.pendingResults = null;
4271 }
4272
4273 if (cleanServices) {
4274 cleanUpActivityServicesLocked(r);
4275 }
4276
4277 if (mPendingThumbnails.size() > 0) {
4278 // There are clients waiting to receive thumbnails so, in case
4279 // this is an activity that someone is waiting for, add it
4280 // to the pending list so we can correctly update the clients.
4281 mCancelledThumbnails.add(r);
4282 }
4283
4284 // Get rid of any pending idle timeouts.
4285 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4286 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4287 }
4288
4289 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4290 if (r.state != ActivityState.DESTROYED) {
4291 mHistory.remove(r);
4292 r.inHistory = false;
4293 r.state = ActivityState.DESTROYED;
4294 mWindowManager.removeAppToken(r);
4295 if (VALIDATE_TOKENS) {
4296 mWindowManager.validateAppTokens(mHistory);
4297 }
4298 cleanUpActivityServicesLocked(r);
4299 removeActivityUriPermissionsLocked(r);
4300 }
4301 }
4302
4303 /**
4304 * Destroy the current CLIENT SIDE instance of an activity. This may be
4305 * called both when actually finishing an activity, or when performing
4306 * a configuration switch where we destroy the current client-side object
4307 * but then create a new client-side object for this same HistoryRecord.
4308 */
4309 private final boolean destroyActivityLocked(HistoryRecord r,
4310 boolean removeFromApp) {
4311 if (DEBUG_SWITCH) Log.v(
4312 TAG, "Removing activity: token=" + r
4313 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4314 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4315 System.identityHashCode(r),
4316 r.task.taskId, r.shortComponentName);
4317
4318 boolean removedFromHistory = false;
4319
4320 cleanUpActivityLocked(r, false);
4321
4322 if (r.app != null) {
4323 if (removeFromApp) {
4324 int idx = r.app.activities.indexOf(r);
4325 if (idx >= 0) {
4326 r.app.activities.remove(idx);
4327 }
4328 if (r.persistent) {
4329 decPersistentCountLocked(r.app);
4330 }
4331 }
4332
4333 boolean skipDestroy = false;
4334
4335 try {
4336 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4337 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4338 r.configChangeFlags);
4339 } catch (Exception e) {
4340 // We can just ignore exceptions here... if the process
4341 // has crashed, our death notification will clean things
4342 // up.
4343 //Log.w(TAG, "Exception thrown during finish", e);
4344 if (r.finishing) {
4345 removeActivityFromHistoryLocked(r);
4346 removedFromHistory = true;
4347 skipDestroy = true;
4348 }
4349 }
4350
4351 r.app = null;
4352 r.nowVisible = false;
4353
4354 if (r.finishing && !skipDestroy) {
4355 r.state = ActivityState.DESTROYING;
4356 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4357 msg.obj = r;
4358 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4359 } else {
4360 r.state = ActivityState.DESTROYED;
4361 }
4362 } else {
4363 // remove this record from the history.
4364 if (r.finishing) {
4365 removeActivityFromHistoryLocked(r);
4366 removedFromHistory = true;
4367 } else {
4368 r.state = ActivityState.DESTROYED;
4369 }
4370 }
4371
4372 r.configChangeFlags = 0;
4373
4374 if (!mLRUActivities.remove(r)) {
4375 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4376 }
4377
4378 return removedFromHistory;
4379 }
4380
4381 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4382 ProcessRecord app)
4383 {
4384 int i = list.size();
4385 if (localLOGV) Log.v(
4386 TAG, "Removing app " + app + " from list " + list
4387 + " with " + i + " entries");
4388 while (i > 0) {
4389 i--;
4390 HistoryRecord r = (HistoryRecord)list.get(i);
4391 if (localLOGV) Log.v(
4392 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4393 if (r.app == app) {
4394 if (localLOGV) Log.v(TAG, "Removing this entry!");
4395 list.remove(i);
4396 }
4397 }
4398 }
4399
4400 /**
4401 * Main function for removing an existing process from the activity manager
4402 * as a result of that process going away. Clears out all connections
4403 * to the process.
4404 */
4405 private final void handleAppDiedLocked(ProcessRecord app,
4406 boolean restarting) {
4407 cleanUpApplicationRecordLocked(app, restarting, -1);
4408 if (!restarting) {
4409 mLRUProcesses.remove(app);
4410 }
4411
4412 // Just in case...
4413 if (mPausingActivity != null && mPausingActivity.app == app) {
4414 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4415 mPausingActivity = null;
4416 }
4417 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4418 mLastPausedActivity = null;
4419 }
4420
4421 // Remove this application's activities from active lists.
4422 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4423 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4424 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4425 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4426
4427 boolean atTop = true;
4428 boolean hasVisibleActivities = false;
4429
4430 // Clean out the history list.
4431 int i = mHistory.size();
4432 if (localLOGV) Log.v(
4433 TAG, "Removing app " + app + " from history with " + i + " entries");
4434 while (i > 0) {
4435 i--;
4436 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4437 if (localLOGV) Log.v(
4438 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4439 if (r.app == app) {
4440 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4441 if (localLOGV) Log.v(
4442 TAG, "Removing this entry! frozen=" + r.haveState
4443 + " finishing=" + r.finishing);
4444 mHistory.remove(i);
4445
4446 r.inHistory = false;
4447 mWindowManager.removeAppToken(r);
4448 if (VALIDATE_TOKENS) {
4449 mWindowManager.validateAppTokens(mHistory);
4450 }
4451 removeActivityUriPermissionsLocked(r);
4452
4453 } else {
4454 // We have the current state for this activity, so
4455 // it can be restarted later when needed.
4456 if (localLOGV) Log.v(
4457 TAG, "Keeping entry, setting app to null");
4458 if (r.visible) {
4459 hasVisibleActivities = true;
4460 }
4461 r.app = null;
4462 r.nowVisible = false;
4463 if (!r.haveState) {
4464 r.icicle = null;
4465 }
4466 }
4467
4468 cleanUpActivityLocked(r, true);
4469 r.state = ActivityState.STOPPED;
4470 }
4471 atTop = false;
4472 }
4473
4474 app.activities.clear();
4475
4476 if (app.instrumentationClass != null) {
4477 Log.w(TAG, "Crash of app " + app.processName
4478 + " running instrumentation " + app.instrumentationClass);
4479 Bundle info = new Bundle();
4480 info.putString("shortMsg", "Process crashed.");
4481 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4482 }
4483
4484 if (!restarting) {
4485 if (!resumeTopActivityLocked(null)) {
4486 // If there was nothing to resume, and we are not already
4487 // restarting this process, but there is a visible activity that
4488 // is hosted by the process... then make sure all visible
4489 // activities are running, taking care of restarting this
4490 // process.
4491 if (hasVisibleActivities) {
4492 ensureActivitiesVisibleLocked(null, 0);
4493 }
4494 }
4495 }
4496 }
4497
4498 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4499 IBinder threadBinder = thread.asBinder();
4500
4501 // Find the application record.
4502 int count = mLRUProcesses.size();
4503 int i;
4504 for (i=0; i<count; i++) {
4505 ProcessRecord rec = mLRUProcesses.get(i);
4506 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4507 return i;
4508 }
4509 }
4510 return -1;
4511 }
4512
4513 private final ProcessRecord getRecordForAppLocked(
4514 IApplicationThread thread) {
4515 if (thread == null) {
4516 return null;
4517 }
4518
4519 int appIndex = getLRURecordIndexForAppLocked(thread);
4520 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4521 }
4522
4523 private final void appDiedLocked(ProcessRecord app, int pid,
4524 IApplicationThread thread) {
4525
4526 mProcDeaths[0]++;
4527
4528 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4529 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4530 + ") has died.");
4531 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4532 if (localLOGV) Log.v(
4533 TAG, "Dying app: " + app + ", pid: " + pid
4534 + ", thread: " + thread.asBinder());
4535 boolean doLowMem = app.instrumentationClass == null;
4536 handleAppDiedLocked(app, false);
4537
4538 if (doLowMem) {
4539 // If there are no longer any background processes running,
4540 // and the app that died was not running instrumentation,
4541 // then tell everyone we are now low on memory.
4542 boolean haveBg = false;
4543 int count = mLRUProcesses.size();
4544 int i;
4545 for (i=0; i<count; i++) {
4546 ProcessRecord rec = mLRUProcesses.get(i);
4547 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4548 haveBg = true;
4549 break;
4550 }
4551 }
4552
4553 if (!haveBg) {
4554 Log.i(TAG, "Low Memory: No more background processes.");
4555 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004556 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004557 for (i=0; i<count; i++) {
4558 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004559 if (rec.thread != null &&
4560 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4561 // The low memory report is overriding any current
4562 // state for a GC request. Make sure to do
4563 // visible/foreground processes first.
4564 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4565 rec.lastRequestedGc = 0;
4566 } else {
4567 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004568 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004569 rec.reportLowMemory = true;
4570 rec.lastLowMemory = now;
4571 mProcessesToGc.remove(rec);
4572 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004573 }
4574 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004575 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004576 }
4577 }
4578 } else if (Config.LOGD) {
4579 Log.d(TAG, "Received spurious death notification for thread "
4580 + thread.asBinder());
4581 }
4582 }
4583
4584 final String readFile(String filename) {
4585 try {
4586 FileInputStream fs = new FileInputStream(filename);
4587 byte[] inp = new byte[8192];
4588 int size = fs.read(inp);
4589 fs.close();
4590 return new String(inp, 0, 0, size);
4591 } catch (java.io.IOException e) {
4592 }
4593 return "";
4594 }
4595
4596 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004597 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004598 if (app.notResponding || app.crashing) {
4599 return;
4600 }
4601
4602 // Log the ANR to the event log.
4603 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4604
4605 // If we are on a secure build and the application is not interesting to the user (it is
4606 // not visible or in the background), just kill it instead of displaying a dialog.
4607 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4608 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4609 Process.killProcess(app.pid);
4610 return;
4611 }
4612
4613 // DeviceMonitor.start();
4614
4615 String processInfo = null;
4616 if (MONITOR_CPU_USAGE) {
4617 updateCpuStatsNow();
4618 synchronized (mProcessStatsThread) {
4619 processInfo = mProcessStats.printCurrentState();
4620 }
4621 }
4622
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004623 StringBuilder info = mStringBuilder;
4624 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004625 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004626 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004627 if (reportedActivity != null && reportedActivity.app != null) {
4628 info.append(" (last in ");
4629 info.append(reportedActivity.app.processName);
4630 info.append(")");
4631 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004632 if (annotation != null) {
4633 info.append("\nAnnotation: ");
4634 info.append(annotation);
4635 }
4636 if (MONITOR_CPU_USAGE) {
4637 info.append("\nCPU usage:\n");
4638 info.append(processInfo);
4639 }
4640 Log.i(TAG, info.toString());
4641
4642 // The application is not responding. Dump as many thread traces as we can.
4643 boolean fileDump = prepareTraceFile(true);
4644 if (!fileDump) {
4645 // Dumping traces to the log, just dump the process that isn't responding so
4646 // we don't overflow the log
4647 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4648 } else {
4649 // Dumping traces to a file so dump all active processes we know about
4650 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004651 // First, these are the most important processes.
4652 final int[] imppids = new int[3];
4653 int i=0;
4654 imppids[0] = app.pid;
4655 i++;
4656 if (reportedActivity != null && reportedActivity.app != null
4657 && reportedActivity.app.thread != null
4658 && reportedActivity.app.pid != app.pid) {
4659 imppids[i] = reportedActivity.app.pid;
4660 i++;
4661 }
4662 imppids[i] = Process.myPid();
4663 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4664 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4665 synchronized (this) {
4666 try {
4667 wait(200);
4668 } catch (InterruptedException e) {
4669 }
4670 }
4671 }
4672 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004673 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004674 boolean done = false;
4675 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4676 if (imppids[j] == r.pid) {
4677 done = true;
4678 break;
4679 }
4680 }
4681 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004682 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004683 synchronized (this) {
4684 try {
4685 wait(200);
4686 } catch (InterruptedException e) {
4687 }
4688 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004689 }
4690 }
4691 }
4692 }
4693
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004694 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004695 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004696 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004697 app.pid, info.toString());
4698 if (res != 0) {
4699 if (res < 0) {
4700 // wait until the SIGQUIT has had a chance to process before killing the
4701 // process.
4702 try {
4703 wait(2000);
4704 } catch (InterruptedException e) {
4705 }
4706
4707 Process.killProcess(app.pid);
4708 return;
4709 }
4710 }
4711 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004712 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004713 }
4714 }
4715
4716 makeAppNotRespondingLocked(app,
4717 activity != null ? activity.shortComponentName : null,
4718 annotation != null ? "ANR " + annotation : "ANR",
4719 info.toString(), null);
4720 Message msg = Message.obtain();
4721 HashMap map = new HashMap();
4722 msg.what = SHOW_NOT_RESPONDING_MSG;
4723 msg.obj = map;
4724 map.put("app", app);
4725 if (activity != null) {
4726 map.put("activity", activity);
4727 }
4728
4729 mHandler.sendMessage(msg);
4730 return;
4731 }
4732
4733 /**
4734 * If a stack trace file has been configured, prepare the filesystem
4735 * by creating the directory if it doesn't exist and optionally
4736 * removing the old trace file.
4737 *
4738 * @param removeExisting If set, the existing trace file will be removed.
4739 * @return Returns true if the trace file preparations succeeded
4740 */
4741 public static boolean prepareTraceFile(boolean removeExisting) {
4742 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4743 boolean fileReady = false;
4744 if (!TextUtils.isEmpty(tracesPath)) {
4745 File f = new File(tracesPath);
4746 if (!f.exists()) {
4747 // Ensure the enclosing directory exists
4748 File dir = f.getParentFile();
4749 if (!dir.exists()) {
4750 fileReady = dir.mkdirs();
4751 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004752 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004753 } else if (dir.isDirectory()) {
4754 fileReady = true;
4755 }
4756 } else if (removeExisting) {
4757 // Remove the previous traces file, so we don't fill the disk.
4758 // The VM will recreate it
4759 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4760 fileReady = f.delete();
4761 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004762
4763 if (removeExisting) {
4764 try {
4765 f.createNewFile();
4766 FileUtils.setPermissions(f.getAbsolutePath(),
4767 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4768 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4769 fileReady = true;
4770 } catch (IOException e) {
4771 Log.w(TAG, "Unable to make ANR traces file", e);
4772 }
4773 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004774 }
4775
4776 return fileReady;
4777 }
4778
4779
4780 private final void decPersistentCountLocked(ProcessRecord app)
4781 {
4782 app.persistentActivities--;
4783 if (app.persistentActivities > 0) {
4784 // Still more of 'em...
4785 return;
4786 }
4787 if (app.persistent) {
4788 // Ah, but the application itself is persistent. Whatever!
4789 return;
4790 }
4791
4792 // App is no longer persistent... make sure it and the ones
4793 // following it in the LRU list have the correc oom_adj.
4794 updateOomAdjLocked();
4795 }
4796
4797 public void setPersistent(IBinder token, boolean isPersistent) {
4798 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4799 != PackageManager.PERMISSION_GRANTED) {
4800 String msg = "Permission Denial: setPersistent() from pid="
4801 + Binder.getCallingPid()
4802 + ", uid=" + Binder.getCallingUid()
4803 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4804 Log.w(TAG, msg);
4805 throw new SecurityException(msg);
4806 }
4807
4808 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004809 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004810 if (index < 0) {
4811 return;
4812 }
4813 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4814 ProcessRecord app = r.app;
4815
4816 if (localLOGV) Log.v(
4817 TAG, "Setting persistence " + isPersistent + ": " + r);
4818
4819 if (isPersistent) {
4820 if (r.persistent) {
4821 // Okay okay, I heard you already!
4822 if (localLOGV) Log.v(TAG, "Already persistent!");
4823 return;
4824 }
4825 r.persistent = true;
4826 app.persistentActivities++;
4827 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4828 if (app.persistentActivities > 1) {
4829 // We aren't the first...
4830 if (localLOGV) Log.v(TAG, "Not the first!");
4831 return;
4832 }
4833 if (app.persistent) {
4834 // This would be redundant.
4835 if (localLOGV) Log.v(TAG, "App is persistent!");
4836 return;
4837 }
4838
4839 // App is now persistent... make sure it and the ones
4840 // following it now have the correct oom_adj.
4841 final long origId = Binder.clearCallingIdentity();
4842 updateOomAdjLocked();
4843 Binder.restoreCallingIdentity(origId);
4844
4845 } else {
4846 if (!r.persistent) {
4847 // Okay okay, I heard you already!
4848 return;
4849 }
4850 r.persistent = false;
4851 final long origId = Binder.clearCallingIdentity();
4852 decPersistentCountLocked(app);
4853 Binder.restoreCallingIdentity(origId);
4854
4855 }
4856 }
4857 }
4858
4859 public boolean clearApplicationUserData(final String packageName,
4860 final IPackageDataObserver observer) {
4861 int uid = Binder.getCallingUid();
4862 int pid = Binder.getCallingPid();
4863 long callingId = Binder.clearCallingIdentity();
4864 try {
4865 IPackageManager pm = ActivityThread.getPackageManager();
4866 int pkgUid = -1;
4867 synchronized(this) {
4868 try {
4869 pkgUid = pm.getPackageUid(packageName);
4870 } catch (RemoteException e) {
4871 }
4872 if (pkgUid == -1) {
4873 Log.w(TAG, "Invalid packageName:" + packageName);
4874 return false;
4875 }
4876 if (uid == pkgUid || checkComponentPermission(
4877 android.Manifest.permission.CLEAR_APP_USER_DATA,
4878 pid, uid, -1)
4879 == PackageManager.PERMISSION_GRANTED) {
4880 restartPackageLocked(packageName, pkgUid);
4881 } else {
4882 throw new SecurityException(pid+" does not have permission:"+
4883 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4884 "for process:"+packageName);
4885 }
4886 }
4887
4888 try {
4889 //clear application user data
4890 pm.clearApplicationUserData(packageName, observer);
4891 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4892 Uri.fromParts("package", packageName, null));
4893 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4894 broadcastIntentLocked(null, null, intent,
4895 null, null, 0, null, null, null,
4896 false, false, MY_PID, Process.SYSTEM_UID);
4897 } catch (RemoteException e) {
4898 }
4899 } finally {
4900 Binder.restoreCallingIdentity(callingId);
4901 }
4902 return true;
4903 }
4904
4905 public void restartPackage(final String packageName) {
4906 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4907 != PackageManager.PERMISSION_GRANTED) {
4908 String msg = "Permission Denial: restartPackage() from pid="
4909 + Binder.getCallingPid()
4910 + ", uid=" + Binder.getCallingUid()
4911 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4912 Log.w(TAG, msg);
4913 throw new SecurityException(msg);
4914 }
4915
4916 long callingId = Binder.clearCallingIdentity();
4917 try {
4918 IPackageManager pm = ActivityThread.getPackageManager();
4919 int pkgUid = -1;
4920 synchronized(this) {
4921 try {
4922 pkgUid = pm.getPackageUid(packageName);
4923 } catch (RemoteException e) {
4924 }
4925 if (pkgUid == -1) {
4926 Log.w(TAG, "Invalid packageName: " + packageName);
4927 return;
4928 }
4929 restartPackageLocked(packageName, pkgUid);
4930 }
4931 } finally {
4932 Binder.restoreCallingIdentity(callingId);
4933 }
4934 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004935
4936 /*
4937 * The pkg name and uid have to be specified.
4938 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4939 */
4940 public void killApplicationWithUid(String pkg, int uid) {
4941 if (pkg == null) {
4942 return;
4943 }
4944 // Make sure the uid is valid.
4945 if (uid < 0) {
4946 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4947 return;
4948 }
4949 int callerUid = Binder.getCallingUid();
4950 // Only the system server can kill an application
4951 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004952 // Post an aysnc message to kill the application
4953 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4954 msg.arg1 = uid;
4955 msg.arg2 = 0;
4956 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004957 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004958 } else {
4959 throw new SecurityException(callerUid + " cannot kill pkg: " +
4960 pkg);
4961 }
4962 }
4963
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004964 public void closeSystemDialogs(String reason) {
4965 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4966 if (reason != null) {
4967 intent.putExtra("reason", reason);
4968 }
4969
4970 final int uid = Binder.getCallingUid();
4971 final long origId = Binder.clearCallingIdentity();
4972 synchronized (this) {
4973 int i = mWatchers.beginBroadcast();
4974 while (i > 0) {
4975 i--;
4976 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4977 if (w != null) {
4978 try {
4979 w.closingSystemDialogs(reason);
4980 } catch (RemoteException e) {
4981 }
4982 }
4983 }
4984 mWatchers.finishBroadcast();
4985
Dianne Hackbornffa42482009-09-23 22:20:11 -07004986 mWindowManager.closeSystemDialogs(reason);
4987
4988 for (i=mHistory.size()-1; i>=0; i--) {
4989 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4990 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
4991 finishActivityLocked(r, i,
4992 Activity.RESULT_CANCELED, null, "close-sys");
4993 }
4994 }
4995
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004996 broadcastIntentLocked(null, null, intent, null,
4997 null, 0, null, null, null, false, false, -1, uid);
4998 }
4999 Binder.restoreCallingIdentity(origId);
5000 }
5001
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005002 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005003 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005004 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
5005 for (int i=pids.length-1; i>=0; i--) {
5006 infos[i] = new Debug.MemoryInfo();
5007 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005008 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005009 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005010 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07005011
5012 public void killApplicationProcess(String processName, int uid) {
5013 if (processName == null) {
5014 return;
5015 }
5016
5017 int callerUid = Binder.getCallingUid();
5018 // Only the system server can kill an application
5019 if (callerUid == Process.SYSTEM_UID) {
5020 synchronized (this) {
5021 ProcessRecord app = getProcessRecordLocked(processName, uid);
5022 if (app != null) {
5023 try {
5024 app.thread.scheduleSuicide();
5025 } catch (RemoteException e) {
5026 // If the other end already died, then our work here is done.
5027 }
5028 } else {
5029 Log.w(TAG, "Process/uid not found attempting kill of "
5030 + processName + " / " + uid);
5031 }
5032 }
5033 } else {
5034 throw new SecurityException(callerUid + " cannot kill app process: " +
5035 processName);
5036 }
5037 }
5038
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005039 private void restartPackageLocked(final String packageName, int uid) {
5040 uninstallPackageLocked(packageName, uid, false);
5041 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5042 Uri.fromParts("package", packageName, null));
5043 intent.putExtra(Intent.EXTRA_UID, uid);
5044 broadcastIntentLocked(null, null, intent,
5045 null, null, 0, null, null, null,
5046 false, false, MY_PID, Process.SYSTEM_UID);
5047 }
5048
5049 private final void uninstallPackageLocked(String name, int uid,
5050 boolean callerWillRestart) {
5051 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
5052
5053 int i, N;
5054
5055 final String procNamePrefix = name + ":";
5056 if (uid < 0) {
5057 try {
5058 uid = ActivityThread.getPackageManager().getPackageUid(name);
5059 } catch (RemoteException e) {
5060 }
5061 }
5062
5063 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5064 while (badApps.hasNext()) {
5065 SparseArray<Long> ba = badApps.next();
5066 if (ba.get(uid) != null) {
5067 badApps.remove();
5068 }
5069 }
5070
5071 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
5072
5073 // Remove all processes this package may have touched: all with the
5074 // same UID (except for the system or root user), and all whose name
5075 // matches the package name.
5076 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5077 final int NA = apps.size();
5078 for (int ia=0; ia<NA; ia++) {
5079 ProcessRecord app = apps.valueAt(ia);
5080 if (app.removed) {
5081 procs.add(app);
5082 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5083 || app.processName.equals(name)
5084 || app.processName.startsWith(procNamePrefix)) {
5085 app.removed = true;
5086 procs.add(app);
5087 }
5088 }
5089 }
5090
5091 N = procs.size();
5092 for (i=0; i<N; i++) {
5093 removeProcessLocked(procs.get(i), callerWillRestart);
5094 }
5095
5096 for (i=mHistory.size()-1; i>=0; i--) {
5097 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5098 if (r.packageName.equals(name)) {
5099 if (Config.LOGD) Log.d(
5100 TAG, " Force finishing activity "
5101 + r.intent.getComponent().flattenToShortString());
5102 if (r.app != null) {
5103 r.app.removed = true;
5104 }
5105 r.app = null;
5106 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5107 }
5108 }
5109
5110 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5111 for (ServiceRecord service : mServices.values()) {
5112 if (service.packageName.equals(name)) {
5113 if (service.app != null) {
5114 service.app.removed = true;
5115 }
5116 service.app = null;
5117 services.add(service);
5118 }
5119 }
5120
5121 N = services.size();
5122 for (i=0; i<N; i++) {
5123 bringDownServiceLocked(services.get(i), true);
5124 }
5125
5126 resumeTopActivityLocked(null);
5127 }
5128
5129 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5130 final String name = app.processName;
5131 final int uid = app.info.uid;
5132 if (Config.LOGD) Log.d(
5133 TAG, "Force removing process " + app + " (" + name
5134 + "/" + uid + ")");
5135
5136 mProcessNames.remove(name, uid);
5137 boolean needRestart = false;
5138 if (app.pid > 0 && app.pid != MY_PID) {
5139 int pid = app.pid;
5140 synchronized (mPidsSelfLocked) {
5141 mPidsSelfLocked.remove(pid);
5142 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5143 }
5144 handleAppDiedLocked(app, true);
5145 mLRUProcesses.remove(app);
5146 Process.killProcess(pid);
5147
5148 if (app.persistent) {
5149 if (!callerWillRestart) {
5150 addAppLocked(app.info);
5151 } else {
5152 needRestart = true;
5153 }
5154 }
5155 } else {
5156 mRemovedProcesses.add(app);
5157 }
5158
5159 return needRestart;
5160 }
5161
5162 private final void processStartTimedOutLocked(ProcessRecord app) {
5163 final int pid = app.pid;
5164 boolean gone = false;
5165 synchronized (mPidsSelfLocked) {
5166 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5167 if (knownApp != null && knownApp.thread == null) {
5168 mPidsSelfLocked.remove(pid);
5169 gone = true;
5170 }
5171 }
5172
5173 if (gone) {
5174 Log.w(TAG, "Process " + app + " failed to attach");
5175 mProcessNames.remove(app.processName, app.info.uid);
5176 Process.killProcess(pid);
5177 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5178 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5179 mPendingBroadcast = null;
5180 scheduleBroadcastsLocked();
5181 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005182 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5183 Log.w(TAG, "Unattached app died before backup, skipping");
5184 try {
5185 IBackupManager bm = IBackupManager.Stub.asInterface(
5186 ServiceManager.getService(Context.BACKUP_SERVICE));
5187 bm.agentDisconnected(app.info.packageName);
5188 } catch (RemoteException e) {
5189 // Can't happen; the backup manager is local
5190 }
5191 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005192 } else {
5193 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5194 }
5195 }
5196
5197 private final boolean attachApplicationLocked(IApplicationThread thread,
5198 int pid) {
5199
5200 // Find the application record that is being attached... either via
5201 // the pid if we are running in multiple processes, or just pull the
5202 // next app record if we are emulating process with anonymous threads.
5203 ProcessRecord app;
5204 if (pid != MY_PID && pid >= 0) {
5205 synchronized (mPidsSelfLocked) {
5206 app = mPidsSelfLocked.get(pid);
5207 }
5208 } else if (mStartingProcesses.size() > 0) {
5209 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005210 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005211 } else {
5212 app = null;
5213 }
5214
5215 if (app == null) {
5216 Log.w(TAG, "No pending application record for pid " + pid
5217 + " (IApplicationThread " + thread + "); dropping process");
5218 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5219 if (pid > 0 && pid != MY_PID) {
5220 Process.killProcess(pid);
5221 } else {
5222 try {
5223 thread.scheduleExit();
5224 } catch (Exception e) {
5225 // Ignore exceptions.
5226 }
5227 }
5228 return false;
5229 }
5230
5231 // If this application record is still attached to a previous
5232 // process, clean it up now.
5233 if (app.thread != null) {
5234 handleAppDiedLocked(app, true);
5235 }
5236
5237 // Tell the process all about itself.
5238
5239 if (localLOGV) Log.v(
5240 TAG, "Binding process pid " + pid + " to record " + app);
5241
5242 String processName = app.processName;
5243 try {
5244 thread.asBinder().linkToDeath(new AppDeathRecipient(
5245 app, pid, thread), 0);
5246 } catch (RemoteException e) {
5247 app.resetPackageList();
5248 startProcessLocked(app, "link fail", processName);
5249 return false;
5250 }
5251
5252 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5253
5254 app.thread = thread;
5255 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005256 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005257 app.forcingToForeground = null;
5258 app.foregroundServices = false;
5259 app.debugging = false;
5260
5261 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5262
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005263 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5264 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005265
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005266 if (!normalMode) {
5267 Log.i(TAG, "Launching preboot mode app: " + app);
5268 }
5269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005270 if (localLOGV) Log.v(
5271 TAG, "New app record " + app
5272 + " thread=" + thread.asBinder() + " pid=" + pid);
5273 try {
5274 int testMode = IApplicationThread.DEBUG_OFF;
5275 if (mDebugApp != null && mDebugApp.equals(processName)) {
5276 testMode = mWaitForDebugger
5277 ? IApplicationThread.DEBUG_WAIT
5278 : IApplicationThread.DEBUG_ON;
5279 app.debugging = true;
5280 if (mDebugTransient) {
5281 mDebugApp = mOrigDebugApp;
5282 mWaitForDebugger = mOrigWaitForDebugger;
5283 }
5284 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005285
Christopher Tate181fafa2009-05-14 11:12:14 -07005286 // If the app is being launched for restore or full backup, set it up specially
5287 boolean isRestrictedBackupMode = false;
5288 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5289 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5290 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5291 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005292
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005293 ensurePackageDexOpt(app.instrumentationInfo != null
5294 ? app.instrumentationInfo.packageName
5295 : app.info.packageName);
5296 if (app.instrumentationClass != null) {
5297 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005298 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005299 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5300 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005301 thread.bindApplication(processName, app.instrumentationInfo != null
5302 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005303 app.instrumentationClass, app.instrumentationProfileFile,
5304 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005305 isRestrictedBackupMode || !normalMode,
5306 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005307 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005308 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005309 } catch (Exception e) {
5310 // todo: Yikes! What should we do? For now we will try to
5311 // start another process, but that could easily get us in
5312 // an infinite loop of restarting processes...
5313 Log.w(TAG, "Exception thrown during bind!", e);
5314
5315 app.resetPackageList();
5316 startProcessLocked(app, "bind fail", processName);
5317 return false;
5318 }
5319
5320 // Remove this record from the list of starting applications.
5321 mPersistentStartingProcesses.remove(app);
5322 mProcessesOnHold.remove(app);
5323
5324 boolean badApp = false;
5325 boolean didSomething = false;
5326
5327 // See if the top visible activity is waiting to run in this process...
5328 HistoryRecord hr = topRunningActivityLocked(null);
5329 if (hr != null) {
5330 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5331 && processName.equals(hr.processName)) {
5332 try {
5333 if (realStartActivityLocked(hr, app, true, true)) {
5334 didSomething = true;
5335 }
5336 } catch (Exception e) {
5337 Log.w(TAG, "Exception in new application when starting activity "
5338 + hr.intent.getComponent().flattenToShortString(), e);
5339 badApp = true;
5340 }
5341 } else {
5342 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5343 }
5344 }
5345
5346 // Find any services that should be running in this process...
5347 if (!badApp && mPendingServices.size() > 0) {
5348 ServiceRecord sr = null;
5349 try {
5350 for (int i=0; i<mPendingServices.size(); i++) {
5351 sr = mPendingServices.get(i);
5352 if (app.info.uid != sr.appInfo.uid
5353 || !processName.equals(sr.processName)) {
5354 continue;
5355 }
5356
5357 mPendingServices.remove(i);
5358 i--;
5359 realStartServiceLocked(sr, app);
5360 didSomething = true;
5361 }
5362 } catch (Exception e) {
5363 Log.w(TAG, "Exception in new application when starting service "
5364 + sr.shortName, e);
5365 badApp = true;
5366 }
5367 }
5368
5369 // Check if the next broadcast receiver is in this process...
5370 BroadcastRecord br = mPendingBroadcast;
5371 if (!badApp && br != null && br.curApp == app) {
5372 try {
5373 mPendingBroadcast = null;
5374 processCurBroadcastLocked(br, app);
5375 didSomething = true;
5376 } catch (Exception e) {
5377 Log.w(TAG, "Exception in new application when starting receiver "
5378 + br.curComponent.flattenToShortString(), e);
5379 badApp = true;
5380 logBroadcastReceiverDiscard(br);
5381 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5382 br.resultExtras, br.resultAbort, true);
5383 scheduleBroadcastsLocked();
5384 }
5385 }
5386
Christopher Tate181fafa2009-05-14 11:12:14 -07005387 // Check whether the next backup agent is in this process...
5388 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5389 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005390 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005391 try {
5392 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5393 } catch (Exception e) {
5394 Log.w(TAG, "Exception scheduling backup agent creation: ");
5395 e.printStackTrace();
5396 }
5397 }
5398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005399 if (badApp) {
5400 // todo: Also need to kill application to deal with all
5401 // kinds of exceptions.
5402 handleAppDiedLocked(app, false);
5403 return false;
5404 }
5405
5406 if (!didSomething) {
5407 updateOomAdjLocked();
5408 }
5409
5410 return true;
5411 }
5412
5413 public final void attachApplication(IApplicationThread thread) {
5414 synchronized (this) {
5415 int callingPid = Binder.getCallingPid();
5416 final long origId = Binder.clearCallingIdentity();
5417 attachApplicationLocked(thread, callingPid);
5418 Binder.restoreCallingIdentity(origId);
5419 }
5420 }
5421
5422 public final void activityIdle(IBinder token) {
5423 final long origId = Binder.clearCallingIdentity();
5424 activityIdleInternal(token, false);
5425 Binder.restoreCallingIdentity(origId);
5426 }
5427
5428 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5429 boolean remove) {
5430 int N = mStoppingActivities.size();
5431 if (N <= 0) return null;
5432
5433 ArrayList<HistoryRecord> stops = null;
5434
5435 final boolean nowVisible = mResumedActivity != null
5436 && mResumedActivity.nowVisible
5437 && !mResumedActivity.waitingVisible;
5438 for (int i=0; i<N; i++) {
5439 HistoryRecord s = mStoppingActivities.get(i);
5440 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5441 + nowVisible + " waitingVisible=" + s.waitingVisible
5442 + " finishing=" + s.finishing);
5443 if (s.waitingVisible && nowVisible) {
5444 mWaitingVisibleActivities.remove(s);
5445 s.waitingVisible = false;
5446 if (s.finishing) {
5447 // If this activity is finishing, it is sitting on top of
5448 // everyone else but we now know it is no longer needed...
5449 // so get rid of it. Otherwise, we need to go through the
5450 // normal flow and hide it once we determine that it is
5451 // hidden by the activities in front of it.
5452 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5453 mWindowManager.setAppVisibility(s, false);
5454 }
5455 }
5456 if (!s.waitingVisible && remove) {
5457 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5458 if (stops == null) {
5459 stops = new ArrayList<HistoryRecord>();
5460 }
5461 stops.add(s);
5462 mStoppingActivities.remove(i);
5463 N--;
5464 i--;
5465 }
5466 }
5467
5468 return stops;
5469 }
5470
5471 void enableScreenAfterBoot() {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005472 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5473 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005474 mWindowManager.enableScreenAfterBoot();
5475 }
5476
5477 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5478 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5479
5480 ArrayList<HistoryRecord> stops = null;
5481 ArrayList<HistoryRecord> finishes = null;
5482 ArrayList<HistoryRecord> thumbnails = null;
5483 int NS = 0;
5484 int NF = 0;
5485 int NT = 0;
5486 IApplicationThread sendThumbnail = null;
5487 boolean booting = false;
5488 boolean enableScreen = false;
5489
5490 synchronized (this) {
5491 if (token != null) {
5492 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5493 }
5494
5495 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005496 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005497 if (index >= 0) {
5498 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5499
5500 // No longer need to keep the device awake.
5501 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5502 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5503 mLaunchingActivity.release();
5504 }
5505
5506 // We are now idle. If someone is waiting for a thumbnail from
5507 // us, we can now deliver.
5508 r.idle = true;
5509 scheduleAppGcsLocked();
5510 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5511 sendThumbnail = r.app.thread;
5512 r.thumbnailNeeded = false;
5513 }
5514
5515 // If this activity is fullscreen, set up to hide those under it.
5516
5517 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5518 ensureActivitiesVisibleLocked(null, 0);
5519
5520 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5521 if (!mBooted && !fromTimeout) {
5522 mBooted = true;
5523 enableScreen = true;
5524 }
5525 }
5526
5527 // Atomically retrieve all of the other things to do.
5528 stops = processStoppingActivitiesLocked(true);
5529 NS = stops != null ? stops.size() : 0;
5530 if ((NF=mFinishingActivities.size()) > 0) {
5531 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5532 mFinishingActivities.clear();
5533 }
5534 if ((NT=mCancelledThumbnails.size()) > 0) {
5535 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5536 mCancelledThumbnails.clear();
5537 }
5538
5539 booting = mBooting;
5540 mBooting = false;
5541 }
5542
5543 int i;
5544
5545 // Send thumbnail if requested.
5546 if (sendThumbnail != null) {
5547 try {
5548 sendThumbnail.requestThumbnail(token);
5549 } catch (Exception e) {
5550 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5551 sendPendingThumbnail(null, token, null, null, true);
5552 }
5553 }
5554
5555 // Stop any activities that are scheduled to do so but have been
5556 // waiting for the next one to start.
5557 for (i=0; i<NS; i++) {
5558 HistoryRecord r = (HistoryRecord)stops.get(i);
5559 synchronized (this) {
5560 if (r.finishing) {
5561 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5562 } else {
5563 stopActivityLocked(r);
5564 }
5565 }
5566 }
5567
5568 // Finish any activities that are scheduled to do so but have been
5569 // waiting for the next one to start.
5570 for (i=0; i<NF; i++) {
5571 HistoryRecord r = (HistoryRecord)finishes.get(i);
5572 synchronized (this) {
5573 destroyActivityLocked(r, true);
5574 }
5575 }
5576
5577 // Report back to any thumbnail receivers.
5578 for (i=0; i<NT; i++) {
5579 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5580 sendPendingThumbnail(r, null, null, null, true);
5581 }
5582
5583 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005584 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005585 }
5586
5587 trimApplications();
5588 //dump();
5589 //mWindowManager.dump();
5590
5591 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005592 enableScreenAfterBoot();
5593 }
5594 }
5595
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005596 final void finishBooting() {
5597 // Ensure that any processes we had put on hold are now started
5598 // up.
5599 final int NP = mProcessesOnHold.size();
5600 if (NP > 0) {
5601 ArrayList<ProcessRecord> procs =
5602 new ArrayList<ProcessRecord>(mProcessesOnHold);
5603 for (int ip=0; ip<NP; ip++) {
5604 this.startProcessLocked(procs.get(ip), "on-hold", null);
5605 }
5606 }
5607 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5608 // Tell anyone interested that we are done booting!
5609 synchronized (this) {
5610 broadcastIntentLocked(null, null,
5611 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5612 null, null, 0, null, null,
5613 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5614 false, false, MY_PID, Process.SYSTEM_UID);
5615 }
5616 }
5617 }
5618
5619 final void ensureBootCompleted() {
5620 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005621 boolean enableScreen;
5622 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005623 booting = mBooting;
5624 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005625 enableScreen = !mBooted;
5626 mBooted = true;
5627 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005628
5629 if (booting) {
5630 finishBooting();
5631 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005632
5633 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005634 enableScreenAfterBoot();
5635 }
5636 }
5637
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005638 public final void activityPaused(IBinder token, Bundle icicle) {
5639 // Refuse possible leaked file descriptors
5640 if (icicle != null && icicle.hasFileDescriptors()) {
5641 throw new IllegalArgumentException("File descriptors passed in Bundle");
5642 }
5643
5644 final long origId = Binder.clearCallingIdentity();
5645 activityPaused(token, icicle, false);
5646 Binder.restoreCallingIdentity(origId);
5647 }
5648
5649 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5650 if (DEBUG_PAUSE) Log.v(
5651 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5652 + ", timeout=" + timeout);
5653
5654 HistoryRecord r = null;
5655
5656 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005657 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005658 if (index >= 0) {
5659 r = (HistoryRecord)mHistory.get(index);
5660 if (!timeout) {
5661 r.icicle = icicle;
5662 r.haveState = true;
5663 }
5664 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5665 if (mPausingActivity == r) {
5666 r.state = ActivityState.PAUSED;
5667 completePauseLocked();
5668 } else {
5669 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5670 System.identityHashCode(r), r.shortComponentName,
5671 mPausingActivity != null
5672 ? mPausingActivity.shortComponentName : "(none)");
5673 }
5674 }
5675 }
5676 }
5677
5678 public final void activityStopped(IBinder token, Bitmap thumbnail,
5679 CharSequence description) {
5680 if (localLOGV) Log.v(
5681 TAG, "Activity stopped: token=" + token);
5682
5683 HistoryRecord r = null;
5684
5685 final long origId = Binder.clearCallingIdentity();
5686
5687 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005688 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005689 if (index >= 0) {
5690 r = (HistoryRecord)mHistory.get(index);
5691 r.thumbnail = thumbnail;
5692 r.description = description;
5693 r.stopped = true;
5694 r.state = ActivityState.STOPPED;
5695 if (!r.finishing) {
5696 if (r.configDestroy) {
5697 destroyActivityLocked(r, true);
5698 resumeTopActivityLocked(null);
5699 }
5700 }
5701 }
5702 }
5703
5704 if (r != null) {
5705 sendPendingThumbnail(r, null, null, null, false);
5706 }
5707
5708 trimApplications();
5709
5710 Binder.restoreCallingIdentity(origId);
5711 }
5712
5713 public final void activityDestroyed(IBinder token) {
5714 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5715 synchronized (this) {
5716 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5717
Dianne Hackborn75b03852009-06-12 15:43:26 -07005718 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005719 if (index >= 0) {
5720 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5721 if (r.state == ActivityState.DESTROYING) {
5722 final long origId = Binder.clearCallingIdentity();
5723 removeActivityFromHistoryLocked(r);
5724 Binder.restoreCallingIdentity(origId);
5725 }
5726 }
5727 }
5728 }
5729
5730 public String getCallingPackage(IBinder token) {
5731 synchronized (this) {
5732 HistoryRecord r = getCallingRecordLocked(token);
5733 return r != null && r.app != null ? r.app.processName : null;
5734 }
5735 }
5736
5737 public ComponentName getCallingActivity(IBinder token) {
5738 synchronized (this) {
5739 HistoryRecord r = getCallingRecordLocked(token);
5740 return r != null ? r.intent.getComponent() : null;
5741 }
5742 }
5743
5744 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005745 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005746 if (index >= 0) {
5747 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5748 if (r != null) {
5749 return r.resultTo;
5750 }
5751 }
5752 return null;
5753 }
5754
5755 public ComponentName getActivityClassForToken(IBinder token) {
5756 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005757 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005758 if (index >= 0) {
5759 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5760 return r.intent.getComponent();
5761 }
5762 return null;
5763 }
5764 }
5765
5766 public String getPackageForToken(IBinder token) {
5767 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005768 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005769 if (index >= 0) {
5770 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5771 return r.packageName;
5772 }
5773 return null;
5774 }
5775 }
5776
5777 public IIntentSender getIntentSender(int type,
5778 String packageName, IBinder token, String resultWho,
5779 int requestCode, Intent intent, String resolvedType, int flags) {
5780 // Refuse possible leaked file descriptors
5781 if (intent != null && intent.hasFileDescriptors() == true) {
5782 throw new IllegalArgumentException("File descriptors passed in Intent");
5783 }
5784
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005785 if (type == INTENT_SENDER_BROADCAST) {
5786 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5787 throw new IllegalArgumentException(
5788 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5789 }
5790 }
5791
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005792 synchronized(this) {
5793 int callingUid = Binder.getCallingUid();
5794 try {
5795 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5796 Process.supportsProcesses()) {
5797 int uid = ActivityThread.getPackageManager()
5798 .getPackageUid(packageName);
5799 if (uid != Binder.getCallingUid()) {
5800 String msg = "Permission Denial: getIntentSender() from pid="
5801 + Binder.getCallingPid()
5802 + ", uid=" + Binder.getCallingUid()
5803 + ", (need uid=" + uid + ")"
5804 + " is not allowed to send as package " + packageName;
5805 Log.w(TAG, msg);
5806 throw new SecurityException(msg);
5807 }
5808 }
5809 } catch (RemoteException e) {
5810 throw new SecurityException(e);
5811 }
5812 HistoryRecord activity = null;
5813 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005814 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005815 if (index < 0) {
5816 return null;
5817 }
5818 activity = (HistoryRecord)mHistory.get(index);
5819 if (activity.finishing) {
5820 return null;
5821 }
5822 }
5823
5824 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5825 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5826 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5827 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5828 |PendingIntent.FLAG_UPDATE_CURRENT);
5829
5830 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5831 type, packageName, activity, resultWho,
5832 requestCode, intent, resolvedType, flags);
5833 WeakReference<PendingIntentRecord> ref;
5834 ref = mIntentSenderRecords.get(key);
5835 PendingIntentRecord rec = ref != null ? ref.get() : null;
5836 if (rec != null) {
5837 if (!cancelCurrent) {
5838 if (updateCurrent) {
5839 rec.key.requestIntent.replaceExtras(intent);
5840 }
5841 return rec;
5842 }
5843 rec.canceled = true;
5844 mIntentSenderRecords.remove(key);
5845 }
5846 if (noCreate) {
5847 return rec;
5848 }
5849 rec = new PendingIntentRecord(this, key, callingUid);
5850 mIntentSenderRecords.put(key, rec.ref);
5851 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5852 if (activity.pendingResults == null) {
5853 activity.pendingResults
5854 = new HashSet<WeakReference<PendingIntentRecord>>();
5855 }
5856 activity.pendingResults.add(rec.ref);
5857 }
5858 return rec;
5859 }
5860 }
5861
5862 public void cancelIntentSender(IIntentSender sender) {
5863 if (!(sender instanceof PendingIntentRecord)) {
5864 return;
5865 }
5866 synchronized(this) {
5867 PendingIntentRecord rec = (PendingIntentRecord)sender;
5868 try {
5869 int uid = ActivityThread.getPackageManager()
5870 .getPackageUid(rec.key.packageName);
5871 if (uid != Binder.getCallingUid()) {
5872 String msg = "Permission Denial: cancelIntentSender() from pid="
5873 + Binder.getCallingPid()
5874 + ", uid=" + Binder.getCallingUid()
5875 + " is not allowed to cancel packges "
5876 + rec.key.packageName;
5877 Log.w(TAG, msg);
5878 throw new SecurityException(msg);
5879 }
5880 } catch (RemoteException e) {
5881 throw new SecurityException(e);
5882 }
5883 cancelIntentSenderLocked(rec, true);
5884 }
5885 }
5886
5887 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5888 rec.canceled = true;
5889 mIntentSenderRecords.remove(rec.key);
5890 if (cleanActivity && rec.key.activity != null) {
5891 rec.key.activity.pendingResults.remove(rec.ref);
5892 }
5893 }
5894
5895 public String getPackageForIntentSender(IIntentSender pendingResult) {
5896 if (!(pendingResult instanceof PendingIntentRecord)) {
5897 return null;
5898 }
5899 synchronized(this) {
5900 try {
5901 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5902 return res.key.packageName;
5903 } catch (ClassCastException e) {
5904 }
5905 }
5906 return null;
5907 }
5908
5909 public void setProcessLimit(int max) {
5910 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5911 "setProcessLimit()");
5912 mProcessLimit = max;
5913 }
5914
5915 public int getProcessLimit() {
5916 return mProcessLimit;
5917 }
5918
5919 void foregroundTokenDied(ForegroundToken token) {
5920 synchronized (ActivityManagerService.this) {
5921 synchronized (mPidsSelfLocked) {
5922 ForegroundToken cur
5923 = mForegroundProcesses.get(token.pid);
5924 if (cur != token) {
5925 return;
5926 }
5927 mForegroundProcesses.remove(token.pid);
5928 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5929 if (pr == null) {
5930 return;
5931 }
5932 pr.forcingToForeground = null;
5933 pr.foregroundServices = false;
5934 }
5935 updateOomAdjLocked();
5936 }
5937 }
5938
5939 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5940 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5941 "setProcessForeground()");
5942 synchronized(this) {
5943 boolean changed = false;
5944
5945 synchronized (mPidsSelfLocked) {
5946 ProcessRecord pr = mPidsSelfLocked.get(pid);
5947 if (pr == null) {
5948 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5949 return;
5950 }
5951 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5952 if (oldToken != null) {
5953 oldToken.token.unlinkToDeath(oldToken, 0);
5954 mForegroundProcesses.remove(pid);
5955 pr.forcingToForeground = null;
5956 changed = true;
5957 }
5958 if (isForeground && token != null) {
5959 ForegroundToken newToken = new ForegroundToken() {
5960 public void binderDied() {
5961 foregroundTokenDied(this);
5962 }
5963 };
5964 newToken.pid = pid;
5965 newToken.token = token;
5966 try {
5967 token.linkToDeath(newToken, 0);
5968 mForegroundProcesses.put(pid, newToken);
5969 pr.forcingToForeground = token;
5970 changed = true;
5971 } catch (RemoteException e) {
5972 // If the process died while doing this, we will later
5973 // do the cleanup with the process death link.
5974 }
5975 }
5976 }
5977
5978 if (changed) {
5979 updateOomAdjLocked();
5980 }
5981 }
5982 }
5983
5984 // =========================================================
5985 // PERMISSIONS
5986 // =========================================================
5987
5988 static class PermissionController extends IPermissionController.Stub {
5989 ActivityManagerService mActivityManagerService;
5990 PermissionController(ActivityManagerService activityManagerService) {
5991 mActivityManagerService = activityManagerService;
5992 }
5993
5994 public boolean checkPermission(String permission, int pid, int uid) {
5995 return mActivityManagerService.checkPermission(permission, pid,
5996 uid) == PackageManager.PERMISSION_GRANTED;
5997 }
5998 }
5999
6000 /**
6001 * This can be called with or without the global lock held.
6002 */
6003 int checkComponentPermission(String permission, int pid, int uid,
6004 int reqUid) {
6005 // We might be performing an operation on behalf of an indirect binder
6006 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
6007 // client identity accordingly before proceeding.
6008 Identity tlsIdentity = sCallerIdentity.get();
6009 if (tlsIdentity != null) {
6010 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6011 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6012 uid = tlsIdentity.uid;
6013 pid = tlsIdentity.pid;
6014 }
6015
6016 // Root, system server and our own process get to do everything.
6017 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6018 !Process.supportsProcesses()) {
6019 return PackageManager.PERMISSION_GRANTED;
6020 }
6021 // If the target requires a specific UID, always fail for others.
6022 if (reqUid >= 0 && uid != reqUid) {
6023 return PackageManager.PERMISSION_DENIED;
6024 }
6025 if (permission == null) {
6026 return PackageManager.PERMISSION_GRANTED;
6027 }
6028 try {
6029 return ActivityThread.getPackageManager()
6030 .checkUidPermission(permission, uid);
6031 } catch (RemoteException e) {
6032 // Should never happen, but if it does... deny!
6033 Log.e(TAG, "PackageManager is dead?!?", e);
6034 }
6035 return PackageManager.PERMISSION_DENIED;
6036 }
6037
6038 /**
6039 * As the only public entry point for permissions checking, this method
6040 * can enforce the semantic that requesting a check on a null global
6041 * permission is automatically denied. (Internally a null permission
6042 * string is used when calling {@link #checkComponentPermission} in cases
6043 * when only uid-based security is needed.)
6044 *
6045 * This can be called with or without the global lock held.
6046 */
6047 public int checkPermission(String permission, int pid, int uid) {
6048 if (permission == null) {
6049 return PackageManager.PERMISSION_DENIED;
6050 }
6051 return checkComponentPermission(permission, pid, uid, -1);
6052 }
6053
6054 /**
6055 * Binder IPC calls go through the public entry point.
6056 * This can be called with or without the global lock held.
6057 */
6058 int checkCallingPermission(String permission) {
6059 return checkPermission(permission,
6060 Binder.getCallingPid(),
6061 Binder.getCallingUid());
6062 }
6063
6064 /**
6065 * This can be called with or without the global lock held.
6066 */
6067 void enforceCallingPermission(String permission, String func) {
6068 if (checkCallingPermission(permission)
6069 == PackageManager.PERMISSION_GRANTED) {
6070 return;
6071 }
6072
6073 String msg = "Permission Denial: " + func + " from pid="
6074 + Binder.getCallingPid()
6075 + ", uid=" + Binder.getCallingUid()
6076 + " requires " + permission;
6077 Log.w(TAG, msg);
6078 throw new SecurityException(msg);
6079 }
6080
6081 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6082 ProviderInfo pi, int uid, int modeFlags) {
6083 try {
6084 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6085 if ((pi.readPermission != null) &&
6086 (pm.checkUidPermission(pi.readPermission, uid)
6087 != PackageManager.PERMISSION_GRANTED)) {
6088 return false;
6089 }
6090 }
6091 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6092 if ((pi.writePermission != null) &&
6093 (pm.checkUidPermission(pi.writePermission, uid)
6094 != PackageManager.PERMISSION_GRANTED)) {
6095 return false;
6096 }
6097 }
6098 return true;
6099 } catch (RemoteException e) {
6100 return false;
6101 }
6102 }
6103
6104 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6105 int modeFlags) {
6106 // Root gets to do everything.
6107 if (uid == 0 || !Process.supportsProcesses()) {
6108 return true;
6109 }
6110 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6111 if (perms == null) return false;
6112 UriPermission perm = perms.get(uri);
6113 if (perm == null) return false;
6114 return (modeFlags&perm.modeFlags) == modeFlags;
6115 }
6116
6117 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6118 // Another redirected-binder-call permissions check as in
6119 // {@link checkComponentPermission}.
6120 Identity tlsIdentity = sCallerIdentity.get();
6121 if (tlsIdentity != null) {
6122 uid = tlsIdentity.uid;
6123 pid = tlsIdentity.pid;
6124 }
6125
6126 // Our own process gets to do everything.
6127 if (pid == MY_PID) {
6128 return PackageManager.PERMISSION_GRANTED;
6129 }
6130 synchronized(this) {
6131 return checkUriPermissionLocked(uri, uid, modeFlags)
6132 ? PackageManager.PERMISSION_GRANTED
6133 : PackageManager.PERMISSION_DENIED;
6134 }
6135 }
6136
6137 private void grantUriPermissionLocked(int callingUid,
6138 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6139 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6140 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6141 if (modeFlags == 0) {
6142 return;
6143 }
6144
6145 final IPackageManager pm = ActivityThread.getPackageManager();
6146
6147 // If this is not a content: uri, we can't do anything with it.
6148 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6149 return;
6150 }
6151
6152 String name = uri.getAuthority();
6153 ProviderInfo pi = null;
6154 ContentProviderRecord cpr
6155 = (ContentProviderRecord)mProvidersByName.get(name);
6156 if (cpr != null) {
6157 pi = cpr.info;
6158 } else {
6159 try {
6160 pi = pm.resolveContentProvider(name,
6161 PackageManager.GET_URI_PERMISSION_PATTERNS);
6162 } catch (RemoteException ex) {
6163 }
6164 }
6165 if (pi == null) {
6166 Log.w(TAG, "No content provider found for: " + name);
6167 return;
6168 }
6169
6170 int targetUid;
6171 try {
6172 targetUid = pm.getPackageUid(targetPkg);
6173 if (targetUid < 0) {
6174 return;
6175 }
6176 } catch (RemoteException ex) {
6177 return;
6178 }
6179
6180 // First... does the target actually need this permission?
6181 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6182 // No need to grant the target this permission.
6183 return;
6184 }
6185
6186 // Second... maybe someone else has already granted the
6187 // permission?
6188 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6189 // No need to grant the target this permission.
6190 return;
6191 }
6192
6193 // Third... is the provider allowing granting of URI permissions?
6194 if (!pi.grantUriPermissions) {
6195 throw new SecurityException("Provider " + pi.packageName
6196 + "/" + pi.name
6197 + " does not allow granting of Uri permissions (uri "
6198 + uri + ")");
6199 }
6200 if (pi.uriPermissionPatterns != null) {
6201 final int N = pi.uriPermissionPatterns.length;
6202 boolean allowed = false;
6203 for (int i=0; i<N; i++) {
6204 if (pi.uriPermissionPatterns[i] != null
6205 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6206 allowed = true;
6207 break;
6208 }
6209 }
6210 if (!allowed) {
6211 throw new SecurityException("Provider " + pi.packageName
6212 + "/" + pi.name
6213 + " does not allow granting of permission to path of Uri "
6214 + uri);
6215 }
6216 }
6217
6218 // Fourth... does the caller itself have permission to access
6219 // this uri?
6220 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6221 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6222 throw new SecurityException("Uid " + callingUid
6223 + " does not have permission to uri " + uri);
6224 }
6225 }
6226
6227 // Okay! So here we are: the caller has the assumed permission
6228 // to the uri, and the target doesn't. Let's now give this to
6229 // the target.
6230
6231 HashMap<Uri, UriPermission> targetUris
6232 = mGrantedUriPermissions.get(targetUid);
6233 if (targetUris == null) {
6234 targetUris = new HashMap<Uri, UriPermission>();
6235 mGrantedUriPermissions.put(targetUid, targetUris);
6236 }
6237
6238 UriPermission perm = targetUris.get(uri);
6239 if (perm == null) {
6240 perm = new UriPermission(targetUid, uri);
6241 targetUris.put(uri, perm);
6242
6243 }
6244 perm.modeFlags |= modeFlags;
6245 if (activity == null) {
6246 perm.globalModeFlags |= modeFlags;
6247 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6248 perm.readActivities.add(activity);
6249 if (activity.readUriPermissions == null) {
6250 activity.readUriPermissions = new HashSet<UriPermission>();
6251 }
6252 activity.readUriPermissions.add(perm);
6253 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6254 perm.writeActivities.add(activity);
6255 if (activity.writeUriPermissions == null) {
6256 activity.writeUriPermissions = new HashSet<UriPermission>();
6257 }
6258 activity.writeUriPermissions.add(perm);
6259 }
6260 }
6261
6262 private void grantUriPermissionFromIntentLocked(int callingUid,
6263 String targetPkg, Intent intent, HistoryRecord activity) {
6264 if (intent == null) {
6265 return;
6266 }
6267 Uri data = intent.getData();
6268 if (data == null) {
6269 return;
6270 }
6271 grantUriPermissionLocked(callingUid, targetPkg, data,
6272 intent.getFlags(), activity);
6273 }
6274
6275 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6276 Uri uri, int modeFlags) {
6277 synchronized(this) {
6278 final ProcessRecord r = getRecordForAppLocked(caller);
6279 if (r == null) {
6280 throw new SecurityException("Unable to find app for caller "
6281 + caller
6282 + " when granting permission to uri " + uri);
6283 }
6284 if (targetPkg == null) {
6285 Log.w(TAG, "grantUriPermission: null target");
6286 return;
6287 }
6288 if (uri == null) {
6289 Log.w(TAG, "grantUriPermission: null uri");
6290 return;
6291 }
6292
6293 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6294 null);
6295 }
6296 }
6297
6298 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6299 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6300 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6301 HashMap<Uri, UriPermission> perms
6302 = mGrantedUriPermissions.get(perm.uid);
6303 if (perms != null) {
6304 perms.remove(perm.uri);
6305 if (perms.size() == 0) {
6306 mGrantedUriPermissions.remove(perm.uid);
6307 }
6308 }
6309 }
6310 }
6311
6312 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6313 if (activity.readUriPermissions != null) {
6314 for (UriPermission perm : activity.readUriPermissions) {
6315 perm.readActivities.remove(activity);
6316 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6317 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6318 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6319 removeUriPermissionIfNeededLocked(perm);
6320 }
6321 }
6322 }
6323 if (activity.writeUriPermissions != null) {
6324 for (UriPermission perm : activity.writeUriPermissions) {
6325 perm.writeActivities.remove(activity);
6326 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6327 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6328 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6329 removeUriPermissionIfNeededLocked(perm);
6330 }
6331 }
6332 }
6333 }
6334
6335 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6336 int modeFlags) {
6337 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6338 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6339 if (modeFlags == 0) {
6340 return;
6341 }
6342
6343 final IPackageManager pm = ActivityThread.getPackageManager();
6344
6345 final String authority = uri.getAuthority();
6346 ProviderInfo pi = null;
6347 ContentProviderRecord cpr
6348 = (ContentProviderRecord)mProvidersByName.get(authority);
6349 if (cpr != null) {
6350 pi = cpr.info;
6351 } else {
6352 try {
6353 pi = pm.resolveContentProvider(authority,
6354 PackageManager.GET_URI_PERMISSION_PATTERNS);
6355 } catch (RemoteException ex) {
6356 }
6357 }
6358 if (pi == null) {
6359 Log.w(TAG, "No content provider found for: " + authority);
6360 return;
6361 }
6362
6363 // Does the caller have this permission on the URI?
6364 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6365 // Right now, if you are not the original owner of the permission,
6366 // you are not allowed to revoke it.
6367 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6368 throw new SecurityException("Uid " + callingUid
6369 + " does not have permission to uri " + uri);
6370 //}
6371 }
6372
6373 // Go through all of the permissions and remove any that match.
6374 final List<String> SEGMENTS = uri.getPathSegments();
6375 if (SEGMENTS != null) {
6376 final int NS = SEGMENTS.size();
6377 int N = mGrantedUriPermissions.size();
6378 for (int i=0; i<N; i++) {
6379 HashMap<Uri, UriPermission> perms
6380 = mGrantedUriPermissions.valueAt(i);
6381 Iterator<UriPermission> it = perms.values().iterator();
6382 toploop:
6383 while (it.hasNext()) {
6384 UriPermission perm = it.next();
6385 Uri targetUri = perm.uri;
6386 if (!authority.equals(targetUri.getAuthority())) {
6387 continue;
6388 }
6389 List<String> targetSegments = targetUri.getPathSegments();
6390 if (targetSegments == null) {
6391 continue;
6392 }
6393 if (targetSegments.size() < NS) {
6394 continue;
6395 }
6396 for (int j=0; j<NS; j++) {
6397 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6398 continue toploop;
6399 }
6400 }
6401 perm.clearModes(modeFlags);
6402 if (perm.modeFlags == 0) {
6403 it.remove();
6404 }
6405 }
6406 if (perms.size() == 0) {
6407 mGrantedUriPermissions.remove(
6408 mGrantedUriPermissions.keyAt(i));
6409 N--;
6410 i--;
6411 }
6412 }
6413 }
6414 }
6415
6416 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6417 int modeFlags) {
6418 synchronized(this) {
6419 final ProcessRecord r = getRecordForAppLocked(caller);
6420 if (r == null) {
6421 throw new SecurityException("Unable to find app for caller "
6422 + caller
6423 + " when revoking permission to uri " + uri);
6424 }
6425 if (uri == null) {
6426 Log.w(TAG, "revokeUriPermission: null uri");
6427 return;
6428 }
6429
6430 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6431 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6432 if (modeFlags == 0) {
6433 return;
6434 }
6435
6436 final IPackageManager pm = ActivityThread.getPackageManager();
6437
6438 final String authority = uri.getAuthority();
6439 ProviderInfo pi = null;
6440 ContentProviderRecord cpr
6441 = (ContentProviderRecord)mProvidersByName.get(authority);
6442 if (cpr != null) {
6443 pi = cpr.info;
6444 } else {
6445 try {
6446 pi = pm.resolveContentProvider(authority,
6447 PackageManager.GET_URI_PERMISSION_PATTERNS);
6448 } catch (RemoteException ex) {
6449 }
6450 }
6451 if (pi == null) {
6452 Log.w(TAG, "No content provider found for: " + authority);
6453 return;
6454 }
6455
6456 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6457 }
6458 }
6459
6460 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6461 synchronized (this) {
6462 ProcessRecord app =
6463 who != null ? getRecordForAppLocked(who) : null;
6464 if (app == null) return;
6465
6466 Message msg = Message.obtain();
6467 msg.what = WAIT_FOR_DEBUGGER_MSG;
6468 msg.obj = app;
6469 msg.arg1 = waiting ? 1 : 0;
6470 mHandler.sendMessage(msg);
6471 }
6472 }
6473
6474 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6475 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006476 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006477 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006478 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006479 }
6480
6481 // =========================================================
6482 // TASK MANAGEMENT
6483 // =========================================================
6484
6485 public List getTasks(int maxNum, int flags,
6486 IThumbnailReceiver receiver) {
6487 ArrayList list = new ArrayList();
6488
6489 PendingThumbnailsRecord pending = null;
6490 IApplicationThread topThumbnail = null;
6491 HistoryRecord topRecord = null;
6492
6493 synchronized(this) {
6494 if (localLOGV) Log.v(
6495 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6496 + ", receiver=" + receiver);
6497
6498 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6499 != PackageManager.PERMISSION_GRANTED) {
6500 if (receiver != null) {
6501 // If the caller wants to wait for pending thumbnails,
6502 // it ain't gonna get them.
6503 try {
6504 receiver.finished();
6505 } catch (RemoteException ex) {
6506 }
6507 }
6508 String msg = "Permission Denial: getTasks() from pid="
6509 + Binder.getCallingPid()
6510 + ", uid=" + Binder.getCallingUid()
6511 + " requires " + android.Manifest.permission.GET_TASKS;
6512 Log.w(TAG, msg);
6513 throw new SecurityException(msg);
6514 }
6515
6516 int pos = mHistory.size()-1;
6517 HistoryRecord next =
6518 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6519 HistoryRecord top = null;
6520 CharSequence topDescription = null;
6521 TaskRecord curTask = null;
6522 int numActivities = 0;
6523 int numRunning = 0;
6524 while (pos >= 0 && maxNum > 0) {
6525 final HistoryRecord r = next;
6526 pos--;
6527 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6528
6529 // Initialize state for next task if needed.
6530 if (top == null ||
6531 (top.state == ActivityState.INITIALIZING
6532 && top.task == r.task)) {
6533 top = r;
6534 topDescription = r.description;
6535 curTask = r.task;
6536 numActivities = numRunning = 0;
6537 }
6538
6539 // Add 'r' into the current task.
6540 numActivities++;
6541 if (r.app != null && r.app.thread != null) {
6542 numRunning++;
6543 }
6544 if (topDescription == null) {
6545 topDescription = r.description;
6546 }
6547
6548 if (localLOGV) Log.v(
6549 TAG, r.intent.getComponent().flattenToShortString()
6550 + ": task=" + r.task);
6551
6552 // If the next one is a different task, generate a new
6553 // TaskInfo entry for what we have.
6554 if (next == null || next.task != curTask) {
6555 ActivityManager.RunningTaskInfo ci
6556 = new ActivityManager.RunningTaskInfo();
6557 ci.id = curTask.taskId;
6558 ci.baseActivity = r.intent.getComponent();
6559 ci.topActivity = top.intent.getComponent();
6560 ci.thumbnail = top.thumbnail;
6561 ci.description = topDescription;
6562 ci.numActivities = numActivities;
6563 ci.numRunning = numRunning;
6564 //System.out.println(
6565 // "#" + maxNum + ": " + " descr=" + ci.description);
6566 if (ci.thumbnail == null && receiver != null) {
6567 if (localLOGV) Log.v(
6568 TAG, "State=" + top.state + "Idle=" + top.idle
6569 + " app=" + top.app
6570 + " thr=" + (top.app != null ? top.app.thread : null));
6571 if (top.state == ActivityState.RESUMED
6572 || top.state == ActivityState.PAUSING) {
6573 if (top.idle && top.app != null
6574 && top.app.thread != null) {
6575 topRecord = top;
6576 topThumbnail = top.app.thread;
6577 } else {
6578 top.thumbnailNeeded = true;
6579 }
6580 }
6581 if (pending == null) {
6582 pending = new PendingThumbnailsRecord(receiver);
6583 }
6584 pending.pendingRecords.add(top);
6585 }
6586 list.add(ci);
6587 maxNum--;
6588 top = null;
6589 }
6590 }
6591
6592 if (pending != null) {
6593 mPendingThumbnails.add(pending);
6594 }
6595 }
6596
6597 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6598
6599 if (topThumbnail != null) {
6600 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6601 try {
6602 topThumbnail.requestThumbnail(topRecord);
6603 } catch (Exception e) {
6604 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6605 sendPendingThumbnail(null, topRecord, null, null, true);
6606 }
6607 }
6608
6609 if (pending == null && receiver != null) {
6610 // In this case all thumbnails were available and the client
6611 // is being asked to be told when the remaining ones come in...
6612 // which is unusually, since the top-most currently running
6613 // activity should never have a canned thumbnail! Oh well.
6614 try {
6615 receiver.finished();
6616 } catch (RemoteException ex) {
6617 }
6618 }
6619
6620 return list;
6621 }
6622
6623 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6624 int flags) {
6625 synchronized (this) {
6626 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6627 "getRecentTasks()");
6628
6629 final int N = mRecentTasks.size();
6630 ArrayList<ActivityManager.RecentTaskInfo> res
6631 = new ArrayList<ActivityManager.RecentTaskInfo>(
6632 maxNum < N ? maxNum : N);
6633 for (int i=0; i<N && maxNum > 0; i++) {
6634 TaskRecord tr = mRecentTasks.get(i);
6635 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6636 || (tr.intent == null)
6637 || ((tr.intent.getFlags()
6638 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6639 ActivityManager.RecentTaskInfo rti
6640 = new ActivityManager.RecentTaskInfo();
6641 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6642 rti.baseIntent = new Intent(
6643 tr.intent != null ? tr.intent : tr.affinityIntent);
6644 rti.origActivity = tr.origActivity;
6645 res.add(rti);
6646 maxNum--;
6647 }
6648 }
6649 return res;
6650 }
6651 }
6652
6653 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6654 int j;
6655 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6656 TaskRecord jt = startTask;
6657
6658 // First look backwards
6659 for (j=startIndex-1; j>=0; j--) {
6660 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6661 if (r.task != jt) {
6662 jt = r.task;
6663 if (affinity.equals(jt.affinity)) {
6664 return j;
6665 }
6666 }
6667 }
6668
6669 // Now look forwards
6670 final int N = mHistory.size();
6671 jt = startTask;
6672 for (j=startIndex+1; j<N; j++) {
6673 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6674 if (r.task != jt) {
6675 if (affinity.equals(jt.affinity)) {
6676 return j;
6677 }
6678 jt = r.task;
6679 }
6680 }
6681
6682 // Might it be at the top?
6683 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6684 return N-1;
6685 }
6686
6687 return -1;
6688 }
6689
6690 /**
6691 * Perform a reset of the given task, if needed as part of launching it.
6692 * Returns the new HistoryRecord at the top of the task.
6693 */
6694 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6695 HistoryRecord newActivity) {
6696 boolean forceReset = (newActivity.info.flags
6697 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6698 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6699 if ((newActivity.info.flags
6700 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6701 forceReset = true;
6702 }
6703 }
6704
6705 final TaskRecord task = taskTop.task;
6706
6707 // We are going to move through the history list so that we can look
6708 // at each activity 'target' with 'below' either the interesting
6709 // activity immediately below it in the stack or null.
6710 HistoryRecord target = null;
6711 int targetI = 0;
6712 int taskTopI = -1;
6713 int replyChainEnd = -1;
6714 int lastReparentPos = -1;
6715 for (int i=mHistory.size()-1; i>=-1; i--) {
6716 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6717
6718 if (below != null && below.finishing) {
6719 continue;
6720 }
6721 if (target == null) {
6722 target = below;
6723 targetI = i;
6724 // If we were in the middle of a reply chain before this
6725 // task, it doesn't appear like the root of the chain wants
6726 // anything interesting, so drop it.
6727 replyChainEnd = -1;
6728 continue;
6729 }
6730
6731 final int flags = target.info.flags;
6732
6733 final boolean finishOnTaskLaunch =
6734 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6735 final boolean allowTaskReparenting =
6736 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6737
6738 if (target.task == task) {
6739 // We are inside of the task being reset... we'll either
6740 // finish this activity, push it out for another task,
6741 // or leave it as-is. We only do this
6742 // for activities that are not the root of the task (since
6743 // if we finish the root, we may no longer have the task!).
6744 if (taskTopI < 0) {
6745 taskTopI = targetI;
6746 }
6747 if (below != null && below.task == task) {
6748 final boolean clearWhenTaskReset =
6749 (target.intent.getFlags()
6750 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006751 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006752 // If this activity is sending a reply to a previous
6753 // activity, we can't do anything with it now until
6754 // we reach the start of the reply chain.
6755 // XXX note that we are assuming the result is always
6756 // to the previous activity, which is almost always
6757 // the case but we really shouldn't count on.
6758 if (replyChainEnd < 0) {
6759 replyChainEnd = targetI;
6760 }
Ed Heyl73798232009-03-24 21:32:21 -07006761 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006762 && target.taskAffinity != null
6763 && !target.taskAffinity.equals(task.affinity)) {
6764 // If this activity has an affinity for another
6765 // task, then we need to move it out of here. We will
6766 // move it as far out of the way as possible, to the
6767 // bottom of the activity stack. This also keeps it
6768 // correctly ordered with any activities we previously
6769 // moved.
6770 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6771 if (target.taskAffinity != null
6772 && target.taskAffinity.equals(p.task.affinity)) {
6773 // If the activity currently at the bottom has the
6774 // same task affinity as the one we are moving,
6775 // then merge it into the same task.
6776 target.task = p.task;
6777 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6778 + " out to bottom task " + p.task);
6779 } else {
6780 mCurTask++;
6781 if (mCurTask <= 0) {
6782 mCurTask = 1;
6783 }
6784 target.task = new TaskRecord(mCurTask, target.info, null,
6785 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6786 target.task.affinityIntent = target.intent;
6787 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6788 + " out to new task " + target.task);
6789 }
6790 mWindowManager.setAppGroupId(target, task.taskId);
6791 if (replyChainEnd < 0) {
6792 replyChainEnd = targetI;
6793 }
6794 int dstPos = 0;
6795 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6796 p = (HistoryRecord)mHistory.get(srcPos);
6797 if (p.finishing) {
6798 continue;
6799 }
6800 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6801 + " out to target's task " + target.task);
6802 task.numActivities--;
6803 p.task = target.task;
6804 target.task.numActivities++;
6805 mHistory.remove(srcPos);
6806 mHistory.add(dstPos, p);
6807 mWindowManager.moveAppToken(dstPos, p);
6808 mWindowManager.setAppGroupId(p, p.task.taskId);
6809 dstPos++;
6810 if (VALIDATE_TOKENS) {
6811 mWindowManager.validateAppTokens(mHistory);
6812 }
6813 i++;
6814 }
6815 if (taskTop == p) {
6816 taskTop = below;
6817 }
6818 if (taskTopI == replyChainEnd) {
6819 taskTopI = -1;
6820 }
6821 replyChainEnd = -1;
6822 addRecentTask(target.task);
6823 } else if (forceReset || finishOnTaskLaunch
6824 || clearWhenTaskReset) {
6825 // If the activity should just be removed -- either
6826 // because it asks for it, or the task should be
6827 // cleared -- then finish it and anything that is
6828 // part of its reply chain.
6829 if (clearWhenTaskReset) {
6830 // In this case, we want to finish this activity
6831 // and everything above it, so be sneaky and pretend
6832 // like these are all in the reply chain.
6833 replyChainEnd = targetI+1;
6834 while (replyChainEnd < mHistory.size() &&
6835 ((HistoryRecord)mHistory.get(
6836 replyChainEnd)).task == task) {
6837 replyChainEnd++;
6838 }
6839 replyChainEnd--;
6840 } else if (replyChainEnd < 0) {
6841 replyChainEnd = targetI;
6842 }
6843 HistoryRecord p = null;
6844 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6845 p = (HistoryRecord)mHistory.get(srcPos);
6846 if (p.finishing) {
6847 continue;
6848 }
6849 if (finishActivityLocked(p, srcPos,
6850 Activity.RESULT_CANCELED, null, "reset")) {
6851 replyChainEnd--;
6852 srcPos--;
6853 }
6854 }
6855 if (taskTop == p) {
6856 taskTop = below;
6857 }
6858 if (taskTopI == replyChainEnd) {
6859 taskTopI = -1;
6860 }
6861 replyChainEnd = -1;
6862 } else {
6863 // If we were in the middle of a chain, well the
6864 // activity that started it all doesn't want anything
6865 // special, so leave it all as-is.
6866 replyChainEnd = -1;
6867 }
6868 } else {
6869 // Reached the bottom of the task -- any reply chain
6870 // should be left as-is.
6871 replyChainEnd = -1;
6872 }
6873
6874 } else if (target.resultTo != null) {
6875 // If this activity is sending a reply to a previous
6876 // activity, we can't do anything with it now until
6877 // we reach the start of the reply chain.
6878 // XXX note that we are assuming the result is always
6879 // to the previous activity, which is almost always
6880 // the case but we really shouldn't count on.
6881 if (replyChainEnd < 0) {
6882 replyChainEnd = targetI;
6883 }
6884
6885 } else if (taskTopI >= 0 && allowTaskReparenting
6886 && task.affinity != null
6887 && task.affinity.equals(target.taskAffinity)) {
6888 // We are inside of another task... if this activity has
6889 // an affinity for our task, then either remove it if we are
6890 // clearing or move it over to our task. Note that
6891 // we currently punt on the case where we are resetting a
6892 // task that is not at the top but who has activities above
6893 // with an affinity to it... this is really not a normal
6894 // case, and we will need to later pull that task to the front
6895 // and usually at that point we will do the reset and pick
6896 // up those remaining activities. (This only happens if
6897 // someone starts an activity in a new task from an activity
6898 // in a task that is not currently on top.)
6899 if (forceReset || finishOnTaskLaunch) {
6900 if (replyChainEnd < 0) {
6901 replyChainEnd = targetI;
6902 }
6903 HistoryRecord p = null;
6904 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6905 p = (HistoryRecord)mHistory.get(srcPos);
6906 if (p.finishing) {
6907 continue;
6908 }
6909 if (finishActivityLocked(p, srcPos,
6910 Activity.RESULT_CANCELED, null, "reset")) {
6911 taskTopI--;
6912 lastReparentPos--;
6913 replyChainEnd--;
6914 srcPos--;
6915 }
6916 }
6917 replyChainEnd = -1;
6918 } else {
6919 if (replyChainEnd < 0) {
6920 replyChainEnd = targetI;
6921 }
6922 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6923 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6924 if (p.finishing) {
6925 continue;
6926 }
6927 if (lastReparentPos < 0) {
6928 lastReparentPos = taskTopI;
6929 taskTop = p;
6930 } else {
6931 lastReparentPos--;
6932 }
6933 mHistory.remove(srcPos);
6934 p.task.numActivities--;
6935 p.task = task;
6936 mHistory.add(lastReparentPos, p);
6937 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6938 + " in to resetting task " + task);
6939 task.numActivities++;
6940 mWindowManager.moveAppToken(lastReparentPos, p);
6941 mWindowManager.setAppGroupId(p, p.task.taskId);
6942 if (VALIDATE_TOKENS) {
6943 mWindowManager.validateAppTokens(mHistory);
6944 }
6945 }
6946 replyChainEnd = -1;
6947
6948 // Now we've moved it in to place... but what if this is
6949 // a singleTop activity and we have put it on top of another
6950 // instance of the same activity? Then we drop the instance
6951 // below so it remains singleTop.
6952 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6953 for (int j=lastReparentPos-1; j>=0; j--) {
6954 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6955 if (p.finishing) {
6956 continue;
6957 }
6958 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6959 if (finishActivityLocked(p, j,
6960 Activity.RESULT_CANCELED, null, "replace")) {
6961 taskTopI--;
6962 lastReparentPos--;
6963 }
6964 }
6965 }
6966 }
6967 }
6968 }
6969
6970 target = below;
6971 targetI = i;
6972 }
6973
6974 return taskTop;
6975 }
6976
6977 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006978 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006979 */
6980 public void moveTaskToFront(int task) {
6981 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6982 "moveTaskToFront()");
6983
6984 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006985 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6986 Binder.getCallingUid(), "Task to front")) {
6987 return;
6988 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006989 final long origId = Binder.clearCallingIdentity();
6990 try {
6991 int N = mRecentTasks.size();
6992 for (int i=0; i<N; i++) {
6993 TaskRecord tr = mRecentTasks.get(i);
6994 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07006995 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006996 return;
6997 }
6998 }
6999 for (int i=mHistory.size()-1; i>=0; i--) {
7000 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
7001 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007002 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007003 return;
7004 }
7005 }
7006 } finally {
7007 Binder.restoreCallingIdentity(origId);
7008 }
7009 }
7010 }
7011
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007012 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007013 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7014
7015 final int task = tr.taskId;
7016 int top = mHistory.size()-1;
7017
7018 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7019 // nothing to do!
7020 return;
7021 }
7022
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007023 ArrayList moved = new ArrayList();
7024
7025 // Applying the affinities may have removed entries from the history,
7026 // so get the size again.
7027 top = mHistory.size()-1;
7028 int pos = top;
7029
7030 // Shift all activities with this task up to the top
7031 // of the stack, keeping them in the same internal order.
7032 while (pos >= 0) {
7033 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7034 if (localLOGV) Log.v(
7035 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7036 boolean first = true;
7037 if (r.task.taskId == task) {
7038 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7039 mHistory.remove(pos);
7040 mHistory.add(top, r);
7041 moved.add(0, r);
7042 top--;
7043 if (first) {
7044 addRecentTask(r.task);
7045 first = false;
7046 }
7047 }
7048 pos--;
7049 }
7050
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007051 if (DEBUG_TRANSITION) Log.v(TAG,
7052 "Prepare to front transition: task=" + tr);
7053 if (reason != null &&
7054 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7055 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7056 HistoryRecord r = topRunningActivityLocked(null);
7057 if (r != null) {
7058 mNoAnimActivities.add(r);
7059 }
7060 } else {
7061 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7062 }
7063
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007064 mWindowManager.moveAppTokensToTop(moved);
7065 if (VALIDATE_TOKENS) {
7066 mWindowManager.validateAppTokens(mHistory);
7067 }
7068
7069 finishTaskMove(task);
7070 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
7071 }
7072
7073 private final void finishTaskMove(int task) {
7074 resumeTopActivityLocked(null);
7075 }
7076
7077 public void moveTaskToBack(int task) {
7078 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7079 "moveTaskToBack()");
7080
7081 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007082 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7083 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7084 Binder.getCallingUid(), "Task to back")) {
7085 return;
7086 }
7087 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007088 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007089 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007090 Binder.restoreCallingIdentity(origId);
7091 }
7092 }
7093
7094 /**
7095 * Moves an activity, and all of the other activities within the same task, to the bottom
7096 * of the history stack. The activity's order within the task is unchanged.
7097 *
7098 * @param token A reference to the activity we wish to move
7099 * @param nonRoot If false then this only works if the activity is the root
7100 * of a task; if true it will work for any activity in a task.
7101 * @return Returns true if the move completed, false if not.
7102 */
7103 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7104 synchronized(this) {
7105 final long origId = Binder.clearCallingIdentity();
7106 int taskId = getTaskForActivityLocked(token, !nonRoot);
7107 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007108 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007109 }
7110 Binder.restoreCallingIdentity(origId);
7111 }
7112 return false;
7113 }
7114
7115 /**
7116 * Worker method for rearranging history stack. Implements the function of moving all
7117 * activities for a specific task (gathering them if disjoint) into a single group at the
7118 * bottom of the stack.
7119 *
7120 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7121 * to premeptively cancel the move.
7122 *
7123 * @param task The taskId to collect and move to the bottom.
7124 * @return Returns true if the move completed, false if not.
7125 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007126 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007127 Log.i(TAG, "moveTaskToBack: " + task);
7128
7129 // If we have a watcher, preflight the move before committing to it. First check
7130 // for *other* available tasks, but if none are available, then try again allowing the
7131 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007132 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007133 HistoryRecord next = topRunningActivityLocked(null, task);
7134 if (next == null) {
7135 next = topRunningActivityLocked(null, 0);
7136 }
7137 if (next != null) {
7138 // ask watcher if this is allowed
7139 boolean moveOK = true;
7140 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007141 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007142 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007143 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007144 }
7145 if (!moveOK) {
7146 return false;
7147 }
7148 }
7149 }
7150
7151 ArrayList moved = new ArrayList();
7152
7153 if (DEBUG_TRANSITION) Log.v(TAG,
7154 "Prepare to back transition: task=" + task);
7155 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
7156
7157 final int N = mHistory.size();
7158 int bottom = 0;
7159 int pos = 0;
7160
7161 // Shift all activities with this task down to the bottom
7162 // of the stack, keeping them in the same internal order.
7163 while (pos < N) {
7164 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7165 if (localLOGV) Log.v(
7166 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7167 if (r.task.taskId == task) {
7168 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7169 mHistory.remove(pos);
7170 mHistory.add(bottom, r);
7171 moved.add(r);
7172 bottom++;
7173 }
7174 pos++;
7175 }
7176
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007177 if (reason != null &&
7178 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7179 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7180 HistoryRecord r = topRunningActivityLocked(null);
7181 if (r != null) {
7182 mNoAnimActivities.add(r);
7183 }
7184 } else {
7185 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7186 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007187 mWindowManager.moveAppTokensToBottom(moved);
7188 if (VALIDATE_TOKENS) {
7189 mWindowManager.validateAppTokens(mHistory);
7190 }
7191
7192 finishTaskMove(task);
7193 return true;
7194 }
7195
7196 public void moveTaskBackwards(int task) {
7197 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7198 "moveTaskBackwards()");
7199
7200 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007201 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7202 Binder.getCallingUid(), "Task backwards")) {
7203 return;
7204 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007205 final long origId = Binder.clearCallingIdentity();
7206 moveTaskBackwardsLocked(task);
7207 Binder.restoreCallingIdentity(origId);
7208 }
7209 }
7210
7211 private final void moveTaskBackwardsLocked(int task) {
7212 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7213 }
7214
7215 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7216 synchronized(this) {
7217 return getTaskForActivityLocked(token, onlyRoot);
7218 }
7219 }
7220
7221 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7222 final int N = mHistory.size();
7223 TaskRecord lastTask = null;
7224 for (int i=0; i<N; i++) {
7225 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7226 if (r == token) {
7227 if (!onlyRoot || lastTask != r.task) {
7228 return r.task.taskId;
7229 }
7230 return -1;
7231 }
7232 lastTask = r.task;
7233 }
7234
7235 return -1;
7236 }
7237
7238 /**
7239 * Returns the top activity in any existing task matching the given
7240 * Intent. Returns null if no such task is found.
7241 */
7242 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7243 ComponentName cls = intent.getComponent();
7244 if (info.targetActivity != null) {
7245 cls = new ComponentName(info.packageName, info.targetActivity);
7246 }
7247
7248 TaskRecord cp = null;
7249
7250 final int N = mHistory.size();
7251 for (int i=(N-1); i>=0; i--) {
7252 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7253 if (!r.finishing && r.task != cp
7254 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7255 cp = r.task;
7256 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7257 // + "/aff=" + r.task.affinity + " to new cls="
7258 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7259 if (r.task.affinity != null) {
7260 if (r.task.affinity.equals(info.taskAffinity)) {
7261 //Log.i(TAG, "Found matching affinity!");
7262 return r;
7263 }
7264 } else if (r.task.intent != null
7265 && r.task.intent.getComponent().equals(cls)) {
7266 //Log.i(TAG, "Found matching class!");
7267 //dump();
7268 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7269 return r;
7270 } else if (r.task.affinityIntent != null
7271 && r.task.affinityIntent.getComponent().equals(cls)) {
7272 //Log.i(TAG, "Found matching class!");
7273 //dump();
7274 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7275 return r;
7276 }
7277 }
7278 }
7279
7280 return null;
7281 }
7282
7283 /**
7284 * Returns the first activity (starting from the top of the stack) that
7285 * is the same as the given activity. Returns null if no such activity
7286 * is found.
7287 */
7288 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7289 ComponentName cls = intent.getComponent();
7290 if (info.targetActivity != null) {
7291 cls = new ComponentName(info.packageName, info.targetActivity);
7292 }
7293
7294 final int N = mHistory.size();
7295 for (int i=(N-1); i>=0; i--) {
7296 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7297 if (!r.finishing) {
7298 if (r.intent.getComponent().equals(cls)) {
7299 //Log.i(TAG, "Found matching class!");
7300 //dump();
7301 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7302 return r;
7303 }
7304 }
7305 }
7306
7307 return null;
7308 }
7309
7310 public void finishOtherInstances(IBinder token, ComponentName className) {
7311 synchronized(this) {
7312 final long origId = Binder.clearCallingIdentity();
7313
7314 int N = mHistory.size();
7315 TaskRecord lastTask = null;
7316 for (int i=0; i<N; i++) {
7317 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7318 if (r.realActivity.equals(className)
7319 && r != token && lastTask != r.task) {
7320 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7321 null, "others")) {
7322 i--;
7323 N--;
7324 }
7325 }
7326 lastTask = r.task;
7327 }
7328
7329 Binder.restoreCallingIdentity(origId);
7330 }
7331 }
7332
7333 // =========================================================
7334 // THUMBNAILS
7335 // =========================================================
7336
7337 public void reportThumbnail(IBinder token,
7338 Bitmap thumbnail, CharSequence description) {
7339 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7340 final long origId = Binder.clearCallingIdentity();
7341 sendPendingThumbnail(null, token, thumbnail, description, true);
7342 Binder.restoreCallingIdentity(origId);
7343 }
7344
7345 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7346 Bitmap thumbnail, CharSequence description, boolean always) {
7347 TaskRecord task = null;
7348 ArrayList receivers = null;
7349
7350 //System.out.println("Send pending thumbnail: " + r);
7351
7352 synchronized(this) {
7353 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007354 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007355 if (index < 0) {
7356 return;
7357 }
7358 r = (HistoryRecord)mHistory.get(index);
7359 }
7360 if (thumbnail == null) {
7361 thumbnail = r.thumbnail;
7362 description = r.description;
7363 }
7364 if (thumbnail == null && !always) {
7365 // If there is no thumbnail, and this entry is not actually
7366 // going away, then abort for now and pick up the next
7367 // thumbnail we get.
7368 return;
7369 }
7370 task = r.task;
7371
7372 int N = mPendingThumbnails.size();
7373 int i=0;
7374 while (i<N) {
7375 PendingThumbnailsRecord pr =
7376 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7377 //System.out.println("Looking in " + pr.pendingRecords);
7378 if (pr.pendingRecords.remove(r)) {
7379 if (receivers == null) {
7380 receivers = new ArrayList();
7381 }
7382 receivers.add(pr);
7383 if (pr.pendingRecords.size() == 0) {
7384 pr.finished = true;
7385 mPendingThumbnails.remove(i);
7386 N--;
7387 continue;
7388 }
7389 }
7390 i++;
7391 }
7392 }
7393
7394 if (receivers != null) {
7395 final int N = receivers.size();
7396 for (int i=0; i<N; i++) {
7397 try {
7398 PendingThumbnailsRecord pr =
7399 (PendingThumbnailsRecord)receivers.get(i);
7400 pr.receiver.newThumbnail(
7401 task != null ? task.taskId : -1, thumbnail, description);
7402 if (pr.finished) {
7403 pr.receiver.finished();
7404 }
7405 } catch (Exception e) {
7406 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7407 }
7408 }
7409 }
7410 }
7411
7412 // =========================================================
7413 // CONTENT PROVIDERS
7414 // =========================================================
7415
7416 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7417 List providers = null;
7418 try {
7419 providers = ActivityThread.getPackageManager().
7420 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007421 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007422 } catch (RemoteException ex) {
7423 }
7424 if (providers != null) {
7425 final int N = providers.size();
7426 for (int i=0; i<N; i++) {
7427 ProviderInfo cpi =
7428 (ProviderInfo)providers.get(i);
7429 ContentProviderRecord cpr =
7430 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7431 if (cpr == null) {
7432 cpr = new ContentProviderRecord(cpi, app.info);
7433 mProvidersByClass.put(cpi.name, cpr);
7434 }
7435 app.pubProviders.put(cpi.name, cpr);
7436 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007437 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007438 }
7439 }
7440 return providers;
7441 }
7442
7443 private final String checkContentProviderPermissionLocked(
7444 ProviderInfo cpi, ProcessRecord r, int mode) {
7445 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7446 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7447 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7448 cpi.exported ? -1 : cpi.applicationInfo.uid)
7449 == PackageManager.PERMISSION_GRANTED
7450 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7451 return null;
7452 }
7453 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7454 cpi.exported ? -1 : cpi.applicationInfo.uid)
7455 == PackageManager.PERMISSION_GRANTED) {
7456 return null;
7457 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007458
7459 PathPermission[] pps = cpi.pathPermissions;
7460 if (pps != null) {
7461 int i = pps.length;
7462 while (i > 0) {
7463 i--;
7464 PathPermission pp = pps[i];
7465 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7466 cpi.exported ? -1 : cpi.applicationInfo.uid)
7467 == PackageManager.PERMISSION_GRANTED
7468 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7469 return null;
7470 }
7471 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7472 cpi.exported ? -1 : cpi.applicationInfo.uid)
7473 == PackageManager.PERMISSION_GRANTED) {
7474 return null;
7475 }
7476 }
7477 }
7478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007479 String msg = "Permission Denial: opening provider " + cpi.name
7480 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7481 + ", uid=" + callingUid + ") requires "
7482 + cpi.readPermission + " or " + cpi.writePermission;
7483 Log.w(TAG, msg);
7484 return msg;
7485 }
7486
7487 private final ContentProviderHolder getContentProviderImpl(
7488 IApplicationThread caller, String name) {
7489 ContentProviderRecord cpr;
7490 ProviderInfo cpi = null;
7491
7492 synchronized(this) {
7493 ProcessRecord r = null;
7494 if (caller != null) {
7495 r = getRecordForAppLocked(caller);
7496 if (r == null) {
7497 throw new SecurityException(
7498 "Unable to find app for caller " + caller
7499 + " (pid=" + Binder.getCallingPid()
7500 + ") when getting content provider " + name);
7501 }
7502 }
7503
7504 // First check if this content provider has been published...
7505 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7506 if (cpr != null) {
7507 cpi = cpr.info;
7508 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7509 return new ContentProviderHolder(cpi,
7510 cpi.readPermission != null
7511 ? cpi.readPermission : cpi.writePermission);
7512 }
7513
7514 if (r != null && cpr.canRunHere(r)) {
7515 // This provider has been published or is in the process
7516 // of being published... but it is also allowed to run
7517 // in the caller's process, so don't make a connection
7518 // and just let the caller instantiate its own instance.
7519 if (cpr.provider != null) {
7520 // don't give caller the provider object, it needs
7521 // to make its own.
7522 cpr = new ContentProviderRecord(cpr);
7523 }
7524 return cpr;
7525 }
7526
7527 final long origId = Binder.clearCallingIdentity();
7528
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007529 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007530 // return it right away.
7531 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007532 if (DEBUG_PROVIDER) Log.v(TAG,
7533 "Adding provider requested by "
7534 + r.processName + " from process "
7535 + cpr.info.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007536 r.conProviders.add(cpr);
7537 cpr.clients.add(r);
7538 } else {
7539 cpr.externals++;
7540 }
7541
7542 if (cpr.app != null) {
7543 updateOomAdjLocked(cpr.app);
7544 }
7545
7546 Binder.restoreCallingIdentity(origId);
7547
7548 } else {
7549 try {
7550 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007551 resolveContentProvider(name,
7552 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007553 } catch (RemoteException ex) {
7554 }
7555 if (cpi == null) {
7556 return null;
7557 }
7558
7559 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7560 return new ContentProviderHolder(cpi,
7561 cpi.readPermission != null
7562 ? cpi.readPermission : cpi.writePermission);
7563 }
7564
7565 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7566 final boolean firstClass = cpr == null;
7567 if (firstClass) {
7568 try {
7569 ApplicationInfo ai =
7570 ActivityThread.getPackageManager().
7571 getApplicationInfo(
7572 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007573 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007574 if (ai == null) {
7575 Log.w(TAG, "No package info for content provider "
7576 + cpi.name);
7577 return null;
7578 }
7579 cpr = new ContentProviderRecord(cpi, ai);
7580 } catch (RemoteException ex) {
7581 // pm is in same process, this will never happen.
7582 }
7583 }
7584
7585 if (r != null && cpr.canRunHere(r)) {
7586 // If this is a multiprocess provider, then just return its
7587 // info and allow the caller to instantiate it. Only do
7588 // this if the provider is the same user as the caller's
7589 // process, or can run as root (so can be in any process).
7590 return cpr;
7591 }
7592
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007593 if (DEBUG_PROVIDER) {
7594 RuntimeException e = new RuntimeException("here");
7595 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7596 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007597 }
7598
7599 // This is single process, and our app is now connecting to it.
7600 // See if we are already in the process of launching this
7601 // provider.
7602 final int N = mLaunchingProviders.size();
7603 int i;
7604 for (i=0; i<N; i++) {
7605 if (mLaunchingProviders.get(i) == cpr) {
7606 break;
7607 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007608 }
7609
7610 // If the provider is not already being launched, then get it
7611 // started.
7612 if (i >= N) {
7613 final long origId = Binder.clearCallingIdentity();
7614 ProcessRecord proc = startProcessLocked(cpi.processName,
7615 cpr.appInfo, false, 0, "content provider",
7616 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007617 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007618 if (proc == null) {
7619 Log.w(TAG, "Unable to launch app "
7620 + cpi.applicationInfo.packageName + "/"
7621 + cpi.applicationInfo.uid + " for provider "
7622 + name + ": process is bad");
7623 return null;
7624 }
7625 cpr.launchingApp = proc;
7626 mLaunchingProviders.add(cpr);
7627 Binder.restoreCallingIdentity(origId);
7628 }
7629
7630 // Make sure the provider is published (the same provider class
7631 // may be published under multiple names).
7632 if (firstClass) {
7633 mProvidersByClass.put(cpi.name, cpr);
7634 }
7635 mProvidersByName.put(name, cpr);
7636
7637 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007638 if (DEBUG_PROVIDER) Log.v(TAG,
7639 "Adding provider requested by "
7640 + r.processName + " from process "
7641 + cpr.info.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007642 r.conProviders.add(cpr);
7643 cpr.clients.add(r);
7644 } else {
7645 cpr.externals++;
7646 }
7647 }
7648 }
7649
7650 // Wait for the provider to be published...
7651 synchronized (cpr) {
7652 while (cpr.provider == null) {
7653 if (cpr.launchingApp == null) {
7654 Log.w(TAG, "Unable to launch app "
7655 + cpi.applicationInfo.packageName + "/"
7656 + cpi.applicationInfo.uid + " for provider "
7657 + name + ": launching app became null");
7658 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7659 cpi.applicationInfo.packageName,
7660 cpi.applicationInfo.uid, name);
7661 return null;
7662 }
7663 try {
7664 cpr.wait();
7665 } catch (InterruptedException ex) {
7666 }
7667 }
7668 }
7669 return cpr;
7670 }
7671
7672 public final ContentProviderHolder getContentProvider(
7673 IApplicationThread caller, String name) {
7674 if (caller == null) {
7675 String msg = "null IApplicationThread when getting content provider "
7676 + name;
7677 Log.w(TAG, msg);
7678 throw new SecurityException(msg);
7679 }
7680
7681 return getContentProviderImpl(caller, name);
7682 }
7683
7684 private ContentProviderHolder getContentProviderExternal(String name) {
7685 return getContentProviderImpl(null, name);
7686 }
7687
7688 /**
7689 * Drop a content provider from a ProcessRecord's bookkeeping
7690 * @param cpr
7691 */
7692 public void removeContentProvider(IApplicationThread caller, String name) {
7693 synchronized (this) {
7694 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7695 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007696 // remove from mProvidersByClass
7697 if (DEBUG_PROVIDER) Log.v(TAG, name +
7698 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007699 return;
7700 }
7701 final ProcessRecord r = getRecordForAppLocked(caller);
7702 if (r == null) {
7703 throw new SecurityException(
7704 "Unable to find app for caller " + caller +
7705 " when removing content provider " + name);
7706 }
7707 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007708 ContentProviderRecord localCpr = (ContentProviderRecord)
7709 mProvidersByClass.get(cpr.info.name);
7710 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7711 + r.info.processName + " from process "
7712 + localCpr.appInfo.processName);
7713 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007714 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007715 Log.w(TAG, "removeContentProvider called on local provider: "
7716 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007717 return;
7718 } else {
7719 localCpr.clients.remove(r);
7720 r.conProviders.remove(localCpr);
7721 }
7722 updateOomAdjLocked();
7723 }
7724 }
7725
7726 private void removeContentProviderExternal(String name) {
7727 synchronized (this) {
7728 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7729 if(cpr == null) {
7730 //remove from mProvidersByClass
7731 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7732 return;
7733 }
7734
7735 //update content provider record entry info
7736 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7737 localCpr.externals--;
7738 if (localCpr.externals < 0) {
7739 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7740 }
7741 updateOomAdjLocked();
7742 }
7743 }
7744
7745 public final void publishContentProviders(IApplicationThread caller,
7746 List<ContentProviderHolder> providers) {
7747 if (providers == null) {
7748 return;
7749 }
7750
7751 synchronized(this) {
7752 final ProcessRecord r = getRecordForAppLocked(caller);
7753 if (r == null) {
7754 throw new SecurityException(
7755 "Unable to find app for caller " + caller
7756 + " (pid=" + Binder.getCallingPid()
7757 + ") when publishing content providers");
7758 }
7759
7760 final long origId = Binder.clearCallingIdentity();
7761
7762 final int N = providers.size();
7763 for (int i=0; i<N; i++) {
7764 ContentProviderHolder src = providers.get(i);
7765 if (src == null || src.info == null || src.provider == null) {
7766 continue;
7767 }
7768 ContentProviderRecord dst =
7769 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7770 if (dst != null) {
7771 mProvidersByClass.put(dst.info.name, dst);
7772 String names[] = dst.info.authority.split(";");
7773 for (int j = 0; j < names.length; j++) {
7774 mProvidersByName.put(names[j], dst);
7775 }
7776
7777 int NL = mLaunchingProviders.size();
7778 int j;
7779 for (j=0; j<NL; j++) {
7780 if (mLaunchingProviders.get(j) == dst) {
7781 mLaunchingProviders.remove(j);
7782 j--;
7783 NL--;
7784 }
7785 }
7786 synchronized (dst) {
7787 dst.provider = src.provider;
7788 dst.app = r;
7789 dst.notifyAll();
7790 }
7791 updateOomAdjLocked(r);
7792 }
7793 }
7794
7795 Binder.restoreCallingIdentity(origId);
7796 }
7797 }
7798
7799 public static final void installSystemProviders() {
7800 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7801 List providers = mSelf.generateApplicationProvidersLocked(app);
7802 mSystemThread.installSystemProviders(providers);
7803 }
7804
7805 // =========================================================
7806 // GLOBAL MANAGEMENT
7807 // =========================================================
7808
7809 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7810 ApplicationInfo info, String customProcess) {
7811 String proc = customProcess != null ? customProcess : info.processName;
7812 BatteryStatsImpl.Uid.Proc ps = null;
7813 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7814 synchronized (stats) {
7815 ps = stats.getProcessStatsLocked(info.uid, proc);
7816 }
7817 return new ProcessRecord(ps, thread, info, proc);
7818 }
7819
7820 final ProcessRecord addAppLocked(ApplicationInfo info) {
7821 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7822
7823 if (app == null) {
7824 app = newProcessRecordLocked(null, info, null);
7825 mProcessNames.put(info.processName, info.uid, app);
7826 updateLRUListLocked(app, true);
7827 }
7828
7829 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7830 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7831 app.persistent = true;
7832 app.maxAdj = CORE_SERVER_ADJ;
7833 }
7834 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7835 mPersistentStartingProcesses.add(app);
7836 startProcessLocked(app, "added application", app.processName);
7837 }
7838
7839 return app;
7840 }
7841
7842 public void unhandledBack() {
7843 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7844 "unhandledBack()");
7845
7846 synchronized(this) {
7847 int count = mHistory.size();
7848 if (Config.LOGD) Log.d(
7849 TAG, "Performing unhandledBack(): stack size = " + count);
7850 if (count > 1) {
7851 final long origId = Binder.clearCallingIdentity();
7852 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7853 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7854 Binder.restoreCallingIdentity(origId);
7855 }
7856 }
7857 }
7858
7859 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7860 String name = uri.getAuthority();
7861 ContentProviderHolder cph = getContentProviderExternal(name);
7862 ParcelFileDescriptor pfd = null;
7863 if (cph != null) {
7864 // We record the binder invoker's uid in thread-local storage before
7865 // going to the content provider to open the file. Later, in the code
7866 // that handles all permissions checks, we look for this uid and use
7867 // that rather than the Activity Manager's own uid. The effect is that
7868 // we do the check against the caller's permissions even though it looks
7869 // to the content provider like the Activity Manager itself is making
7870 // the request.
7871 sCallerIdentity.set(new Identity(
7872 Binder.getCallingPid(), Binder.getCallingUid()));
7873 try {
7874 pfd = cph.provider.openFile(uri, "r");
7875 } catch (FileNotFoundException e) {
7876 // do nothing; pfd will be returned null
7877 } finally {
7878 // Ensure that whatever happens, we clean up the identity state
7879 sCallerIdentity.remove();
7880 }
7881
7882 // We've got the fd now, so we're done with the provider.
7883 removeContentProviderExternal(name);
7884 } else {
7885 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7886 }
7887 return pfd;
7888 }
7889
7890 public void goingToSleep() {
7891 synchronized(this) {
7892 mSleeping = true;
7893 mWindowManager.setEventDispatching(false);
7894
7895 if (mResumedActivity != null) {
7896 pauseIfSleepingLocked();
7897 } else {
7898 Log.w(TAG, "goingToSleep with no resumed activity!");
7899 }
7900 }
7901 }
7902
Dianne Hackborn55280a92009-05-07 15:53:46 -07007903 public boolean shutdown(int timeout) {
7904 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7905 != PackageManager.PERMISSION_GRANTED) {
7906 throw new SecurityException("Requires permission "
7907 + android.Manifest.permission.SHUTDOWN);
7908 }
7909
7910 boolean timedout = false;
7911
7912 synchronized(this) {
7913 mShuttingDown = true;
7914 mWindowManager.setEventDispatching(false);
7915
7916 if (mResumedActivity != null) {
7917 pauseIfSleepingLocked();
7918 final long endTime = System.currentTimeMillis() + timeout;
7919 while (mResumedActivity != null || mPausingActivity != null) {
7920 long delay = endTime - System.currentTimeMillis();
7921 if (delay <= 0) {
7922 Log.w(TAG, "Activity manager shutdown timed out");
7923 timedout = true;
7924 break;
7925 }
7926 try {
7927 this.wait();
7928 } catch (InterruptedException e) {
7929 }
7930 }
7931 }
7932 }
7933
7934 mUsageStatsService.shutdown();
7935 mBatteryStatsService.shutdown();
7936
7937 return timedout;
7938 }
7939
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007940 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007941 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007942 if (!mGoingToSleep.isHeld()) {
7943 mGoingToSleep.acquire();
7944 if (mLaunchingActivity.isHeld()) {
7945 mLaunchingActivity.release();
7946 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7947 }
7948 }
7949
7950 // If we are not currently pausing an activity, get the current
7951 // one to pause. If we are pausing one, we will just let that stuff
7952 // run and release the wake lock when all done.
7953 if (mPausingActivity == null) {
7954 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7955 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7956 startPausingLocked(false, true);
7957 }
7958 }
7959 }
7960
7961 public void wakingUp() {
7962 synchronized(this) {
7963 if (mGoingToSleep.isHeld()) {
7964 mGoingToSleep.release();
7965 }
7966 mWindowManager.setEventDispatching(true);
7967 mSleeping = false;
7968 resumeTopActivityLocked(null);
7969 }
7970 }
7971
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007972 public void stopAppSwitches() {
7973 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7974 != PackageManager.PERMISSION_GRANTED) {
7975 throw new SecurityException("Requires permission "
7976 + android.Manifest.permission.STOP_APP_SWITCHES);
7977 }
7978
7979 synchronized(this) {
7980 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7981 + APP_SWITCH_DELAY_TIME;
7982 mDidAppSwitch = false;
7983 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7984 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7985 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7986 }
7987 }
7988
7989 public void resumeAppSwitches() {
7990 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7991 != PackageManager.PERMISSION_GRANTED) {
7992 throw new SecurityException("Requires permission "
7993 + android.Manifest.permission.STOP_APP_SWITCHES);
7994 }
7995
7996 synchronized(this) {
7997 // Note that we don't execute any pending app switches... we will
7998 // let those wait until either the timeout, or the next start
7999 // activity request.
8000 mAppSwitchesAllowedTime = 0;
8001 }
8002 }
8003
8004 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8005 String name) {
8006 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8007 return true;
8008 }
8009
8010 final int perm = checkComponentPermission(
8011 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8012 callingUid, -1);
8013 if (perm == PackageManager.PERMISSION_GRANTED) {
8014 return true;
8015 }
8016
8017 Log.w(TAG, name + " request from " + callingUid + " stopped");
8018 return false;
8019 }
8020
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008021 public void setDebugApp(String packageName, boolean waitForDebugger,
8022 boolean persistent) {
8023 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8024 "setDebugApp()");
8025
8026 // Note that this is not really thread safe if there are multiple
8027 // callers into it at the same time, but that's not a situation we
8028 // care about.
8029 if (persistent) {
8030 final ContentResolver resolver = mContext.getContentResolver();
8031 Settings.System.putString(
8032 resolver, Settings.System.DEBUG_APP,
8033 packageName);
8034 Settings.System.putInt(
8035 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8036 waitForDebugger ? 1 : 0);
8037 }
8038
8039 synchronized (this) {
8040 if (!persistent) {
8041 mOrigDebugApp = mDebugApp;
8042 mOrigWaitForDebugger = mWaitForDebugger;
8043 }
8044 mDebugApp = packageName;
8045 mWaitForDebugger = waitForDebugger;
8046 mDebugTransient = !persistent;
8047 if (packageName != null) {
8048 final long origId = Binder.clearCallingIdentity();
8049 uninstallPackageLocked(packageName, -1, false);
8050 Binder.restoreCallingIdentity(origId);
8051 }
8052 }
8053 }
8054
8055 public void setAlwaysFinish(boolean enabled) {
8056 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8057 "setAlwaysFinish()");
8058
8059 Settings.System.putInt(
8060 mContext.getContentResolver(),
8061 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8062
8063 synchronized (this) {
8064 mAlwaysFinishActivities = enabled;
8065 }
8066 }
8067
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008068 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008069 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008070 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008071 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008072 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008073 }
8074 }
8075
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008076 public void registerActivityWatcher(IActivityWatcher watcher) {
8077 mWatchers.register(watcher);
8078 }
8079
8080 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8081 mWatchers.unregister(watcher);
8082 }
8083
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008084 public final void enterSafeMode() {
8085 synchronized(this) {
8086 // It only makes sense to do this before the system is ready
8087 // and started launching other packages.
8088 if (!mSystemReady) {
8089 try {
8090 ActivityThread.getPackageManager().enterSafeMode();
8091 } catch (RemoteException e) {
8092 }
8093
8094 View v = LayoutInflater.from(mContext).inflate(
8095 com.android.internal.R.layout.safe_mode, null);
8096 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8097 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8098 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8099 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8100 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8101 lp.format = v.getBackground().getOpacity();
8102 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8103 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8104 ((WindowManager)mContext.getSystemService(
8105 Context.WINDOW_SERVICE)).addView(v, lp);
8106 }
8107 }
8108 }
8109
8110 public void noteWakeupAlarm(IIntentSender sender) {
8111 if (!(sender instanceof PendingIntentRecord)) {
8112 return;
8113 }
8114 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8115 synchronized (stats) {
8116 if (mBatteryStatsService.isOnBattery()) {
8117 mBatteryStatsService.enforceCallingPermission();
8118 PendingIntentRecord rec = (PendingIntentRecord)sender;
8119 int MY_UID = Binder.getCallingUid();
8120 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8121 BatteryStatsImpl.Uid.Pkg pkg =
8122 stats.getPackageStatsLocked(uid, rec.key.packageName);
8123 pkg.incWakeupsLocked();
8124 }
8125 }
8126 }
8127
8128 public boolean killPidsForMemory(int[] pids) {
8129 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8130 throw new SecurityException("killPidsForMemory only available to the system");
8131 }
8132
8133 // XXX Note: don't acquire main activity lock here, because the window
8134 // manager calls in with its locks held.
8135
8136 boolean killed = false;
8137 synchronized (mPidsSelfLocked) {
8138 int[] types = new int[pids.length];
8139 int worstType = 0;
8140 for (int i=0; i<pids.length; i++) {
8141 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8142 if (proc != null) {
8143 int type = proc.setAdj;
8144 types[i] = type;
8145 if (type > worstType) {
8146 worstType = type;
8147 }
8148 }
8149 }
8150
8151 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8152 // then constrain it so we will kill all hidden procs.
8153 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8154 worstType = HIDDEN_APP_MIN_ADJ;
8155 }
8156 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8157 for (int i=0; i<pids.length; i++) {
8158 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8159 if (proc == null) {
8160 continue;
8161 }
8162 int adj = proc.setAdj;
8163 if (adj >= worstType) {
8164 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8165 + adj + ")");
8166 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
8167 proc.processName, adj);
8168 killed = true;
8169 Process.killProcess(pids[i]);
8170 }
8171 }
8172 }
8173 return killed;
8174 }
8175
8176 public void reportPss(IApplicationThread caller, int pss) {
8177 Watchdog.PssRequestor req;
8178 String name;
8179 ProcessRecord callerApp;
8180 synchronized (this) {
8181 if (caller == null) {
8182 return;
8183 }
8184 callerApp = getRecordForAppLocked(caller);
8185 if (callerApp == null) {
8186 return;
8187 }
8188 callerApp.lastPss = pss;
8189 req = callerApp;
8190 name = callerApp.processName;
8191 }
8192 Watchdog.getInstance().reportPss(req, name, pss);
8193 if (!callerApp.persistent) {
8194 removeRequestedPss(callerApp);
8195 }
8196 }
8197
8198 public void requestPss(Runnable completeCallback) {
8199 ArrayList<ProcessRecord> procs;
8200 synchronized (this) {
8201 mRequestPssCallback = completeCallback;
8202 mRequestPssList.clear();
8203 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8204 ProcessRecord proc = mLRUProcesses.get(i);
8205 if (!proc.persistent) {
8206 mRequestPssList.add(proc);
8207 }
8208 }
8209 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8210 }
8211
8212 int oldPri = Process.getThreadPriority(Process.myTid());
8213 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8214 for (int i=procs.size()-1; i>=0; i--) {
8215 ProcessRecord proc = procs.get(i);
8216 proc.lastPss = 0;
8217 proc.requestPss();
8218 }
8219 Process.setThreadPriority(oldPri);
8220 }
8221
8222 void removeRequestedPss(ProcessRecord proc) {
8223 Runnable callback = null;
8224 synchronized (this) {
8225 if (mRequestPssList.remove(proc)) {
8226 if (mRequestPssList.size() == 0) {
8227 callback = mRequestPssCallback;
8228 mRequestPssCallback = null;
8229 }
8230 }
8231 }
8232
8233 if (callback != null) {
8234 callback.run();
8235 }
8236 }
8237
8238 public void collectPss(Watchdog.PssStats stats) {
8239 stats.mEmptyPss = 0;
8240 stats.mEmptyCount = 0;
8241 stats.mBackgroundPss = 0;
8242 stats.mBackgroundCount = 0;
8243 stats.mServicePss = 0;
8244 stats.mServiceCount = 0;
8245 stats.mVisiblePss = 0;
8246 stats.mVisibleCount = 0;
8247 stats.mForegroundPss = 0;
8248 stats.mForegroundCount = 0;
8249 stats.mNoPssCount = 0;
8250 synchronized (this) {
8251 int i;
8252 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8253 ? mProcDeaths.length : stats.mProcDeaths.length;
8254 int aggr = 0;
8255 for (i=0; i<NPD; i++) {
8256 aggr += mProcDeaths[i];
8257 stats.mProcDeaths[i] = aggr;
8258 }
8259 while (i<stats.mProcDeaths.length) {
8260 stats.mProcDeaths[i] = 0;
8261 i++;
8262 }
8263
8264 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8265 ProcessRecord proc = mLRUProcesses.get(i);
8266 if (proc.persistent) {
8267 continue;
8268 }
8269 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8270 if (proc.lastPss == 0) {
8271 stats.mNoPssCount++;
8272 continue;
8273 }
8274 if (proc.setAdj == EMPTY_APP_ADJ) {
8275 stats.mEmptyPss += proc.lastPss;
8276 stats.mEmptyCount++;
8277 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8278 stats.mEmptyPss += proc.lastPss;
8279 stats.mEmptyCount++;
8280 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8281 stats.mBackgroundPss += proc.lastPss;
8282 stats.mBackgroundCount++;
8283 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8284 stats.mVisiblePss += proc.lastPss;
8285 stats.mVisibleCount++;
8286 } else {
8287 stats.mForegroundPss += proc.lastPss;
8288 stats.mForegroundCount++;
8289 }
8290 }
8291 }
8292 }
8293
8294 public final void startRunning(String pkg, String cls, String action,
8295 String data) {
8296 synchronized(this) {
8297 if (mStartRunning) {
8298 return;
8299 }
8300 mStartRunning = true;
8301 mTopComponent = pkg != null && cls != null
8302 ? new ComponentName(pkg, cls) : null;
8303 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8304 mTopData = data;
8305 if (!mSystemReady) {
8306 return;
8307 }
8308 }
8309
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008310 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008311 }
8312
8313 private void retrieveSettings() {
8314 final ContentResolver resolver = mContext.getContentResolver();
8315 String debugApp = Settings.System.getString(
8316 resolver, Settings.System.DEBUG_APP);
8317 boolean waitForDebugger = Settings.System.getInt(
8318 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8319 boolean alwaysFinishActivities = Settings.System.getInt(
8320 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8321
8322 Configuration configuration = new Configuration();
8323 Settings.System.getConfiguration(resolver, configuration);
8324
8325 synchronized (this) {
8326 mDebugApp = mOrigDebugApp = debugApp;
8327 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8328 mAlwaysFinishActivities = alwaysFinishActivities;
8329 // This happens before any activities are started, so we can
8330 // change mConfiguration in-place.
8331 mConfiguration.updateFrom(configuration);
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008332 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008333 }
8334 }
8335
8336 public boolean testIsSystemReady() {
8337 // no need to synchronize(this) just to read & return the value
8338 return mSystemReady;
8339 }
8340
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008341 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008342 // In the simulator, startRunning will never have been called, which
8343 // normally sets a few crucial variables. Do it here instead.
8344 if (!Process.supportsProcesses()) {
8345 mStartRunning = true;
8346 mTopAction = Intent.ACTION_MAIN;
8347 }
8348
8349 synchronized(this) {
8350 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008351 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008352 return;
8353 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008354
8355 // Check to see if there are any update receivers to run.
8356 if (!mDidUpdate) {
8357 if (mWaitingUpdate) {
8358 return;
8359 }
8360 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8361 List<ResolveInfo> ris = null;
8362 try {
8363 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8364 intent, null, 0);
8365 } catch (RemoteException e) {
8366 }
8367 if (ris != null) {
8368 for (int i=ris.size()-1; i>=0; i--) {
8369 if ((ris.get(i).activityInfo.applicationInfo.flags
8370 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8371 ris.remove(i);
8372 }
8373 }
8374 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8375 for (int i=0; i<ris.size(); i++) {
8376 ActivityInfo ai = ris.get(i).activityInfo;
8377 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8378 IIntentReceiver finisher = null;
8379 if (i == 0) {
8380 finisher = new IIntentReceiver.Stub() {
8381 public void performReceive(Intent intent, int resultCode,
8382 String data, Bundle extras, boolean ordered)
8383 throws RemoteException {
8384 synchronized (ActivityManagerService.this) {
8385 mDidUpdate = true;
8386 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008387 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008388 }
8389 };
8390 }
8391 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8392 broadcastIntentLocked(null, null, intent, null, finisher,
8393 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8394 if (i == 0) {
8395 mWaitingUpdate = true;
8396 }
8397 }
8398 }
8399 if (mWaitingUpdate) {
8400 return;
8401 }
8402 mDidUpdate = true;
8403 }
8404
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008405 mSystemReady = true;
8406 if (!mStartRunning) {
8407 return;
8408 }
8409 }
8410
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008411 ArrayList<ProcessRecord> procsToKill = null;
8412 synchronized(mPidsSelfLocked) {
8413 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8414 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8415 if (!isAllowedWhileBooting(proc.info)){
8416 if (procsToKill == null) {
8417 procsToKill = new ArrayList<ProcessRecord>();
8418 }
8419 procsToKill.add(proc);
8420 }
8421 }
8422 }
8423
8424 if (procsToKill != null) {
8425 synchronized(this) {
8426 for (int i=procsToKill.size()-1; i>=0; i--) {
8427 ProcessRecord proc = procsToKill.get(i);
8428 Log.i(TAG, "Removing system update proc: " + proc);
8429 removeProcessLocked(proc, true);
8430 }
8431 }
8432 }
8433
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008434 Log.i(TAG, "System now ready");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008435 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8436 SystemClock.uptimeMillis());
8437
8438 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008439 // Make sure we have no pre-ready processes sitting around.
8440
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008441 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8442 ResolveInfo ri = mContext.getPackageManager()
8443 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008444 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008445 CharSequence errorMsg = null;
8446 if (ri != null) {
8447 ActivityInfo ai = ri.activityInfo;
8448 ApplicationInfo app = ai.applicationInfo;
8449 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8450 mTopAction = Intent.ACTION_FACTORY_TEST;
8451 mTopData = null;
8452 mTopComponent = new ComponentName(app.packageName,
8453 ai.name);
8454 } else {
8455 errorMsg = mContext.getResources().getText(
8456 com.android.internal.R.string.factorytest_not_system);
8457 }
8458 } else {
8459 errorMsg = mContext.getResources().getText(
8460 com.android.internal.R.string.factorytest_no_action);
8461 }
8462 if (errorMsg != null) {
8463 mTopAction = null;
8464 mTopData = null;
8465 mTopComponent = null;
8466 Message msg = Message.obtain();
8467 msg.what = SHOW_FACTORY_ERROR_MSG;
8468 msg.getData().putCharSequence("msg", errorMsg);
8469 mHandler.sendMessage(msg);
8470 }
8471 }
8472 }
8473
8474 retrieveSettings();
8475
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008476 if (goingCallback != null) goingCallback.run();
8477
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008478 synchronized (this) {
8479 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8480 try {
8481 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008482 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008483 if (apps != null) {
8484 int N = apps.size();
8485 int i;
8486 for (i=0; i<N; i++) {
8487 ApplicationInfo info
8488 = (ApplicationInfo)apps.get(i);
8489 if (info != null &&
8490 !info.packageName.equals("android")) {
8491 addAppLocked(info);
8492 }
8493 }
8494 }
8495 } catch (RemoteException ex) {
8496 // pm is in same process, this will never happen.
8497 }
8498 }
8499
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008500 // Start up initial activity.
8501 mBooting = true;
8502
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008503 try {
8504 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8505 Message msg = Message.obtain();
8506 msg.what = SHOW_UID_ERROR_MSG;
8507 mHandler.sendMessage(msg);
8508 }
8509 } catch (RemoteException e) {
8510 }
8511
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008512 resumeTopActivityLocked(null);
8513 }
8514 }
8515
8516 boolean makeAppCrashingLocked(ProcessRecord app,
8517 String tag, String shortMsg, String longMsg, byte[] crashData) {
8518 app.crashing = true;
8519 app.crashingReport = generateProcessError(app,
8520 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8521 startAppProblemLocked(app);
8522 app.stopFreezingAllLocked();
8523 return handleAppCrashLocked(app);
8524 }
8525
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008526 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Jacek Surazskia2339432009-09-18 15:01:26 +02008527 // check if error reporting is enabled in Gservices
8528 int enabled = Settings.Gservices.getInt(mContext.getContentResolver(),
8529 Settings.Gservices.SEND_ACTION_APP_ERROR, 0);
8530 if (enabled == 0) {
8531 return null;
8532 }
8533
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008534 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008535
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008536 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008537 // look for receiver in the installer package
8538 String candidate = pm.getInstallerPackageName(app.info.packageName);
8539 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8540 if (result != null) {
8541 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008542 }
8543
Jacek Surazski82a73df2009-06-17 14:33:18 +02008544 // if the error app is on the system image, look for system apps
8545 // error receiver
8546 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8547 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8548 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8549 if (result != null) {
8550 return result;
8551 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008552 }
8553
Jacek Surazski82a73df2009-06-17 14:33:18 +02008554 // if there is a default receiver, try that
8555 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8556 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008557 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008558 // should not happen
8559 Log.e(TAG, "error talking to PackageManager", e);
8560 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008561 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008562 }
8563
8564 /**
8565 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8566 *
8567 * @param pm PackageManager isntance
8568 * @param errorPackage package which caused the error
8569 * @param receiverPackage candidate package to receive the error
8570 * @return activity component within receiverPackage which handles
8571 * ACTION_APP_ERROR, or null if not found
8572 */
8573 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8574 String receiverPackage) throws RemoteException {
8575 if (receiverPackage == null || receiverPackage.length() == 0) {
8576 return null;
8577 }
8578
8579 // break the loop if it's the error report receiver package that crashed
8580 if (receiverPackage.equals(errorPackage)) {
8581 return null;
8582 }
8583
8584 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8585 intent.setPackage(receiverPackage);
8586 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8587 if (info == null || info.activityInfo == null) {
8588 return null;
8589 }
8590 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008591 }
8592
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008593 void makeAppNotRespondingLocked(ProcessRecord app,
8594 String tag, String shortMsg, String longMsg, byte[] crashData) {
8595 app.notResponding = true;
8596 app.notRespondingReport = generateProcessError(app,
8597 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8598 crashData);
8599 startAppProblemLocked(app);
8600 app.stopFreezingAllLocked();
8601 }
8602
8603 /**
8604 * Generate a process error record, suitable for attachment to a ProcessRecord.
8605 *
8606 * @param app The ProcessRecord in which the error occurred.
8607 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8608 * ActivityManager.AppErrorStateInfo
8609 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8610 * @param shortMsg Short message describing the crash.
8611 * @param longMsg Long message describing the crash.
8612 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8613 *
8614 * @return Returns a fully-formed AppErrorStateInfo record.
8615 */
8616 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8617 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8618 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8619
8620 report.condition = condition;
8621 report.processName = app.processName;
8622 report.pid = app.pid;
8623 report.uid = app.info.uid;
8624 report.tag = tag;
8625 report.shortMsg = shortMsg;
8626 report.longMsg = longMsg;
8627 report.crashData = crashData;
8628
8629 return report;
8630 }
8631
8632 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8633 boolean crashed) {
8634 synchronized (this) {
8635 app.crashing = false;
8636 app.crashingReport = null;
8637 app.notResponding = false;
8638 app.notRespondingReport = null;
8639 if (app.anrDialog == fromDialog) {
8640 app.anrDialog = null;
8641 }
8642 if (app.waitDialog == fromDialog) {
8643 app.waitDialog = null;
8644 }
8645 if (app.pid > 0 && app.pid != MY_PID) {
8646 if (crashed) {
8647 handleAppCrashLocked(app);
8648 }
8649 Log.i(ActivityManagerService.TAG, "Killing process "
8650 + app.processName
8651 + " (pid=" + app.pid + ") at user's request");
8652 Process.killProcess(app.pid);
8653 }
8654
8655 }
8656 }
8657
8658 boolean handleAppCrashLocked(ProcessRecord app) {
8659 long now = SystemClock.uptimeMillis();
8660
8661 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8662 app.info.uid);
8663 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8664 // This process loses!
8665 Log.w(TAG, "Process " + app.info.processName
8666 + " has crashed too many times: killing!");
8667 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8668 app.info.processName, app.info.uid);
8669 killServicesLocked(app, false);
8670 for (int i=mHistory.size()-1; i>=0; i--) {
8671 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8672 if (r.app == app) {
8673 if (Config.LOGD) Log.d(
8674 TAG, " Force finishing activity "
8675 + r.intent.getComponent().flattenToShortString());
8676 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8677 }
8678 }
8679 if (!app.persistent) {
8680 // We don't want to start this process again until the user
8681 // explicitly does so... but for persistent process, we really
8682 // need to keep it running. If a persistent process is actually
8683 // repeatedly crashing, then badness for everyone.
8684 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8685 app.info.processName);
8686 mBadProcesses.put(app.info.processName, app.info.uid, now);
8687 app.bad = true;
8688 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8689 app.removed = true;
8690 removeProcessLocked(app, false);
8691 return false;
8692 }
8693 }
8694
8695 // Bump up the crash count of any services currently running in the proc.
8696 if (app.services.size() != 0) {
8697 // Any services running in the application need to be placed
8698 // back in the pending list.
8699 Iterator it = app.services.iterator();
8700 while (it.hasNext()) {
8701 ServiceRecord sr = (ServiceRecord)it.next();
8702 sr.crashCount++;
8703 }
8704 }
8705
8706 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8707 return true;
8708 }
8709
8710 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008711 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008712 skipCurrentReceiverLocked(app);
8713 }
8714
8715 void skipCurrentReceiverLocked(ProcessRecord app) {
8716 boolean reschedule = false;
8717 BroadcastRecord r = app.curReceiver;
8718 if (r != null) {
8719 // The current broadcast is waiting for this app's receiver
8720 // to be finished. Looks like that's not going to happen, so
8721 // let the broadcast continue.
8722 logBroadcastReceiverDiscard(r);
8723 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8724 r.resultExtras, r.resultAbort, true);
8725 reschedule = true;
8726 }
8727 r = mPendingBroadcast;
8728 if (r != null && r.curApp == app) {
8729 if (DEBUG_BROADCAST) Log.v(TAG,
8730 "skip & discard pending app " + r);
8731 logBroadcastReceiverDiscard(r);
8732 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8733 r.resultExtras, r.resultAbort, true);
8734 reschedule = true;
8735 }
8736 if (reschedule) {
8737 scheduleBroadcastsLocked();
8738 }
8739 }
8740
8741 public int handleApplicationError(IBinder app, int flags,
8742 String tag, String shortMsg, String longMsg, byte[] crashData) {
8743 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008744 ProcessRecord r = null;
8745 synchronized (this) {
8746 if (app != null) {
8747 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8748 final int NA = apps.size();
8749 for (int ia=0; ia<NA; ia++) {
8750 ProcessRecord p = apps.valueAt(ia);
8751 if (p.thread != null && p.thread.asBinder() == app) {
8752 r = p;
8753 break;
8754 }
8755 }
8756 }
8757 }
8758
8759 if (r != null) {
8760 // The application has crashed. Send the SIGQUIT to the process so
8761 // that it can dump its state.
8762 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8763 //Log.i(TAG, "Current system threads:");
8764 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8765 }
8766
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008767 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008768 try {
8769 String name = r != null ? r.processName : null;
8770 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008771 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008772 shortMsg, longMsg, crashData)) {
8773 Log.w(TAG, "Force-killing crashed app " + name
8774 + " at watcher's request");
8775 Process.killProcess(pid);
8776 return 0;
8777 }
8778 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008779 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008780 }
8781 }
8782
8783 final long origId = Binder.clearCallingIdentity();
8784
8785 // If this process is running instrumentation, finish it.
8786 if (r != null && r.instrumentationClass != null) {
8787 Log.w(TAG, "Error in app " + r.processName
8788 + " running instrumentation " + r.instrumentationClass + ":");
8789 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8790 if (longMsg != null) Log.w(TAG, " " + longMsg);
8791 Bundle info = new Bundle();
8792 info.putString("shortMsg", shortMsg);
8793 info.putString("longMsg", longMsg);
8794 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8795 Binder.restoreCallingIdentity(origId);
8796 return 0;
8797 }
8798
8799 if (r != null) {
8800 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8801 return 0;
8802 }
8803 } else {
8804 Log.w(TAG, "Some application object " + app + " tag " + tag
8805 + " has crashed, but I don't know who it is.");
8806 Log.w(TAG, "ShortMsg:" + shortMsg);
8807 Log.w(TAG, "LongMsg:" + longMsg);
8808 Binder.restoreCallingIdentity(origId);
8809 return 0;
8810 }
8811
8812 Message msg = Message.obtain();
8813 msg.what = SHOW_ERROR_MSG;
8814 HashMap data = new HashMap();
8815 data.put("result", result);
8816 data.put("app", r);
8817 data.put("flags", flags);
8818 data.put("shortMsg", shortMsg);
8819 data.put("longMsg", longMsg);
8820 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8821 // For system processes, submit crash data to the server.
8822 data.put("crashData", crashData);
8823 }
8824 msg.obj = data;
8825 mHandler.sendMessage(msg);
8826
8827 Binder.restoreCallingIdentity(origId);
8828 }
8829
8830 int res = result.get();
8831
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008832 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008833 synchronized (this) {
8834 if (r != null) {
8835 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8836 SystemClock.uptimeMillis());
8837 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008838 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8839 appErrorIntent = createAppErrorIntentLocked(r);
8840 res = AppErrorDialog.FORCE_QUIT;
8841 }
8842 }
8843
8844 if (appErrorIntent != null) {
8845 try {
8846 mContext.startActivity(appErrorIntent);
8847 } catch (ActivityNotFoundException e) {
8848 Log.w(TAG, "bug report receiver dissappeared", e);
8849 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008850 }
8851
8852 return res;
8853 }
8854
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008855 Intent createAppErrorIntentLocked(ProcessRecord r) {
8856 ApplicationErrorReport report = createAppErrorReportLocked(r);
8857 if (report == null) {
8858 return null;
8859 }
8860 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8861 result.setComponent(r.errorReportReceiver);
8862 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8863 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8864 return result;
8865 }
8866
8867 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8868 if (r.errorReportReceiver == null) {
8869 return null;
8870 }
8871
8872 if (!r.crashing && !r.notResponding) {
8873 return null;
8874 }
8875
8876 try {
8877 ApplicationErrorReport report = new ApplicationErrorReport();
8878 report.packageName = r.info.packageName;
8879 report.installerPackageName = r.errorReportReceiver.getPackageName();
8880 report.processName = r.processName;
8881
8882 if (r.crashing) {
8883 report.type = ApplicationErrorReport.TYPE_CRASH;
8884 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8885
8886 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8887 r.crashingReport.crashData);
8888 DataInputStream dataStream = new DataInputStream(byteStream);
8889 CrashData crashData = new CrashData(dataStream);
8890 ThrowableData throwData = crashData.getThrowableData();
8891
8892 report.time = crashData.getTime();
8893 report.crashInfo.stackTrace = throwData.toString();
8894
Jacek Surazskif829a782009-06-11 22:47:02 +02008895 // Extract the source of the exception, useful for report
8896 // clustering. Also extract the "deepest" non-null exception
8897 // message.
8898 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008899 while (throwData.getCause() != null) {
8900 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008901 String msg = throwData.getMessage();
8902 if (msg != null && msg.length() > 0) {
8903 exceptionMessage = msg;
8904 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008905 }
8906 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008907 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008908 report.crashInfo.exceptionClassName = throwData.getType();
8909 report.crashInfo.throwFileName = trace.getFileName();
8910 report.crashInfo.throwClassName = trace.getClassName();
8911 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008912 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008913 } else if (r.notResponding) {
8914 report.type = ApplicationErrorReport.TYPE_ANR;
8915 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8916
8917 report.anrInfo.activity = r.notRespondingReport.tag;
8918 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8919 report.anrInfo.info = r.notRespondingReport.longMsg;
8920 }
8921
8922 return report;
8923 } catch (IOException e) {
8924 // we don't send it
8925 }
8926
8927 return null;
8928 }
8929
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008930 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8931 // assume our apps are happy - lazy create the list
8932 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8933
8934 synchronized (this) {
8935
8936 // iterate across all processes
8937 final int N = mLRUProcesses.size();
8938 for (int i = 0; i < N; i++) {
8939 ProcessRecord app = mLRUProcesses.get(i);
8940 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8941 // This one's in trouble, so we'll generate a report for it
8942 // crashes are higher priority (in case there's a crash *and* an anr)
8943 ActivityManager.ProcessErrorStateInfo report = null;
8944 if (app.crashing) {
8945 report = app.crashingReport;
8946 } else if (app.notResponding) {
8947 report = app.notRespondingReport;
8948 }
8949
8950 if (report != null) {
8951 if (errList == null) {
8952 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8953 }
8954 errList.add(report);
8955 } else {
8956 Log.w(TAG, "Missing app error report, app = " + app.processName +
8957 " crashing = " + app.crashing +
8958 " notResponding = " + app.notResponding);
8959 }
8960 }
8961 }
8962 }
8963
8964 return errList;
8965 }
8966
8967 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8968 // Lazy instantiation of list
8969 List<ActivityManager.RunningAppProcessInfo> runList = null;
8970 synchronized (this) {
8971 // Iterate across all processes
8972 final int N = mLRUProcesses.size();
8973 for (int i = 0; i < N; i++) {
8974 ProcessRecord app = mLRUProcesses.get(i);
8975 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8976 // Generate process state info for running application
8977 ActivityManager.RunningAppProcessInfo currApp =
8978 new ActivityManager.RunningAppProcessInfo(app.processName,
8979 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07008980 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008981 int adj = app.curAdj;
8982 if (adj >= CONTENT_PROVIDER_ADJ) {
8983 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8984 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8985 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008986 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8987 } else if (adj >= HOME_APP_ADJ) {
8988 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8989 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008990 } else if (adj >= SECONDARY_SERVER_ADJ) {
8991 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8992 } else if (adj >= VISIBLE_APP_ADJ) {
8993 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8994 } else {
8995 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8996 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07008997 currApp.importanceReasonCode = app.adjTypeCode;
8998 if (app.adjSource instanceof ProcessRecord) {
8999 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9000 } else if (app.adjSource instanceof HistoryRecord) {
9001 HistoryRecord r = (HistoryRecord)app.adjSource;
9002 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9003 }
9004 if (app.adjTarget instanceof ComponentName) {
9005 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9006 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009007 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9008 // + " lru=" + currApp.lru);
9009 if (runList == null) {
9010 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9011 }
9012 runList.add(currApp);
9013 }
9014 }
9015 }
9016 return runList;
9017 }
9018
9019 @Override
9020 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9021 synchronized (this) {
9022 if (checkCallingPermission(android.Manifest.permission.DUMP)
9023 != PackageManager.PERMISSION_GRANTED) {
9024 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9025 + Binder.getCallingPid()
9026 + ", uid=" + Binder.getCallingUid()
9027 + " without permission "
9028 + android.Manifest.permission.DUMP);
9029 return;
9030 }
9031 if (args.length != 0 && "service".equals(args[0])) {
9032 dumpService(fd, pw, args);
9033 return;
9034 }
9035 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009036 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009037 pw.println(" ");
9038 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009039 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009040 if (mWaitingVisibleActivities.size() > 0) {
9041 pw.println(" ");
9042 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009043 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009044 }
9045 if (mStoppingActivities.size() > 0) {
9046 pw.println(" ");
9047 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009048 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009049 }
9050 if (mFinishingActivities.size() > 0) {
9051 pw.println(" ");
9052 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009053 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009054 }
9055
9056 pw.println(" ");
9057 pw.println(" mPausingActivity: " + mPausingActivity);
9058 pw.println(" mResumedActivity: " + mResumedActivity);
9059 pw.println(" mFocusedActivity: " + mFocusedActivity);
9060 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
9061
9062 if (mRecentTasks.size() > 0) {
9063 pw.println(" ");
9064 pw.println("Recent tasks in Current Activity Manager State:");
9065
9066 final int N = mRecentTasks.size();
9067 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009068 TaskRecord tr = mRecentTasks.get(i);
9069 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9070 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009071 mRecentTasks.get(i).dump(pw, " ");
9072 }
9073 }
9074
9075 pw.println(" ");
9076 pw.println(" mCurTask: " + mCurTask);
9077
9078 pw.println(" ");
9079 pw.println("Processes in Current Activity Manager State:");
9080
9081 boolean needSep = false;
9082 int numPers = 0;
9083
9084 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9085 final int NA = procs.size();
9086 for (int ia=0; ia<NA; ia++) {
9087 if (!needSep) {
9088 pw.println(" All known processes:");
9089 needSep = true;
9090 }
9091 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009092 pw.print(r.persistent ? " *PERS*" : " *APP*");
9093 pw.print(" UID "); pw.print(procs.keyAt(ia));
9094 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009095 r.dump(pw, " ");
9096 if (r.persistent) {
9097 numPers++;
9098 }
9099 }
9100 }
9101
9102 if (mLRUProcesses.size() > 0) {
9103 if (needSep) pw.println(" ");
9104 needSep = true;
9105 pw.println(" Running processes (most recent first):");
9106 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009107 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009108 needSep = true;
9109 }
9110
9111 synchronized (mPidsSelfLocked) {
9112 if (mPidsSelfLocked.size() > 0) {
9113 if (needSep) pw.println(" ");
9114 needSep = true;
9115 pw.println(" PID mappings:");
9116 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009117 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9118 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009119 }
9120 }
9121 }
9122
9123 if (mForegroundProcesses.size() > 0) {
9124 if (needSep) pw.println(" ");
9125 needSep = true;
9126 pw.println(" Foreground Processes:");
9127 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009128 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9129 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009130 }
9131 }
9132
9133 if (mPersistentStartingProcesses.size() > 0) {
9134 if (needSep) pw.println(" ");
9135 needSep = true;
9136 pw.println(" Persisent processes that are starting:");
9137 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009138 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009139 }
9140
9141 if (mStartingProcesses.size() > 0) {
9142 if (needSep) pw.println(" ");
9143 needSep = true;
9144 pw.println(" Processes that are starting:");
9145 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009146 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009147 }
9148
9149 if (mRemovedProcesses.size() > 0) {
9150 if (needSep) pw.println(" ");
9151 needSep = true;
9152 pw.println(" Processes that are being removed:");
9153 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009154 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009155 }
9156
9157 if (mProcessesOnHold.size() > 0) {
9158 if (needSep) pw.println(" ");
9159 needSep = true;
9160 pw.println(" Processes that are on old until the system is ready:");
9161 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009162 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009163 }
9164
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009165 if (mProcessesToGc.size() > 0) {
9166 if (needSep) pw.println(" ");
9167 needSep = true;
9168 pw.println(" Processes that are waiting to GC:");
9169 long now = SystemClock.uptimeMillis();
9170 for (int i=0; i<mProcessesToGc.size(); i++) {
9171 ProcessRecord proc = mProcessesToGc.get(i);
9172 pw.print(" Process "); pw.println(proc);
9173 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9174 pw.print(", last gced=");
9175 pw.print(now-proc.lastRequestedGc);
9176 pw.print(" ms ago, last lowMwm=");
9177 pw.print(now-proc.lastLowMemory);
9178 pw.println(" ms ago");
9179
9180 }
9181 }
9182
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009183 if (mProcessCrashTimes.getMap().size() > 0) {
9184 if (needSep) pw.println(" ");
9185 needSep = true;
9186 pw.println(" Time since processes crashed:");
9187 long now = SystemClock.uptimeMillis();
9188 for (Map.Entry<String, SparseArray<Long>> procs
9189 : mProcessCrashTimes.getMap().entrySet()) {
9190 SparseArray<Long> uids = procs.getValue();
9191 final int N = uids.size();
9192 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009193 pw.print(" Process "); pw.print(procs.getKey());
9194 pw.print(" uid "); pw.print(uids.keyAt(i));
9195 pw.print(": last crashed ");
9196 pw.print((now-uids.valueAt(i)));
9197 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009198 }
9199 }
9200 }
9201
9202 if (mBadProcesses.getMap().size() > 0) {
9203 if (needSep) pw.println(" ");
9204 needSep = true;
9205 pw.println(" Bad processes:");
9206 for (Map.Entry<String, SparseArray<Long>> procs
9207 : mBadProcesses.getMap().entrySet()) {
9208 SparseArray<Long> uids = procs.getValue();
9209 final int N = uids.size();
9210 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009211 pw.print(" Bad process "); pw.print(procs.getKey());
9212 pw.print(" uid "); pw.print(uids.keyAt(i));
9213 pw.print(": crashed at time ");
9214 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009215 }
9216 }
9217 }
9218
9219 pw.println(" ");
9220 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009221 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009222 pw.println(" mConfiguration: " + mConfiguration);
9223 pw.println(" mStartRunning=" + mStartRunning
9224 + " mSystemReady=" + mSystemReady
9225 + " mBooting=" + mBooting
9226 + " mBooted=" + mBooted
9227 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009228 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009229 pw.println(" mGoingToSleep=" + mGoingToSleep);
9230 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9231 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9232 + " mDebugTransient=" + mDebugTransient
9233 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9234 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009235 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009236 }
9237 }
9238
9239 /**
9240 * There are three ways to call this:
9241 * - no service specified: dump all the services
9242 * - a flattened component name that matched an existing service was specified as the
9243 * first arg: dump that one service
9244 * - the first arg isn't the flattened component name of an existing service:
9245 * dump all services whose component contains the first arg as a substring
9246 */
9247 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9248 String[] newArgs;
9249 String componentNameString;
9250 ServiceRecord r;
9251 if (args.length == 1) {
9252 componentNameString = null;
9253 newArgs = EMPTY_STRING_ARRAY;
9254 r = null;
9255 } else {
9256 componentNameString = args[1];
9257 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9258 r = componentName != null ? mServices.get(componentName) : null;
9259 newArgs = new String[args.length - 2];
9260 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9261 }
9262
9263 if (r != null) {
9264 dumpService(fd, pw, r, newArgs);
9265 } else {
9266 for (ServiceRecord r1 : mServices.values()) {
9267 if (componentNameString == null
9268 || r1.name.flattenToString().contains(componentNameString)) {
9269 dumpService(fd, pw, r1, newArgs);
9270 }
9271 }
9272 }
9273 }
9274
9275 /**
9276 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9277 * there is a thread associated with the service.
9278 */
9279 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9280 pw.println(" Service " + r.name.flattenToString());
9281 if (r.app != null && r.app.thread != null) {
9282 try {
9283 // flush anything that is already in the PrintWriter since the thread is going
9284 // to write to the file descriptor directly
9285 pw.flush();
9286 r.app.thread.dumpService(fd, r, args);
9287 pw.print("\n");
9288 } catch (RemoteException e) {
9289 pw.println("got a RemoteException while dumping the service");
9290 }
9291 }
9292 }
9293
9294 void dumpBroadcasts(PrintWriter pw) {
9295 synchronized (this) {
9296 if (checkCallingPermission(android.Manifest.permission.DUMP)
9297 != PackageManager.PERMISSION_GRANTED) {
9298 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9299 + Binder.getCallingPid()
9300 + ", uid=" + Binder.getCallingUid()
9301 + " without permission "
9302 + android.Manifest.permission.DUMP);
9303 return;
9304 }
9305 pw.println("Broadcasts in Current Activity Manager State:");
9306
9307 if (mRegisteredReceivers.size() > 0) {
9308 pw.println(" ");
9309 pw.println(" Registered Receivers:");
9310 Iterator it = mRegisteredReceivers.values().iterator();
9311 while (it.hasNext()) {
9312 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009313 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009314 r.dump(pw, " ");
9315 }
9316 }
9317
9318 pw.println(" ");
9319 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009320 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009321
9322 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9323 || mPendingBroadcast != null) {
9324 if (mParallelBroadcasts.size() > 0) {
9325 pw.println(" ");
9326 pw.println(" Active broadcasts:");
9327 }
9328 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9329 pw.println(" Broadcast #" + i + ":");
9330 mParallelBroadcasts.get(i).dump(pw, " ");
9331 }
9332 if (mOrderedBroadcasts.size() > 0) {
9333 pw.println(" ");
9334 pw.println(" Active serialized broadcasts:");
9335 }
9336 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9337 pw.println(" Serialized Broadcast #" + i + ":");
9338 mOrderedBroadcasts.get(i).dump(pw, " ");
9339 }
9340 pw.println(" ");
9341 pw.println(" Pending broadcast:");
9342 if (mPendingBroadcast != null) {
9343 mPendingBroadcast.dump(pw, " ");
9344 } else {
9345 pw.println(" (null)");
9346 }
9347 }
9348
9349 pw.println(" ");
9350 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9351 if (mStickyBroadcasts != null) {
9352 pw.println(" ");
9353 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009354 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009355 for (Map.Entry<String, ArrayList<Intent>> ent
9356 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009357 pw.print(" * Sticky action "); pw.print(ent.getKey());
9358 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009359 ArrayList<Intent> intents = ent.getValue();
9360 final int N = intents.size();
9361 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009362 sb.setLength(0);
9363 sb.append(" Intent: ");
9364 intents.get(i).toShortString(sb, true, false);
9365 pw.println(sb.toString());
9366 Bundle bundle = intents.get(i).getExtras();
9367 if (bundle != null) {
9368 pw.print(" ");
9369 pw.println(bundle.toString());
9370 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009371 }
9372 }
9373 }
9374
9375 pw.println(" ");
9376 pw.println(" mHandler:");
9377 mHandler.dump(new PrintWriterPrinter(pw), " ");
9378 }
9379 }
9380
9381 void dumpServices(PrintWriter pw) {
9382 synchronized (this) {
9383 if (checkCallingPermission(android.Manifest.permission.DUMP)
9384 != PackageManager.PERMISSION_GRANTED) {
9385 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9386 + Binder.getCallingPid()
9387 + ", uid=" + Binder.getCallingUid()
9388 + " without permission "
9389 + android.Manifest.permission.DUMP);
9390 return;
9391 }
9392 pw.println("Services in Current Activity Manager State:");
9393
9394 boolean needSep = false;
9395
9396 if (mServices.size() > 0) {
9397 pw.println(" Active services:");
9398 Iterator<ServiceRecord> it = mServices.values().iterator();
9399 while (it.hasNext()) {
9400 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009401 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009402 r.dump(pw, " ");
9403 }
9404 needSep = true;
9405 }
9406
9407 if (mPendingServices.size() > 0) {
9408 if (needSep) pw.println(" ");
9409 pw.println(" Pending services:");
9410 for (int i=0; i<mPendingServices.size(); i++) {
9411 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009412 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009413 r.dump(pw, " ");
9414 }
9415 needSep = true;
9416 }
9417
9418 if (mRestartingServices.size() > 0) {
9419 if (needSep) pw.println(" ");
9420 pw.println(" Restarting services:");
9421 for (int i=0; i<mRestartingServices.size(); i++) {
9422 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009423 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009424 r.dump(pw, " ");
9425 }
9426 needSep = true;
9427 }
9428
9429 if (mStoppingServices.size() > 0) {
9430 if (needSep) pw.println(" ");
9431 pw.println(" Stopping services:");
9432 for (int i=0; i<mStoppingServices.size(); i++) {
9433 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009434 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009435 r.dump(pw, " ");
9436 }
9437 needSep = true;
9438 }
9439
9440 if (mServiceConnections.size() > 0) {
9441 if (needSep) pw.println(" ");
9442 pw.println(" Connection bindings to services:");
9443 Iterator<ConnectionRecord> it
9444 = mServiceConnections.values().iterator();
9445 while (it.hasNext()) {
9446 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009447 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009448 r.dump(pw, " ");
9449 }
9450 }
9451 }
9452 }
9453
9454 void dumpProviders(PrintWriter pw) {
9455 synchronized (this) {
9456 if (checkCallingPermission(android.Manifest.permission.DUMP)
9457 != PackageManager.PERMISSION_GRANTED) {
9458 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9459 + Binder.getCallingPid()
9460 + ", uid=" + Binder.getCallingUid()
9461 + " without permission "
9462 + android.Manifest.permission.DUMP);
9463 return;
9464 }
9465
9466 pw.println("Content Providers in Current Activity Manager State:");
9467
9468 boolean needSep = false;
9469
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009470 if (mProvidersByClass.size() > 0) {
9471 if (needSep) pw.println(" ");
9472 pw.println(" Published content providers (by class):");
9473 Iterator it = mProvidersByClass.entrySet().iterator();
9474 while (it.hasNext()) {
9475 Map.Entry e = (Map.Entry)it.next();
9476 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009477 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009478 r.dump(pw, " ");
9479 }
9480 needSep = true;
9481 }
9482
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009483 if (mProvidersByName.size() > 0) {
9484 pw.println(" ");
9485 pw.println(" Authority to provider mappings:");
9486 Iterator it = mProvidersByName.entrySet().iterator();
9487 while (it.hasNext()) {
9488 Map.Entry e = (Map.Entry)it.next();
9489 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9490 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9491 pw.println(r);
9492 }
9493 needSep = true;
9494 }
9495
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009496 if (mLaunchingProviders.size() > 0) {
9497 if (needSep) pw.println(" ");
9498 pw.println(" Launching content providers:");
9499 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009500 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9501 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009502 }
9503 needSep = true;
9504 }
9505
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009506 if (mGrantedUriPermissions.size() > 0) {
9507 pw.println();
9508 pw.println("Granted Uri Permissions:");
9509 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9510 int uid = mGrantedUriPermissions.keyAt(i);
9511 HashMap<Uri, UriPermission> perms
9512 = mGrantedUriPermissions.valueAt(i);
9513 pw.print(" * UID "); pw.print(uid);
9514 pw.println(" holds:");
9515 for (UriPermission perm : perms.values()) {
9516 pw.print(" "); pw.println(perm);
9517 perm.dump(pw, " ");
9518 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009519 }
9520 }
9521 }
9522 }
9523
9524 void dumpSenders(PrintWriter pw) {
9525 synchronized (this) {
9526 if (checkCallingPermission(android.Manifest.permission.DUMP)
9527 != PackageManager.PERMISSION_GRANTED) {
9528 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9529 + Binder.getCallingPid()
9530 + ", uid=" + Binder.getCallingUid()
9531 + " without permission "
9532 + android.Manifest.permission.DUMP);
9533 return;
9534 }
9535
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009536 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009537
9538 if (this.mIntentSenderRecords.size() > 0) {
9539 Iterator<WeakReference<PendingIntentRecord>> it
9540 = mIntentSenderRecords.values().iterator();
9541 while (it.hasNext()) {
9542 WeakReference<PendingIntentRecord> ref = it.next();
9543 PendingIntentRecord rec = ref != null ? ref.get(): null;
9544 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009545 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009546 rec.dump(pw, " ");
9547 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009548 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009549 }
9550 }
9551 }
9552 }
9553 }
9554
9555 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009556 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009557 TaskRecord lastTask = null;
9558 for (int i=list.size()-1; i>=0; i--) {
9559 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009560 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009561 if (lastTask != r.task) {
9562 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009563 pw.print(prefix);
9564 pw.print(full ? "* " : " ");
9565 pw.println(lastTask);
9566 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009567 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009568 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009569 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009570 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9571 pw.print(" #"); pw.print(i); pw.print(": ");
9572 pw.println(r);
9573 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009574 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009575 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009576 }
9577 }
9578
9579 private static final int dumpProcessList(PrintWriter pw, List list,
9580 String prefix, String normalLabel, String persistentLabel,
9581 boolean inclOomAdj) {
9582 int numPers = 0;
9583 for (int i=list.size()-1; i>=0; i--) {
9584 ProcessRecord r = (ProcessRecord)list.get(i);
9585 if (false) {
9586 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9587 + " #" + i + ":");
9588 r.dump(pw, prefix + " ");
9589 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009590 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009591 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009592 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9593 if (r.adjSource != null || r.adjTarget != null) {
9594 pw.println(prefix + " " + r.adjTarget
9595 + " used by " + r.adjSource);
9596 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009597 } else {
9598 pw.println(String.format("%s%s #%2d: %s",
9599 prefix, (r.persistent ? persistentLabel : normalLabel),
9600 i, r.toString()));
9601 }
9602 if (r.persistent) {
9603 numPers++;
9604 }
9605 }
9606 return numPers;
9607 }
9608
9609 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9610 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009611 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009612 long uptime = SystemClock.uptimeMillis();
9613 long realtime = SystemClock.elapsedRealtime();
9614
9615 if (isCheckinRequest) {
9616 // short checkin version
9617 pw.println(uptime + "," + realtime);
9618 pw.flush();
9619 } else {
9620 pw.println("Applications Memory Usage (kB):");
9621 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9622 }
9623 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9624 ProcessRecord r = (ProcessRecord)list.get(i);
9625 if (r.thread != null) {
9626 if (!isCheckinRequest) {
9627 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9628 pw.flush();
9629 }
9630 try {
9631 r.thread.asBinder().dump(fd, args);
9632 } catch (RemoteException e) {
9633 if (!isCheckinRequest) {
9634 pw.println("Got RemoteException!");
9635 pw.flush();
9636 }
9637 }
9638 }
9639 }
9640 }
9641
9642 /**
9643 * Searches array of arguments for the specified string
9644 * @param args array of argument strings
9645 * @param value value to search for
9646 * @return true if the value is contained in the array
9647 */
9648 private static boolean scanArgs(String[] args, String value) {
9649 if (args != null) {
9650 for (String arg : args) {
9651 if (value.equals(arg)) {
9652 return true;
9653 }
9654 }
9655 }
9656 return false;
9657 }
9658
Dianne Hackborn75b03852009-06-12 15:43:26 -07009659 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009660 int count = mHistory.size();
9661
9662 // convert the token to an entry in the history.
9663 HistoryRecord r = null;
9664 int index = -1;
9665 for (int i=count-1; i>=0; i--) {
9666 Object o = mHistory.get(i);
9667 if (o == token) {
9668 r = (HistoryRecord)o;
9669 index = i;
9670 break;
9671 }
9672 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009673
9674 return index;
9675 }
9676
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009677 private final void killServicesLocked(ProcessRecord app,
9678 boolean allowRestart) {
9679 // Report disconnected services.
9680 if (false) {
9681 // XXX we are letting the client link to the service for
9682 // death notifications.
9683 if (app.services.size() > 0) {
9684 Iterator it = app.services.iterator();
9685 while (it.hasNext()) {
9686 ServiceRecord r = (ServiceRecord)it.next();
9687 if (r.connections.size() > 0) {
9688 Iterator<ConnectionRecord> jt
9689 = r.connections.values().iterator();
9690 while (jt.hasNext()) {
9691 ConnectionRecord c = jt.next();
9692 if (c.binding.client != app) {
9693 try {
9694 //c.conn.connected(r.className, null);
9695 } catch (Exception e) {
9696 // todo: this should be asynchronous!
9697 Log.w(TAG, "Exception thrown disconnected servce "
9698 + r.shortName
9699 + " from app " + app.processName, e);
9700 }
9701 }
9702 }
9703 }
9704 }
9705 }
9706 }
9707
9708 // Clean up any connections this application has to other services.
9709 if (app.connections.size() > 0) {
9710 Iterator<ConnectionRecord> it = app.connections.iterator();
9711 while (it.hasNext()) {
9712 ConnectionRecord r = it.next();
9713 removeConnectionLocked(r, app, null);
9714 }
9715 }
9716 app.connections.clear();
9717
9718 if (app.services.size() != 0) {
9719 // Any services running in the application need to be placed
9720 // back in the pending list.
9721 Iterator it = app.services.iterator();
9722 while (it.hasNext()) {
9723 ServiceRecord sr = (ServiceRecord)it.next();
9724 synchronized (sr.stats.getBatteryStats()) {
9725 sr.stats.stopLaunchedLocked();
9726 }
9727 sr.app = null;
9728 sr.executeNesting = 0;
9729 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009730
9731 boolean hasClients = sr.bindings.size() > 0;
9732 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009733 Iterator<IntentBindRecord> bindings
9734 = sr.bindings.values().iterator();
9735 while (bindings.hasNext()) {
9736 IntentBindRecord b = bindings.next();
9737 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9738 + ": shouldUnbind=" + b.hasBound);
9739 b.binder = null;
9740 b.requested = b.received = b.hasBound = false;
9741 }
9742 }
9743
9744 if (sr.crashCount >= 2) {
9745 Log.w(TAG, "Service crashed " + sr.crashCount
9746 + " times, stopping: " + sr);
9747 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9748 sr.crashCount, sr.shortName, app.pid);
9749 bringDownServiceLocked(sr, true);
9750 } else if (!allowRestart) {
9751 bringDownServiceLocked(sr, true);
9752 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009753 boolean canceled = scheduleServiceRestartLocked(sr, true);
9754
9755 // Should the service remain running? Note that in the
9756 // extreme case of so many attempts to deliver a command
9757 // that it failed, that we also will stop it here.
9758 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9759 if (sr.pendingStarts.size() == 0) {
9760 sr.startRequested = false;
9761 if (!hasClients) {
9762 // Whoops, no reason to restart!
9763 bringDownServiceLocked(sr, true);
9764 }
9765 }
9766 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009767 }
9768 }
9769
9770 if (!allowRestart) {
9771 app.services.clear();
9772 }
9773 }
9774
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009775 // Make sure we have no more records on the stopping list.
9776 int i = mStoppingServices.size();
9777 while (i > 0) {
9778 i--;
9779 ServiceRecord sr = mStoppingServices.get(i);
9780 if (sr.app == app) {
9781 mStoppingServices.remove(i);
9782 }
9783 }
9784
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009785 app.executingServices.clear();
9786 }
9787
9788 private final void removeDyingProviderLocked(ProcessRecord proc,
9789 ContentProviderRecord cpr) {
9790 synchronized (cpr) {
9791 cpr.launchingApp = null;
9792 cpr.notifyAll();
9793 }
9794
9795 mProvidersByClass.remove(cpr.info.name);
9796 String names[] = cpr.info.authority.split(";");
9797 for (int j = 0; j < names.length; j++) {
9798 mProvidersByName.remove(names[j]);
9799 }
9800
9801 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9802 while (cit.hasNext()) {
9803 ProcessRecord capp = cit.next();
9804 if (!capp.persistent && capp.thread != null
9805 && capp.pid != 0
9806 && capp.pid != MY_PID) {
9807 Log.i(TAG, "Killing app " + capp.processName
9808 + " (pid " + capp.pid
9809 + ") because provider " + cpr.info.name
9810 + " is in dying process " + proc.processName);
9811 Process.killProcess(capp.pid);
9812 }
9813 }
9814
9815 mLaunchingProviders.remove(cpr);
9816 }
9817
9818 /**
9819 * Main code for cleaning up a process when it has gone away. This is
9820 * called both as a result of the process dying, or directly when stopping
9821 * a process when running in single process mode.
9822 */
9823 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9824 boolean restarting, int index) {
9825 if (index >= 0) {
9826 mLRUProcesses.remove(index);
9827 }
9828
9829 // Dismiss any open dialogs.
9830 if (app.crashDialog != null) {
9831 app.crashDialog.dismiss();
9832 app.crashDialog = null;
9833 }
9834 if (app.anrDialog != null) {
9835 app.anrDialog.dismiss();
9836 app.anrDialog = null;
9837 }
9838 if (app.waitDialog != null) {
9839 app.waitDialog.dismiss();
9840 app.waitDialog = null;
9841 }
9842
9843 app.crashing = false;
9844 app.notResponding = false;
9845
9846 app.resetPackageList();
9847 app.thread = null;
9848 app.forcingToForeground = null;
9849 app.foregroundServices = false;
9850
9851 killServicesLocked(app, true);
9852
9853 boolean restart = false;
9854
9855 int NL = mLaunchingProviders.size();
9856
9857 // Remove published content providers.
9858 if (!app.pubProviders.isEmpty()) {
9859 Iterator it = app.pubProviders.values().iterator();
9860 while (it.hasNext()) {
9861 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9862 cpr.provider = null;
9863 cpr.app = null;
9864
9865 // See if someone is waiting for this provider... in which
9866 // case we don't remove it, but just let it restart.
9867 int i = 0;
9868 if (!app.bad) {
9869 for (; i<NL; i++) {
9870 if (mLaunchingProviders.get(i) == cpr) {
9871 restart = true;
9872 break;
9873 }
9874 }
9875 } else {
9876 i = NL;
9877 }
9878
9879 if (i >= NL) {
9880 removeDyingProviderLocked(app, cpr);
9881 NL = mLaunchingProviders.size();
9882 }
9883 }
9884 app.pubProviders.clear();
9885 }
9886
9887 // Look through the content providers we are waiting to have launched,
9888 // and if any run in this process then either schedule a restart of
9889 // the process or kill the client waiting for it if this process has
9890 // gone bad.
9891 for (int i=0; i<NL; i++) {
9892 ContentProviderRecord cpr = (ContentProviderRecord)
9893 mLaunchingProviders.get(i);
9894 if (cpr.launchingApp == app) {
9895 if (!app.bad) {
9896 restart = true;
9897 } else {
9898 removeDyingProviderLocked(app, cpr);
9899 NL = mLaunchingProviders.size();
9900 }
9901 }
9902 }
9903
9904 // Unregister from connected content providers.
9905 if (!app.conProviders.isEmpty()) {
9906 Iterator it = app.conProviders.iterator();
9907 while (it.hasNext()) {
9908 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9909 cpr.clients.remove(app);
9910 }
9911 app.conProviders.clear();
9912 }
9913
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009914 // At this point there may be remaining entries in mLaunchingProviders
9915 // where we were the only one waiting, so they are no longer of use.
9916 // Look for these and clean up if found.
9917 // XXX Commented out for now. Trying to figure out a way to reproduce
9918 // the actual situation to identify what is actually going on.
9919 if (false) {
9920 for (int i=0; i<NL; i++) {
9921 ContentProviderRecord cpr = (ContentProviderRecord)
9922 mLaunchingProviders.get(i);
9923 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9924 synchronized (cpr) {
9925 cpr.launchingApp = null;
9926 cpr.notifyAll();
9927 }
9928 }
9929 }
9930 }
9931
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009932 skipCurrentReceiverLocked(app);
9933
9934 // Unregister any receivers.
9935 if (app.receivers.size() > 0) {
9936 Iterator<ReceiverList> it = app.receivers.iterator();
9937 while (it.hasNext()) {
9938 removeReceiverLocked(it.next());
9939 }
9940 app.receivers.clear();
9941 }
9942
Christopher Tate181fafa2009-05-14 11:12:14 -07009943 // If the app is undergoing backup, tell the backup manager about it
9944 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9945 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9946 try {
9947 IBackupManager bm = IBackupManager.Stub.asInterface(
9948 ServiceManager.getService(Context.BACKUP_SERVICE));
9949 bm.agentDisconnected(app.info.packageName);
9950 } catch (RemoteException e) {
9951 // can't happen; backup manager is local
9952 }
9953 }
9954
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009955 // If the caller is restarting this app, then leave it in its
9956 // current lists and let the caller take care of it.
9957 if (restarting) {
9958 return;
9959 }
9960
9961 if (!app.persistent) {
9962 if (DEBUG_PROCESSES) Log.v(TAG,
9963 "Removing non-persistent process during cleanup: " + app);
9964 mProcessNames.remove(app.processName, app.info.uid);
9965 } else if (!app.removed) {
9966 // This app is persistent, so we need to keep its record around.
9967 // If it is not already on the pending app list, add it there
9968 // and start a new process for it.
9969 app.thread = null;
9970 app.forcingToForeground = null;
9971 app.foregroundServices = false;
9972 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9973 mPersistentStartingProcesses.add(app);
9974 restart = true;
9975 }
9976 }
9977 mProcessesOnHold.remove(app);
9978
The Android Open Source Project4df24232009-03-05 14:34:35 -08009979 if (app == mHomeProcess) {
9980 mHomeProcess = null;
9981 }
9982
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009983 if (restart) {
9984 // We have components that still need to be running in the
9985 // process, so re-launch it.
9986 mProcessNames.put(app.processName, app.info.uid, app);
9987 startProcessLocked(app, "restart", app.processName);
9988 } else if (app.pid > 0 && app.pid != MY_PID) {
9989 // Goodbye!
9990 synchronized (mPidsSelfLocked) {
9991 mPidsSelfLocked.remove(app.pid);
9992 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9993 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009994 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009995 }
9996 }
9997
9998 // =========================================================
9999 // SERVICES
10000 // =========================================================
10001
10002 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10003 ActivityManager.RunningServiceInfo info =
10004 new ActivityManager.RunningServiceInfo();
10005 info.service = r.name;
10006 if (r.app != null) {
10007 info.pid = r.app.pid;
10008 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010009 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010010 info.process = r.processName;
10011 info.foreground = r.isForeground;
10012 info.activeSince = r.createTime;
10013 info.started = r.startRequested;
10014 info.clientCount = r.connections.size();
10015 info.crashCount = r.crashCount;
10016 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010017 if (r.isForeground) {
10018 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10019 }
10020 if (r.startRequested) {
10021 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10022 }
10023 if (r.app != null && r.app.pid == Process.myPid()) {
10024 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10025 }
10026 if (r.app != null && r.app.persistent) {
10027 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10028 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010029 for (ConnectionRecord conn : r.connections.values()) {
10030 if (conn.clientLabel != 0) {
10031 info.clientPackage = conn.binding.client.info.packageName;
10032 info.clientLabel = conn.clientLabel;
10033 break;
10034 }
10035 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010036 return info;
10037 }
10038
10039 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10040 int flags) {
10041 synchronized (this) {
10042 ArrayList<ActivityManager.RunningServiceInfo> res
10043 = new ArrayList<ActivityManager.RunningServiceInfo>();
10044
10045 if (mServices.size() > 0) {
10046 Iterator<ServiceRecord> it = mServices.values().iterator();
10047 while (it.hasNext() && res.size() < maxNum) {
10048 res.add(makeRunningServiceInfoLocked(it.next()));
10049 }
10050 }
10051
10052 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10053 ServiceRecord r = mRestartingServices.get(i);
10054 ActivityManager.RunningServiceInfo info =
10055 makeRunningServiceInfoLocked(r);
10056 info.restarting = r.nextRestartTime;
10057 res.add(info);
10058 }
10059
10060 return res;
10061 }
10062 }
10063
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010064 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10065 synchronized (this) {
10066 ServiceRecord r = mServices.get(name);
10067 if (r != null) {
10068 for (ConnectionRecord conn : r.connections.values()) {
10069 if (conn.clientIntent != null) {
10070 return conn.clientIntent;
10071 }
10072 }
10073 }
10074 }
10075 return null;
10076 }
10077
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010078 private final ServiceRecord findServiceLocked(ComponentName name,
10079 IBinder token) {
10080 ServiceRecord r = mServices.get(name);
10081 return r == token ? r : null;
10082 }
10083
10084 private final class ServiceLookupResult {
10085 final ServiceRecord record;
10086 final String permission;
10087
10088 ServiceLookupResult(ServiceRecord _record, String _permission) {
10089 record = _record;
10090 permission = _permission;
10091 }
10092 };
10093
10094 private ServiceLookupResult findServiceLocked(Intent service,
10095 String resolvedType) {
10096 ServiceRecord r = null;
10097 if (service.getComponent() != null) {
10098 r = mServices.get(service.getComponent());
10099 }
10100 if (r == null) {
10101 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10102 r = mServicesByIntent.get(filter);
10103 }
10104
10105 if (r == null) {
10106 try {
10107 ResolveInfo rInfo =
10108 ActivityThread.getPackageManager().resolveService(
10109 service, resolvedType, 0);
10110 ServiceInfo sInfo =
10111 rInfo != null ? rInfo.serviceInfo : null;
10112 if (sInfo == null) {
10113 return null;
10114 }
10115
10116 ComponentName name = new ComponentName(
10117 sInfo.applicationInfo.packageName, sInfo.name);
10118 r = mServices.get(name);
10119 } catch (RemoteException ex) {
10120 // pm is in same process, this will never happen.
10121 }
10122 }
10123 if (r != null) {
10124 int callingPid = Binder.getCallingPid();
10125 int callingUid = Binder.getCallingUid();
10126 if (checkComponentPermission(r.permission,
10127 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10128 != PackageManager.PERMISSION_GRANTED) {
10129 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10130 + " from pid=" + callingPid
10131 + ", uid=" + callingUid
10132 + " requires " + r.permission);
10133 return new ServiceLookupResult(null, r.permission);
10134 }
10135 return new ServiceLookupResult(r, null);
10136 }
10137 return null;
10138 }
10139
10140 private class ServiceRestarter implements Runnable {
10141 private ServiceRecord mService;
10142
10143 void setService(ServiceRecord service) {
10144 mService = service;
10145 }
10146
10147 public void run() {
10148 synchronized(ActivityManagerService.this) {
10149 performServiceRestartLocked(mService);
10150 }
10151 }
10152 }
10153
10154 private ServiceLookupResult retrieveServiceLocked(Intent service,
10155 String resolvedType, int callingPid, int callingUid) {
10156 ServiceRecord r = null;
10157 if (service.getComponent() != null) {
10158 r = mServices.get(service.getComponent());
10159 }
10160 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10161 r = mServicesByIntent.get(filter);
10162 if (r == null) {
10163 try {
10164 ResolveInfo rInfo =
10165 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010166 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010167 ServiceInfo sInfo =
10168 rInfo != null ? rInfo.serviceInfo : null;
10169 if (sInfo == null) {
10170 Log.w(TAG, "Unable to start service " + service +
10171 ": not found");
10172 return null;
10173 }
10174
10175 ComponentName name = new ComponentName(
10176 sInfo.applicationInfo.packageName, sInfo.name);
10177 r = mServices.get(name);
10178 if (r == null) {
10179 filter = new Intent.FilterComparison(service.cloneFilter());
10180 ServiceRestarter res = new ServiceRestarter();
10181 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10182 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10183 synchronized (stats) {
10184 ss = stats.getServiceStatsLocked(
10185 sInfo.applicationInfo.uid, sInfo.packageName,
10186 sInfo.name);
10187 }
10188 r = new ServiceRecord(ss, name, filter, sInfo, res);
10189 res.setService(r);
10190 mServices.put(name, r);
10191 mServicesByIntent.put(filter, r);
10192
10193 // Make sure this component isn't in the pending list.
10194 int N = mPendingServices.size();
10195 for (int i=0; i<N; i++) {
10196 ServiceRecord pr = mPendingServices.get(i);
10197 if (pr.name.equals(name)) {
10198 mPendingServices.remove(i);
10199 i--;
10200 N--;
10201 }
10202 }
10203 }
10204 } catch (RemoteException ex) {
10205 // pm is in same process, this will never happen.
10206 }
10207 }
10208 if (r != null) {
10209 if (checkComponentPermission(r.permission,
10210 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10211 != PackageManager.PERMISSION_GRANTED) {
10212 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10213 + " from pid=" + Binder.getCallingPid()
10214 + ", uid=" + Binder.getCallingUid()
10215 + " requires " + r.permission);
10216 return new ServiceLookupResult(null, r.permission);
10217 }
10218 return new ServiceLookupResult(r, null);
10219 }
10220 return null;
10221 }
10222
10223 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10224 long now = SystemClock.uptimeMillis();
10225 if (r.executeNesting == 0 && r.app != null) {
10226 if (r.app.executingServices.size() == 0) {
10227 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10228 msg.obj = r.app;
10229 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10230 }
10231 r.app.executingServices.add(r);
10232 }
10233 r.executeNesting++;
10234 r.executingStart = now;
10235 }
10236
10237 private final void sendServiceArgsLocked(ServiceRecord r,
10238 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010239 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010240 if (N == 0) {
10241 return;
10242 }
10243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010244 int i = 0;
10245 while (i < N) {
10246 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010247 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010248 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010249 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010250 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010251 // If somehow we got a dummy start at the front, then
10252 // just drop it here.
10253 i++;
10254 continue;
10255 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010256 bumpServiceExecutingLocked(r);
10257 if (!oomAdjusted) {
10258 oomAdjusted = true;
10259 updateOomAdjLocked(r.app);
10260 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010261 int flags = 0;
10262 if (si.deliveryCount > 0) {
10263 flags |= Service.START_FLAG_RETRY;
10264 }
10265 if (si.doneExecutingCount > 0) {
10266 flags |= Service.START_FLAG_REDELIVERY;
10267 }
10268 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10269 si.deliveredTime = SystemClock.uptimeMillis();
10270 r.deliveredStarts.add(si);
10271 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010272 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010273 } catch (RemoteException e) {
10274 // Remote process gone... we'll let the normal cleanup take
10275 // care of this.
10276 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010277 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010278 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010279 break;
10280 }
10281 }
10282 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010283 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010284 } else {
10285 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010286 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010287 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010288 }
10289 }
10290 }
10291
10292 private final boolean requestServiceBindingLocked(ServiceRecord r,
10293 IntentBindRecord i, boolean rebind) {
10294 if (r.app == null || r.app.thread == null) {
10295 // If service is not currently running, can't yet bind.
10296 return false;
10297 }
10298 if ((!i.requested || rebind) && i.apps.size() > 0) {
10299 try {
10300 bumpServiceExecutingLocked(r);
10301 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10302 + ": shouldUnbind=" + i.hasBound);
10303 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10304 if (!rebind) {
10305 i.requested = true;
10306 }
10307 i.hasBound = true;
10308 i.doRebind = false;
10309 } catch (RemoteException e) {
10310 return false;
10311 }
10312 }
10313 return true;
10314 }
10315
10316 private final void requestServiceBindingsLocked(ServiceRecord r) {
10317 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10318 while (bindings.hasNext()) {
10319 IntentBindRecord i = bindings.next();
10320 if (!requestServiceBindingLocked(r, i, false)) {
10321 break;
10322 }
10323 }
10324 }
10325
10326 private final void realStartServiceLocked(ServiceRecord r,
10327 ProcessRecord app) throws RemoteException {
10328 if (app.thread == null) {
10329 throw new RemoteException();
10330 }
10331
10332 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010333 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010334
10335 app.services.add(r);
10336 bumpServiceExecutingLocked(r);
10337 updateLRUListLocked(app, true);
10338
10339 boolean created = false;
10340 try {
10341 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10342 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010343 mStringBuilder.setLength(0);
10344 r.intent.getIntent().toShortString(mStringBuilder, false, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010345 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
10346 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010347 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010348 synchronized (r.stats.getBatteryStats()) {
10349 r.stats.startLaunchedLocked();
10350 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010351 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010352 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010353 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010354 created = true;
10355 } finally {
10356 if (!created) {
10357 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010358 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010359 }
10360 }
10361
10362 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010363
10364 // If the service is in the started state, and there are no
10365 // pending arguments, then fake up one so its onStartCommand() will
10366 // be called.
10367 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10368 r.lastStartId++;
10369 if (r.lastStartId < 1) {
10370 r.lastStartId = 1;
10371 }
10372 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10373 }
10374
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010375 sendServiceArgsLocked(r, true);
10376 }
10377
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010378 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10379 boolean allowCancel) {
10380 boolean canceled = false;
10381
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010382 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010383 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010384 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010385
10386 // Any delivered but not yet finished starts should be put back
10387 // on the pending list.
10388 final int N = r.deliveredStarts.size();
10389 if (N > 0) {
10390 for (int i=N-1; i>=0; i--) {
10391 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10392 if (si.intent == null) {
10393 // We'll generate this again if needed.
10394 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10395 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10396 r.pendingStarts.add(0, si);
10397 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10398 dur *= 2;
10399 if (minDuration < dur) minDuration = dur;
10400 if (resetTime < dur) resetTime = dur;
10401 } else {
10402 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10403 + r.name);
10404 canceled = true;
10405 }
10406 }
10407 r.deliveredStarts.clear();
10408 }
10409
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010410 r.totalRestartCount++;
10411 if (r.restartDelay == 0) {
10412 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010413 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010414 } else {
10415 // If it has been a "reasonably long time" since the service
10416 // was started, then reset our restart duration back to
10417 // the beginning, so we don't infinitely increase the duration
10418 // on a service that just occasionally gets killed (which is
10419 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010420 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010421 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010422 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010423 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010424 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010425 if (r.restartDelay < minDuration) {
10426 r.restartDelay = minDuration;
10427 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010428 }
10429 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010430
10431 r.nextRestartTime = now + r.restartDelay;
10432
10433 // Make sure that we don't end up restarting a bunch of services
10434 // all at the same time.
10435 boolean repeat;
10436 do {
10437 repeat = false;
10438 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10439 ServiceRecord r2 = mRestartingServices.get(i);
10440 if (r2 != r && r.nextRestartTime
10441 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10442 && r.nextRestartTime
10443 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10444 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10445 r.restartDelay = r.nextRestartTime - now;
10446 repeat = true;
10447 break;
10448 }
10449 }
10450 } while (repeat);
10451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010452 if (!mRestartingServices.contains(r)) {
10453 mRestartingServices.add(r);
10454 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010455
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010456 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010457
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010458 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010459 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010460 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10461 Log.w(TAG, "Scheduling restart of crashed service "
10462 + r.shortName + " in " + r.restartDelay + "ms");
10463 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10464 r.shortName, r.restartDelay);
10465
10466 Message msg = Message.obtain();
10467 msg.what = SERVICE_ERROR_MSG;
10468 msg.obj = r;
10469 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010470
10471 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010472 }
10473
10474 final void performServiceRestartLocked(ServiceRecord r) {
10475 if (!mRestartingServices.contains(r)) {
10476 return;
10477 }
10478 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10479 }
10480
10481 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10482 if (r.restartDelay == 0) {
10483 return false;
10484 }
10485 r.resetRestartCounter();
10486 mRestartingServices.remove(r);
10487 mHandler.removeCallbacks(r.restarter);
10488 return true;
10489 }
10490
10491 private final boolean bringUpServiceLocked(ServiceRecord r,
10492 int intentFlags, boolean whileRestarting) {
10493 //Log.i(TAG, "Bring up service:");
10494 //r.dump(" ");
10495
10496 if (r.app != null) {
10497 sendServiceArgsLocked(r, false);
10498 return true;
10499 }
10500
10501 if (!whileRestarting && r.restartDelay > 0) {
10502 // If waiting for a restart, then do nothing.
10503 return true;
10504 }
10505
10506 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10507 + " " + r.intent);
10508
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010509 // We are now bringing the service up, so no longer in the
10510 // restarting state.
10511 mRestartingServices.remove(r);
10512
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010513 final String appName = r.processName;
10514 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10515 if (app != null && app.thread != null) {
10516 try {
10517 realStartServiceLocked(r, app);
10518 return true;
10519 } catch (RemoteException e) {
10520 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10521 }
10522
10523 // If a dead object exception was thrown -- fall through to
10524 // restart the application.
10525 }
10526
10527 if (!mPendingServices.contains(r)) {
10528 // Not running -- get it started, and enqueue this service record
10529 // to be executed when the app comes up.
10530 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070010531 "service", r.name, false) == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010532 Log.w(TAG, "Unable to launch app "
10533 + r.appInfo.packageName + "/"
10534 + r.appInfo.uid + " for service "
10535 + r.intent.getIntent() + ": process is bad");
10536 bringDownServiceLocked(r, true);
10537 return false;
10538 }
10539 mPendingServices.add(r);
10540 }
10541 return true;
10542 }
10543
10544 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10545 //Log.i(TAG, "Bring down service:");
10546 //r.dump(" ");
10547
10548 // Does it still need to run?
10549 if (!force && r.startRequested) {
10550 return;
10551 }
10552 if (r.connections.size() > 0) {
10553 if (!force) {
10554 // XXX should probably keep a count of the number of auto-create
10555 // connections directly in the service.
10556 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10557 while (it.hasNext()) {
10558 ConnectionRecord cr = it.next();
10559 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10560 return;
10561 }
10562 }
10563 }
10564
10565 // Report to all of the connections that the service is no longer
10566 // available.
10567 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10568 while (it.hasNext()) {
10569 ConnectionRecord c = it.next();
10570 try {
10571 // todo: shouldn't be a synchronous call!
10572 c.conn.connected(r.name, null);
10573 } catch (Exception e) {
10574 Log.w(TAG, "Failure disconnecting service " + r.name +
10575 " to connection " + c.conn.asBinder() +
10576 " (in " + c.binding.client.processName + ")", e);
10577 }
10578 }
10579 }
10580
10581 // Tell the service that it has been unbound.
10582 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10583 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10584 while (it.hasNext()) {
10585 IntentBindRecord ibr = it.next();
10586 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10587 + ": hasBound=" + ibr.hasBound);
10588 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10589 try {
10590 bumpServiceExecutingLocked(r);
10591 updateOomAdjLocked(r.app);
10592 ibr.hasBound = false;
10593 r.app.thread.scheduleUnbindService(r,
10594 ibr.intent.getIntent());
10595 } catch (Exception e) {
10596 Log.w(TAG, "Exception when unbinding service "
10597 + r.shortName, e);
10598 serviceDoneExecutingLocked(r, true);
10599 }
10600 }
10601 }
10602 }
10603
10604 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10605 + " " + r.intent);
10606 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10607 System.identityHashCode(r), r.shortName,
10608 (r.app != null) ? r.app.pid : -1);
10609
10610 mServices.remove(r.name);
10611 mServicesByIntent.remove(r.intent);
10612 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10613 r.totalRestartCount = 0;
10614 unscheduleServiceRestartLocked(r);
10615
10616 // Also make sure it is not on the pending list.
10617 int N = mPendingServices.size();
10618 for (int i=0; i<N; i++) {
10619 if (mPendingServices.get(i) == r) {
10620 mPendingServices.remove(i);
10621 if (DEBUG_SERVICE) Log.v(
10622 TAG, "Removed pending service: " + r.shortName);
10623 i--;
10624 N--;
10625 }
10626 }
10627
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010628 r.cancelNotification();
10629 r.isForeground = false;
10630 r.foregroundId = 0;
10631 r.foregroundNoti = null;
10632
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010633 // Clear start entries.
10634 r.deliveredStarts.clear();
10635 r.pendingStarts.clear();
10636
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010637 if (r.app != null) {
10638 synchronized (r.stats.getBatteryStats()) {
10639 r.stats.stopLaunchedLocked();
10640 }
10641 r.app.services.remove(r);
10642 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010643 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010644 if (DEBUG_SERVICE) Log.v(TAG,
10645 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010646 bumpServiceExecutingLocked(r);
10647 mStoppingServices.add(r);
10648 updateOomAdjLocked(r.app);
10649 r.app.thread.scheduleStopService(r);
10650 } catch (Exception e) {
10651 Log.w(TAG, "Exception when stopping service "
10652 + r.shortName, e);
10653 serviceDoneExecutingLocked(r, true);
10654 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010655 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010656 } else {
10657 if (DEBUG_SERVICE) Log.v(
10658 TAG, "Removed service that has no process: " + r.shortName);
10659 }
10660 } else {
10661 if (DEBUG_SERVICE) Log.v(
10662 TAG, "Removed service that is not running: " + r.shortName);
10663 }
10664 }
10665
10666 ComponentName startServiceLocked(IApplicationThread caller,
10667 Intent service, String resolvedType,
10668 int callingPid, int callingUid) {
10669 synchronized(this) {
10670 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10671 + " type=" + resolvedType + " args=" + service.getExtras());
10672
10673 if (caller != null) {
10674 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10675 if (callerApp == null) {
10676 throw new SecurityException(
10677 "Unable to find app for caller " + caller
10678 + " (pid=" + Binder.getCallingPid()
10679 + ") when starting service " + service);
10680 }
10681 }
10682
10683 ServiceLookupResult res =
10684 retrieveServiceLocked(service, resolvedType,
10685 callingPid, callingUid);
10686 if (res == null) {
10687 return null;
10688 }
10689 if (res.record == null) {
10690 return new ComponentName("!", res.permission != null
10691 ? res.permission : "private to package");
10692 }
10693 ServiceRecord r = res.record;
10694 if (unscheduleServiceRestartLocked(r)) {
10695 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10696 + r.shortName);
10697 }
10698 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010699 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010700 r.lastStartId++;
10701 if (r.lastStartId < 1) {
10702 r.lastStartId = 1;
10703 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010704 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010705 r.lastActivity = SystemClock.uptimeMillis();
10706 synchronized (r.stats.getBatteryStats()) {
10707 r.stats.startRunningLocked();
10708 }
10709 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10710 return new ComponentName("!", "Service process is bad");
10711 }
10712 return r.name;
10713 }
10714 }
10715
10716 public ComponentName startService(IApplicationThread caller, Intent service,
10717 String resolvedType) {
10718 // Refuse possible leaked file descriptors
10719 if (service != null && service.hasFileDescriptors() == true) {
10720 throw new IllegalArgumentException("File descriptors passed in Intent");
10721 }
10722
10723 synchronized(this) {
10724 final int callingPid = Binder.getCallingPid();
10725 final int callingUid = Binder.getCallingUid();
10726 final long origId = Binder.clearCallingIdentity();
10727 ComponentName res = startServiceLocked(caller, service,
10728 resolvedType, callingPid, callingUid);
10729 Binder.restoreCallingIdentity(origId);
10730 return res;
10731 }
10732 }
10733
10734 ComponentName startServiceInPackage(int uid,
10735 Intent service, String resolvedType) {
10736 synchronized(this) {
10737 final long origId = Binder.clearCallingIdentity();
10738 ComponentName res = startServiceLocked(null, service,
10739 resolvedType, -1, uid);
10740 Binder.restoreCallingIdentity(origId);
10741 return res;
10742 }
10743 }
10744
10745 public int stopService(IApplicationThread caller, Intent service,
10746 String resolvedType) {
10747 // Refuse possible leaked file descriptors
10748 if (service != null && service.hasFileDescriptors() == true) {
10749 throw new IllegalArgumentException("File descriptors passed in Intent");
10750 }
10751
10752 synchronized(this) {
10753 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10754 + " type=" + resolvedType);
10755
10756 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10757 if (caller != null && callerApp == null) {
10758 throw new SecurityException(
10759 "Unable to find app for caller " + caller
10760 + " (pid=" + Binder.getCallingPid()
10761 + ") when stopping service " + service);
10762 }
10763
10764 // If this service is active, make sure it is stopped.
10765 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10766 if (r != null) {
10767 if (r.record != null) {
10768 synchronized (r.record.stats.getBatteryStats()) {
10769 r.record.stats.stopRunningLocked();
10770 }
10771 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010772 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010773 final long origId = Binder.clearCallingIdentity();
10774 bringDownServiceLocked(r.record, false);
10775 Binder.restoreCallingIdentity(origId);
10776 return 1;
10777 }
10778 return -1;
10779 }
10780 }
10781
10782 return 0;
10783 }
10784
10785 public IBinder peekService(Intent service, String resolvedType) {
10786 // Refuse possible leaked file descriptors
10787 if (service != null && service.hasFileDescriptors() == true) {
10788 throw new IllegalArgumentException("File descriptors passed in Intent");
10789 }
10790
10791 IBinder ret = null;
10792
10793 synchronized(this) {
10794 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10795
10796 if (r != null) {
10797 // r.record is null if findServiceLocked() failed the caller permission check
10798 if (r.record == null) {
10799 throw new SecurityException(
10800 "Permission Denial: Accessing service " + r.record.name
10801 + " from pid=" + Binder.getCallingPid()
10802 + ", uid=" + Binder.getCallingUid()
10803 + " requires " + r.permission);
10804 }
10805 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10806 if (ib != null) {
10807 ret = ib.binder;
10808 }
10809 }
10810 }
10811
10812 return ret;
10813 }
10814
10815 public boolean stopServiceToken(ComponentName className, IBinder token,
10816 int startId) {
10817 synchronized(this) {
10818 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10819 + " " + token + " startId=" + startId);
10820 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010821 if (r != null) {
10822 if (startId >= 0) {
10823 // Asked to only stop if done with all work. Note that
10824 // to avoid leaks, we will take this as dropping all
10825 // start items up to and including this one.
10826 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10827 if (si != null) {
10828 while (r.deliveredStarts.size() > 0) {
10829 if (r.deliveredStarts.remove(0) == si) {
10830 break;
10831 }
10832 }
10833 }
10834
10835 if (r.lastStartId != startId) {
10836 return false;
10837 }
10838
10839 if (r.deliveredStarts.size() > 0) {
10840 Log.w(TAG, "stopServiceToken startId " + startId
10841 + " is last, but have " + r.deliveredStarts.size()
10842 + " remaining args");
10843 }
10844 }
10845
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010846 synchronized (r.stats.getBatteryStats()) {
10847 r.stats.stopRunningLocked();
10848 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010849 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010850 }
10851 final long origId = Binder.clearCallingIdentity();
10852 bringDownServiceLocked(r, false);
10853 Binder.restoreCallingIdentity(origId);
10854 return true;
10855 }
10856 }
10857 return false;
10858 }
10859
10860 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010861 int id, Notification notification, boolean removeNotification) {
10862 final long origId = Binder.clearCallingIdentity();
10863 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010864 synchronized(this) {
10865 ServiceRecord r = findServiceLocked(className, token);
10866 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010867 if (id != 0) {
10868 if (notification == null) {
10869 throw new IllegalArgumentException("null notification");
10870 }
10871 if (r.foregroundId != id) {
10872 r.cancelNotification();
10873 r.foregroundId = id;
10874 }
10875 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10876 r.foregroundNoti = notification;
10877 r.isForeground = true;
10878 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010879 if (r.app != null) {
10880 updateServiceForegroundLocked(r.app, true);
10881 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010882 } else {
10883 if (r.isForeground) {
10884 r.isForeground = false;
10885 if (r.app != null) {
10886 updateServiceForegroundLocked(r.app, true);
10887 }
10888 }
10889 if (removeNotification) {
10890 r.cancelNotification();
10891 r.foregroundId = 0;
10892 r.foregroundNoti = null;
10893 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010894 }
10895 }
10896 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010897 } finally {
10898 Binder.restoreCallingIdentity(origId);
10899 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010900 }
10901
10902 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10903 boolean anyForeground = false;
10904 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10905 if (sr.isForeground) {
10906 anyForeground = true;
10907 break;
10908 }
10909 }
10910 if (anyForeground != proc.foregroundServices) {
10911 proc.foregroundServices = anyForeground;
10912 if (oomAdj) {
10913 updateOomAdjLocked();
10914 }
10915 }
10916 }
10917
10918 public int bindService(IApplicationThread caller, IBinder token,
10919 Intent service, String resolvedType,
10920 IServiceConnection connection, int flags) {
10921 // Refuse possible leaked file descriptors
10922 if (service != null && service.hasFileDescriptors() == true) {
10923 throw new IllegalArgumentException("File descriptors passed in Intent");
10924 }
10925
10926 synchronized(this) {
10927 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10928 + " type=" + resolvedType + " conn=" + connection.asBinder()
10929 + " flags=0x" + Integer.toHexString(flags));
10930 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10931 if (callerApp == null) {
10932 throw new SecurityException(
10933 "Unable to find app for caller " + caller
10934 + " (pid=" + Binder.getCallingPid()
10935 + ") when binding service " + service);
10936 }
10937
10938 HistoryRecord activity = null;
10939 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010940 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010941 if (aindex < 0) {
10942 Log.w(TAG, "Binding with unknown activity: " + token);
10943 return 0;
10944 }
10945 activity = (HistoryRecord)mHistory.get(aindex);
10946 }
10947
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010948 int clientLabel = 0;
10949 PendingIntent clientIntent = null;
10950
10951 if (callerApp.info.uid == Process.SYSTEM_UID) {
10952 // Hacky kind of thing -- allow system stuff to tell us
10953 // what they are, so we can report this elsewhere for
10954 // others to know why certain services are running.
10955 try {
10956 clientIntent = (PendingIntent)service.getParcelableExtra(
10957 Intent.EXTRA_CLIENT_INTENT);
10958 } catch (RuntimeException e) {
10959 }
10960 if (clientIntent != null) {
10961 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
10962 if (clientLabel != 0) {
10963 // There are no useful extras in the intent, trash them.
10964 // System code calling with this stuff just needs to know
10965 // this will happen.
10966 service = service.cloneFilter();
10967 }
10968 }
10969 }
10970
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010971 ServiceLookupResult res =
10972 retrieveServiceLocked(service, resolvedType,
10973 Binder.getCallingPid(), Binder.getCallingUid());
10974 if (res == null) {
10975 return 0;
10976 }
10977 if (res.record == null) {
10978 return -1;
10979 }
10980 ServiceRecord s = res.record;
10981
10982 final long origId = Binder.clearCallingIdentity();
10983
10984 if (unscheduleServiceRestartLocked(s)) {
10985 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10986 + s.shortName);
10987 }
10988
10989 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10990 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010991 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010992
10993 IBinder binder = connection.asBinder();
10994 s.connections.put(binder, c);
10995 b.connections.add(c);
10996 if (activity != null) {
10997 if (activity.connections == null) {
10998 activity.connections = new HashSet<ConnectionRecord>();
10999 }
11000 activity.connections.add(c);
11001 }
11002 b.client.connections.add(c);
11003 mServiceConnections.put(binder, c);
11004
11005 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11006 s.lastActivity = SystemClock.uptimeMillis();
11007 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11008 return 0;
11009 }
11010 }
11011
11012 if (s.app != null) {
11013 // This could have made the service more important.
11014 updateOomAdjLocked(s.app);
11015 }
11016
11017 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11018 + ": received=" + b.intent.received
11019 + " apps=" + b.intent.apps.size()
11020 + " doRebind=" + b.intent.doRebind);
11021
11022 if (s.app != null && b.intent.received) {
11023 // Service is already running, so we can immediately
11024 // publish the connection.
11025 try {
11026 c.conn.connected(s.name, b.intent.binder);
11027 } catch (Exception e) {
11028 Log.w(TAG, "Failure sending service " + s.shortName
11029 + " to connection " + c.conn.asBinder()
11030 + " (in " + c.binding.client.processName + ")", e);
11031 }
11032
11033 // If this is the first app connected back to this binding,
11034 // and the service had previously asked to be told when
11035 // rebound, then do so.
11036 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11037 requestServiceBindingLocked(s, b.intent, true);
11038 }
11039 } else if (!b.intent.requested) {
11040 requestServiceBindingLocked(s, b.intent, false);
11041 }
11042
11043 Binder.restoreCallingIdentity(origId);
11044 }
11045
11046 return 1;
11047 }
11048
11049 private void removeConnectionLocked(
11050 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11051 IBinder binder = c.conn.asBinder();
11052 AppBindRecord b = c.binding;
11053 ServiceRecord s = b.service;
11054 s.connections.remove(binder);
11055 b.connections.remove(c);
11056 if (c.activity != null && c.activity != skipAct) {
11057 if (c.activity.connections != null) {
11058 c.activity.connections.remove(c);
11059 }
11060 }
11061 if (b.client != skipApp) {
11062 b.client.connections.remove(c);
11063 }
11064 mServiceConnections.remove(binder);
11065
11066 if (b.connections.size() == 0) {
11067 b.intent.apps.remove(b.client);
11068 }
11069
11070 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11071 + ": shouldUnbind=" + b.intent.hasBound);
11072 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11073 && b.intent.hasBound) {
11074 try {
11075 bumpServiceExecutingLocked(s);
11076 updateOomAdjLocked(s.app);
11077 b.intent.hasBound = false;
11078 // Assume the client doesn't want to know about a rebind;
11079 // we will deal with that later if it asks for one.
11080 b.intent.doRebind = false;
11081 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11082 } catch (Exception e) {
11083 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11084 serviceDoneExecutingLocked(s, true);
11085 }
11086 }
11087
11088 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11089 bringDownServiceLocked(s, false);
11090 }
11091 }
11092
11093 public boolean unbindService(IServiceConnection connection) {
11094 synchronized (this) {
11095 IBinder binder = connection.asBinder();
11096 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11097 ConnectionRecord r = mServiceConnections.get(binder);
11098 if (r == null) {
11099 Log.w(TAG, "Unbind failed: could not find connection for "
11100 + connection.asBinder());
11101 return false;
11102 }
11103
11104 final long origId = Binder.clearCallingIdentity();
11105
11106 removeConnectionLocked(r, null, null);
11107
11108 if (r.binding.service.app != null) {
11109 // This could have made the service less important.
11110 updateOomAdjLocked(r.binding.service.app);
11111 }
11112
11113 Binder.restoreCallingIdentity(origId);
11114 }
11115
11116 return true;
11117 }
11118
11119 public void publishService(IBinder token, Intent intent, IBinder service) {
11120 // Refuse possible leaked file descriptors
11121 if (intent != null && intent.hasFileDescriptors() == true) {
11122 throw new IllegalArgumentException("File descriptors passed in Intent");
11123 }
11124
11125 synchronized(this) {
11126 if (!(token instanceof ServiceRecord)) {
11127 throw new IllegalArgumentException("Invalid service token");
11128 }
11129 ServiceRecord r = (ServiceRecord)token;
11130
11131 final long origId = Binder.clearCallingIdentity();
11132
11133 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11134 + " " + intent + ": " + service);
11135 if (r != null) {
11136 Intent.FilterComparison filter
11137 = new Intent.FilterComparison(intent);
11138 IntentBindRecord b = r.bindings.get(filter);
11139 if (b != null && !b.received) {
11140 b.binder = service;
11141 b.requested = true;
11142 b.received = true;
11143 if (r.connections.size() > 0) {
11144 Iterator<ConnectionRecord> it
11145 = r.connections.values().iterator();
11146 while (it.hasNext()) {
11147 ConnectionRecord c = it.next();
11148 if (!filter.equals(c.binding.intent.intent)) {
11149 if (DEBUG_SERVICE) Log.v(
11150 TAG, "Not publishing to: " + c);
11151 if (DEBUG_SERVICE) Log.v(
11152 TAG, "Bound intent: " + c.binding.intent.intent);
11153 if (DEBUG_SERVICE) Log.v(
11154 TAG, "Published intent: " + intent);
11155 continue;
11156 }
11157 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11158 try {
11159 c.conn.connected(r.name, service);
11160 } catch (Exception e) {
11161 Log.w(TAG, "Failure sending service " + r.name +
11162 " to connection " + c.conn.asBinder() +
11163 " (in " + c.binding.client.processName + ")", e);
11164 }
11165 }
11166 }
11167 }
11168
11169 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11170
11171 Binder.restoreCallingIdentity(origId);
11172 }
11173 }
11174 }
11175
11176 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11177 // Refuse possible leaked file descriptors
11178 if (intent != null && intent.hasFileDescriptors() == true) {
11179 throw new IllegalArgumentException("File descriptors passed in Intent");
11180 }
11181
11182 synchronized(this) {
11183 if (!(token instanceof ServiceRecord)) {
11184 throw new IllegalArgumentException("Invalid service token");
11185 }
11186 ServiceRecord r = (ServiceRecord)token;
11187
11188 final long origId = Binder.clearCallingIdentity();
11189
11190 if (r != null) {
11191 Intent.FilterComparison filter
11192 = new Intent.FilterComparison(intent);
11193 IntentBindRecord b = r.bindings.get(filter);
11194 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11195 + " at " + b + ": apps="
11196 + (b != null ? b.apps.size() : 0));
11197 if (b != null) {
11198 if (b.apps.size() > 0) {
11199 // Applications have already bound since the last
11200 // unbind, so just rebind right here.
11201 requestServiceBindingLocked(r, b, true);
11202 } else {
11203 // Note to tell the service the next time there is
11204 // a new client.
11205 b.doRebind = true;
11206 }
11207 }
11208
11209 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11210
11211 Binder.restoreCallingIdentity(origId);
11212 }
11213 }
11214 }
11215
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011216 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011217 synchronized(this) {
11218 if (!(token instanceof ServiceRecord)) {
11219 throw new IllegalArgumentException("Invalid service token");
11220 }
11221 ServiceRecord r = (ServiceRecord)token;
11222 boolean inStopping = mStoppingServices.contains(token);
11223 if (r != null) {
11224 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11225 + ": nesting=" + r.executeNesting
11226 + ", inStopping=" + inStopping);
11227 if (r != token) {
11228 Log.w(TAG, "Done executing service " + r.name
11229 + " with incorrect token: given " + token
11230 + ", expected " + r);
11231 return;
11232 }
11233
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011234 if (type == 1) {
11235 // This is a call from a service start... take care of
11236 // book-keeping.
11237 r.callStart = true;
11238 switch (res) {
11239 case Service.START_STICKY_COMPATIBILITY:
11240 case Service.START_STICKY: {
11241 // We are done with the associated start arguments.
11242 r.findDeliveredStart(startId, true);
11243 // Don't stop if killed.
11244 r.stopIfKilled = false;
11245 break;
11246 }
11247 case Service.START_NOT_STICKY: {
11248 // We are done with the associated start arguments.
11249 r.findDeliveredStart(startId, true);
11250 if (r.lastStartId == startId) {
11251 // There is no more work, and this service
11252 // doesn't want to hang around if killed.
11253 r.stopIfKilled = true;
11254 }
11255 break;
11256 }
11257 case Service.START_REDELIVER_INTENT: {
11258 // We'll keep this item until they explicitly
11259 // call stop for it, but keep track of the fact
11260 // that it was delivered.
11261 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11262 if (si != null) {
11263 si.deliveryCount = 0;
11264 si.doneExecutingCount++;
11265 // Don't stop if killed.
11266 r.stopIfKilled = true;
11267 }
11268 break;
11269 }
11270 default:
11271 throw new IllegalArgumentException(
11272 "Unknown service start result: " + res);
11273 }
11274 if (res == Service.START_STICKY_COMPATIBILITY) {
11275 r.callStart = false;
11276 }
11277 }
11278
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011279 final long origId = Binder.clearCallingIdentity();
11280 serviceDoneExecutingLocked(r, inStopping);
11281 Binder.restoreCallingIdentity(origId);
11282 } else {
11283 Log.w(TAG, "Done executing unknown service " + r.name
11284 + " with token " + token);
11285 }
11286 }
11287 }
11288
11289 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11290 r.executeNesting--;
11291 if (r.executeNesting <= 0 && r.app != null) {
11292 r.app.executingServices.remove(r);
11293 if (r.app.executingServices.size() == 0) {
11294 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11295 }
11296 if (inStopping) {
11297 mStoppingServices.remove(r);
11298 }
11299 updateOomAdjLocked(r.app);
11300 }
11301 }
11302
11303 void serviceTimeout(ProcessRecord proc) {
11304 synchronized(this) {
11305 if (proc.executingServices.size() == 0 || proc.thread == null) {
11306 return;
11307 }
11308 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11309 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11310 ServiceRecord timeout = null;
11311 long nextTime = 0;
11312 while (it.hasNext()) {
11313 ServiceRecord sr = it.next();
11314 if (sr.executingStart < maxTime) {
11315 timeout = sr;
11316 break;
11317 }
11318 if (sr.executingStart > nextTime) {
11319 nextTime = sr.executingStart;
11320 }
11321 }
11322 if (timeout != null && mLRUProcesses.contains(proc)) {
11323 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011324 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011325 + timeout.name);
11326 } else {
11327 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11328 msg.obj = proc;
11329 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11330 }
11331 }
11332 }
11333
11334 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011335 // BACKUP AND RESTORE
11336 // =========================================================
11337
11338 // Cause the target app to be launched if necessary and its backup agent
11339 // instantiated. The backup agent will invoke backupAgentCreated() on the
11340 // activity manager to announce its creation.
11341 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11342 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11343 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11344
11345 synchronized(this) {
11346 // !!! TODO: currently no check here that we're already bound
11347 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11348 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11349 synchronized (stats) {
11350 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11351 }
11352
11353 BackupRecord r = new BackupRecord(ss, app, backupMode);
11354 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11355 // startProcessLocked() returns existing proc's record if it's already running
11356 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011357 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011358 if (proc == null) {
11359 Log.e(TAG, "Unable to start backup agent process " + r);
11360 return false;
11361 }
11362
11363 r.app = proc;
11364 mBackupTarget = r;
11365 mBackupAppName = app.packageName;
11366
Christopher Tate6fa95972009-06-05 18:43:55 -070011367 // Try not to kill the process during backup
11368 updateOomAdjLocked(proc);
11369
Christopher Tate181fafa2009-05-14 11:12:14 -070011370 // If the process is already attached, schedule the creation of the backup agent now.
11371 // If it is not yet live, this will be done when it attaches to the framework.
11372 if (proc.thread != null) {
11373 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11374 try {
11375 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11376 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011377 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011378 }
11379 } else {
11380 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11381 }
11382 // Invariants: at this point, the target app process exists and the application
11383 // is either already running or in the process of coming up. mBackupTarget and
11384 // mBackupAppName describe the app, so that when it binds back to the AM we
11385 // know that it's scheduled for a backup-agent operation.
11386 }
11387
11388 return true;
11389 }
11390
11391 // A backup agent has just come up
11392 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11393 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11394 + " = " + agent);
11395
11396 synchronized(this) {
11397 if (!agentPackageName.equals(mBackupAppName)) {
11398 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11399 return;
11400 }
11401
Christopher Tate043dadc2009-06-02 16:11:00 -070011402 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011403 try {
11404 IBackupManager bm = IBackupManager.Stub.asInterface(
11405 ServiceManager.getService(Context.BACKUP_SERVICE));
11406 bm.agentConnected(agentPackageName, agent);
11407 } catch (RemoteException e) {
11408 // can't happen; the backup manager service is local
11409 } catch (Exception e) {
11410 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11411 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011412 } finally {
11413 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011414 }
11415 }
11416 }
11417
11418 // done with this agent
11419 public void unbindBackupAgent(ApplicationInfo appInfo) {
11420 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011421 if (appInfo == null) {
11422 Log.w(TAG, "unbind backup agent for null app");
11423 return;
11424 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011425
11426 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011427 if (mBackupAppName == null) {
11428 Log.w(TAG, "Unbinding backup agent with no active backup");
11429 return;
11430 }
11431
Christopher Tate181fafa2009-05-14 11:12:14 -070011432 if (!mBackupAppName.equals(appInfo.packageName)) {
11433 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11434 return;
11435 }
11436
Christopher Tate6fa95972009-06-05 18:43:55 -070011437 ProcessRecord proc = mBackupTarget.app;
11438 mBackupTarget = null;
11439 mBackupAppName = null;
11440
11441 // Not backing this app up any more; reset its OOM adjustment
11442 updateOomAdjLocked(proc);
11443
Christopher Tatec7b31e32009-06-10 15:49:30 -070011444 // If the app crashed during backup, 'thread' will be null here
11445 if (proc.thread != null) {
11446 try {
11447 proc.thread.scheduleDestroyBackupAgent(appInfo);
11448 } catch (Exception e) {
11449 Log.e(TAG, "Exception when unbinding backup agent:");
11450 e.printStackTrace();
11451 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011452 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011453 }
11454 }
11455 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011456 // BROADCASTS
11457 // =========================================================
11458
11459 private final List getStickies(String action, IntentFilter filter,
11460 List cur) {
11461 final ContentResolver resolver = mContext.getContentResolver();
11462 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11463 if (list == null) {
11464 return cur;
11465 }
11466 int N = list.size();
11467 for (int i=0; i<N; i++) {
11468 Intent intent = list.get(i);
11469 if (filter.match(resolver, intent, true, TAG) >= 0) {
11470 if (cur == null) {
11471 cur = new ArrayList<Intent>();
11472 }
11473 cur.add(intent);
11474 }
11475 }
11476 return cur;
11477 }
11478
11479 private final void scheduleBroadcastsLocked() {
11480 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11481 + mBroadcastsScheduled);
11482
11483 if (mBroadcastsScheduled) {
11484 return;
11485 }
11486 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11487 mBroadcastsScheduled = true;
11488 }
11489
11490 public Intent registerReceiver(IApplicationThread caller,
11491 IIntentReceiver receiver, IntentFilter filter, String permission) {
11492 synchronized(this) {
11493 ProcessRecord callerApp = null;
11494 if (caller != null) {
11495 callerApp = getRecordForAppLocked(caller);
11496 if (callerApp == null) {
11497 throw new SecurityException(
11498 "Unable to find app for caller " + caller
11499 + " (pid=" + Binder.getCallingPid()
11500 + ") when registering receiver " + receiver);
11501 }
11502 }
11503
11504 List allSticky = null;
11505
11506 // Look for any matching sticky broadcasts...
11507 Iterator actions = filter.actionsIterator();
11508 if (actions != null) {
11509 while (actions.hasNext()) {
11510 String action = (String)actions.next();
11511 allSticky = getStickies(action, filter, allSticky);
11512 }
11513 } else {
11514 allSticky = getStickies(null, filter, allSticky);
11515 }
11516
11517 // The first sticky in the list is returned directly back to
11518 // the client.
11519 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11520
11521 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11522 + ": " + sticky);
11523
11524 if (receiver == null) {
11525 return sticky;
11526 }
11527
11528 ReceiverList rl
11529 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11530 if (rl == null) {
11531 rl = new ReceiverList(this, callerApp,
11532 Binder.getCallingPid(),
11533 Binder.getCallingUid(), receiver);
11534 if (rl.app != null) {
11535 rl.app.receivers.add(rl);
11536 } else {
11537 try {
11538 receiver.asBinder().linkToDeath(rl, 0);
11539 } catch (RemoteException e) {
11540 return sticky;
11541 }
11542 rl.linkedToDeath = true;
11543 }
11544 mRegisteredReceivers.put(receiver.asBinder(), rl);
11545 }
11546 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11547 rl.add(bf);
11548 if (!bf.debugCheck()) {
11549 Log.w(TAG, "==> For Dynamic broadast");
11550 }
11551 mReceiverResolver.addFilter(bf);
11552
11553 // Enqueue broadcasts for all existing stickies that match
11554 // this filter.
11555 if (allSticky != null) {
11556 ArrayList receivers = new ArrayList();
11557 receivers.add(bf);
11558
11559 int N = allSticky.size();
11560 for (int i=0; i<N; i++) {
11561 Intent intent = (Intent)allSticky.get(i);
11562 BroadcastRecord r = new BroadcastRecord(intent, null,
11563 null, -1, -1, null, receivers, null, 0, null, null,
11564 false);
11565 if (mParallelBroadcasts.size() == 0) {
11566 scheduleBroadcastsLocked();
11567 }
11568 mParallelBroadcasts.add(r);
11569 }
11570 }
11571
11572 return sticky;
11573 }
11574 }
11575
11576 public void unregisterReceiver(IIntentReceiver receiver) {
11577 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11578
11579 boolean doNext = false;
11580
11581 synchronized(this) {
11582 ReceiverList rl
11583 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11584 if (rl != null) {
11585 if (rl.curBroadcast != null) {
11586 BroadcastRecord r = rl.curBroadcast;
11587 doNext = finishReceiverLocked(
11588 receiver.asBinder(), r.resultCode, r.resultData,
11589 r.resultExtras, r.resultAbort, true);
11590 }
11591
11592 if (rl.app != null) {
11593 rl.app.receivers.remove(rl);
11594 }
11595 removeReceiverLocked(rl);
11596 if (rl.linkedToDeath) {
11597 rl.linkedToDeath = false;
11598 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11599 }
11600 }
11601 }
11602
11603 if (!doNext) {
11604 return;
11605 }
11606
11607 final long origId = Binder.clearCallingIdentity();
11608 processNextBroadcast(false);
11609 trimApplications();
11610 Binder.restoreCallingIdentity(origId);
11611 }
11612
11613 void removeReceiverLocked(ReceiverList rl) {
11614 mRegisteredReceivers.remove(rl.receiver.asBinder());
11615 int N = rl.size();
11616 for (int i=0; i<N; i++) {
11617 mReceiverResolver.removeFilter(rl.get(i));
11618 }
11619 }
11620
11621 private final int broadcastIntentLocked(ProcessRecord callerApp,
11622 String callerPackage, Intent intent, String resolvedType,
11623 IIntentReceiver resultTo, int resultCode, String resultData,
11624 Bundle map, String requiredPermission,
11625 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11626 intent = new Intent(intent);
11627
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011628 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011629 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11630 + " ordered=" + ordered);
11631 if ((resultTo != null) && !ordered) {
11632 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11633 }
11634
11635 // Handle special intents: if this broadcast is from the package
11636 // manager about a package being removed, we need to remove all of
11637 // its activities from the history stack.
11638 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11639 intent.getAction());
11640 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11641 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11642 || uidRemoved) {
11643 if (checkComponentPermission(
11644 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11645 callingPid, callingUid, -1)
11646 == PackageManager.PERMISSION_GRANTED) {
11647 if (uidRemoved) {
11648 final Bundle intentExtras = intent.getExtras();
11649 final int uid = intentExtras != null
11650 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11651 if (uid >= 0) {
11652 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11653 synchronized (bs) {
11654 bs.removeUidStatsLocked(uid);
11655 }
11656 }
11657 } else {
11658 Uri data = intent.getData();
11659 String ssp;
11660 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11661 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11662 uninstallPackageLocked(ssp,
11663 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011664 AttributeCache ac = AttributeCache.instance();
11665 if (ac != null) {
11666 ac.removePackage(ssp);
11667 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011668 }
11669 }
11670 }
11671 } else {
11672 String msg = "Permission Denial: " + intent.getAction()
11673 + " broadcast from " + callerPackage + " (pid=" + callingPid
11674 + ", uid=" + callingUid + ")"
11675 + " requires "
11676 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11677 Log.w(TAG, msg);
11678 throw new SecurityException(msg);
11679 }
11680 }
11681
11682 /*
11683 * If this is the time zone changed action, queue up a message that will reset the timezone
11684 * of all currently running processes. This message will get queued up before the broadcast
11685 * happens.
11686 */
11687 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11688 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11689 }
11690
Dianne Hackborn854060af2009-07-09 18:14:31 -070011691 /*
11692 * Prevent non-system code (defined here to be non-persistent
11693 * processes) from sending protected broadcasts.
11694 */
11695 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11696 || callingUid == Process.SHELL_UID || callingUid == 0) {
11697 // Always okay.
11698 } else if (callerApp == null || !callerApp.persistent) {
11699 try {
11700 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11701 intent.getAction())) {
11702 String msg = "Permission Denial: not allowed to send broadcast "
11703 + intent.getAction() + " from pid="
11704 + callingPid + ", uid=" + callingUid;
11705 Log.w(TAG, msg);
11706 throw new SecurityException(msg);
11707 }
11708 } catch (RemoteException e) {
11709 Log.w(TAG, "Remote exception", e);
11710 return BROADCAST_SUCCESS;
11711 }
11712 }
11713
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011714 // Add to the sticky list if requested.
11715 if (sticky) {
11716 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11717 callingPid, callingUid)
11718 != PackageManager.PERMISSION_GRANTED) {
11719 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11720 + callingPid + ", uid=" + callingUid
11721 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11722 Log.w(TAG, msg);
11723 throw new SecurityException(msg);
11724 }
11725 if (requiredPermission != null) {
11726 Log.w(TAG, "Can't broadcast sticky intent " + intent
11727 + " and enforce permission " + requiredPermission);
11728 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11729 }
11730 if (intent.getComponent() != null) {
11731 throw new SecurityException(
11732 "Sticky broadcasts can't target a specific component");
11733 }
11734 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11735 if (list == null) {
11736 list = new ArrayList<Intent>();
11737 mStickyBroadcasts.put(intent.getAction(), list);
11738 }
11739 int N = list.size();
11740 int i;
11741 for (i=0; i<N; i++) {
11742 if (intent.filterEquals(list.get(i))) {
11743 // This sticky already exists, replace it.
11744 list.set(i, new Intent(intent));
11745 break;
11746 }
11747 }
11748 if (i >= N) {
11749 list.add(new Intent(intent));
11750 }
11751 }
11752
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011753 // Figure out who all will receive this broadcast.
11754 List receivers = null;
11755 List<BroadcastFilter> registeredReceivers = null;
11756 try {
11757 if (intent.getComponent() != null) {
11758 // Broadcast is going to one specific receiver class...
11759 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011760 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011761 if (ai != null) {
11762 receivers = new ArrayList();
11763 ResolveInfo ri = new ResolveInfo();
11764 ri.activityInfo = ai;
11765 receivers.add(ri);
11766 }
11767 } else {
11768 // Need to resolve the intent to interested receivers...
11769 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11770 == 0) {
11771 receivers =
11772 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011773 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011774 }
Mihai Preda074edef2009-05-18 17:13:31 +020011775 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011776 }
11777 } catch (RemoteException ex) {
11778 // pm is in same process, this will never happen.
11779 }
11780
11781 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11782 if (!ordered && NR > 0) {
11783 // If we are not serializing this broadcast, then send the
11784 // registered receivers separately so they don't wait for the
11785 // components to be launched.
11786 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11787 callerPackage, callingPid, callingUid, requiredPermission,
11788 registeredReceivers, resultTo, resultCode, resultData, map,
11789 ordered);
11790 if (DEBUG_BROADCAST) Log.v(
11791 TAG, "Enqueueing parallel broadcast " + r
11792 + ": prev had " + mParallelBroadcasts.size());
11793 mParallelBroadcasts.add(r);
11794 scheduleBroadcastsLocked();
11795 registeredReceivers = null;
11796 NR = 0;
11797 }
11798
11799 // Merge into one list.
11800 int ir = 0;
11801 if (receivers != null) {
11802 // A special case for PACKAGE_ADDED: do not allow the package
11803 // being added to see this broadcast. This prevents them from
11804 // using this as a back door to get run as soon as they are
11805 // installed. Maybe in the future we want to have a special install
11806 // broadcast or such for apps, but we'd like to deliberately make
11807 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011808 boolean skip = false;
11809 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011810 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011811 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11812 skip = true;
11813 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11814 skip = true;
11815 }
11816 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011817 ? intent.getData().getSchemeSpecificPart()
11818 : null;
11819 if (skipPackage != null && receivers != null) {
11820 int NT = receivers.size();
11821 for (int it=0; it<NT; it++) {
11822 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11823 if (curt.activityInfo.packageName.equals(skipPackage)) {
11824 receivers.remove(it);
11825 it--;
11826 NT--;
11827 }
11828 }
11829 }
11830
11831 int NT = receivers != null ? receivers.size() : 0;
11832 int it = 0;
11833 ResolveInfo curt = null;
11834 BroadcastFilter curr = null;
11835 while (it < NT && ir < NR) {
11836 if (curt == null) {
11837 curt = (ResolveInfo)receivers.get(it);
11838 }
11839 if (curr == null) {
11840 curr = registeredReceivers.get(ir);
11841 }
11842 if (curr.getPriority() >= curt.priority) {
11843 // Insert this broadcast record into the final list.
11844 receivers.add(it, curr);
11845 ir++;
11846 curr = null;
11847 it++;
11848 NT++;
11849 } else {
11850 // Skip to the next ResolveInfo in the final list.
11851 it++;
11852 curt = null;
11853 }
11854 }
11855 }
11856 while (ir < NR) {
11857 if (receivers == null) {
11858 receivers = new ArrayList();
11859 }
11860 receivers.add(registeredReceivers.get(ir));
11861 ir++;
11862 }
11863
11864 if ((receivers != null && receivers.size() > 0)
11865 || resultTo != null) {
11866 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11867 callerPackage, callingPid, callingUid, requiredPermission,
11868 receivers, resultTo, resultCode, resultData, map, ordered);
11869 if (DEBUG_BROADCAST) Log.v(
11870 TAG, "Enqueueing ordered broadcast " + r
11871 + ": prev had " + mOrderedBroadcasts.size());
11872 if (DEBUG_BROADCAST) {
11873 int seq = r.intent.getIntExtra("seq", -1);
11874 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11875 }
11876 mOrderedBroadcasts.add(r);
11877 scheduleBroadcastsLocked();
11878 }
11879
11880 return BROADCAST_SUCCESS;
11881 }
11882
11883 public final int broadcastIntent(IApplicationThread caller,
11884 Intent intent, String resolvedType, IIntentReceiver resultTo,
11885 int resultCode, String resultData, Bundle map,
11886 String requiredPermission, boolean serialized, boolean sticky) {
11887 // Refuse possible leaked file descriptors
11888 if (intent != null && intent.hasFileDescriptors() == true) {
11889 throw new IllegalArgumentException("File descriptors passed in Intent");
11890 }
11891
11892 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011893 int flags = intent.getFlags();
11894
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011895 if (!mSystemReady) {
11896 // if the caller really truly claims to know what they're doing, go
11897 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011898 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11899 intent = new Intent(intent);
11900 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11901 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11902 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11903 + " before boot completion");
11904 throw new IllegalStateException("Cannot broadcast before boot completed");
11905 }
11906 }
11907
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011908 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
11909 throw new IllegalArgumentException(
11910 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
11911 }
11912
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011913 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11914 final int callingPid = Binder.getCallingPid();
11915 final int callingUid = Binder.getCallingUid();
11916 final long origId = Binder.clearCallingIdentity();
11917 int res = broadcastIntentLocked(callerApp,
11918 callerApp != null ? callerApp.info.packageName : null,
11919 intent, resolvedType, resultTo,
11920 resultCode, resultData, map, requiredPermission, serialized,
11921 sticky, callingPid, callingUid);
11922 Binder.restoreCallingIdentity(origId);
11923 return res;
11924 }
11925 }
11926
11927 int broadcastIntentInPackage(String packageName, int uid,
11928 Intent intent, String resolvedType, IIntentReceiver resultTo,
11929 int resultCode, String resultData, Bundle map,
11930 String requiredPermission, boolean serialized, boolean sticky) {
11931 synchronized(this) {
11932 final long origId = Binder.clearCallingIdentity();
11933 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11934 resultTo, resultCode, resultData, map, requiredPermission,
11935 serialized, sticky, -1, uid);
11936 Binder.restoreCallingIdentity(origId);
11937 return res;
11938 }
11939 }
11940
11941 public final void unbroadcastIntent(IApplicationThread caller,
11942 Intent intent) {
11943 // Refuse possible leaked file descriptors
11944 if (intent != null && intent.hasFileDescriptors() == true) {
11945 throw new IllegalArgumentException("File descriptors passed in Intent");
11946 }
11947
11948 synchronized(this) {
11949 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11950 != PackageManager.PERMISSION_GRANTED) {
11951 String msg = "Permission Denial: unbroadcastIntent() from pid="
11952 + Binder.getCallingPid()
11953 + ", uid=" + Binder.getCallingUid()
11954 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11955 Log.w(TAG, msg);
11956 throw new SecurityException(msg);
11957 }
11958 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11959 if (list != null) {
11960 int N = list.size();
11961 int i;
11962 for (i=0; i<N; i++) {
11963 if (intent.filterEquals(list.get(i))) {
11964 list.remove(i);
11965 break;
11966 }
11967 }
11968 }
11969 }
11970 }
11971
11972 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11973 String resultData, Bundle resultExtras, boolean resultAbort,
11974 boolean explicit) {
11975 if (mOrderedBroadcasts.size() == 0) {
11976 if (explicit) {
11977 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11978 }
11979 return false;
11980 }
11981 BroadcastRecord r = mOrderedBroadcasts.get(0);
11982 if (r.receiver == null) {
11983 if (explicit) {
11984 Log.w(TAG, "finishReceiver called but none active");
11985 }
11986 return false;
11987 }
11988 if (r.receiver != receiver) {
11989 Log.w(TAG, "finishReceiver called but active receiver is different");
11990 return false;
11991 }
11992 int state = r.state;
11993 r.state = r.IDLE;
11994 if (state == r.IDLE) {
11995 if (explicit) {
11996 Log.w(TAG, "finishReceiver called but state is IDLE");
11997 }
11998 }
11999 r.receiver = null;
12000 r.intent.setComponent(null);
12001 if (r.curApp != null) {
12002 r.curApp.curReceiver = null;
12003 }
12004 if (r.curFilter != null) {
12005 r.curFilter.receiverList.curBroadcast = null;
12006 }
12007 r.curFilter = null;
12008 r.curApp = null;
12009 r.curComponent = null;
12010 r.curReceiver = null;
12011 mPendingBroadcast = null;
12012
12013 r.resultCode = resultCode;
12014 r.resultData = resultData;
12015 r.resultExtras = resultExtras;
12016 r.resultAbort = resultAbort;
12017
12018 // We will process the next receiver right now if this is finishing
12019 // an app receiver (which is always asynchronous) or after we have
12020 // come back from calling a receiver.
12021 return state == BroadcastRecord.APP_RECEIVE
12022 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12023 }
12024
12025 public void finishReceiver(IBinder who, int resultCode, String resultData,
12026 Bundle resultExtras, boolean resultAbort) {
12027 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12028
12029 // Refuse possible leaked file descriptors
12030 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12031 throw new IllegalArgumentException("File descriptors passed in Bundle");
12032 }
12033
12034 boolean doNext;
12035
12036 final long origId = Binder.clearCallingIdentity();
12037
12038 synchronized(this) {
12039 doNext = finishReceiverLocked(
12040 who, resultCode, resultData, resultExtras, resultAbort, true);
12041 }
12042
12043 if (doNext) {
12044 processNextBroadcast(false);
12045 }
12046 trimApplications();
12047
12048 Binder.restoreCallingIdentity(origId);
12049 }
12050
12051 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12052 if (r.nextReceiver > 0) {
12053 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12054 if (curReceiver instanceof BroadcastFilter) {
12055 BroadcastFilter bf = (BroadcastFilter) curReceiver;
12056 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
12057 System.identityHashCode(r),
12058 r.intent.getAction(),
12059 r.nextReceiver - 1,
12060 System.identityHashCode(bf));
12061 } else {
12062 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12063 System.identityHashCode(r),
12064 r.intent.getAction(),
12065 r.nextReceiver - 1,
12066 ((ResolveInfo)curReceiver).toString());
12067 }
12068 } else {
12069 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12070 + r);
12071 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12072 System.identityHashCode(r),
12073 r.intent.getAction(),
12074 r.nextReceiver,
12075 "NONE");
12076 }
12077 }
12078
12079 private final void broadcastTimeout() {
12080 synchronized (this) {
12081 if (mOrderedBroadcasts.size() == 0) {
12082 return;
12083 }
12084 long now = SystemClock.uptimeMillis();
12085 BroadcastRecord r = mOrderedBroadcasts.get(0);
12086 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
12087 if (DEBUG_BROADCAST) Log.v(TAG,
12088 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
12089 + (r.startTime + BROADCAST_TIMEOUT));
12090 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12091 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12092 return;
12093 }
12094
12095 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
12096 r.startTime = now;
12097 r.anrCount++;
12098
12099 // Current receiver has passed its expiration date.
12100 if (r.nextReceiver <= 0) {
12101 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12102 return;
12103 }
12104
12105 ProcessRecord app = null;
12106
12107 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12108 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12109 logBroadcastReceiverDiscard(r);
12110 if (curReceiver instanceof BroadcastFilter) {
12111 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12112 if (bf.receiverList.pid != 0
12113 && bf.receiverList.pid != MY_PID) {
12114 synchronized (this.mPidsSelfLocked) {
12115 app = this.mPidsSelfLocked.get(
12116 bf.receiverList.pid);
12117 }
12118 }
12119 } else {
12120 app = r.curApp;
12121 }
12122
12123 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070012124 appNotRespondingLocked(app, null, null,
12125 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012126 }
12127
12128 if (mPendingBroadcast == r) {
12129 mPendingBroadcast = null;
12130 }
12131
12132 // Move on to the next receiver.
12133 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12134 r.resultExtras, r.resultAbort, true);
12135 scheduleBroadcastsLocked();
12136 }
12137 }
12138
12139 private final void processCurBroadcastLocked(BroadcastRecord r,
12140 ProcessRecord app) throws RemoteException {
12141 if (app.thread == null) {
12142 throw new RemoteException();
12143 }
12144 r.receiver = app.thread.asBinder();
12145 r.curApp = app;
12146 app.curReceiver = r;
12147 updateLRUListLocked(app, true);
12148
12149 // Tell the application to launch this receiver.
12150 r.intent.setComponent(r.curComponent);
12151
12152 boolean started = false;
12153 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012154 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012155 "Delivering to component " + r.curComponent
12156 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012157 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012158 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12159 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12160 started = true;
12161 } finally {
12162 if (!started) {
12163 r.receiver = null;
12164 r.curApp = null;
12165 app.curReceiver = null;
12166 }
12167 }
12168
12169 }
12170
12171 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
12172 Intent intent, int resultCode, String data,
12173 Bundle extras, boolean ordered) throws RemoteException {
12174 if (app != null && app.thread != null) {
12175 // If we have an app thread, do the call through that so it is
12176 // correctly ordered with other one-way calls.
12177 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
12178 data, extras, ordered);
12179 } else {
12180 receiver.performReceive(intent, resultCode, data, extras, ordered);
12181 }
12182 }
12183
12184 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12185 BroadcastFilter filter, boolean ordered) {
12186 boolean skip = false;
12187 if (filter.requiredPermission != null) {
12188 int perm = checkComponentPermission(filter.requiredPermission,
12189 r.callingPid, r.callingUid, -1);
12190 if (perm != PackageManager.PERMISSION_GRANTED) {
12191 Log.w(TAG, "Permission Denial: broadcasting "
12192 + r.intent.toString()
12193 + " from " + r.callerPackage + " (pid="
12194 + r.callingPid + ", uid=" + r.callingUid + ")"
12195 + " requires " + filter.requiredPermission
12196 + " due to registered receiver " + filter);
12197 skip = true;
12198 }
12199 }
12200 if (r.requiredPermission != null) {
12201 int perm = checkComponentPermission(r.requiredPermission,
12202 filter.receiverList.pid, filter.receiverList.uid, -1);
12203 if (perm != PackageManager.PERMISSION_GRANTED) {
12204 Log.w(TAG, "Permission Denial: receiving "
12205 + r.intent.toString()
12206 + " to " + filter.receiverList.app
12207 + " (pid=" + filter.receiverList.pid
12208 + ", uid=" + filter.receiverList.uid + ")"
12209 + " requires " + r.requiredPermission
12210 + " due to sender " + r.callerPackage
12211 + " (uid " + r.callingUid + ")");
12212 skip = true;
12213 }
12214 }
12215
12216 if (!skip) {
12217 // If this is not being sent as an ordered broadcast, then we
12218 // don't want to touch the fields that keep track of the current
12219 // state of ordered broadcasts.
12220 if (ordered) {
12221 r.receiver = filter.receiverList.receiver.asBinder();
12222 r.curFilter = filter;
12223 filter.receiverList.curBroadcast = r;
12224 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012225 if (filter.receiverList.app != null) {
12226 // Bump hosting application to no longer be in background
12227 // scheduling class. Note that we can't do that if there
12228 // isn't an app... but we can only be in that case for
12229 // things that directly call the IActivityManager API, which
12230 // are already core system stuff so don't matter for this.
12231 r.curApp = filter.receiverList.app;
12232 filter.receiverList.app.curReceiver = r;
12233 updateOomAdjLocked();
12234 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012235 }
12236 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012237 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012238 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012239 Log.i(TAG, "Delivering to " + filter.receiverList.app
12240 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012241 }
12242 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12243 new Intent(r.intent), r.resultCode,
12244 r.resultData, r.resultExtras, r.ordered);
12245 if (ordered) {
12246 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12247 }
12248 } catch (RemoteException e) {
12249 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12250 if (ordered) {
12251 r.receiver = null;
12252 r.curFilter = null;
12253 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012254 if (filter.receiverList.app != null) {
12255 filter.receiverList.app.curReceiver = null;
12256 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012257 }
12258 }
12259 }
12260 }
12261
12262 private final void processNextBroadcast(boolean fromMsg) {
12263 synchronized(this) {
12264 BroadcastRecord r;
12265
12266 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12267 + mParallelBroadcasts.size() + " broadcasts, "
12268 + mOrderedBroadcasts.size() + " serialized broadcasts");
12269
12270 updateCpuStats();
12271
12272 if (fromMsg) {
12273 mBroadcastsScheduled = false;
12274 }
12275
12276 // First, deliver any non-serialized broadcasts right away.
12277 while (mParallelBroadcasts.size() > 0) {
12278 r = mParallelBroadcasts.remove(0);
12279 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012280 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12281 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012282 for (int i=0; i<N; i++) {
12283 Object target = r.receivers.get(i);
12284 if (DEBUG_BROADCAST) Log.v(TAG,
12285 "Delivering non-serialized to registered "
12286 + target + ": " + r);
12287 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12288 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012289 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12290 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012291 }
12292
12293 // Now take care of the next serialized one...
12294
12295 // If we are waiting for a process to come up to handle the next
12296 // broadcast, then do nothing at this point. Just in case, we
12297 // check that the process we're waiting for still exists.
12298 if (mPendingBroadcast != null) {
12299 Log.i(TAG, "processNextBroadcast: waiting for "
12300 + mPendingBroadcast.curApp);
12301
12302 boolean isDead;
12303 synchronized (mPidsSelfLocked) {
12304 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12305 }
12306 if (!isDead) {
12307 // It's still alive, so keep waiting
12308 return;
12309 } else {
12310 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12311 + " died before responding to broadcast");
12312 mPendingBroadcast = null;
12313 }
12314 }
12315
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012316 boolean looped = false;
12317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012318 do {
12319 if (mOrderedBroadcasts.size() == 0) {
12320 // No more broadcasts pending, so all done!
12321 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012322 if (looped) {
12323 // If we had finished the last ordered broadcast, then
12324 // make sure all processes have correct oom and sched
12325 // adjustments.
12326 updateOomAdjLocked();
12327 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012328 return;
12329 }
12330 r = mOrderedBroadcasts.get(0);
12331 boolean forceReceive = false;
12332
12333 // Ensure that even if something goes awry with the timeout
12334 // detection, we catch "hung" broadcasts here, discard them,
12335 // and continue to make progress.
12336 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12337 long now = SystemClock.uptimeMillis();
12338 if (r.dispatchTime > 0) {
12339 if ((numReceivers > 0) &&
12340 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12341 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12342 + " now=" + now
12343 + " dispatchTime=" + r.dispatchTime
12344 + " startTime=" + r.startTime
12345 + " intent=" + r.intent
12346 + " numReceivers=" + numReceivers
12347 + " nextReceiver=" + r.nextReceiver
12348 + " state=" + r.state);
12349 broadcastTimeout(); // forcibly finish this broadcast
12350 forceReceive = true;
12351 r.state = BroadcastRecord.IDLE;
12352 }
12353 }
12354
12355 if (r.state != BroadcastRecord.IDLE) {
12356 if (DEBUG_BROADCAST) Log.d(TAG,
12357 "processNextBroadcast() called when not idle (state="
12358 + r.state + ")");
12359 return;
12360 }
12361
12362 if (r.receivers == null || r.nextReceiver >= numReceivers
12363 || r.resultAbort || forceReceive) {
12364 // No more receivers for this broadcast! Send the final
12365 // result if requested...
12366 if (r.resultTo != null) {
12367 try {
12368 if (DEBUG_BROADCAST) {
12369 int seq = r.intent.getIntExtra("seq", -1);
12370 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12371 + " seq=" + seq + " app=" + r.callerApp);
12372 }
12373 performReceive(r.callerApp, r.resultTo,
12374 new Intent(r.intent), r.resultCode,
12375 r.resultData, r.resultExtras, false);
12376 } catch (RemoteException e) {
12377 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12378 }
12379 }
12380
12381 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12382 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12383
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012384 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12385 + r);
12386
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012387 // ... and on to the next...
12388 mOrderedBroadcasts.remove(0);
12389 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012390 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012391 continue;
12392 }
12393 } while (r == null);
12394
12395 // Get the next receiver...
12396 int recIdx = r.nextReceiver++;
12397
12398 // Keep track of when this receiver started, and make sure there
12399 // is a timeout message pending to kill it if need be.
12400 r.startTime = SystemClock.uptimeMillis();
12401 if (recIdx == 0) {
12402 r.dispatchTime = r.startTime;
12403
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012404 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12405 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012406 if (DEBUG_BROADCAST) Log.v(TAG,
12407 "Submitting BROADCAST_TIMEOUT_MSG for "
12408 + (r.startTime + BROADCAST_TIMEOUT));
12409 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12410 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12411 }
12412
12413 Object nextReceiver = r.receivers.get(recIdx);
12414 if (nextReceiver instanceof BroadcastFilter) {
12415 // Simple case: this is a registered receiver who gets
12416 // a direct call.
12417 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12418 if (DEBUG_BROADCAST) Log.v(TAG,
12419 "Delivering serialized to registered "
12420 + filter + ": " + r);
12421 deliverToRegisteredReceiver(r, filter, r.ordered);
12422 if (r.receiver == null || !r.ordered) {
12423 // The receiver has already finished, so schedule to
12424 // process the next one.
12425 r.state = BroadcastRecord.IDLE;
12426 scheduleBroadcastsLocked();
12427 }
12428 return;
12429 }
12430
12431 // Hard case: need to instantiate the receiver, possibly
12432 // starting its application process to host it.
12433
12434 ResolveInfo info =
12435 (ResolveInfo)nextReceiver;
12436
12437 boolean skip = false;
12438 int perm = checkComponentPermission(info.activityInfo.permission,
12439 r.callingPid, r.callingUid,
12440 info.activityInfo.exported
12441 ? -1 : info.activityInfo.applicationInfo.uid);
12442 if (perm != PackageManager.PERMISSION_GRANTED) {
12443 Log.w(TAG, "Permission Denial: broadcasting "
12444 + r.intent.toString()
12445 + " from " + r.callerPackage + " (pid=" + r.callingPid
12446 + ", uid=" + r.callingUid + ")"
12447 + " requires " + info.activityInfo.permission
12448 + " due to receiver " + info.activityInfo.packageName
12449 + "/" + info.activityInfo.name);
12450 skip = true;
12451 }
12452 if (r.callingUid != Process.SYSTEM_UID &&
12453 r.requiredPermission != null) {
12454 try {
12455 perm = ActivityThread.getPackageManager().
12456 checkPermission(r.requiredPermission,
12457 info.activityInfo.applicationInfo.packageName);
12458 } catch (RemoteException e) {
12459 perm = PackageManager.PERMISSION_DENIED;
12460 }
12461 if (perm != PackageManager.PERMISSION_GRANTED) {
12462 Log.w(TAG, "Permission Denial: receiving "
12463 + r.intent + " to "
12464 + info.activityInfo.applicationInfo.packageName
12465 + " requires " + r.requiredPermission
12466 + " due to sender " + r.callerPackage
12467 + " (uid " + r.callingUid + ")");
12468 skip = true;
12469 }
12470 }
12471 if (r.curApp != null && r.curApp.crashing) {
12472 // If the target process is crashing, just skip it.
12473 skip = true;
12474 }
12475
12476 if (skip) {
12477 r.receiver = null;
12478 r.curFilter = null;
12479 r.state = BroadcastRecord.IDLE;
12480 scheduleBroadcastsLocked();
12481 return;
12482 }
12483
12484 r.state = BroadcastRecord.APP_RECEIVE;
12485 String targetProcess = info.activityInfo.processName;
12486 r.curComponent = new ComponentName(
12487 info.activityInfo.applicationInfo.packageName,
12488 info.activityInfo.name);
12489 r.curReceiver = info.activityInfo;
12490
12491 // Is this receiver's application already running?
12492 ProcessRecord app = getProcessRecordLocked(targetProcess,
12493 info.activityInfo.applicationInfo.uid);
12494 if (app != null && app.thread != null) {
12495 try {
12496 processCurBroadcastLocked(r, app);
12497 return;
12498 } catch (RemoteException e) {
12499 Log.w(TAG, "Exception when sending broadcast to "
12500 + r.curComponent, e);
12501 }
12502
12503 // If a dead object exception was thrown -- fall through to
12504 // restart the application.
12505 }
12506
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012507 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012508 if ((r.curApp=startProcessLocked(targetProcess,
12509 info.activityInfo.applicationInfo, true,
12510 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012511 "broadcast", r.curComponent,
12512 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12513 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012514 // Ah, this recipient is unavailable. Finish it if necessary,
12515 // and mark the broadcast record as ready for the next.
12516 Log.w(TAG, "Unable to launch app "
12517 + info.activityInfo.applicationInfo.packageName + "/"
12518 + info.activityInfo.applicationInfo.uid + " for broadcast "
12519 + r.intent + ": process is bad");
12520 logBroadcastReceiverDiscard(r);
12521 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12522 r.resultExtras, r.resultAbort, true);
12523 scheduleBroadcastsLocked();
12524 r.state = BroadcastRecord.IDLE;
12525 return;
12526 }
12527
12528 mPendingBroadcast = r;
12529 }
12530 }
12531
12532 // =========================================================
12533 // INSTRUMENTATION
12534 // =========================================================
12535
12536 public boolean startInstrumentation(ComponentName className,
12537 String profileFile, int flags, Bundle arguments,
12538 IInstrumentationWatcher watcher) {
12539 // Refuse possible leaked file descriptors
12540 if (arguments != null && arguments.hasFileDescriptors()) {
12541 throw new IllegalArgumentException("File descriptors passed in Bundle");
12542 }
12543
12544 synchronized(this) {
12545 InstrumentationInfo ii = null;
12546 ApplicationInfo ai = null;
12547 try {
12548 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012549 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012550 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012551 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012552 } catch (PackageManager.NameNotFoundException e) {
12553 }
12554 if (ii == null) {
12555 reportStartInstrumentationFailure(watcher, className,
12556 "Unable to find instrumentation info for: " + className);
12557 return false;
12558 }
12559 if (ai == null) {
12560 reportStartInstrumentationFailure(watcher, className,
12561 "Unable to find instrumentation target package: " + ii.targetPackage);
12562 return false;
12563 }
12564
12565 int match = mContext.getPackageManager().checkSignatures(
12566 ii.targetPackage, ii.packageName);
12567 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12568 String msg = "Permission Denial: starting instrumentation "
12569 + className + " from pid="
12570 + Binder.getCallingPid()
12571 + ", uid=" + Binder.getCallingPid()
12572 + " not allowed because package " + ii.packageName
12573 + " does not have a signature matching the target "
12574 + ii.targetPackage;
12575 reportStartInstrumentationFailure(watcher, className, msg);
12576 throw new SecurityException(msg);
12577 }
12578
12579 final long origId = Binder.clearCallingIdentity();
12580 uninstallPackageLocked(ii.targetPackage, -1, true);
12581 ProcessRecord app = addAppLocked(ai);
12582 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012583 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012584 app.instrumentationProfileFile = profileFile;
12585 app.instrumentationArguments = arguments;
12586 app.instrumentationWatcher = watcher;
12587 app.instrumentationResultClass = className;
12588 Binder.restoreCallingIdentity(origId);
12589 }
12590
12591 return true;
12592 }
12593
12594 /**
12595 * Report errors that occur while attempting to start Instrumentation. Always writes the
12596 * error to the logs, but if somebody is watching, send the report there too. This enables
12597 * the "am" command to report errors with more information.
12598 *
12599 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12600 * @param cn The component name of the instrumentation.
12601 * @param report The error report.
12602 */
12603 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12604 ComponentName cn, String report) {
12605 Log.w(TAG, report);
12606 try {
12607 if (watcher != null) {
12608 Bundle results = new Bundle();
12609 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12610 results.putString("Error", report);
12611 watcher.instrumentationStatus(cn, -1, results);
12612 }
12613 } catch (RemoteException e) {
12614 Log.w(TAG, e);
12615 }
12616 }
12617
12618 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12619 if (app.instrumentationWatcher != null) {
12620 try {
12621 // NOTE: IInstrumentationWatcher *must* be oneway here
12622 app.instrumentationWatcher.instrumentationFinished(
12623 app.instrumentationClass,
12624 resultCode,
12625 results);
12626 } catch (RemoteException e) {
12627 }
12628 }
12629 app.instrumentationWatcher = null;
12630 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012631 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012632 app.instrumentationProfileFile = null;
12633 app.instrumentationArguments = null;
12634
12635 uninstallPackageLocked(app.processName, -1, false);
12636 }
12637
12638 public void finishInstrumentation(IApplicationThread target,
12639 int resultCode, Bundle results) {
12640 // Refuse possible leaked file descriptors
12641 if (results != null && results.hasFileDescriptors()) {
12642 throw new IllegalArgumentException("File descriptors passed in Intent");
12643 }
12644
12645 synchronized(this) {
12646 ProcessRecord app = getRecordForAppLocked(target);
12647 if (app == null) {
12648 Log.w(TAG, "finishInstrumentation: no app for " + target);
12649 return;
12650 }
12651 final long origId = Binder.clearCallingIdentity();
12652 finishInstrumentationLocked(app, resultCode, results);
12653 Binder.restoreCallingIdentity(origId);
12654 }
12655 }
12656
12657 // =========================================================
12658 // CONFIGURATION
12659 // =========================================================
12660
12661 public ConfigurationInfo getDeviceConfigurationInfo() {
12662 ConfigurationInfo config = new ConfigurationInfo();
12663 synchronized (this) {
12664 config.reqTouchScreen = mConfiguration.touchscreen;
12665 config.reqKeyboardType = mConfiguration.keyboard;
12666 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012667 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12668 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012669 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12670 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012671 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12672 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012673 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12674 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012675 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012676 }
12677 return config;
12678 }
12679
12680 public Configuration getConfiguration() {
12681 Configuration ci;
12682 synchronized(this) {
12683 ci = new Configuration(mConfiguration);
12684 }
12685 return ci;
12686 }
12687
12688 public void updateConfiguration(Configuration values) {
12689 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12690 "updateConfiguration()");
12691
12692 synchronized(this) {
12693 if (values == null && mWindowManager != null) {
12694 // sentinel: fetch the current configuration from the window manager
12695 values = mWindowManager.computeNewConfiguration();
12696 }
12697
12698 final long origId = Binder.clearCallingIdentity();
12699 updateConfigurationLocked(values, null);
12700 Binder.restoreCallingIdentity(origId);
12701 }
12702 }
12703
12704 /**
12705 * Do either or both things: (1) change the current configuration, and (2)
12706 * make sure the given activity is running with the (now) current
12707 * configuration. Returns true if the activity has been left running, or
12708 * false if <var>starting</var> is being destroyed to match the new
12709 * configuration.
12710 */
12711 public boolean updateConfigurationLocked(Configuration values,
12712 HistoryRecord starting) {
12713 int changes = 0;
12714
12715 boolean kept = true;
12716
12717 if (values != null) {
12718 Configuration newConfig = new Configuration(mConfiguration);
12719 changes = newConfig.updateFrom(values);
12720 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012721 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012722 Log.i(TAG, "Updating configuration to: " + values);
12723 }
12724
12725 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12726
12727 if (values.locale != null) {
12728 saveLocaleLocked(values.locale,
12729 !values.locale.equals(mConfiguration.locale),
12730 values.userSetLocale);
12731 }
12732
12733 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012734 Log.i(TAG, "Config changed: " + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012735
12736 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12737 msg.obj = new Configuration(mConfiguration);
12738 mHandler.sendMessage(msg);
12739
12740 final int N = mLRUProcesses.size();
12741 for (int i=0; i<N; i++) {
12742 ProcessRecord app = mLRUProcesses.get(i);
12743 try {
12744 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012745 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
12746 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012747 app.thread.scheduleConfigurationChanged(mConfiguration);
12748 }
12749 } catch (Exception e) {
12750 }
12751 }
12752 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12753 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12754 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012755
12756 AttributeCache ac = AttributeCache.instance();
12757 if (ac != null) {
12758 ac.updateConfiguration(mConfiguration);
12759 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012760 }
12761 }
12762
12763 if (changes != 0 && starting == null) {
12764 // If the configuration changed, and the caller is not already
12765 // in the process of starting an activity, then find the top
12766 // activity to check if its configuration needs to change.
12767 starting = topRunningActivityLocked(null);
12768 }
12769
12770 if (starting != null) {
12771 kept = ensureActivityConfigurationLocked(starting, changes);
12772 if (kept) {
12773 // If this didn't result in the starting activity being
12774 // destroyed, then we need to make sure at this point that all
12775 // other activities are made visible.
12776 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12777 + ", ensuring others are correct.");
12778 ensureActivitiesVisibleLocked(starting, changes);
12779 }
12780 }
12781
12782 return kept;
12783 }
12784
12785 private final boolean relaunchActivityLocked(HistoryRecord r,
12786 int changes, boolean andResume) {
12787 List<ResultInfo> results = null;
12788 List<Intent> newIntents = null;
12789 if (andResume) {
12790 results = r.results;
12791 newIntents = r.newIntents;
12792 }
12793 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12794 + " with results=" + results + " newIntents=" + newIntents
12795 + " andResume=" + andResume);
12796 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12797 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12798 r.task.taskId, r.shortComponentName);
12799
12800 r.startFreezingScreenLocked(r.app, 0);
12801
12802 try {
12803 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12804 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12805 changes, !andResume);
12806 // Note: don't need to call pauseIfSleepingLocked() here, because
12807 // the caller will only pass in 'andResume' if this activity is
12808 // currently resumed, which implies we aren't sleeping.
12809 } catch (RemoteException e) {
12810 return false;
12811 }
12812
12813 if (andResume) {
12814 r.results = null;
12815 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070012816 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012817 }
12818
12819 return true;
12820 }
12821
12822 /**
12823 * Make sure the given activity matches the current configuration. Returns
12824 * false if the activity had to be destroyed. Returns true if the
12825 * configuration is the same, or the activity will remain running as-is
12826 * for whatever reason. Ensures the HistoryRecord is updated with the
12827 * correct configuration and all other bookkeeping is handled.
12828 */
12829 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12830 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012831 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12832 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012833
12834 // Short circuit: if the two configurations are the exact same
12835 // object (the common case), then there is nothing to do.
12836 Configuration newConfig = mConfiguration;
12837 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012838 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12839 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012840 return true;
12841 }
12842
12843 // We don't worry about activities that are finishing.
12844 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012845 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012846 "Configuration doesn't matter in finishing " + r);
12847 r.stopFreezingScreenLocked(false);
12848 return true;
12849 }
12850
12851 // Okay we now are going to make this activity have the new config.
12852 // But then we need to figure out how it needs to deal with that.
12853 Configuration oldConfig = r.configuration;
12854 r.configuration = newConfig;
12855
12856 // If the activity isn't currently running, just leave the new
12857 // configuration and it will pick that up next time it starts.
12858 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012859 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012860 "Configuration doesn't matter not running " + r);
12861 r.stopFreezingScreenLocked(false);
12862 return true;
12863 }
12864
12865 // If the activity isn't persistent, there is a chance we will
12866 // need to restart it.
12867 if (!r.persistent) {
12868
12869 // Figure out what has changed between the two configurations.
12870 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012871 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
12872 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012873 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012874 + Integer.toHexString(r.info.configChanges)
12875 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012876 }
12877 if ((changes&(~r.info.configChanges)) != 0) {
12878 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12879 r.configChangeFlags |= changes;
12880 r.startFreezingScreenLocked(r.app, globalChanges);
12881 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012882 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12883 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012884 destroyActivityLocked(r, true);
12885 } else if (r.state == ActivityState.PAUSING) {
12886 // A little annoying: we are waiting for this activity to
12887 // finish pausing. Let's not do anything now, but just
12888 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012889 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12890 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012891 r.configDestroy = true;
12892 return true;
12893 } else if (r.state == ActivityState.RESUMED) {
12894 // Try to optimize this case: the configuration is changing
12895 // and we need to restart the top, resumed activity.
12896 // Instead of doing the normal handshaking, just say
12897 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012898 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12899 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012900 relaunchActivityLocked(r, r.configChangeFlags, true);
12901 r.configChangeFlags = 0;
12902 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012903 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12904 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012905 relaunchActivityLocked(r, r.configChangeFlags, false);
12906 r.configChangeFlags = 0;
12907 }
12908
12909 // All done... tell the caller we weren't able to keep this
12910 // activity around.
12911 return false;
12912 }
12913 }
12914
12915 // Default case: the activity can handle this new configuration, so
12916 // hand it over. Note that we don't need to give it the new
12917 // configuration, since we always send configuration changes to all
12918 // process when they happen so it can just use whatever configuration
12919 // it last got.
12920 if (r.app != null && r.app.thread != null) {
12921 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012922 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012923 r.app.thread.scheduleActivityConfigurationChanged(r);
12924 } catch (RemoteException e) {
12925 // If process died, whatever.
12926 }
12927 }
12928 r.stopFreezingScreenLocked(false);
12929
12930 return true;
12931 }
12932
12933 /**
12934 * Save the locale. You must be inside a synchronized (this) block.
12935 */
12936 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12937 if(isDiff) {
12938 SystemProperties.set("user.language", l.getLanguage());
12939 SystemProperties.set("user.region", l.getCountry());
12940 }
12941
12942 if(isPersist) {
12943 SystemProperties.set("persist.sys.language", l.getLanguage());
12944 SystemProperties.set("persist.sys.country", l.getCountry());
12945 SystemProperties.set("persist.sys.localevar", l.getVariant());
12946 }
12947 }
12948
12949 // =========================================================
12950 // LIFETIME MANAGEMENT
12951 // =========================================================
12952
12953 private final int computeOomAdjLocked(
12954 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12955 if (mAdjSeq == app.adjSeq) {
12956 // This adjustment has already been computed.
12957 return app.curAdj;
12958 }
12959
12960 if (app.thread == null) {
12961 app.adjSeq = mAdjSeq;
12962 return (app.curAdj=EMPTY_APP_ADJ);
12963 }
12964
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012965 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
12966 // The max adjustment doesn't allow this app to be anything
12967 // below foreground, so it is not worth doing work for it.
12968 app.adjType = "fixed";
12969 app.adjSeq = mAdjSeq;
12970 app.curRawAdj = app.maxAdj;
12971 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
12972 return (app.curAdj=app.maxAdj);
12973 }
12974
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070012975 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012976 app.adjSource = null;
12977 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012978
The Android Open Source Project4df24232009-03-05 14:34:35 -080012979 // Determine the importance of the process, starting with most
12980 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012981 int adj;
12982 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012983 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012984 // The last app on the list is the foreground app.
12985 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012986 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012987 } else if (app.instrumentationClass != null) {
12988 // Don't want to kill running instrumentation.
12989 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012990 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012991 } else if (app.persistentActivities > 0) {
12992 // Special persistent activities... shouldn't be used these days.
12993 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012994 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012995 } else if (app.curReceiver != null ||
12996 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12997 // An app that is currently receiving a broadcast also
12998 // counts as being in the foreground.
12999 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013000 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013001 } else if (app.executingServices.size() > 0) {
13002 // An app that is currently executing a service callback also
13003 // counts as being in the foreground.
13004 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013005 app.adjType = "exec-service";
13006 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013007 // The user is aware of this app, so make it visible.
13008 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013009 app.adjType = "foreground-service";
13010 } else if (app.forcingToForeground != null) {
13011 // The user is aware of this app, so make it visible.
13012 adj = VISIBLE_APP_ADJ;
13013 app.adjType = "force-foreground";
13014 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013015 } else if (app == mHomeProcess) {
13016 // This process is hosting what we currently consider to be the
13017 // home app, so we don't want to let it go into the background.
13018 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013019 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013020 } else if ((N=app.activities.size()) != 0) {
13021 // This app is in the background with paused activities.
13022 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013023 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013024 for (int j=0; j<N; j++) {
13025 if (((HistoryRecord)app.activities.get(j)).visible) {
13026 // This app has a visible activity!
13027 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013028 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013029 break;
13030 }
13031 }
13032 } else {
13033 // A very not-needed process.
13034 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013035 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013036 }
13037
The Android Open Source Project4df24232009-03-05 14:34:35 -080013038 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013039 // there are applications dependent on our services or providers, but
13040 // this gives us a baseline and makes sure we don't get into an
13041 // infinite recursion.
13042 app.adjSeq = mAdjSeq;
13043 app.curRawAdj = adj;
13044 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
13045
Christopher Tate6fa95972009-06-05 18:43:55 -070013046 if (mBackupTarget != null && app == mBackupTarget.app) {
13047 // If possible we want to avoid killing apps while they're being backed up
13048 if (adj > BACKUP_APP_ADJ) {
13049 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13050 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013051 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070013052 }
13053 }
13054
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013055 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013056 final long now = SystemClock.uptimeMillis();
13057 // This process is more important if the top activity is
13058 // bound to the service.
13059 Iterator jt = app.services.iterator();
13060 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13061 ServiceRecord s = (ServiceRecord)jt.next();
13062 if (s.startRequested) {
13063 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13064 // This service has seen some activity within
13065 // recent memory, so we will keep its process ahead
13066 // of the background processes.
13067 if (adj > SECONDARY_SERVER_ADJ) {
13068 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013069 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013070 }
13071 }
13072 }
13073 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
13074 Iterator<ConnectionRecord> kt
13075 = s.connections.values().iterator();
13076 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13077 // XXX should compute this based on the max of
13078 // all connected clients.
13079 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013080 if (cr.binding.client == app) {
13081 // Binding to ourself is not interesting.
13082 continue;
13083 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013084 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13085 ProcessRecord client = cr.binding.client;
13086 int myHiddenAdj = hiddenAdj;
13087 if (myHiddenAdj > client.hiddenAdj) {
13088 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13089 myHiddenAdj = client.hiddenAdj;
13090 } else {
13091 myHiddenAdj = VISIBLE_APP_ADJ;
13092 }
13093 }
13094 int clientAdj = computeOomAdjLocked(
13095 client, myHiddenAdj, TOP_APP);
13096 if (adj > clientAdj) {
13097 adj = clientAdj > VISIBLE_APP_ADJ
13098 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013099 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013100 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13101 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013102 app.adjSource = cr.binding.client;
13103 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013104 }
13105 }
13106 HistoryRecord a = cr.activity;
13107 //if (a != null) {
13108 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13109 //}
13110 if (a != null && adj > FOREGROUND_APP_ADJ &&
13111 (a.state == ActivityState.RESUMED
13112 || a.state == ActivityState.PAUSING)) {
13113 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013114 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013115 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13116 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013117 app.adjSource = a;
13118 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013119 }
13120 }
13121 }
13122 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013123
13124 // Finally, f this process has active services running in it, we
13125 // would like to avoid killing it unless it would prevent the current
13126 // application from running. By default we put the process in
13127 // with the rest of the background processes; as we scan through
13128 // its services we may bump it up from there.
13129 if (adj > hiddenAdj) {
13130 adj = hiddenAdj;
13131 app.adjType = "bg-services";
13132 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013133 }
13134
13135 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013136 Iterator jt = app.pubProviders.values().iterator();
13137 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13138 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13139 if (cpr.clients.size() != 0) {
13140 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13141 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13142 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013143 if (client == app) {
13144 // Being our own client is not interesting.
13145 continue;
13146 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013147 int myHiddenAdj = hiddenAdj;
13148 if (myHiddenAdj > client.hiddenAdj) {
13149 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13150 myHiddenAdj = client.hiddenAdj;
13151 } else {
13152 myHiddenAdj = FOREGROUND_APP_ADJ;
13153 }
13154 }
13155 int clientAdj = computeOomAdjLocked(
13156 client, myHiddenAdj, TOP_APP);
13157 if (adj > clientAdj) {
13158 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013159 ? clientAdj : FOREGROUND_APP_ADJ;
13160 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013161 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13162 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013163 app.adjSource = client;
13164 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013165 }
13166 }
13167 }
13168 // If the provider has external (non-framework) process
13169 // dependencies, ensure that its adjustment is at least
13170 // FOREGROUND_APP_ADJ.
13171 if (cpr.externals != 0) {
13172 if (adj > FOREGROUND_APP_ADJ) {
13173 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013174 app.adjType = "provider";
13175 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013176 }
13177 }
13178 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013179
13180 // Finally, if this process has published any content providers,
13181 // then its adjustment makes it at least as important as any of the
13182 // processes using those providers, and no less important than
13183 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
13184 if (adj > CONTENT_PROVIDER_ADJ) {
13185 adj = CONTENT_PROVIDER_ADJ;
13186 app.adjType = "pub-providers";
13187 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013188 }
13189
13190 app.curRawAdj = adj;
13191
13192 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13193 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13194 if (adj > app.maxAdj) {
13195 adj = app.maxAdj;
13196 }
13197
13198 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013199 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013200 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
13201 : Process.THREAD_GROUP_DEFAULT;
13202
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013203 return adj;
13204 }
13205
13206 /**
13207 * Ask a given process to GC right now.
13208 */
13209 final void performAppGcLocked(ProcessRecord app) {
13210 try {
13211 app.lastRequestedGc = SystemClock.uptimeMillis();
13212 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013213 if (app.reportLowMemory) {
13214 app.reportLowMemory = false;
13215 app.thread.scheduleLowMemory();
13216 } else {
13217 app.thread.processInBackground();
13218 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013219 }
13220 } catch (Exception e) {
13221 // whatever.
13222 }
13223 }
13224
13225 /**
13226 * Returns true if things are idle enough to perform GCs.
13227 */
13228 private final boolean canGcNow() {
13229 return mParallelBroadcasts.size() == 0
13230 && mOrderedBroadcasts.size() == 0
13231 && (mSleeping || (mResumedActivity != null &&
13232 mResumedActivity.idle));
13233 }
13234
13235 /**
13236 * Perform GCs on all processes that are waiting for it, but only
13237 * if things are idle.
13238 */
13239 final void performAppGcsLocked() {
13240 final int N = mProcessesToGc.size();
13241 if (N <= 0) {
13242 return;
13243 }
13244 if (canGcNow()) {
13245 while (mProcessesToGc.size() > 0) {
13246 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013247 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13248 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13249 <= SystemClock.uptimeMillis()) {
13250 // To avoid spamming the system, we will GC processes one
13251 // at a time, waiting a few seconds between each.
13252 performAppGcLocked(proc);
13253 scheduleAppGcsLocked();
13254 return;
13255 } else {
13256 // It hasn't been long enough since we last GCed this
13257 // process... put it in the list to wait for its time.
13258 addProcessToGcListLocked(proc);
13259 break;
13260 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013261 }
13262 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013263
13264 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013265 }
13266 }
13267
13268 /**
13269 * If all looks good, perform GCs on all processes waiting for them.
13270 */
13271 final void performAppGcsIfAppropriateLocked() {
13272 if (canGcNow()) {
13273 performAppGcsLocked();
13274 return;
13275 }
13276 // Still not idle, wait some more.
13277 scheduleAppGcsLocked();
13278 }
13279
13280 /**
13281 * Schedule the execution of all pending app GCs.
13282 */
13283 final void scheduleAppGcsLocked() {
13284 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013285
13286 if (mProcessesToGc.size() > 0) {
13287 // Schedule a GC for the time to the next process.
13288 ProcessRecord proc = mProcessesToGc.get(0);
13289 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13290
13291 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13292 long now = SystemClock.uptimeMillis();
13293 if (when < (now+GC_TIMEOUT)) {
13294 when = now + GC_TIMEOUT;
13295 }
13296 mHandler.sendMessageAtTime(msg, when);
13297 }
13298 }
13299
13300 /**
13301 * Add a process to the array of processes waiting to be GCed. Keeps the
13302 * list in sorted order by the last GC time. The process can't already be
13303 * on the list.
13304 */
13305 final void addProcessToGcListLocked(ProcessRecord proc) {
13306 boolean added = false;
13307 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13308 if (mProcessesToGc.get(i).lastRequestedGc <
13309 proc.lastRequestedGc) {
13310 added = true;
13311 mProcessesToGc.add(i+1, proc);
13312 break;
13313 }
13314 }
13315 if (!added) {
13316 mProcessesToGc.add(0, proc);
13317 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013318 }
13319
13320 /**
13321 * Set up to ask a process to GC itself. This will either do it
13322 * immediately, or put it on the list of processes to gc the next
13323 * time things are idle.
13324 */
13325 final void scheduleAppGcLocked(ProcessRecord app) {
13326 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013327 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013328 return;
13329 }
13330 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013331 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013332 scheduleAppGcsLocked();
13333 }
13334 }
13335
13336 private final boolean updateOomAdjLocked(
13337 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13338 app.hiddenAdj = hiddenAdj;
13339
13340 if (app.thread == null) {
13341 return true;
13342 }
13343
13344 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
13345
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013346 if (app.pid != 0 && app.pid != MY_PID) {
13347 if (app.curRawAdj != app.setRawAdj) {
13348 if (app.curRawAdj > FOREGROUND_APP_ADJ
13349 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13350 // If this app is transitioning from foreground to
13351 // non-foreground, have it do a gc.
13352 scheduleAppGcLocked(app);
13353 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13354 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13355 // Likewise do a gc when an app is moving in to the
13356 // background (such as a service stopping).
13357 scheduleAppGcLocked(app);
13358 }
13359 app.setRawAdj = app.curRawAdj;
13360 }
13361 if (adj != app.setAdj) {
13362 if (Process.setOomAdj(app.pid, adj)) {
13363 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13364 TAG, "Set app " + app.processName +
13365 " oom adj to " + adj);
13366 app.setAdj = adj;
13367 } else {
13368 return false;
13369 }
13370 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013371 if (app.setSchedGroup != app.curSchedGroup) {
13372 app.setSchedGroup = app.curSchedGroup;
13373 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13374 "Setting process group of " + app.processName
13375 + " to " + app.curSchedGroup);
13376 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013377 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013378 try {
13379 Process.setProcessGroup(app.pid, app.curSchedGroup);
13380 } catch (Exception e) {
13381 Log.w(TAG, "Failed setting process group of " + app.pid
13382 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013383 e.printStackTrace();
13384 } finally {
13385 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013386 }
13387 }
13388 if (false) {
13389 if (app.thread != null) {
13390 try {
13391 app.thread.setSchedulingGroup(app.curSchedGroup);
13392 } catch (RemoteException e) {
13393 }
13394 }
13395 }
13396 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013397 }
13398
13399 return true;
13400 }
13401
13402 private final HistoryRecord resumedAppLocked() {
13403 HistoryRecord resumedActivity = mResumedActivity;
13404 if (resumedActivity == null || resumedActivity.app == null) {
13405 resumedActivity = mPausingActivity;
13406 if (resumedActivity == null || resumedActivity.app == null) {
13407 resumedActivity = topRunningActivityLocked(null);
13408 }
13409 }
13410 return resumedActivity;
13411 }
13412
13413 private final boolean updateOomAdjLocked(ProcessRecord app) {
13414 final HistoryRecord TOP_ACT = resumedAppLocked();
13415 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13416 int curAdj = app.curAdj;
13417 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13418 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13419
13420 mAdjSeq++;
13421
13422 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13423 if (res) {
13424 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13425 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13426 if (nowHidden != wasHidden) {
13427 // Changed to/from hidden state, so apps after it in the LRU
13428 // list may also be changed.
13429 updateOomAdjLocked();
13430 }
13431 }
13432 return res;
13433 }
13434
13435 private final boolean updateOomAdjLocked() {
13436 boolean didOomAdj = true;
13437 final HistoryRecord TOP_ACT = resumedAppLocked();
13438 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13439
13440 if (false) {
13441 RuntimeException e = new RuntimeException();
13442 e.fillInStackTrace();
13443 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13444 }
13445
13446 mAdjSeq++;
13447
13448 // First try updating the OOM adjustment for each of the
13449 // application processes based on their current state.
13450 int i = mLRUProcesses.size();
13451 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13452 while (i > 0) {
13453 i--;
13454 ProcessRecord app = mLRUProcesses.get(i);
13455 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13456 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13457 && app.curAdj == curHiddenAdj) {
13458 curHiddenAdj++;
13459 }
13460 } else {
13461 didOomAdj = false;
13462 }
13463 }
13464
13465 // todo: for now pretend like OOM ADJ didn't work, because things
13466 // aren't behaving as expected on Linux -- it's not killing processes.
13467 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13468 }
13469
13470 private final void trimApplications() {
13471 synchronized (this) {
13472 int i;
13473
13474 // First remove any unused application processes whose package
13475 // has been removed.
13476 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13477 final ProcessRecord app = mRemovedProcesses.get(i);
13478 if (app.activities.size() == 0
13479 && app.curReceiver == null && app.services.size() == 0) {
13480 Log.i(
13481 TAG, "Exiting empty application process "
13482 + app.processName + " ("
13483 + (app.thread != null ? app.thread.asBinder() : null)
13484 + ")\n");
13485 if (app.pid > 0 && app.pid != MY_PID) {
13486 Process.killProcess(app.pid);
13487 } else {
13488 try {
13489 app.thread.scheduleExit();
13490 } catch (Exception e) {
13491 // Ignore exceptions.
13492 }
13493 }
13494 cleanUpApplicationRecordLocked(app, false, -1);
13495 mRemovedProcesses.remove(i);
13496
13497 if (app.persistent) {
13498 if (app.persistent) {
13499 addAppLocked(app.info);
13500 }
13501 }
13502 }
13503 }
13504
13505 // Now try updating the OOM adjustment for each of the
13506 // application processes based on their current state.
13507 // If the setOomAdj() API is not supported, then go with our
13508 // back-up plan...
13509 if (!updateOomAdjLocked()) {
13510
13511 // Count how many processes are running services.
13512 int numServiceProcs = 0;
13513 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13514 final ProcessRecord app = mLRUProcesses.get(i);
13515
13516 if (app.persistent || app.services.size() != 0
13517 || app.curReceiver != null
13518 || app.persistentActivities > 0) {
13519 // Don't count processes holding services against our
13520 // maximum process count.
13521 if (localLOGV) Log.v(
13522 TAG, "Not trimming app " + app + " with services: "
13523 + app.services);
13524 numServiceProcs++;
13525 }
13526 }
13527
13528 int curMaxProcs = mProcessLimit;
13529 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13530 if (mAlwaysFinishActivities) {
13531 curMaxProcs = 1;
13532 }
13533 curMaxProcs += numServiceProcs;
13534
13535 // Quit as many processes as we can to get down to the desired
13536 // process count. First remove any processes that no longer
13537 // have activites running in them.
13538 for ( i=0;
13539 i<mLRUProcesses.size()
13540 && mLRUProcesses.size() > curMaxProcs;
13541 i++) {
13542 final ProcessRecord app = mLRUProcesses.get(i);
13543 // Quit an application only if it is not currently
13544 // running any activities.
13545 if (!app.persistent && app.activities.size() == 0
13546 && app.curReceiver == null && app.services.size() == 0) {
13547 Log.i(
13548 TAG, "Exiting empty application process "
13549 + app.processName + " ("
13550 + (app.thread != null ? app.thread.asBinder() : null)
13551 + ")\n");
13552 if (app.pid > 0 && app.pid != MY_PID) {
13553 Process.killProcess(app.pid);
13554 } else {
13555 try {
13556 app.thread.scheduleExit();
13557 } catch (Exception e) {
13558 // Ignore exceptions.
13559 }
13560 }
13561 // todo: For now we assume the application is not buggy
13562 // or evil, and will quit as a result of our request.
13563 // Eventually we need to drive this off of the death
13564 // notification, and kill the process if it takes too long.
13565 cleanUpApplicationRecordLocked(app, false, i);
13566 i--;
13567 }
13568 }
13569
13570 // If we still have too many processes, now from the least
13571 // recently used process we start finishing activities.
13572 if (Config.LOGV) Log.v(
13573 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13574 " of " + curMaxProcs + " processes");
13575 for ( i=0;
13576 i<mLRUProcesses.size()
13577 && mLRUProcesses.size() > curMaxProcs;
13578 i++) {
13579 final ProcessRecord app = mLRUProcesses.get(i);
13580 // Quit the application only if we have a state saved for
13581 // all of its activities.
13582 boolean canQuit = !app.persistent && app.curReceiver == null
13583 && app.services.size() == 0
13584 && app.persistentActivities == 0;
13585 int NUMA = app.activities.size();
13586 int j;
13587 if (Config.LOGV) Log.v(
13588 TAG, "Looking to quit " + app.processName);
13589 for (j=0; j<NUMA && canQuit; j++) {
13590 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13591 if (Config.LOGV) Log.v(
13592 TAG, " " + r.intent.getComponent().flattenToShortString()
13593 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13594 canQuit = (r.haveState || !r.stateNotNeeded)
13595 && !r.visible && r.stopped;
13596 }
13597 if (canQuit) {
13598 // Finish all of the activities, and then the app itself.
13599 for (j=0; j<NUMA; j++) {
13600 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13601 if (!r.finishing) {
13602 destroyActivityLocked(r, false);
13603 }
13604 r.resultTo = null;
13605 }
13606 Log.i(TAG, "Exiting application process "
13607 + app.processName + " ("
13608 + (app.thread != null ? app.thread.asBinder() : null)
13609 + ")\n");
13610 if (app.pid > 0 && app.pid != MY_PID) {
13611 Process.killProcess(app.pid);
13612 } else {
13613 try {
13614 app.thread.scheduleExit();
13615 } catch (Exception e) {
13616 // Ignore exceptions.
13617 }
13618 }
13619 // todo: For now we assume the application is not buggy
13620 // or evil, and will quit as a result of our request.
13621 // Eventually we need to drive this off of the death
13622 // notification, and kill the process if it takes too long.
13623 cleanUpApplicationRecordLocked(app, false, i);
13624 i--;
13625 //dump();
13626 }
13627 }
13628
13629 }
13630
13631 int curMaxActivities = MAX_ACTIVITIES;
13632 if (mAlwaysFinishActivities) {
13633 curMaxActivities = 1;
13634 }
13635
13636 // Finally, if there are too many activities now running, try to
13637 // finish as many as we can to get back down to the limit.
13638 for ( i=0;
13639 i<mLRUActivities.size()
13640 && mLRUActivities.size() > curMaxActivities;
13641 i++) {
13642 final HistoryRecord r
13643 = (HistoryRecord)mLRUActivities.get(i);
13644
13645 // We can finish this one if we have its icicle saved and
13646 // it is not persistent.
13647 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13648 && r.stopped && !r.persistent && !r.finishing) {
13649 final int origSize = mLRUActivities.size();
13650 destroyActivityLocked(r, true);
13651
13652 // This will remove it from the LRU list, so keep
13653 // our index at the same value. Note that this check to
13654 // see if the size changes is just paranoia -- if
13655 // something unexpected happens, we don't want to end up
13656 // in an infinite loop.
13657 if (origSize > mLRUActivities.size()) {
13658 i--;
13659 }
13660 }
13661 }
13662 }
13663 }
13664
13665 /** This method sends the specified signal to each of the persistent apps */
13666 public void signalPersistentProcesses(int sig) throws RemoteException {
13667 if (sig != Process.SIGNAL_USR1) {
13668 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13669 }
13670
13671 synchronized (this) {
13672 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13673 != PackageManager.PERMISSION_GRANTED) {
13674 throw new SecurityException("Requires permission "
13675 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13676 }
13677
13678 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13679 ProcessRecord r = mLRUProcesses.get(i);
13680 if (r.thread != null && r.persistent) {
13681 Process.sendSignal(r.pid, sig);
13682 }
13683 }
13684 }
13685 }
13686
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013687 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013688 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013689
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013690 try {
13691 synchronized (this) {
13692 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13693 // its own permission.
13694 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13695 != PackageManager.PERMISSION_GRANTED) {
13696 throw new SecurityException("Requires permission "
13697 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013698 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013699
13700 if (start && fd == null) {
13701 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013702 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013703
13704 ProcessRecord proc = null;
13705 try {
13706 int pid = Integer.parseInt(process);
13707 synchronized (mPidsSelfLocked) {
13708 proc = mPidsSelfLocked.get(pid);
13709 }
13710 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013711 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013712
13713 if (proc == null) {
13714 HashMap<String, SparseArray<ProcessRecord>> all
13715 = mProcessNames.getMap();
13716 SparseArray<ProcessRecord> procs = all.get(process);
13717 if (procs != null && procs.size() > 0) {
13718 proc = procs.valueAt(0);
13719 }
13720 }
13721
13722 if (proc == null || proc.thread == null) {
13723 throw new IllegalArgumentException("Unknown process: " + process);
13724 }
13725
13726 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13727 if (isSecure) {
13728 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13729 throw new SecurityException("Process not debuggable: " + proc);
13730 }
13731 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013732
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013733 proc.thread.profilerControl(start, path, fd);
13734 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013735 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013736 }
13737 } catch (RemoteException e) {
13738 throw new IllegalStateException("Process disappeared");
13739 } finally {
13740 if (fd != null) {
13741 try {
13742 fd.close();
13743 } catch (IOException e) {
13744 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013745 }
13746 }
13747 }
13748
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013749 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13750 public void monitor() {
13751 synchronized (this) { }
13752 }
13753}