blob: 5d34d002f76d8257de5964342199136c94832467 [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;
42import android.app.PendingIntent;
43import android.app.ResultInfo;
Christopher Tate181fafa2009-05-14 11:12:14 -070044import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020045import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.content.ComponentName;
47import android.content.ContentResolver;
48import android.content.Context;
49import android.content.Intent;
50import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070051import android.content.IIntentReceiver;
52import android.content.IIntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.content.pm.ActivityInfo;
54import android.content.pm.ApplicationInfo;
55import android.content.pm.ConfigurationInfo;
56import android.content.pm.IPackageDataObserver;
57import android.content.pm.IPackageManager;
58import android.content.pm.InstrumentationInfo;
59import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070060import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.content.pm.ProviderInfo;
62import android.content.pm.ResolveInfo;
63import android.content.pm.ServiceInfo;
64import android.content.res.Configuration;
65import android.graphics.Bitmap;
66import android.net.Uri;
67import android.os.Binder;
68import android.os.Bundle;
69import android.os.Environment;
70import android.os.FileUtils;
71import android.os.Handler;
72import android.os.IBinder;
73import android.os.IPermissionController;
74import android.os.Looper;
75import android.os.Message;
76import android.os.Parcel;
77import android.os.ParcelFileDescriptor;
78import android.os.PowerManager;
79import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070080import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081import android.os.RemoteException;
82import android.os.ServiceManager;
83import android.os.SystemClock;
84import android.os.SystemProperties;
85import android.provider.Checkin;
86import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020087import android.server.data.CrashData;
88import android.server.data.StackTraceElementData;
89import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090import android.text.TextUtils;
91import android.util.Config;
92import android.util.EventLog;
93import android.util.Log;
94import android.util.PrintWriterPrinter;
95import android.util.SparseArray;
96import android.view.Gravity;
97import android.view.LayoutInflater;
98import android.view.View;
99import android.view.WindowManager;
100import android.view.WindowManagerPolicy;
101
102import dalvik.system.Zygote;
103
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200104import java.io.ByteArrayInputStream;
105import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106import java.io.File;
107import java.io.FileDescriptor;
108import java.io.FileInputStream;
109import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200110import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111import java.io.PrintWriter;
112import java.lang.IllegalStateException;
113import java.lang.ref.WeakReference;
114import java.util.ArrayList;
115import java.util.HashMap;
116import java.util.HashSet;
117import java.util.Iterator;
118import java.util.List;
119import java.util.Locale;
120import java.util.Map;
121
122public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
123 static final String TAG = "ActivityManager";
124 static final boolean DEBUG = false;
125 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
126 static final boolean DEBUG_SWITCH = localLOGV || false;
127 static final boolean DEBUG_TASKS = localLOGV || false;
128 static final boolean DEBUG_PAUSE = localLOGV || false;
129 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
130 static final boolean DEBUG_TRANSITION = localLOGV || false;
131 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700132 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 static final boolean DEBUG_SERVICE = localLOGV || false;
134 static final boolean DEBUG_VISBILITY = localLOGV || false;
135 static final boolean DEBUG_PROCESSES = localLOGV || false;
136 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700137 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700138 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 static final boolean VALIDATE_TOKENS = false;
140 static final boolean SHOW_ACTIVITY_START_TIME = true;
141
142 // Control over CPU and battery monitoring.
143 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
144 static final boolean MONITOR_CPU_USAGE = true;
145 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
146 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
147 static final boolean MONITOR_THREAD_CPU_USAGE = false;
148
149 // Event log tags
150 static final int LOG_CONFIGURATION_CHANGED = 2719;
151 static final int LOG_CPU = 2721;
152 static final int LOG_AM_FINISH_ACTIVITY = 30001;
153 static final int LOG_TASK_TO_FRONT = 30002;
154 static final int LOG_AM_NEW_INTENT = 30003;
155 static final int LOG_AM_CREATE_TASK = 30004;
156 static final int LOG_AM_CREATE_ACTIVITY = 30005;
157 static final int LOG_AM_RESTART_ACTIVITY = 30006;
158 static final int LOG_AM_RESUME_ACTIVITY = 30007;
159 static final int LOG_ANR = 30008;
160 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
161 static final int LOG_AM_PROCESS_BOUND = 30010;
162 static final int LOG_AM_PROCESS_DIED = 30011;
163 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
164 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
165 static final int LOG_AM_PROCESS_START = 30014;
166 static final int LOG_AM_PROCESS_BAD = 30015;
167 static final int LOG_AM_PROCESS_GOOD = 30016;
168 static final int LOG_AM_LOW_MEMORY = 30017;
169 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
170 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
171 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
172 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
173 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
174 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
175 static final int LOG_AM_CREATE_SERVICE = 30030;
176 static final int LOG_AM_DESTROY_SERVICE = 30031;
177 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
178 static final int LOG_AM_DROP_PROCESS = 30033;
179 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
180 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
181 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
182
183 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
184 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
185
Dianne Hackborn1655be42009-05-08 14:29:01 -0700186 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700187 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700188
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 private static final String SYSTEM_SECURE = "ro.secure";
190
191 // This is the maximum number of application processes we would like
192 // to have running. Due to the asynchronous nature of things, we can
193 // temporarily go beyond this limit.
194 static final int MAX_PROCESSES = 2;
195
196 // Set to false to leave processes running indefinitely, relying on
197 // the kernel killing them as resources are required.
198 static final boolean ENFORCE_PROCESS_LIMIT = false;
199
200 // This is the maximum number of activities that we would like to have
201 // running at a given time.
202 static final int MAX_ACTIVITIES = 20;
203
204 // Maximum number of recent tasks that we can remember.
205 static final int MAX_RECENT_TASKS = 20;
206
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700207 // Amount of time after a call to stopAppSwitches() during which we will
208 // prevent further untrusted switches from happening.
209 static final long APP_SWITCH_DELAY_TIME = 5*1000;
210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 // How long until we reset a task when the user returns to it. Currently
212 // 30 minutes.
213 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
214
215 // Set to true to disable the icon that is shown while a new activity
216 // is being started.
217 static final boolean SHOW_APP_STARTING_ICON = true;
218
219 // How long we wait until giving up on the last activity to pause. This
220 // is short because it directly impacts the responsiveness of starting the
221 // next activity.
222 static final int PAUSE_TIMEOUT = 500;
223
224 /**
225 * How long we can hold the launch wake lock before giving up.
226 */
227 static final int LAUNCH_TIMEOUT = 10*1000;
228
229 // How long we wait for a launched process to attach to the activity manager
230 // before we decide it's never going to come up for real.
231 static final int PROC_START_TIMEOUT = 10*1000;
232
233 // How long we wait until giving up on the last activity telling us it
234 // is idle.
235 static final int IDLE_TIMEOUT = 10*1000;
236
237 // How long to wait after going idle before forcing apps to GC.
238 static final int GC_TIMEOUT = 5*1000;
239
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700240 // The minimum amount of time between successive GC requests for a process.
241 static final int GC_MIN_INTERVAL = 60*1000;
242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 // How long we wait until giving up on an activity telling us it has
244 // finished destroying itself.
245 static final int DESTROY_TIMEOUT = 10*1000;
246
247 // How long we allow a receiver to run before giving up on it.
248 static final int BROADCAST_TIMEOUT = 10*1000;
249
250 // How long we wait for a service to finish executing.
251 static final int SERVICE_TIMEOUT = 20*1000;
252
253 // How long a service needs to be running until restarting its process
254 // is no longer considered to be a relaunch of the service.
255 static final int SERVICE_RESTART_DURATION = 5*1000;
256
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700257 // How long a service needs to be running until it will start back at
258 // SERVICE_RESTART_DURATION after being killed.
259 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
260
261 // Multiplying factor to increase restart duration time by, for each time
262 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
263 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
264
265 // The minimum amount of time between restarting services that we allow.
266 // That is, when multiple services are restarting, we won't allow each
267 // to restart less than this amount of time from the last one.
268 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 // Maximum amount of time for there to be no activity on a service before
271 // we consider it non-essential and allow its process to go on the
272 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700273 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274
275 // How long we wait until we timeout on key dispatching.
276 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
277
278 // The minimum time we allow between crashes, for us to consider this
279 // application to be bad and stop and its services and reject broadcasts.
280 static final int MIN_CRASH_INTERVAL = 60*1000;
281
282 // How long we wait until we timeout on key dispatching during instrumentation.
283 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
284
285 // OOM adjustments for processes in various states:
286
287 // This is a process without anything currently running in it. Definitely
288 // the first to go! Value set in system/rootdir/init.rc on startup.
289 // This value is initalized in the constructor, careful when refering to
290 // this static variable externally.
291 static int EMPTY_APP_ADJ;
292
293 // This is a process with a content provider that does not have any clients
294 // attached to it. If it did have any clients, its adjustment would be the
295 // one for the highest-priority of those processes.
296 static int CONTENT_PROVIDER_ADJ;
297
298 // This is a process only hosting activities that are not visible,
299 // so it can be killed without any disruption. Value set in
300 // system/rootdir/init.rc on startup.
301 final int HIDDEN_APP_MAX_ADJ;
302 static int HIDDEN_APP_MIN_ADJ;
303
The Android Open Source Project4df24232009-03-05 14:34:35 -0800304 // This is a process holding the home application -- we want to try
305 // avoiding killing it, even if it would normally be in the background,
306 // because the user interacts with it so much.
307 final int HOME_APP_ADJ;
308
Christopher Tate6fa95972009-06-05 18:43:55 -0700309 // This is a process currently hosting a backup operation. Killing it
310 // is not entirely fatal but is generally a bad idea.
311 final int BACKUP_APP_ADJ;
312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313 // This is a process holding a secondary server -- killing it will not
314 // have much of an impact as far as the user is concerned. Value set in
315 // system/rootdir/init.rc on startup.
316 final int SECONDARY_SERVER_ADJ;
317
318 // This is a process only hosting activities that are visible to the
319 // user, so we'd prefer they don't disappear. Value set in
320 // system/rootdir/init.rc on startup.
321 final int VISIBLE_APP_ADJ;
322
323 // This is the process running the current foreground app. We'd really
324 // rather not kill it! Value set in system/rootdir/init.rc on startup.
325 final int FOREGROUND_APP_ADJ;
326
327 // This is a process running a core server, such as telephony. Definitely
328 // don't want to kill it, but doing so is not completely fatal.
329 static final int CORE_SERVER_ADJ = -12;
330
331 // The system process runs at the default adjustment.
332 static final int SYSTEM_ADJ = -16;
333
334 // Memory pages are 4K.
335 static final int PAGE_SIZE = 4*1024;
336
337 // Corresponding memory levels for above adjustments.
338 final int EMPTY_APP_MEM;
339 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800340 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700341 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 final int SECONDARY_SERVER_MEM;
343 final int VISIBLE_APP_MEM;
344 final int FOREGROUND_APP_MEM;
345
346 final int MY_PID;
347
348 static final String[] EMPTY_STRING_ARRAY = new String[0];
349
350 enum ActivityState {
351 INITIALIZING,
352 RESUMED,
353 PAUSING,
354 PAUSED,
355 STOPPING,
356 STOPPED,
357 FINISHING,
358 DESTROYING,
359 DESTROYED
360 }
361
362 /**
363 * The back history of all previous (and possibly still
364 * running) activities. It contains HistoryRecord objects.
365 */
366 final ArrayList mHistory = new ArrayList();
367
368 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700369 * Description of a request to start a new activity, which has been held
370 * due to app switches being disabled.
371 */
372 class PendingActivityLaunch {
373 HistoryRecord r;
374 HistoryRecord sourceRecord;
375 Uri[] grantedUriPermissions;
376 int grantedMode;
377 boolean onlyIfNeeded;
378 }
379
380 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
381 = new ArrayList<PendingActivityLaunch>();
382
383 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 * List of all active broadcasts that are to be executed immediately
385 * (without waiting for another broadcast to finish). Currently this only
386 * contains broadcasts to registered receivers, to avoid spinning up
387 * a bunch of processes to execute IntentReceiver components.
388 */
389 final ArrayList<BroadcastRecord> mParallelBroadcasts
390 = new ArrayList<BroadcastRecord>();
391
392 /**
393 * List of all active broadcasts that are to be executed one at a time.
394 * The object at the top of the list is the currently activity broadcasts;
395 * those after it are waiting for the top to finish..
396 */
397 final ArrayList<BroadcastRecord> mOrderedBroadcasts
398 = new ArrayList<BroadcastRecord>();
399
400 /**
401 * Set when we current have a BROADCAST_INTENT_MSG in flight.
402 */
403 boolean mBroadcastsScheduled = false;
404
405 /**
406 * Set to indicate whether to issue an onUserLeaving callback when a
407 * newly launched activity is being brought in front of us.
408 */
409 boolean mUserLeaving = false;
410
411 /**
412 * When we are in the process of pausing an activity, before starting the
413 * next one, this variable holds the activity that is currently being paused.
414 */
415 HistoryRecord mPausingActivity = null;
416
417 /**
418 * Current activity that is resumed, or null if there is none.
419 */
420 HistoryRecord mResumedActivity = null;
421
422 /**
423 * Activity we have told the window manager to have key focus.
424 */
425 HistoryRecord mFocusedActivity = null;
426
427 /**
428 * This is the last activity that we put into the paused state. This is
429 * used to determine if we need to do an activity transition while sleeping,
430 * when we normally hold the top activity paused.
431 */
432 HistoryRecord mLastPausedActivity = null;
433
434 /**
435 * List of activities that are waiting for a new activity
436 * to become visible before completing whatever operation they are
437 * supposed to do.
438 */
439 final ArrayList mWaitingVisibleActivities = new ArrayList();
440
441 /**
442 * List of activities that are ready to be stopped, but waiting
443 * for the next activity to settle down before doing so. It contains
444 * HistoryRecord objects.
445 */
446 final ArrayList<HistoryRecord> mStoppingActivities
447 = new ArrayList<HistoryRecord>();
448
449 /**
450 * List of intents that were used to start the most recent tasks.
451 */
452 final ArrayList<TaskRecord> mRecentTasks
453 = new ArrayList<TaskRecord>();
454
455 /**
456 * List of activities that are ready to be finished, but waiting
457 * for the previous activity to settle down before doing so. It contains
458 * HistoryRecord objects.
459 */
460 final ArrayList mFinishingActivities = new ArrayList();
461
462 /**
463 * All of the applications we currently have running organized by name.
464 * The keys are strings of the application package name (as
465 * returned by the package manager), and the keys are ApplicationRecord
466 * objects.
467 */
468 final ProcessMap<ProcessRecord> mProcessNames
469 = new ProcessMap<ProcessRecord>();
470
471 /**
472 * The last time that various processes have crashed.
473 */
474 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
475
476 /**
477 * Set of applications that we consider to be bad, and will reject
478 * incoming broadcasts from (which the user has no control over).
479 * Processes are added to this set when they have crashed twice within
480 * a minimum amount of time; they are removed from it when they are
481 * later restarted (hopefully due to some user action). The value is the
482 * time it was added to the list.
483 */
484 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
485
486 /**
487 * All of the processes we currently have running organized by pid.
488 * The keys are the pid running the application.
489 *
490 * <p>NOTE: This object is protected by its own lock, NOT the global
491 * activity manager lock!
492 */
493 final SparseArray<ProcessRecord> mPidsSelfLocked
494 = new SparseArray<ProcessRecord>();
495
496 /**
497 * All of the processes that have been forced to be foreground. The key
498 * is the pid of the caller who requested it (we hold a death
499 * link on it).
500 */
501 abstract class ForegroundToken implements IBinder.DeathRecipient {
502 int pid;
503 IBinder token;
504 }
505 final SparseArray<ForegroundToken> mForegroundProcesses
506 = new SparseArray<ForegroundToken>();
507
508 /**
509 * List of records for processes that someone had tried to start before the
510 * system was ready. We don't start them at that point, but ensure they
511 * are started by the time booting is complete.
512 */
513 final ArrayList<ProcessRecord> mProcessesOnHold
514 = new ArrayList<ProcessRecord>();
515
516 /**
517 * List of records for processes that we have started and are waiting
518 * for them to call back. This is really only needed when running in
519 * single processes mode, in which case we do not have a unique pid for
520 * each process.
521 */
522 final ArrayList<ProcessRecord> mStartingProcesses
523 = new ArrayList<ProcessRecord>();
524
525 /**
526 * List of persistent applications that are in the process
527 * of being started.
528 */
529 final ArrayList<ProcessRecord> mPersistentStartingProcesses
530 = new ArrayList<ProcessRecord>();
531
532 /**
533 * Processes that are being forcibly torn down.
534 */
535 final ArrayList<ProcessRecord> mRemovedProcesses
536 = new ArrayList<ProcessRecord>();
537
538 /**
539 * List of running applications, sorted by recent usage.
540 * The first entry in the list is the least recently used.
541 * It contains ApplicationRecord objects. This list does NOT include
542 * any persistent application records (since we never want to exit them).
543 */
544 final ArrayList<ProcessRecord> mLRUProcesses
545 = new ArrayList<ProcessRecord>();
546
547 /**
548 * List of processes that should gc as soon as things are idle.
549 */
550 final ArrayList<ProcessRecord> mProcessesToGc
551 = new ArrayList<ProcessRecord>();
552
553 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800554 * This is the process holding what we currently consider to be
555 * the "home" activity.
556 */
557 private ProcessRecord mHomeProcess;
558
559 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 * List of running activities, sorted by recent usage.
561 * The first entry in the list is the least recently used.
562 * It contains HistoryRecord objects.
563 */
564 private final ArrayList mLRUActivities = new ArrayList();
565
566 /**
567 * Set of PendingResultRecord objects that are currently active.
568 */
569 final HashSet mPendingResultRecords = new HashSet();
570
571 /**
572 * Set of IntentSenderRecord objects that are currently active.
573 */
574 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
575 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
576
577 /**
578 * Intent broadcast that we have tried to start, but are
579 * waiting for its application's process to be created. We only
580 * need one (instead of a list) because we always process broadcasts
581 * one at a time, so no others can be started while waiting for this
582 * one.
583 */
584 BroadcastRecord mPendingBroadcast = null;
585
586 /**
587 * Keeps track of all IIntentReceivers that have been registered for
588 * broadcasts. Hash keys are the receiver IBinder, hash value is
589 * a ReceiverList.
590 */
591 final HashMap mRegisteredReceivers = new HashMap();
592
593 /**
594 * Resolver for broadcast intents to registered receivers.
595 * Holds BroadcastFilter (subclass of IntentFilter).
596 */
597 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
598 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
599 @Override
600 protected boolean allowFilterResult(
601 BroadcastFilter filter, List<BroadcastFilter> dest) {
602 IBinder target = filter.receiverList.receiver.asBinder();
603 for (int i=dest.size()-1; i>=0; i--) {
604 if (dest.get(i).receiverList.receiver.asBinder() == target) {
605 return false;
606 }
607 }
608 return true;
609 }
610 };
611
612 /**
613 * State of all active sticky broadcasts. Keys are the action of the
614 * sticky Intent, values are an ArrayList of all broadcasted intents with
615 * that action (which should usually be one).
616 */
617 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
618 new HashMap<String, ArrayList<Intent>>();
619
620 /**
621 * All currently running services.
622 */
623 final HashMap<ComponentName, ServiceRecord> mServices =
624 new HashMap<ComponentName, ServiceRecord>();
625
626 /**
627 * All currently running services indexed by the Intent used to start them.
628 */
629 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
630 new HashMap<Intent.FilterComparison, ServiceRecord>();
631
632 /**
633 * All currently bound service connections. Keys are the IBinder of
634 * the client's IServiceConnection.
635 */
636 final HashMap<IBinder, ConnectionRecord> mServiceConnections
637 = new HashMap<IBinder, ConnectionRecord>();
638
639 /**
640 * List of services that we have been asked to start,
641 * but haven't yet been able to. It is used to hold start requests
642 * while waiting for their corresponding application thread to get
643 * going.
644 */
645 final ArrayList<ServiceRecord> mPendingServices
646 = new ArrayList<ServiceRecord>();
647
648 /**
649 * List of services that are scheduled to restart following a crash.
650 */
651 final ArrayList<ServiceRecord> mRestartingServices
652 = new ArrayList<ServiceRecord>();
653
654 /**
655 * List of services that are in the process of being stopped.
656 */
657 final ArrayList<ServiceRecord> mStoppingServices
658 = new ArrayList<ServiceRecord>();
659
660 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700661 * Backup/restore process management
662 */
663 String mBackupAppName = null;
664 BackupRecord mBackupTarget = null;
665
666 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 * List of PendingThumbnailsRecord objects of clients who are still
668 * waiting to receive all of the thumbnails for a task.
669 */
670 final ArrayList mPendingThumbnails = new ArrayList();
671
672 /**
673 * List of HistoryRecord objects that have been finished and must
674 * still report back to a pending thumbnail receiver.
675 */
676 final ArrayList mCancelledThumbnails = new ArrayList();
677
678 /**
679 * All of the currently running global content providers. Keys are a
680 * string containing the provider name and values are a
681 * ContentProviderRecord object containing the data about it. Note
682 * that a single provider may be published under multiple names, so
683 * there may be multiple entries here for a single one in mProvidersByClass.
684 */
685 final HashMap mProvidersByName = new HashMap();
686
687 /**
688 * All of the currently running global content providers. Keys are a
689 * string containing the provider's implementation class and values are a
690 * ContentProviderRecord object containing the data about it.
691 */
692 final HashMap mProvidersByClass = new HashMap();
693
694 /**
695 * List of content providers who have clients waiting for them. The
696 * application is currently being launched and the provider will be
697 * removed from this list once it is published.
698 */
699 final ArrayList mLaunchingProviders = new ArrayList();
700
701 /**
702 * Global set of specific Uri permissions that have been granted.
703 */
704 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
705 = new SparseArray<HashMap<Uri, UriPermission>>();
706
707 /**
708 * Thread-local storage used to carry caller permissions over through
709 * indirect content-provider access.
710 * @see #ActivityManagerService.openContentUri()
711 */
712 private class Identity {
713 public int pid;
714 public int uid;
715
716 Identity(int _pid, int _uid) {
717 pid = _pid;
718 uid = _uid;
719 }
720 }
721 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
722
723 /**
724 * All information we have collected about the runtime performance of
725 * any user id that can impact battery performance.
726 */
727 final BatteryStatsService mBatteryStatsService;
728
729 /**
730 * information about component usage
731 */
732 final UsageStatsService mUsageStatsService;
733
734 /**
735 * Current configuration information. HistoryRecord objects are given
736 * a reference to this object to indicate which configuration they are
737 * currently running in, so this object must be kept immutable.
738 */
739 Configuration mConfiguration = new Configuration();
740
741 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700742 * Hardware-reported OpenGLES version.
743 */
744 final int GL_ES_VERSION;
745
746 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 * List of initialization arguments to pass to all processes when binding applications to them.
748 * For example, references to the commonly used services.
749 */
750 HashMap<String, IBinder> mAppBindArgs;
751
752 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700753 * Temporary to avoid allocations. Protected by main lock.
754 */
755 final StringBuilder mStringBuilder = new StringBuilder(256);
756
757 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 * Used to control how we initialize the service.
759 */
760 boolean mStartRunning = false;
761 ComponentName mTopComponent;
762 String mTopAction;
763 String mTopData;
764 boolean mSystemReady = false;
765 boolean mBooting = false;
766
767 Context mContext;
768
769 int mFactoryTest;
770
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700771 boolean mCheckedForSetup;
772
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700774 * The time at which we will allow normal application switches again,
775 * after a call to {@link #stopAppSwitches()}.
776 */
777 long mAppSwitchesAllowedTime;
778
779 /**
780 * This is set to true after the first switch after mAppSwitchesAllowedTime
781 * is set; any switches after that will clear the time.
782 */
783 boolean mDidAppSwitch;
784
785 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 * Set while we are wanting to sleep, to prevent any
787 * activities from being started/resumed.
788 */
789 boolean mSleeping = false;
790
791 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700792 * Set if we are shutting down the system, similar to sleeping.
793 */
794 boolean mShuttingDown = false;
795
796 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 * Set when the system is going to sleep, until we have
798 * successfully paused the current activity and released our wake lock.
799 * At that point the system is allowed to actually sleep.
800 */
801 PowerManager.WakeLock mGoingToSleep;
802
803 /**
804 * We don't want to allow the device to go to sleep while in the process
805 * of launching an activity. This is primarily to allow alarm intent
806 * receivers to launch an activity and get that to run before the device
807 * goes back to sleep.
808 */
809 PowerManager.WakeLock mLaunchingActivity;
810
811 /**
812 * Task identifier that activities are currently being started
813 * in. Incremented each time a new task is created.
814 * todo: Replace this with a TokenSpace class that generates non-repeating
815 * integers that won't wrap.
816 */
817 int mCurTask = 1;
818
819 /**
820 * Current sequence id for oom_adj computation traversal.
821 */
822 int mAdjSeq = 0;
823
824 /**
825 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
826 * is set, indicating the user wants processes started in such a way
827 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
828 * running in each process (thus no pre-initialized process, etc).
829 */
830 boolean mSimpleProcessManagement = false;
831
832 /**
833 * System monitoring: number of processes that died since the last
834 * N procs were started.
835 */
836 int[] mProcDeaths = new int[20];
837
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700838 /**
839 * This is set if we had to do a delayed dexopt of an app before launching
840 * it, to increasing the ANR timeouts in that case.
841 */
842 boolean mDidDexOpt;
843
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 String mDebugApp = null;
845 boolean mWaitForDebugger = false;
846 boolean mDebugTransient = false;
847 String mOrigDebugApp = null;
848 boolean mOrigWaitForDebugger = false;
849 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700850 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800851
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700852 final RemoteCallbackList<IActivityWatcher> mWatchers
853 = new RemoteCallbackList<IActivityWatcher>();
854
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 /**
856 * Callback of last caller to {@link #requestPss}.
857 */
858 Runnable mRequestPssCallback;
859
860 /**
861 * Remaining processes for which we are waiting results from the last
862 * call to {@link #requestPss}.
863 */
864 final ArrayList<ProcessRecord> mRequestPssList
865 = new ArrayList<ProcessRecord>();
866
867 /**
868 * Runtime statistics collection thread. This object's lock is used to
869 * protect all related state.
870 */
871 final Thread mProcessStatsThread;
872
873 /**
874 * Used to collect process stats when showing not responding dialog.
875 * Protected by mProcessStatsThread.
876 */
877 final ProcessStats mProcessStats = new ProcessStats(
878 MONITOR_THREAD_CPU_USAGE);
879 long mLastCpuTime = 0;
880 long mLastWriteTime = 0;
881
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700882 long mInitialStartTime = 0;
883
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800884 /**
885 * Set to true after the system has finished booting.
886 */
887 boolean mBooted = false;
888
889 int mProcessLimit = 0;
890
891 WindowManagerService mWindowManager;
892
893 static ActivityManagerService mSelf;
894 static ActivityThread mSystemThread;
895
896 private final class AppDeathRecipient implements IBinder.DeathRecipient {
897 final ProcessRecord mApp;
898 final int mPid;
899 final IApplicationThread mAppThread;
900
901 AppDeathRecipient(ProcessRecord app, int pid,
902 IApplicationThread thread) {
903 if (localLOGV) Log.v(
904 TAG, "New death recipient " + this
905 + " for thread " + thread.asBinder());
906 mApp = app;
907 mPid = pid;
908 mAppThread = thread;
909 }
910
911 public void binderDied() {
912 if (localLOGV) Log.v(
913 TAG, "Death received in " + this
914 + " for thread " + mAppThread.asBinder());
915 removeRequestedPss(mApp);
916 synchronized(ActivityManagerService.this) {
917 appDiedLocked(mApp, mPid, mAppThread);
918 }
919 }
920 }
921
922 static final int SHOW_ERROR_MSG = 1;
923 static final int SHOW_NOT_RESPONDING_MSG = 2;
924 static final int SHOW_FACTORY_ERROR_MSG = 3;
925 static final int UPDATE_CONFIGURATION_MSG = 4;
926 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
927 static final int WAIT_FOR_DEBUGGER_MSG = 6;
928 static final int BROADCAST_INTENT_MSG = 7;
929 static final int BROADCAST_TIMEOUT_MSG = 8;
930 static final int PAUSE_TIMEOUT_MSG = 9;
931 static final int IDLE_TIMEOUT_MSG = 10;
932 static final int IDLE_NOW_MSG = 11;
933 static final int SERVICE_TIMEOUT_MSG = 12;
934 static final int UPDATE_TIME_ZONE = 13;
935 static final int SHOW_UID_ERROR_MSG = 14;
936 static final int IM_FEELING_LUCKY_MSG = 15;
937 static final int LAUNCH_TIMEOUT_MSG = 16;
938 static final int DESTROY_TIMEOUT_MSG = 17;
939 static final int SERVICE_ERROR_MSG = 18;
940 static final int RESUME_TOP_ACTIVITY_MSG = 19;
941 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700942 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700943 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800944
945 AlertDialog mUidAlert;
946
947 final Handler mHandler = new Handler() {
948 //public Handler() {
949 // if (localLOGV) Log.v(TAG, "Handler started!");
950 //}
951
952 public void handleMessage(Message msg) {
953 switch (msg.what) {
954 case SHOW_ERROR_MSG: {
955 HashMap data = (HashMap) msg.obj;
956 byte[] crashData = (byte[])data.get("crashData");
957 if (crashData != null) {
958 // This needs to be *un*synchronized to avoid deadlock.
959 ContentResolver resolver = mContext.getContentResolver();
960 Checkin.reportCrash(resolver, crashData);
961 }
962 synchronized (ActivityManagerService.this) {
963 ProcessRecord proc = (ProcessRecord)data.get("app");
964 if (proc != null && proc.crashDialog != null) {
965 Log.e(TAG, "App already has crash dialog: " + proc);
966 return;
967 }
968 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700969 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 Dialog d = new AppErrorDialog(
971 mContext, res, proc,
972 (Integer)data.get("flags"),
973 (String)data.get("shortMsg"),
974 (String)data.get("longMsg"));
975 d.show();
976 proc.crashDialog = d;
977 } else {
978 // The device is asleep, so just pretend that the user
979 // saw a crash dialog and hit "force quit".
980 res.set(0);
981 }
982 }
983 } break;
984 case SHOW_NOT_RESPONDING_MSG: {
985 synchronized (ActivityManagerService.this) {
986 HashMap data = (HashMap) msg.obj;
987 ProcessRecord proc = (ProcessRecord)data.get("app");
988 if (proc != null && proc.anrDialog != null) {
989 Log.e(TAG, "App already has anr dialog: " + proc);
990 return;
991 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800992
993 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
994 null, null, 0, null, null, null,
995 false, false, MY_PID, Process.SYSTEM_UID);
996
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
998 mContext, proc, (HistoryRecord)data.get("activity"));
999 d.show();
1000 proc.anrDialog = d;
1001 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001002
1003 ensureScreenEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001004 } break;
1005 case SHOW_FACTORY_ERROR_MSG: {
1006 Dialog d = new FactoryErrorDialog(
1007 mContext, msg.getData().getCharSequence("msg"));
1008 d.show();
1009 enableScreenAfterBoot();
1010 } break;
1011 case UPDATE_CONFIGURATION_MSG: {
1012 final ContentResolver resolver = mContext.getContentResolver();
1013 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1014 } break;
1015 case GC_BACKGROUND_PROCESSES_MSG: {
1016 synchronized (ActivityManagerService.this) {
1017 performAppGcsIfAppropriateLocked();
1018 }
1019 } break;
1020 case WAIT_FOR_DEBUGGER_MSG: {
1021 synchronized (ActivityManagerService.this) {
1022 ProcessRecord app = (ProcessRecord)msg.obj;
1023 if (msg.arg1 != 0) {
1024 if (!app.waitedForDebugger) {
1025 Dialog d = new AppWaitingForDebuggerDialog(
1026 ActivityManagerService.this,
1027 mContext, app);
1028 app.waitDialog = d;
1029 app.waitedForDebugger = true;
1030 d.show();
1031 }
1032 } else {
1033 if (app.waitDialog != null) {
1034 app.waitDialog.dismiss();
1035 app.waitDialog = null;
1036 }
1037 }
1038 }
1039 } break;
1040 case BROADCAST_INTENT_MSG: {
1041 if (DEBUG_BROADCAST) Log.v(
1042 TAG, "Received BROADCAST_INTENT_MSG");
1043 processNextBroadcast(true);
1044 } break;
1045 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001046 if (mDidDexOpt) {
1047 mDidDexOpt = false;
1048 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1049 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1050 return;
1051 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 broadcastTimeout();
1053 } break;
1054 case PAUSE_TIMEOUT_MSG: {
1055 IBinder token = (IBinder)msg.obj;
1056 // We don't at this point know if the activity is fullscreen,
1057 // so we need to be conservative and assume it isn't.
1058 Log.w(TAG, "Activity pause timeout for " + token);
1059 activityPaused(token, null, true);
1060 } break;
1061 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001062 if (mDidDexOpt) {
1063 mDidDexOpt = false;
1064 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1065 nmsg.obj = msg.obj;
1066 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1067 return;
1068 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001069 // We don't at this point know if the activity is fullscreen,
1070 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001071 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 Log.w(TAG, "Activity idle timeout for " + token);
1073 activityIdleInternal(token, true);
1074 } break;
1075 case DESTROY_TIMEOUT_MSG: {
1076 IBinder token = (IBinder)msg.obj;
1077 // We don't at this point know if the activity is fullscreen,
1078 // so we need to be conservative and assume it isn't.
1079 Log.w(TAG, "Activity destroy timeout for " + token);
1080 activityDestroyed(token);
1081 } break;
1082 case IDLE_NOW_MSG: {
1083 IBinder token = (IBinder)msg.obj;
1084 activityIdle(token);
1085 } break;
1086 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001087 if (mDidDexOpt) {
1088 mDidDexOpt = false;
1089 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1090 nmsg.obj = msg.obj;
1091 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1092 return;
1093 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 serviceTimeout((ProcessRecord)msg.obj);
1095 } break;
1096 case UPDATE_TIME_ZONE: {
1097 synchronized (ActivityManagerService.this) {
1098 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1099 ProcessRecord r = mLRUProcesses.get(i);
1100 if (r.thread != null) {
1101 try {
1102 r.thread.updateTimeZone();
1103 } catch (RemoteException ex) {
1104 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1105 }
1106 }
1107 }
1108 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001109 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110 case SHOW_UID_ERROR_MSG: {
1111 // XXX This is a temporary dialog, no need to localize.
1112 AlertDialog d = new BaseErrorDialog(mContext);
1113 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1114 d.setCancelable(false);
1115 d.setTitle("System UIDs Inconsistent");
1116 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1117 d.setButton("I'm Feeling Lucky",
1118 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1119 mUidAlert = d;
1120 d.show();
1121 } break;
1122 case IM_FEELING_LUCKY_MSG: {
1123 if (mUidAlert != null) {
1124 mUidAlert.dismiss();
1125 mUidAlert = null;
1126 }
1127 } break;
1128 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001129 if (mDidDexOpt) {
1130 mDidDexOpt = false;
1131 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1132 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1133 return;
1134 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001135 synchronized (ActivityManagerService.this) {
1136 if (mLaunchingActivity.isHeld()) {
1137 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1138 mLaunchingActivity.release();
1139 }
1140 }
1141 } break;
1142 case SERVICE_ERROR_MSG: {
1143 ServiceRecord srv = (ServiceRecord)msg.obj;
1144 // This needs to be *un*synchronized to avoid deadlock.
1145 Checkin.logEvent(mContext.getContentResolver(),
1146 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1147 srv.name.toShortString());
1148 } break;
1149 case RESUME_TOP_ACTIVITY_MSG: {
1150 synchronized (ActivityManagerService.this) {
1151 resumeTopActivityLocked(null);
1152 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001153 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001154 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001155 if (mDidDexOpt) {
1156 mDidDexOpt = false;
1157 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1158 nmsg.obj = msg.obj;
1159 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1160 return;
1161 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 ProcessRecord app = (ProcessRecord)msg.obj;
1163 synchronized (ActivityManagerService.this) {
1164 processStartTimedOutLocked(app);
1165 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001166 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001167 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1168 synchronized (ActivityManagerService.this) {
1169 doPendingActivityLaunchesLocked(true);
1170 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001171 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001172 case KILL_APPLICATION_MSG: {
1173 synchronized (ActivityManagerService.this) {
1174 int uid = msg.arg1;
1175 boolean restart = (msg.arg2 == 1);
1176 String pkg = (String) msg.obj;
1177 uninstallPackageLocked(pkg, uid, restart);
1178 }
1179 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 }
1181 }
1182 };
1183
1184 public static void setSystemProcess() {
1185 try {
1186 ActivityManagerService m = mSelf;
1187
1188 ServiceManager.addService("activity", m);
1189 ServiceManager.addService("meminfo", new MemBinder(m));
1190 if (MONITOR_CPU_USAGE) {
1191 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1192 }
1193 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1194 ServiceManager.addService("activity.services", new ServicesBinder(m));
1195 ServiceManager.addService("activity.senders", new SendersBinder(m));
1196 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1197 ServiceManager.addService("permission", new PermissionController(m));
1198
1199 ApplicationInfo info =
1200 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001201 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 synchronized (mSelf) {
1203 ProcessRecord app = mSelf.newProcessRecordLocked(
1204 mSystemThread.getApplicationThread(), info,
1205 info.processName);
1206 app.persistent = true;
1207 app.pid = Process.myPid();
1208 app.maxAdj = SYSTEM_ADJ;
1209 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1210 synchronized (mSelf.mPidsSelfLocked) {
1211 mSelf.mPidsSelfLocked.put(app.pid, app);
1212 }
1213 mSelf.updateLRUListLocked(app, true);
1214 }
1215 } catch (PackageManager.NameNotFoundException e) {
1216 throw new RuntimeException(
1217 "Unable to find android system package", e);
1218 }
1219 }
1220
1221 public void setWindowManager(WindowManagerService wm) {
1222 mWindowManager = wm;
1223 }
1224
1225 public static final Context main(int factoryTest) {
1226 AThread thr = new AThread();
1227 thr.start();
1228
1229 synchronized (thr) {
1230 while (thr.mService == null) {
1231 try {
1232 thr.wait();
1233 } catch (InterruptedException e) {
1234 }
1235 }
1236 }
1237
1238 ActivityManagerService m = thr.mService;
1239 mSelf = m;
1240 ActivityThread at = ActivityThread.systemMain();
1241 mSystemThread = at;
1242 Context context = at.getSystemContext();
1243 m.mContext = context;
1244 m.mFactoryTest = factoryTest;
1245 PowerManager pm =
1246 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1247 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1248 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1249 m.mLaunchingActivity.setReferenceCounted(false);
1250
1251 m.mBatteryStatsService.publish(context);
1252 m.mUsageStatsService.publish(context);
1253
1254 synchronized (thr) {
1255 thr.mReady = true;
1256 thr.notifyAll();
1257 }
1258
1259 m.startRunning(null, null, null, null);
1260
1261 return context;
1262 }
1263
1264 public static ActivityManagerService self() {
1265 return mSelf;
1266 }
1267
1268 static class AThread extends Thread {
1269 ActivityManagerService mService;
1270 boolean mReady = false;
1271
1272 public AThread() {
1273 super("ActivityManager");
1274 }
1275
1276 public void run() {
1277 Looper.prepare();
1278
1279 android.os.Process.setThreadPriority(
1280 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1281
1282 ActivityManagerService m = new ActivityManagerService();
1283
1284 synchronized (this) {
1285 mService = m;
1286 notifyAll();
1287 }
1288
1289 synchronized (this) {
1290 while (!mReady) {
1291 try {
1292 wait();
1293 } catch (InterruptedException e) {
1294 }
1295 }
1296 }
1297
1298 Looper.loop();
1299 }
1300 }
1301
1302 static class BroadcastsBinder extends Binder {
1303 ActivityManagerService mActivityManagerService;
1304 BroadcastsBinder(ActivityManagerService activityManagerService) {
1305 mActivityManagerService = activityManagerService;
1306 }
1307
1308 @Override
1309 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1310 mActivityManagerService.dumpBroadcasts(pw);
1311 }
1312 }
1313
1314 static class ServicesBinder extends Binder {
1315 ActivityManagerService mActivityManagerService;
1316 ServicesBinder(ActivityManagerService activityManagerService) {
1317 mActivityManagerService = activityManagerService;
1318 }
1319
1320 @Override
1321 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1322 mActivityManagerService.dumpServices(pw);
1323 }
1324 }
1325
1326 static class SendersBinder extends Binder {
1327 ActivityManagerService mActivityManagerService;
1328 SendersBinder(ActivityManagerService activityManagerService) {
1329 mActivityManagerService = activityManagerService;
1330 }
1331
1332 @Override
1333 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1334 mActivityManagerService.dumpSenders(pw);
1335 }
1336 }
1337
1338 static class ProvidersBinder extends Binder {
1339 ActivityManagerService mActivityManagerService;
1340 ProvidersBinder(ActivityManagerService activityManagerService) {
1341 mActivityManagerService = activityManagerService;
1342 }
1343
1344 @Override
1345 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1346 mActivityManagerService.dumpProviders(pw);
1347 }
1348 }
1349
1350 static class MemBinder extends Binder {
1351 ActivityManagerService mActivityManagerService;
1352 MemBinder(ActivityManagerService activityManagerService) {
1353 mActivityManagerService = activityManagerService;
1354 }
1355
1356 @Override
1357 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1358 ActivityManagerService service = mActivityManagerService;
1359 ArrayList<ProcessRecord> procs;
1360 synchronized (mActivityManagerService) {
1361 if (args != null && args.length > 0
1362 && args[0].charAt(0) != '-') {
1363 procs = new ArrayList<ProcessRecord>();
1364 int pid = -1;
1365 try {
1366 pid = Integer.parseInt(args[0]);
1367 } catch (NumberFormatException e) {
1368
1369 }
1370 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1371 ProcessRecord proc = service.mLRUProcesses.get(i);
1372 if (proc.pid == pid) {
1373 procs.add(proc);
1374 } else if (proc.processName.equals(args[0])) {
1375 procs.add(proc);
1376 }
1377 }
1378 if (procs.size() <= 0) {
1379 pw.println("No process found for: " + args[0]);
1380 return;
1381 }
1382 } else {
1383 procs = service.mLRUProcesses;
1384 }
1385 }
1386 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1387 }
1388 }
1389
1390 static class CpuBinder extends Binder {
1391 ActivityManagerService mActivityManagerService;
1392 CpuBinder(ActivityManagerService activityManagerService) {
1393 mActivityManagerService = activityManagerService;
1394 }
1395
1396 @Override
1397 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1398 synchronized (mActivityManagerService.mProcessStatsThread) {
1399 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1400 }
1401 }
1402 }
1403
1404 private ActivityManagerService() {
1405 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1406 if (v != null && Integer.getInteger(v) != 0) {
1407 mSimpleProcessManagement = true;
1408 }
1409 v = System.getenv("ANDROID_DEBUG_APP");
1410 if (v != null) {
1411 mSimpleProcessManagement = true;
1412 }
1413
1414 MY_PID = Process.myPid();
1415
1416 File dataDir = Environment.getDataDirectory();
1417 File systemDir = new File(dataDir, "system");
1418 systemDir.mkdirs();
1419 mBatteryStatsService = new BatteryStatsService(new File(
1420 systemDir, "batterystats.bin").toString());
1421 mBatteryStatsService.getActiveStatistics().readLocked();
1422 mBatteryStatsService.getActiveStatistics().writeLocked();
1423
1424 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001425 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001426
Jack Palevichb90d28c2009-07-22 15:35:24 -07001427 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1428 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1429
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001430 mConfiguration.makeDefault();
1431 mProcessStats.init();
1432
1433 // Add ourself to the Watchdog monitors.
1434 Watchdog.getInstance().addMonitor(this);
1435
1436 // These values are set in system/rootdir/init.rc on startup.
1437 FOREGROUND_APP_ADJ =
1438 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1439 VISIBLE_APP_ADJ =
1440 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1441 SECONDARY_SERVER_ADJ =
1442 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001443 BACKUP_APP_ADJ =
1444 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001445 HOME_APP_ADJ =
1446 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001447 HIDDEN_APP_MIN_ADJ =
1448 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1449 CONTENT_PROVIDER_ADJ =
1450 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1451 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1452 EMPTY_APP_ADJ =
1453 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1454 FOREGROUND_APP_MEM =
1455 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1456 VISIBLE_APP_MEM =
1457 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1458 SECONDARY_SERVER_MEM =
1459 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001460 BACKUP_APP_MEM =
1461 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001462 HOME_APP_MEM =
1463 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001464 HIDDEN_APP_MEM =
1465 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1466 EMPTY_APP_MEM =
1467 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1468
1469 mProcessStatsThread = new Thread("ProcessStats") {
1470 public void run() {
1471 while (true) {
1472 try {
1473 try {
1474 synchronized(this) {
1475 final long now = SystemClock.uptimeMillis();
1476 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1477 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1478 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1479 // + ", write delay=" + nextWriteDelay);
1480 if (nextWriteDelay < nextCpuDelay) {
1481 nextCpuDelay = nextWriteDelay;
1482 }
1483 if (nextCpuDelay > 0) {
1484 this.wait(nextCpuDelay);
1485 }
1486 }
1487 } catch (InterruptedException e) {
1488 }
1489
1490 updateCpuStatsNow();
1491 } catch (Exception e) {
1492 Log.e(TAG, "Unexpected exception collecting process stats", e);
1493 }
1494 }
1495 }
1496 };
1497 mProcessStatsThread.start();
1498 }
1499
1500 @Override
1501 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1502 throws RemoteException {
1503 try {
1504 return super.onTransact(code, data, reply, flags);
1505 } catch (RuntimeException e) {
1506 // The activity manager only throws security exceptions, so let's
1507 // log all others.
1508 if (!(e instanceof SecurityException)) {
1509 Log.e(TAG, "Activity Manager Crash", e);
1510 }
1511 throw e;
1512 }
1513 }
1514
1515 void updateCpuStats() {
1516 synchronized (mProcessStatsThread) {
1517 final long now = SystemClock.uptimeMillis();
1518 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1519 mProcessStatsThread.notify();
1520 }
1521 }
1522 }
1523
1524 void updateCpuStatsNow() {
1525 synchronized (mProcessStatsThread) {
1526 final long now = SystemClock.uptimeMillis();
1527 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001528
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001529 if (MONITOR_CPU_USAGE &&
1530 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1531 mLastCpuTime = now;
1532 haveNewCpuStats = true;
1533 mProcessStats.update();
1534 //Log.i(TAG, mProcessStats.printCurrentState());
1535 //Log.i(TAG, "Total CPU usage: "
1536 // + mProcessStats.getTotalCpuPercent() + "%");
1537
1538 // Log the cpu usage if the property is set.
1539 if ("true".equals(SystemProperties.get("events.cpu"))) {
1540 int user = mProcessStats.getLastUserTime();
1541 int system = mProcessStats.getLastSystemTime();
1542 int iowait = mProcessStats.getLastIoWaitTime();
1543 int irq = mProcessStats.getLastIrqTime();
1544 int softIrq = mProcessStats.getLastSoftIrqTime();
1545 int idle = mProcessStats.getLastIdleTime();
1546
1547 int total = user + system + iowait + irq + softIrq + idle;
1548 if (total == 0) total = 1;
1549
1550 EventLog.writeEvent(LOG_CPU,
1551 ((user+system+iowait+irq+softIrq) * 100) / total,
1552 (user * 100) / total,
1553 (system * 100) / total,
1554 (iowait * 100) / total,
1555 (irq * 100) / total,
1556 (softIrq * 100) / total);
1557 }
1558 }
1559
Amith Yamasani819f9282009-06-24 23:18:15 -07001560 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001561 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001562 synchronized(mPidsSelfLocked) {
1563 if (haveNewCpuStats) {
1564 if (mBatteryStatsService.isOnBattery()) {
1565 final int N = mProcessStats.countWorkingStats();
1566 for (int i=0; i<N; i++) {
1567 ProcessStats.Stats st
1568 = mProcessStats.getWorkingStats(i);
1569 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1570 if (pr != null) {
1571 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1572 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001573 } else {
1574 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001575 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001576 if (ps != null) {
1577 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1578 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001579 }
1580 }
1581 }
1582 }
1583 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1586 mLastWriteTime = now;
1587 mBatteryStatsService.getActiveStatistics().writeLocked();
1588 }
1589 }
1590 }
1591 }
1592
1593 /**
1594 * Initialize the application bind args. These are passed to each
1595 * process when the bindApplication() IPC is sent to the process. They're
1596 * lazily setup to make sure the services are running when they're asked for.
1597 */
1598 private HashMap<String, IBinder> getCommonServicesLocked() {
1599 if (mAppBindArgs == null) {
1600 mAppBindArgs = new HashMap<String, IBinder>();
1601
1602 // Setup the application init args
1603 mAppBindArgs.put("package", ServiceManager.getService("package"));
1604 mAppBindArgs.put("window", ServiceManager.getService("window"));
1605 mAppBindArgs.put(Context.ALARM_SERVICE,
1606 ServiceManager.getService(Context.ALARM_SERVICE));
1607 }
1608 return mAppBindArgs;
1609 }
1610
1611 private final void setFocusedActivityLocked(HistoryRecord r) {
1612 if (mFocusedActivity != r) {
1613 mFocusedActivity = r;
1614 mWindowManager.setFocusedApp(r, true);
1615 }
1616 }
1617
1618 private final void updateLRUListLocked(ProcessRecord app,
1619 boolean oomAdj) {
1620 // put it on the LRU to keep track of when it should be exited.
1621 int lrui = mLRUProcesses.indexOf(app);
1622 if (lrui >= 0) mLRUProcesses.remove(lrui);
1623 mLRUProcesses.add(app);
1624 //Log.i(TAG, "Putting proc to front: " + app.processName);
1625 if (oomAdj) {
1626 updateOomAdjLocked();
1627 }
1628 }
1629
1630 private final boolean updateLRUListLocked(HistoryRecord r) {
1631 final boolean hadit = mLRUActivities.remove(r);
1632 mLRUActivities.add(r);
1633 return hadit;
1634 }
1635
1636 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1637 int i = mHistory.size()-1;
1638 while (i >= 0) {
1639 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1640 if (!r.finishing && r != notTop) {
1641 return r;
1642 }
1643 i--;
1644 }
1645 return null;
1646 }
1647
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001648 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1649 int i = mHistory.size()-1;
1650 while (i >= 0) {
1651 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1652 if (!r.finishing && !r.delayedResume && r != notTop) {
1653 return r;
1654 }
1655 i--;
1656 }
1657 return null;
1658 }
1659
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001660 /**
1661 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001662 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001663 *
1664 * @param token If non-null, any history records matching this token will be skipped.
1665 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1666 *
1667 * @return Returns the HistoryRecord of the next activity on the stack.
1668 */
1669 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1670 int i = mHistory.size()-1;
1671 while (i >= 0) {
1672 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1673 // Note: the taskId check depends on real taskId fields being non-zero
1674 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1675 return r;
1676 }
1677 i--;
1678 }
1679 return null;
1680 }
1681
1682 private final ProcessRecord getProcessRecordLocked(
1683 String processName, int uid) {
1684 if (uid == Process.SYSTEM_UID) {
1685 // The system gets to run in any process. If there are multiple
1686 // processes with the same uid, just pick the first (this
1687 // should never happen).
1688 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1689 processName);
1690 return procs != null ? procs.valueAt(0) : null;
1691 }
1692 ProcessRecord proc = mProcessNames.get(processName, uid);
1693 return proc;
1694 }
1695
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001696 private void ensurePackageDexOpt(String packageName) {
1697 IPackageManager pm = ActivityThread.getPackageManager();
1698 try {
1699 if (pm.performDexOpt(packageName)) {
1700 mDidDexOpt = true;
1701 }
1702 } catch (RemoteException e) {
1703 }
1704 }
1705
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001706 private boolean isNextTransitionForward() {
1707 int transit = mWindowManager.getPendingAppTransition();
1708 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1709 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1710 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1711 }
1712
1713 private final boolean realStartActivityLocked(HistoryRecord r,
1714 ProcessRecord app, boolean andResume, boolean checkConfig)
1715 throws RemoteException {
1716
1717 r.startFreezingScreenLocked(app, 0);
1718 mWindowManager.setAppVisibility(r, true);
1719
1720 // Have the window manager re-evaluate the orientation of
1721 // the screen based on the new activity order. Note that
1722 // as a result of this, it can call back into the activity
1723 // manager with a new orientation. We don't care about that,
1724 // because the activity is not currently running so we are
1725 // just restarting it anyway.
1726 if (checkConfig) {
1727 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001728 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729 r.mayFreezeScreenLocked(app) ? r : null);
1730 updateConfigurationLocked(config, r);
1731 }
1732
1733 r.app = app;
1734
1735 if (localLOGV) Log.v(TAG, "Launching: " + r);
1736
1737 int idx = app.activities.indexOf(r);
1738 if (idx < 0) {
1739 app.activities.add(r);
1740 }
1741 updateLRUListLocked(app, true);
1742
1743 try {
1744 if (app.thread == null) {
1745 throw new RemoteException();
1746 }
1747 List<ResultInfo> results = null;
1748 List<Intent> newIntents = null;
1749 if (andResume) {
1750 results = r.results;
1751 newIntents = r.newIntents;
1752 }
1753 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1754 + " icicle=" + r.icicle
1755 + " with results=" + results + " newIntents=" + newIntents
1756 + " andResume=" + andResume);
1757 if (andResume) {
1758 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1759 System.identityHashCode(r),
1760 r.task.taskId, r.shortComponentName);
1761 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001762 if (r.isHomeActivity) {
1763 mHomeProcess = app;
1764 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001765 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001766 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001767 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001768 r.info, r.icicle, results, newIntents, !andResume,
1769 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001770 } catch (RemoteException e) {
1771 if (r.launchFailed) {
1772 // This is the second time we failed -- finish activity
1773 // and give up.
1774 Log.e(TAG, "Second failure launching "
1775 + r.intent.getComponent().flattenToShortString()
1776 + ", giving up", e);
1777 appDiedLocked(app, app.pid, app.thread);
1778 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1779 "2nd-crash");
1780 return false;
1781 }
1782
1783 // This is the first time we failed -- restart process and
1784 // retry.
1785 app.activities.remove(r);
1786 throw e;
1787 }
1788
1789 r.launchFailed = false;
1790 if (updateLRUListLocked(r)) {
1791 Log.w(TAG, "Activity " + r
1792 + " being launched, but already in LRU list");
1793 }
1794
1795 if (andResume) {
1796 // As part of the process of launching, ActivityThread also performs
1797 // a resume.
1798 r.state = ActivityState.RESUMED;
1799 r.icicle = null;
1800 r.haveState = false;
1801 r.stopped = false;
1802 mResumedActivity = r;
1803 r.task.touchActiveTime();
1804 completeResumeLocked(r);
1805 pauseIfSleepingLocked();
1806 } else {
1807 // This activity is not starting in the resumed state... which
1808 // should look like we asked it to pause+stop (but remain visible),
1809 // and it has done so and reported back the current icicle and
1810 // other state.
1811 r.state = ActivityState.STOPPED;
1812 r.stopped = true;
1813 }
1814
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001815 // Launch the new version setup screen if needed. We do this -after-
1816 // launching the initial activity (that is, home), so that it can have
1817 // a chance to initialize itself while in the background, making the
1818 // switch back to it faster and look better.
1819 startSetupActivityLocked();
1820
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001821 return true;
1822 }
1823
1824 private final void startSpecificActivityLocked(HistoryRecord r,
1825 boolean andResume, boolean checkConfig) {
1826 // Is this activity's application already running?
1827 ProcessRecord app = getProcessRecordLocked(r.processName,
1828 r.info.applicationInfo.uid);
1829
1830 if (r.startTime == 0) {
1831 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001832 if (mInitialStartTime == 0) {
1833 mInitialStartTime = r.startTime;
1834 }
1835 } else if (mInitialStartTime == 0) {
1836 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001837 }
1838
1839 if (app != null && app.thread != null) {
1840 try {
1841 realStartActivityLocked(r, app, andResume, checkConfig);
1842 return;
1843 } catch (RemoteException e) {
1844 Log.w(TAG, "Exception when starting activity "
1845 + r.intent.getComponent().flattenToShortString(), e);
1846 }
1847
1848 // If a dead object exception was thrown -- fall through to
1849 // restart the application.
1850 }
1851
1852 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1853 "activity", r.intent.getComponent());
1854 }
1855
1856 private final ProcessRecord startProcessLocked(String processName,
1857 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1858 String hostingType, ComponentName hostingName) {
1859 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1860 // We don't have to do anything more if:
1861 // (1) There is an existing application record; and
1862 // (2) The caller doesn't think it is dead, OR there is no thread
1863 // object attached to it so we know it couldn't have crashed; and
1864 // (3) There is a pid assigned to it, so it is either starting or
1865 // already running.
1866 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1867 + " app=" + app + " knownToBeDead=" + knownToBeDead
1868 + " thread=" + (app != null ? app.thread : null)
1869 + " pid=" + (app != null ? app.pid : -1));
1870 if (app != null &&
1871 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1872 return app;
1873 }
1874
1875 String hostingNameStr = hostingName != null
1876 ? hostingName.flattenToShortString() : null;
1877
1878 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1879 // If we are in the background, then check to see if this process
1880 // is bad. If so, we will just silently fail.
1881 if (mBadProcesses.get(info.processName, info.uid) != null) {
1882 return null;
1883 }
1884 } else {
1885 // When the user is explicitly starting a process, then clear its
1886 // crash count so that we won't make it bad until they see at
1887 // least one crash dialog again, and make the process good again
1888 // if it had been bad.
1889 mProcessCrashTimes.remove(info.processName, info.uid);
1890 if (mBadProcesses.get(info.processName, info.uid) != null) {
1891 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1892 info.processName);
1893 mBadProcesses.remove(info.processName, info.uid);
1894 if (app != null) {
1895 app.bad = false;
1896 }
1897 }
1898 }
1899
1900 if (app == null) {
1901 app = newProcessRecordLocked(null, info, processName);
1902 mProcessNames.put(processName, info.uid, app);
1903 } else {
1904 // If this is a new package in the process, add the package to the list
1905 app.addPackage(info.packageName);
1906 }
1907
1908 // If the system is not ready yet, then hold off on starting this
1909 // process until it is.
1910 if (!mSystemReady
1911 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1912 if (!mProcessesOnHold.contains(app)) {
1913 mProcessesOnHold.add(app);
1914 }
1915 return app;
1916 }
1917
1918 startProcessLocked(app, hostingType, hostingNameStr);
1919 return (app.pid != 0) ? app : null;
1920 }
1921
1922 private final void startProcessLocked(ProcessRecord app,
1923 String hostingType, String hostingNameStr) {
1924 if (app.pid > 0 && app.pid != MY_PID) {
1925 synchronized (mPidsSelfLocked) {
1926 mPidsSelfLocked.remove(app.pid);
1927 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1928 }
1929 app.pid = 0;
1930 }
1931
1932 mProcessesOnHold.remove(app);
1933
1934 updateCpuStats();
1935
1936 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1937 mProcDeaths[0] = 0;
1938
1939 try {
1940 int uid = app.info.uid;
1941 int[] gids = null;
1942 try {
1943 gids = mContext.getPackageManager().getPackageGids(
1944 app.info.packageName);
1945 } catch (PackageManager.NameNotFoundException e) {
1946 Log.w(TAG, "Unable to retrieve gids", e);
1947 }
1948 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1949 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1950 && mTopComponent != null
1951 && app.processName.equals(mTopComponent.getPackageName())) {
1952 uid = 0;
1953 }
1954 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1955 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1956 uid = 0;
1957 }
1958 }
1959 int debugFlags = 0;
1960 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1961 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1962 }
1963 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1964 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1965 }
1966 if ("1".equals(SystemProperties.get("debug.assert"))) {
1967 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1968 }
1969 int pid = Process.start("android.app.ActivityThread",
1970 mSimpleProcessManagement ? app.processName : null, uid, uid,
1971 gids, debugFlags, null);
1972 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1973 synchronized (bs) {
1974 if (bs.isOnBattery()) {
1975 app.batteryStats.incStartsLocked();
1976 }
1977 }
1978
1979 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1980 app.processName, hostingType,
1981 hostingNameStr != null ? hostingNameStr : "");
1982
1983 if (app.persistent) {
1984 Watchdog.getInstance().processStarted(app, app.processName, pid);
1985 }
1986
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001987 StringBuilder buf = mStringBuilder;
1988 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001989 buf.append("Start proc ");
1990 buf.append(app.processName);
1991 buf.append(" for ");
1992 buf.append(hostingType);
1993 if (hostingNameStr != null) {
1994 buf.append(" ");
1995 buf.append(hostingNameStr);
1996 }
1997 buf.append(": pid=");
1998 buf.append(pid);
1999 buf.append(" uid=");
2000 buf.append(uid);
2001 buf.append(" gids={");
2002 if (gids != null) {
2003 for (int gi=0; gi<gids.length; gi++) {
2004 if (gi != 0) buf.append(", ");
2005 buf.append(gids[gi]);
2006
2007 }
2008 }
2009 buf.append("}");
2010 Log.i(TAG, buf.toString());
2011 if (pid == 0 || pid == MY_PID) {
2012 // Processes are being emulated with threads.
2013 app.pid = MY_PID;
2014 app.removed = false;
2015 mStartingProcesses.add(app);
2016 } else if (pid > 0) {
2017 app.pid = pid;
2018 app.removed = false;
2019 synchronized (mPidsSelfLocked) {
2020 this.mPidsSelfLocked.put(pid, app);
2021 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2022 msg.obj = app;
2023 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2024 }
2025 } else {
2026 app.pid = 0;
2027 RuntimeException e = new RuntimeException(
2028 "Failure starting process " + app.processName
2029 + ": returned pid=" + pid);
2030 Log.e(TAG, e.getMessage(), e);
2031 }
2032 } catch (RuntimeException e) {
2033 // XXX do better error recovery.
2034 app.pid = 0;
2035 Log.e(TAG, "Failure starting process " + app.processName, e);
2036 }
2037 }
2038
2039 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2040 if (mPausingActivity != null) {
2041 RuntimeException e = new RuntimeException();
2042 Log.e(TAG, "Trying to pause when pause is already pending for "
2043 + mPausingActivity, e);
2044 }
2045 HistoryRecord prev = mResumedActivity;
2046 if (prev == null) {
2047 RuntimeException e = new RuntimeException();
2048 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2049 resumeTopActivityLocked(null);
2050 return;
2051 }
2052 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2053 mResumedActivity = null;
2054 mPausingActivity = prev;
2055 mLastPausedActivity = prev;
2056 prev.state = ActivityState.PAUSING;
2057 prev.task.touchActiveTime();
2058
2059 updateCpuStats();
2060
2061 if (prev.app != null && prev.app.thread != null) {
2062 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2063 try {
2064 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2065 System.identityHashCode(prev),
2066 prev.shortComponentName);
2067 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2068 prev.configChangeFlags);
2069 updateUsageStats(prev, false);
2070 } catch (Exception e) {
2071 // Ignore exception, if process died other code will cleanup.
2072 Log.w(TAG, "Exception thrown during pause", e);
2073 mPausingActivity = null;
2074 mLastPausedActivity = null;
2075 }
2076 } else {
2077 mPausingActivity = null;
2078 mLastPausedActivity = null;
2079 }
2080
2081 // If we are not going to sleep, we want to ensure the device is
2082 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002083 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002084 mLaunchingActivity.acquire();
2085 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2086 // To be safe, don't allow the wake lock to be held for too long.
2087 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2088 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2089 }
2090 }
2091
2092
2093 if (mPausingActivity != null) {
2094 // Have the window manager pause its key dispatching until the new
2095 // activity has started. If we're pausing the activity just because
2096 // the screen is being turned off and the UI is sleeping, don't interrupt
2097 // key dispatch; the same activity will pick it up again on wakeup.
2098 if (!uiSleeping) {
2099 prev.pauseKeyDispatchingLocked();
2100 } else {
2101 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2102 }
2103
2104 // Schedule a pause timeout in case the app doesn't respond.
2105 // We don't give it much time because this directly impacts the
2106 // responsiveness seen by the user.
2107 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2108 msg.obj = prev;
2109 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2110 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2111 } else {
2112 // This activity failed to schedule the
2113 // pause, so just treat it as being paused now.
2114 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2115 resumeTopActivityLocked(null);
2116 }
2117 }
2118
2119 private final void completePauseLocked() {
2120 HistoryRecord prev = mPausingActivity;
2121 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2122
2123 if (prev != null) {
2124 if (prev.finishing) {
2125 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2126 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2127 } else if (prev.app != null) {
2128 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2129 if (prev.waitingVisible) {
2130 prev.waitingVisible = false;
2131 mWaitingVisibleActivities.remove(prev);
2132 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2133 TAG, "Complete pause, no longer waiting: " + prev);
2134 }
2135 if (prev.configDestroy) {
2136 // The previous is being paused because the configuration
2137 // is changing, which means it is actually stopping...
2138 // To juggle the fact that we are also starting a new
2139 // instance right now, we need to first completely stop
2140 // the current instance before starting the new one.
2141 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2142 destroyActivityLocked(prev, true);
2143 } else {
2144 mStoppingActivities.add(prev);
2145 if (mStoppingActivities.size() > 3) {
2146 // If we already have a few activities waiting to stop,
2147 // then give up on things going idle and start clearing
2148 // them out.
2149 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2150 Message msg = Message.obtain();
2151 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2152 mHandler.sendMessage(msg);
2153 }
2154 }
2155 } else {
2156 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2157 prev = null;
2158 }
2159 mPausingActivity = null;
2160 }
2161
Dianne Hackborn55280a92009-05-07 15:53:46 -07002162 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002163 resumeTopActivityLocked(prev);
2164 } else {
2165 if (mGoingToSleep.isHeld()) {
2166 mGoingToSleep.release();
2167 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002168 if (mShuttingDown) {
2169 notifyAll();
2170 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002171 }
2172
2173 if (prev != null) {
2174 prev.resumeKeyDispatchingLocked();
2175 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002176
2177 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2178 long diff = 0;
2179 synchronized (mProcessStatsThread) {
2180 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2181 }
2182 if (diff > 0) {
2183 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2184 synchronized (bsi) {
2185 BatteryStatsImpl.Uid.Proc ps =
2186 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2187 prev.info.packageName);
2188 if (ps != null) {
2189 ps.addForegroundTimeLocked(diff);
2190 }
2191 }
2192 }
2193 }
2194 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002195 }
2196
2197 /**
2198 * Once we know that we have asked an application to put an activity in
2199 * the resumed state (either by launching it or explicitly telling it),
2200 * this function updates the rest of our state to match that fact.
2201 */
2202 private final void completeResumeLocked(HistoryRecord next) {
2203 next.idle = false;
2204 next.results = null;
2205 next.newIntents = null;
2206
2207 // schedule an idle timeout in case the app doesn't do it for us.
2208 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2209 msg.obj = next;
2210 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2211
2212 if (false) {
2213 // The activity was never told to pause, so just keep
2214 // things going as-is. To maintain our own state,
2215 // we need to emulate it coming back and saying it is
2216 // idle.
2217 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2218 msg.obj = next;
2219 mHandler.sendMessage(msg);
2220 }
2221
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002222 reportResumedActivity(next);
2223
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002224 next.thumbnail = null;
2225 setFocusedActivityLocked(next);
2226 next.resumeKeyDispatchingLocked();
2227 ensureActivitiesVisibleLocked(null, 0);
2228 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002229
2230 // Mark the point when the activity is resuming
2231 // TODO: To be more accurate, the mark should be before the onCreate,
2232 // not after the onResume. But for subsequent starts, onResume is fine.
2233 if (next.app != null) {
2234 synchronized (mProcessStatsThread) {
2235 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2236 }
2237 } else {
2238 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2239 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002240 }
2241
2242 /**
2243 * Make sure that all activities that need to be visible (that is, they
2244 * currently can be seen by the user) actually are.
2245 */
2246 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2247 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2248 if (DEBUG_VISBILITY) Log.v(
2249 TAG, "ensureActivitiesVisible behind " + top
2250 + " configChanges=0x" + Integer.toHexString(configChanges));
2251
2252 // If the top activity is not fullscreen, then we need to
2253 // make sure any activities under it are now visible.
2254 final int count = mHistory.size();
2255 int i = count-1;
2256 while (mHistory.get(i) != top) {
2257 i--;
2258 }
2259 HistoryRecord r;
2260 boolean behindFullscreen = false;
2261 for (; i>=0; i--) {
2262 r = (HistoryRecord)mHistory.get(i);
2263 if (DEBUG_VISBILITY) Log.v(
2264 TAG, "Make visible? " + r + " finishing=" + r.finishing
2265 + " state=" + r.state);
2266 if (r.finishing) {
2267 continue;
2268 }
2269
2270 final boolean doThisProcess = onlyThisProcess == null
2271 || onlyThisProcess.equals(r.processName);
2272
2273 // First: if this is not the current activity being started, make
2274 // sure it matches the current configuration.
2275 if (r != starting && doThisProcess) {
2276 ensureActivityConfigurationLocked(r, 0);
2277 }
2278
2279 if (r.app == null || r.app.thread == null) {
2280 if (onlyThisProcess == null
2281 || onlyThisProcess.equals(r.processName)) {
2282 // This activity needs to be visible, but isn't even
2283 // running... get it started, but don't resume it
2284 // at this point.
2285 if (DEBUG_VISBILITY) Log.v(
2286 TAG, "Start and freeze screen for " + r);
2287 if (r != starting) {
2288 r.startFreezingScreenLocked(r.app, configChanges);
2289 }
2290 if (!r.visible) {
2291 if (DEBUG_VISBILITY) Log.v(
2292 TAG, "Starting and making visible: " + r);
2293 mWindowManager.setAppVisibility(r, true);
2294 }
2295 if (r != starting) {
2296 startSpecificActivityLocked(r, false, false);
2297 }
2298 }
2299
2300 } else if (r.visible) {
2301 // If this activity is already visible, then there is nothing
2302 // else to do here.
2303 if (DEBUG_VISBILITY) Log.v(
2304 TAG, "Skipping: already visible at " + r);
2305 r.stopFreezingScreenLocked(false);
2306
2307 } else if (onlyThisProcess == null) {
2308 // This activity is not currently visible, but is running.
2309 // Tell it to become visible.
2310 r.visible = true;
2311 if (r.state != ActivityState.RESUMED && r != starting) {
2312 // If this activity is paused, tell it
2313 // to now show its window.
2314 if (DEBUG_VISBILITY) Log.v(
2315 TAG, "Making visible and scheduling visibility: " + r);
2316 try {
2317 mWindowManager.setAppVisibility(r, true);
2318 r.app.thread.scheduleWindowVisibility(r, true);
2319 r.stopFreezingScreenLocked(false);
2320 } catch (Exception e) {
2321 // Just skip on any failure; we'll make it
2322 // visible when it next restarts.
2323 Log.w(TAG, "Exception thrown making visibile: "
2324 + r.intent.getComponent(), e);
2325 }
2326 }
2327 }
2328
2329 // Aggregate current change flags.
2330 configChanges |= r.configChangeFlags;
2331
2332 if (r.fullscreen) {
2333 // At this point, nothing else needs to be shown
2334 if (DEBUG_VISBILITY) Log.v(
2335 TAG, "Stopping: fullscreen at " + r);
2336 behindFullscreen = true;
2337 i--;
2338 break;
2339 }
2340 }
2341
2342 // Now for any activities that aren't visible to the user, make
2343 // sure they no longer are keeping the screen frozen.
2344 while (i >= 0) {
2345 r = (HistoryRecord)mHistory.get(i);
2346 if (DEBUG_VISBILITY) Log.v(
2347 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2348 + " state=" + r.state
2349 + " behindFullscreen=" + behindFullscreen);
2350 if (!r.finishing) {
2351 if (behindFullscreen) {
2352 if (r.visible) {
2353 if (DEBUG_VISBILITY) Log.v(
2354 TAG, "Making invisible: " + r);
2355 r.visible = false;
2356 try {
2357 mWindowManager.setAppVisibility(r, false);
2358 if ((r.state == ActivityState.STOPPING
2359 || r.state == ActivityState.STOPPED)
2360 && r.app != null && r.app.thread != null) {
2361 if (DEBUG_VISBILITY) Log.v(
2362 TAG, "Scheduling invisibility: " + r);
2363 r.app.thread.scheduleWindowVisibility(r, false);
2364 }
2365 } catch (Exception e) {
2366 // Just skip on any failure; we'll make it
2367 // visible when it next restarts.
2368 Log.w(TAG, "Exception thrown making hidden: "
2369 + r.intent.getComponent(), e);
2370 }
2371 } else {
2372 if (DEBUG_VISBILITY) Log.v(
2373 TAG, "Already invisible: " + r);
2374 }
2375 } else if (r.fullscreen) {
2376 if (DEBUG_VISBILITY) Log.v(
2377 TAG, "Now behindFullscreen: " + r);
2378 behindFullscreen = true;
2379 }
2380 }
2381 i--;
2382 }
2383 }
2384
2385 /**
2386 * Version of ensureActivitiesVisible that can easily be called anywhere.
2387 */
2388 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2389 int configChanges) {
2390 HistoryRecord r = topRunningActivityLocked(null);
2391 if (r != null) {
2392 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2393 }
2394 }
2395
2396 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2397 if (resumed) {
2398 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2399 } else {
2400 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2401 }
2402 }
2403
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002404 private boolean startHomeActivityLocked() {
2405 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2406 && mTopAction == null) {
2407 // We are running in factory test mode, but unable to find
2408 // the factory test app, so just sit around displaying the
2409 // error message and don't try to start anything.
2410 return false;
2411 }
2412 Intent intent = new Intent(
2413 mTopAction,
2414 mTopData != null ? Uri.parse(mTopData) : null);
2415 intent.setComponent(mTopComponent);
2416 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2417 intent.addCategory(Intent.CATEGORY_HOME);
2418 }
2419 ActivityInfo aInfo =
2420 intent.resolveActivityInfo(mContext.getPackageManager(),
2421 STOCK_PM_FLAGS);
2422 if (aInfo != null) {
2423 intent.setComponent(new ComponentName(
2424 aInfo.applicationInfo.packageName, aInfo.name));
2425 // Don't do this if the home app is currently being
2426 // instrumented.
2427 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2428 aInfo.applicationInfo.uid);
2429 if (app == null || app.instrumentationClass == null) {
2430 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2431 startActivityLocked(null, intent, null, null, 0, aInfo,
2432 null, null, 0, 0, 0, false, false);
2433 }
2434 }
2435
2436
2437 return true;
2438 }
2439
2440 /**
2441 * Starts the "new version setup screen" if appropriate.
2442 */
2443 private void startSetupActivityLocked() {
2444 // Only do this once per boot.
2445 if (mCheckedForSetup) {
2446 return;
2447 }
2448
2449 // We will show this screen if the current one is a different
2450 // version than the last one shown, and we are not running in
2451 // low-level factory test mode.
2452 final ContentResolver resolver = mContext.getContentResolver();
2453 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2454 Settings.Secure.getInt(resolver,
2455 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2456 mCheckedForSetup = true;
2457
2458 // See if we should be showing the platform update setup UI.
2459 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2460 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2461 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2462
2463 // We don't allow third party apps to replace this.
2464 ResolveInfo ri = null;
2465 for (int i=0; ris != null && i<ris.size(); i++) {
2466 if ((ris.get(i).activityInfo.applicationInfo.flags
2467 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2468 ri = ris.get(i);
2469 break;
2470 }
2471 }
2472
2473 if (ri != null) {
2474 String vers = ri.activityInfo.metaData != null
2475 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2476 : null;
2477 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2478 vers = ri.activityInfo.applicationInfo.metaData.getString(
2479 Intent.METADATA_SETUP_VERSION);
2480 }
2481 String lastVers = Settings.Secure.getString(
2482 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2483 if (vers != null && !vers.equals(lastVers)) {
2484 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2485 intent.setComponent(new ComponentName(
2486 ri.activityInfo.packageName, ri.activityInfo.name));
2487 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2488 null, null, 0, 0, 0, false, false);
2489 }
2490 }
2491 }
2492 }
2493
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002494 private void reportResumedActivity(HistoryRecord r) {
2495 //Log.i(TAG, "**** REPORT RESUME: " + r);
2496
2497 final int identHash = System.identityHashCode(r);
2498 updateUsageStats(r, true);
2499
2500 int i = mWatchers.beginBroadcast();
2501 while (i > 0) {
2502 i--;
2503 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2504 if (w != null) {
2505 try {
2506 w.activityResuming(identHash);
2507 } catch (RemoteException e) {
2508 }
2509 }
2510 }
2511 mWatchers.finishBroadcast();
2512 }
2513
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002514 /**
2515 * Ensure that the top activity in the stack is resumed.
2516 *
2517 * @param prev The previously resumed activity, for when in the process
2518 * of pausing; can be null to call from elsewhere.
2519 *
2520 * @return Returns true if something is being resumed, or false if
2521 * nothing happened.
2522 */
2523 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2524 // Find the first activity that is not finishing.
2525 HistoryRecord next = topRunningActivityLocked(null);
2526
2527 // Remember how we'll process this pause/resume situation, and ensure
2528 // that the state is reset however we wind up proceeding.
2529 final boolean userLeaving = mUserLeaving;
2530 mUserLeaving = false;
2531
2532 if (next == null) {
2533 // There are no more activities! Let's just start up the
2534 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002535 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002536 }
2537
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002538 next.delayedResume = false;
2539
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002540 // If the top activity is the resumed one, nothing to do.
2541 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2542 // Make sure we have executed any pending transitions, since there
2543 // should be nothing left to do at this point.
2544 mWindowManager.executeAppTransition();
2545 return false;
2546 }
2547
2548 // If we are sleeping, and there is no resumed activity, and the top
2549 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002550 if ((mSleeping || mShuttingDown)
2551 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002552 // Make sure we have executed any pending transitions, since there
2553 // should be nothing left to do at this point.
2554 mWindowManager.executeAppTransition();
2555 return false;
2556 }
2557
2558 // The activity may be waiting for stop, but that is no longer
2559 // appropriate for it.
2560 mStoppingActivities.remove(next);
2561 mWaitingVisibleActivities.remove(next);
2562
2563 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2564
2565 // If we are currently pausing an activity, then don't do anything
2566 // until that is done.
2567 if (mPausingActivity != null) {
2568 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2569 return false;
2570 }
2571
2572 // We need to start pausing the current activity so the top one
2573 // can be resumed...
2574 if (mResumedActivity != null) {
2575 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2576 startPausingLocked(userLeaving, false);
2577 return true;
2578 }
2579
2580 if (prev != null && prev != next) {
2581 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2582 prev.waitingVisible = true;
2583 mWaitingVisibleActivities.add(prev);
2584 if (DEBUG_SWITCH) Log.v(
2585 TAG, "Resuming top, waiting visible to hide: " + prev);
2586 } else {
2587 // The next activity is already visible, so hide the previous
2588 // activity's windows right now so we can show the new one ASAP.
2589 // We only do this if the previous is finishing, which should mean
2590 // it is on top of the one being resumed so hiding it quickly
2591 // is good. Otherwise, we want to do the normal route of allowing
2592 // the resumed activity to be shown so we can decide if the
2593 // previous should actually be hidden depending on whether the
2594 // new one is found to be full-screen or not.
2595 if (prev.finishing) {
2596 mWindowManager.setAppVisibility(prev, false);
2597 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2598 + prev + ", waitingVisible="
2599 + (prev != null ? prev.waitingVisible : null)
2600 + ", nowVisible=" + next.nowVisible);
2601 } else {
2602 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2603 + prev + ", waitingVisible="
2604 + (prev != null ? prev.waitingVisible : null)
2605 + ", nowVisible=" + next.nowVisible);
2606 }
2607 }
2608 }
2609
2610 // We are starting up the next activity, so tell the window manager
2611 // that the previous one will be hidden soon. This way it can know
2612 // to ignore it when computing the desired screen orientation.
2613 if (prev != null) {
2614 if (prev.finishing) {
2615 if (DEBUG_TRANSITION) Log.v(TAG,
2616 "Prepare close transition: prev=" + prev);
2617 mWindowManager.prepareAppTransition(prev.task == next.task
2618 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2619 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2620 mWindowManager.setAppWillBeHidden(prev);
2621 mWindowManager.setAppVisibility(prev, false);
2622 } else {
2623 if (DEBUG_TRANSITION) Log.v(TAG,
2624 "Prepare open transition: prev=" + prev);
2625 mWindowManager.prepareAppTransition(prev.task == next.task
2626 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2627 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2628 }
2629 if (false) {
2630 mWindowManager.setAppWillBeHidden(prev);
2631 mWindowManager.setAppVisibility(prev, false);
2632 }
2633 } else if (mHistory.size() > 1) {
2634 if (DEBUG_TRANSITION) Log.v(TAG,
2635 "Prepare open transition: no previous");
2636 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2637 }
2638
2639 if (next.app != null && next.app.thread != null) {
2640 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2641
2642 // This activity is now becoming visible.
2643 mWindowManager.setAppVisibility(next, true);
2644
2645 HistoryRecord lastResumedActivity = mResumedActivity;
2646 ActivityState lastState = next.state;
2647
2648 updateCpuStats();
2649
2650 next.state = ActivityState.RESUMED;
2651 mResumedActivity = next;
2652 next.task.touchActiveTime();
2653 updateLRUListLocked(next.app, true);
2654 updateLRUListLocked(next);
2655
2656 // Have the window manager re-evaluate the orientation of
2657 // the screen based on the new activity order.
2658 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002659 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002660 next.mayFreezeScreenLocked(next.app) ? next : null);
2661 if (config != null) {
2662 next.frozenBeforeDestroy = true;
2663 }
2664 if (!updateConfigurationLocked(config, next)) {
2665 // The configuration update wasn't able to keep the existing
2666 // instance of the activity, and instead started a new one.
2667 // We should be all done, but let's just make sure our activity
2668 // is still at the top and schedule another run if something
2669 // weird happened.
2670 HistoryRecord nextNext = topRunningActivityLocked(null);
2671 if (DEBUG_SWITCH) Log.i(TAG,
2672 "Activity config changed during resume: " + next
2673 + ", new next: " + nextNext);
2674 if (nextNext != next) {
2675 // Do over!
2676 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2677 }
2678 mWindowManager.executeAppTransition();
2679 return true;
2680 }
2681
2682 try {
2683 // Deliver all pending results.
2684 ArrayList a = next.results;
2685 if (a != null) {
2686 final int N = a.size();
2687 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002688 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002689 TAG, "Delivering results to " + next
2690 + ": " + a);
2691 next.app.thread.scheduleSendResult(next, a);
2692 }
2693 }
2694
2695 if (next.newIntents != null) {
2696 next.app.thread.scheduleNewIntent(next.newIntents, next);
2697 }
2698
2699 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2700 System.identityHashCode(next),
2701 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002702
2703 next.app.thread.scheduleResumeActivity(next,
2704 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002705
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002706 pauseIfSleepingLocked();
2707
2708 } catch (Exception e) {
2709 // Whoops, need to restart this activity!
2710 next.state = lastState;
2711 mResumedActivity = lastResumedActivity;
2712 if (Config.LOGD) Log.d(TAG,
2713 "Restarting because process died: " + next);
2714 if (!next.hasBeenLaunched) {
2715 next.hasBeenLaunched = true;
2716 } else {
2717 if (SHOW_APP_STARTING_ICON) {
2718 mWindowManager.setAppStartingWindow(
2719 next, next.packageName, next.theme,
2720 next.nonLocalizedLabel,
2721 next.labelRes, next.icon, null, true);
2722 }
2723 }
2724 startSpecificActivityLocked(next, true, false);
2725 return true;
2726 }
2727
2728 // From this point on, if something goes wrong there is no way
2729 // to recover the activity.
2730 try {
2731 next.visible = true;
2732 completeResumeLocked(next);
2733 } catch (Exception e) {
2734 // If any exception gets thrown, toss away this
2735 // activity and try the next one.
2736 Log.w(TAG, "Exception thrown during resume of " + next, e);
2737 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2738 "resume-exception");
2739 return true;
2740 }
2741
2742 // Didn't need to use the icicle, and it is now out of date.
2743 next.icicle = null;
2744 next.haveState = false;
2745 next.stopped = false;
2746
2747 } else {
2748 // Whoops, need to restart this activity!
2749 if (!next.hasBeenLaunched) {
2750 next.hasBeenLaunched = true;
2751 } else {
2752 if (SHOW_APP_STARTING_ICON) {
2753 mWindowManager.setAppStartingWindow(
2754 next, next.packageName, next.theme,
2755 next.nonLocalizedLabel,
2756 next.labelRes, next.icon, null, true);
2757 }
2758 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2759 }
2760 startSpecificActivityLocked(next, true, true);
2761 }
2762
2763 return true;
2764 }
2765
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002766 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2767 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002768 final int NH = mHistory.size();
2769
2770 int addPos = -1;
2771
2772 if (!newTask) {
2773 // If starting in an existing task, find where that is...
2774 HistoryRecord next = null;
2775 boolean startIt = true;
2776 for (int i = NH-1; i >= 0; i--) {
2777 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2778 if (p.finishing) {
2779 continue;
2780 }
2781 if (p.task == r.task) {
2782 // Here it is! Now, if this is not yet visible to the
2783 // user, then just add it without starting; it will
2784 // get started when the user navigates back to it.
2785 addPos = i+1;
2786 if (!startIt) {
2787 mHistory.add(addPos, r);
2788 r.inHistory = true;
2789 r.task.numActivities++;
2790 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2791 r.info.screenOrientation, r.fullscreen);
2792 if (VALIDATE_TOKENS) {
2793 mWindowManager.validateAppTokens(mHistory);
2794 }
2795 return;
2796 }
2797 break;
2798 }
2799 if (p.fullscreen) {
2800 startIt = false;
2801 }
2802 next = p;
2803 }
2804 }
2805
2806 // Place a new activity at top of stack, so it is next to interact
2807 // with the user.
2808 if (addPos < 0) {
2809 addPos = mHistory.size();
2810 }
2811
2812 // If we are not placing the new activity frontmost, we do not want
2813 // to deliver the onUserLeaving callback to the actual frontmost
2814 // activity
2815 if (addPos < NH) {
2816 mUserLeaving = false;
2817 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2818 }
2819
2820 // Slot the activity into the history stack and proceed
2821 mHistory.add(addPos, r);
2822 r.inHistory = true;
2823 r.frontOfTask = newTask;
2824 r.task.numActivities++;
2825 if (NH > 0) {
2826 // We want to show the starting preview window if we are
2827 // switching to a new task, or the next activity's process is
2828 // not currently running.
2829 boolean showStartingIcon = newTask;
2830 ProcessRecord proc = r.app;
2831 if (proc == null) {
2832 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2833 }
2834 if (proc == null || proc.thread == null) {
2835 showStartingIcon = true;
2836 }
2837 if (DEBUG_TRANSITION) Log.v(TAG,
2838 "Prepare open transition: starting " + r);
2839 mWindowManager.prepareAppTransition(newTask
2840 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2841 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2842 mWindowManager.addAppToken(
2843 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2844 boolean doShow = true;
2845 if (newTask) {
2846 // Even though this activity is starting fresh, we still need
2847 // to reset it to make sure we apply affinities to move any
2848 // existing activities from other tasks in to it.
2849 // If the caller has requested that the target task be
2850 // reset, then do so.
2851 if ((r.intent.getFlags()
2852 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2853 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002854 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002855 }
2856 }
2857 if (SHOW_APP_STARTING_ICON && doShow) {
2858 // Figure out if we are transitioning from another activity that is
2859 // "has the same starting icon" as the next one. This allows the
2860 // window manager to keep the previous window it had previously
2861 // created, if it still had one.
2862 HistoryRecord prev = mResumedActivity;
2863 if (prev != null) {
2864 // We don't want to reuse the previous starting preview if:
2865 // (1) The current activity is in a different task.
2866 if (prev.task != r.task) prev = null;
2867 // (2) The current activity is already displayed.
2868 else if (prev.nowVisible) prev = null;
2869 }
2870 mWindowManager.setAppStartingWindow(
2871 r, r.packageName, r.theme, r.nonLocalizedLabel,
2872 r.labelRes, r.icon, prev, showStartingIcon);
2873 }
2874 } else {
2875 // If this is the first activity, don't do any fancy animations,
2876 // because there is nothing for it to animate on top of.
2877 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2878 r.info.screenOrientation, r.fullscreen);
2879 }
2880 if (VALIDATE_TOKENS) {
2881 mWindowManager.validateAppTokens(mHistory);
2882 }
2883
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002884 if (doResume) {
2885 resumeTopActivityLocked(null);
2886 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002887 }
2888
2889 /**
2890 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002891 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2892 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002893 * an instance of that activity in the stack and, if found, finish all
2894 * activities on top of it and return the instance.
2895 *
2896 * @param newR Description of the new activity being started.
2897 * @return Returns the old activity that should be continue to be used,
2898 * or null if none was found.
2899 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002900 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002901 HistoryRecord newR, boolean doClear) {
2902 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002903
2904 // First find the requested task.
2905 while (i > 0) {
2906 i--;
2907 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2908 if (r.task.taskId == taskId) {
2909 i++;
2910 break;
2911 }
2912 }
2913
2914 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002915 while (i > 0) {
2916 i--;
2917 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2918 if (r.finishing) {
2919 continue;
2920 }
2921 if (r.task.taskId != taskId) {
2922 return null;
2923 }
2924 if (r.realActivity.equals(newR.realActivity)) {
2925 // Here it is! Now finish everything in front...
2926 HistoryRecord ret = r;
2927 if (doClear) {
2928 while (i < (mHistory.size()-1)) {
2929 i++;
2930 r = (HistoryRecord)mHistory.get(i);
2931 if (r.finishing) {
2932 continue;
2933 }
2934 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2935 null, "clear")) {
2936 i--;
2937 }
2938 }
2939 }
2940
2941 // Finally, if this is a normal launch mode (that is, not
2942 // expecting onNewIntent()), then we will finish the current
2943 // instance of the activity so a new fresh one can be started.
2944 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2945 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002946 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002947 if (index >= 0) {
2948 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2949 null, "clear");
2950 }
2951 return null;
2952 }
2953 }
2954
2955 return ret;
2956 }
2957 }
2958
2959 return null;
2960 }
2961
2962 /**
2963 * Find the activity in the history stack within the given task. Returns
2964 * the index within the history at which it's found, or < 0 if not found.
2965 */
2966 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2967 int i = mHistory.size();
2968 while (i > 0) {
2969 i--;
2970 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2971 if (candidate.task.taskId != task) {
2972 break;
2973 }
2974 if (candidate.realActivity.equals(r.realActivity)) {
2975 return i;
2976 }
2977 }
2978
2979 return -1;
2980 }
2981
2982 /**
2983 * Reorder the history stack so that the activity at the given index is
2984 * brought to the front.
2985 */
2986 private final HistoryRecord moveActivityToFrontLocked(int where) {
2987 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2988 int top = mHistory.size();
2989 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2990 mHistory.add(top, newTop);
2991 oldTop.frontOfTask = false;
2992 newTop.frontOfTask = true;
2993 return newTop;
2994 }
2995
2996 /**
2997 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2998 * method will be called at the proper time.
2999 */
3000 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3001 boolean sent = false;
3002 if (r.state == ActivityState.RESUMED
3003 && r.app != null && r.app.thread != null) {
3004 try {
3005 ArrayList<Intent> ar = new ArrayList<Intent>();
3006 ar.add(new Intent(intent));
3007 r.app.thread.scheduleNewIntent(ar, r);
3008 sent = true;
3009 } catch (Exception e) {
3010 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3011 }
3012 }
3013 if (!sent) {
3014 r.addNewIntentLocked(new Intent(intent));
3015 }
3016 }
3017
3018 private final void logStartActivity(int tag, HistoryRecord r,
3019 TaskRecord task) {
3020 EventLog.writeEvent(tag,
3021 System.identityHashCode(r), task.taskId,
3022 r.shortComponentName, r.intent.getAction(),
3023 r.intent.getType(), r.intent.getDataString(),
3024 r.intent.getFlags());
3025 }
3026
3027 private final int startActivityLocked(IApplicationThread caller,
3028 Intent intent, String resolvedType,
3029 Uri[] grantedUriPermissions,
3030 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3031 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003032 int callingPid, int callingUid, boolean onlyIfNeeded,
3033 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003034 Log.i(TAG, "Starting activity: " + intent);
3035
3036 HistoryRecord sourceRecord = null;
3037 HistoryRecord resultRecord = null;
3038 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003039 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003040 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003041 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3042 if (index >= 0) {
3043 sourceRecord = (HistoryRecord)mHistory.get(index);
3044 if (requestCode >= 0 && !sourceRecord.finishing) {
3045 resultRecord = sourceRecord;
3046 }
3047 }
3048 }
3049
3050 int launchFlags = intent.getFlags();
3051
3052 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3053 && sourceRecord != null) {
3054 // Transfer the result target from the source activity to the new
3055 // one being started, including any failures.
3056 if (requestCode >= 0) {
3057 return START_FORWARD_AND_REQUEST_CONFLICT;
3058 }
3059 resultRecord = sourceRecord.resultTo;
3060 resultWho = sourceRecord.resultWho;
3061 requestCode = sourceRecord.requestCode;
3062 sourceRecord.resultTo = null;
3063 if (resultRecord != null) {
3064 resultRecord.removeResultsLocked(
3065 sourceRecord, resultWho, requestCode);
3066 }
3067 }
3068
3069 int err = START_SUCCESS;
3070
3071 if (intent.getComponent() == null) {
3072 // We couldn't find a class that can handle the given Intent.
3073 // That's the end of that!
3074 err = START_INTENT_NOT_RESOLVED;
3075 }
3076
3077 if (err == START_SUCCESS && aInfo == null) {
3078 // We couldn't find the specific class specified in the Intent.
3079 // Also the end of the line.
3080 err = START_CLASS_NOT_FOUND;
3081 }
3082
3083 ProcessRecord callerApp = null;
3084 if (err == START_SUCCESS && caller != null) {
3085 callerApp = getRecordForAppLocked(caller);
3086 if (callerApp != null) {
3087 callingPid = callerApp.pid;
3088 callingUid = callerApp.info.uid;
3089 } else {
3090 Log.w(TAG, "Unable to find app for caller " + caller
3091 + " (pid=" + callingPid + ") when starting: "
3092 + intent.toString());
3093 err = START_PERMISSION_DENIED;
3094 }
3095 }
3096
3097 if (err != START_SUCCESS) {
3098 if (resultRecord != null) {
3099 sendActivityResultLocked(-1,
3100 resultRecord, resultWho, requestCode,
3101 Activity.RESULT_CANCELED, null);
3102 }
3103 return err;
3104 }
3105
3106 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3107 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3108 if (perm != PackageManager.PERMISSION_GRANTED) {
3109 if (resultRecord != null) {
3110 sendActivityResultLocked(-1,
3111 resultRecord, resultWho, requestCode,
3112 Activity.RESULT_CANCELED, null);
3113 }
3114 String msg = "Permission Denial: starting " + intent.toString()
3115 + " from " + callerApp + " (pid=" + callingPid
3116 + ", uid=" + callingUid + ")"
3117 + " requires " + aInfo.permission;
3118 Log.w(TAG, msg);
3119 throw new SecurityException(msg);
3120 }
3121
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003122 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003123 boolean abort = false;
3124 try {
3125 // The Intent we give to the watcher has the extra data
3126 // stripped off, since it can contain private information.
3127 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003128 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003129 aInfo.applicationInfo.packageName);
3130 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003131 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003132 }
3133
3134 if (abort) {
3135 if (resultRecord != null) {
3136 sendActivityResultLocked(-1,
3137 resultRecord, resultWho, requestCode,
3138 Activity.RESULT_CANCELED, null);
3139 }
3140 // We pretend to the caller that it was really started, but
3141 // they will just get a cancel result.
3142 return START_SUCCESS;
3143 }
3144 }
3145
3146 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3147 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003148 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003149
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003150 if (mResumedActivity == null
3151 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3152 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3153 PendingActivityLaunch pal = new PendingActivityLaunch();
3154 pal.r = r;
3155 pal.sourceRecord = sourceRecord;
3156 pal.grantedUriPermissions = grantedUriPermissions;
3157 pal.grantedMode = grantedMode;
3158 pal.onlyIfNeeded = onlyIfNeeded;
3159 mPendingActivityLaunches.add(pal);
3160 return START_SWITCHES_CANCELED;
3161 }
3162 }
3163
3164 if (mDidAppSwitch) {
3165 // This is the second allowed switch since we stopped switches,
3166 // so now just generally allow switches. Use case: user presses
3167 // home (switches disabled, switch to home, mDidAppSwitch now true);
3168 // user taps a home icon (coming from home so allowed, we hit here
3169 // and now allow anyone to switch again).
3170 mAppSwitchesAllowedTime = 0;
3171 } else {
3172 mDidAppSwitch = true;
3173 }
3174
3175 doPendingActivityLaunchesLocked(false);
3176
3177 return startActivityUncheckedLocked(r, sourceRecord,
3178 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3179 }
3180
3181 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3182 final int N = mPendingActivityLaunches.size();
3183 if (N <= 0) {
3184 return;
3185 }
3186 for (int i=0; i<N; i++) {
3187 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3188 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3189 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3190 doResume && i == (N-1));
3191 }
3192 mPendingActivityLaunches.clear();
3193 }
3194
3195 private final int startActivityUncheckedLocked(HistoryRecord r,
3196 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3197 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3198 final Intent intent = r.intent;
3199 final int callingUid = r.launchedFromUid;
3200
3201 int launchFlags = intent.getFlags();
3202
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003203 // We'll invoke onUserLeaving before onPause only if the launching
3204 // activity did not explicitly state that this is an automated launch.
3205 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3206 if (DEBUG_USER_LEAVING) Log.v(TAG,
3207 "startActivity() => mUserLeaving=" + mUserLeaving);
3208
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003209 // If the caller has asked not to resume at this point, we make note
3210 // of this in the record so that we can skip it when trying to find
3211 // the top running activity.
3212 if (!doResume) {
3213 r.delayedResume = true;
3214 }
3215
3216 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3217 != 0 ? r : null;
3218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003219 // If the onlyIfNeeded flag is set, then we can do this if the activity
3220 // being launched is the same as the one making the call... or, as
3221 // a special case, if we do not know the caller then we count the
3222 // current top activity as the caller.
3223 if (onlyIfNeeded) {
3224 HistoryRecord checkedCaller = sourceRecord;
3225 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003226 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003227 }
3228 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3229 // Caller is not the same as launcher, so always needed.
3230 onlyIfNeeded = false;
3231 }
3232 }
3233
3234 if (grantedUriPermissions != null && callingUid > 0) {
3235 for (int i=0; i<grantedUriPermissions.length; i++) {
3236 grantUriPermissionLocked(callingUid, r.packageName,
3237 grantedUriPermissions[i], grantedMode, r);
3238 }
3239 }
3240
3241 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3242 intent, r);
3243
3244 if (sourceRecord == null) {
3245 // This activity is not being started from another... in this
3246 // case we -always- start a new task.
3247 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3248 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3249 + intent);
3250 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3251 }
3252 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3253 // The original activity who is starting us is running as a single
3254 // instance... this new activity it is starting must go on its
3255 // own task.
3256 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3257 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3258 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3259 // The activity being started is a single instance... it always
3260 // gets launched into its own task.
3261 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3262 }
3263
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003264 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003265 // For whatever reason this activity is being launched into a new
3266 // task... yet the caller has requested a result back. Well, that
3267 // is pretty messed up, so instead immediately send back a cancel
3268 // and let the new task continue launched as normal without a
3269 // dependency on its originator.
3270 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3271 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003272 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003273 Activity.RESULT_CANCELED, null);
3274 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003275 }
3276
3277 boolean addingToTask = false;
3278 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3279 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3280 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3281 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3282 // If bring to front is requested, and no result is requested, and
3283 // we can find a task that was started with this same
3284 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003285 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003286 // See if there is a task to bring to the front. If this is
3287 // a SINGLE_INSTANCE activity, there can be one and only one
3288 // instance of it in the history, and it is always in its own
3289 // unique task, so we do a special search.
3290 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3291 ? findTaskLocked(intent, r.info)
3292 : findActivityLocked(intent, r.info);
3293 if (taskTop != null) {
3294 if (taskTop.task.intent == null) {
3295 // This task was started because of movement of
3296 // the activity based on affinity... now that we
3297 // are actually launching it, we can assign the
3298 // base intent.
3299 taskTop.task.setIntent(intent, r.info);
3300 }
3301 // If the target task is not in the front, then we need
3302 // to bring it to the front... except... well, with
3303 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3304 // to have the same behavior as if a new instance was
3305 // being started, which means not bringing it to the front
3306 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003307 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003308 if (curTop.task != taskTop.task) {
3309 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3310 boolean callerAtFront = sourceRecord == null
3311 || curTop.task == sourceRecord.task;
3312 if (callerAtFront) {
3313 // We really do want to push this one into the
3314 // user's face, right now.
3315 moveTaskToFrontLocked(taskTop.task);
3316 }
3317 }
3318 // If the caller has requested that the target task be
3319 // reset, then do so.
3320 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3321 taskTop = resetTaskIfNeededLocked(taskTop, r);
3322 }
3323 if (onlyIfNeeded) {
3324 // We don't need to start a new activity, and
3325 // the client said not to do anything if that
3326 // is the case, so this is it! And for paranoia, make
3327 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003328 if (doResume) {
3329 resumeTopActivityLocked(null);
3330 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003331 return START_RETURN_INTENT_TO_CALLER;
3332 }
3333 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3334 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3335 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3336 // In this situation we want to remove all activities
3337 // from the task up to the one being started. In most
3338 // cases this means we are resetting the task to its
3339 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003340 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003341 taskTop.task.taskId, r, true);
3342 if (top != null) {
3343 if (top.frontOfTask) {
3344 // Activity aliases may mean we use different
3345 // intents for the top activity, so make sure
3346 // the task now has the identity of the new
3347 // intent.
3348 top.task.setIntent(r.intent, r.info);
3349 }
3350 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3351 deliverNewIntentLocked(top, r.intent);
3352 } else {
3353 // A special case: we need to
3354 // start the activity because it is not currently
3355 // running, and the caller has asked to clear the
3356 // current task to have this activity at the top.
3357 addingToTask = true;
3358 // Now pretend like this activity is being started
3359 // by the top of its task, so it is put in the
3360 // right place.
3361 sourceRecord = taskTop;
3362 }
3363 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3364 // In this case the top activity on the task is the
3365 // same as the one being launched, so we take that
3366 // as a request to bring the task to the foreground.
3367 // If the top activity in the task is the root
3368 // activity, deliver this new intent to it if it
3369 // desires.
3370 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3371 && taskTop.realActivity.equals(r.realActivity)) {
3372 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3373 if (taskTop.frontOfTask) {
3374 taskTop.task.setIntent(r.intent, r.info);
3375 }
3376 deliverNewIntentLocked(taskTop, r.intent);
3377 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3378 // In this case we are launching the root activity
3379 // of the task, but with a different intent. We
3380 // should start a new instance on top.
3381 addingToTask = true;
3382 sourceRecord = taskTop;
3383 }
3384 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3385 // In this case an activity is being launched in to an
3386 // existing task, without resetting that task. This
3387 // is typically the situation of launching an activity
3388 // from a notification or shortcut. We want to place
3389 // the new activity on top of the current task.
3390 addingToTask = true;
3391 sourceRecord = taskTop;
3392 } else if (!taskTop.task.rootWasReset) {
3393 // In this case we are launching in to an existing task
3394 // that has not yet been started from its front door.
3395 // The current task has been brought to the front.
3396 // Ideally, we'd probably like to place this new task
3397 // at the bottom of its stack, but that's a little hard
3398 // to do with the current organization of the code so
3399 // for now we'll just drop it.
3400 taskTop.task.setIntent(r.intent, r.info);
3401 }
3402 if (!addingToTask) {
3403 // We didn't do anything... but it was needed (a.k.a., client
3404 // don't use that intent!) And for paranoia, make
3405 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003406 if (doResume) {
3407 resumeTopActivityLocked(null);
3408 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003409 return START_TASK_TO_FRONT;
3410 }
3411 }
3412 }
3413 }
3414
3415 //String uri = r.intent.toURI();
3416 //Intent intent2 = new Intent(uri);
3417 //Log.i(TAG, "Given intent: " + r.intent);
3418 //Log.i(TAG, "URI is: " + uri);
3419 //Log.i(TAG, "To intent: " + intent2);
3420
3421 if (r.packageName != null) {
3422 // If the activity being launched is the same as the one currently
3423 // at the top, then we need to check if it should only be launched
3424 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003425 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3426 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003427 if (top.realActivity.equals(r.realActivity)) {
3428 if (top.app != null && top.app.thread != null) {
3429 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3430 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3431 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3432 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3433 // For paranoia, make sure we have correctly
3434 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003435 if (doResume) {
3436 resumeTopActivityLocked(null);
3437 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003438 if (onlyIfNeeded) {
3439 // We don't need to start a new activity, and
3440 // the client said not to do anything if that
3441 // is the case, so this is it!
3442 return START_RETURN_INTENT_TO_CALLER;
3443 }
3444 deliverNewIntentLocked(top, r.intent);
3445 return START_DELIVERED_TO_TOP;
3446 }
3447 }
3448 }
3449 }
3450
3451 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003452 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003453 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003454 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003455 Activity.RESULT_CANCELED, null);
3456 }
3457 return START_CLASS_NOT_FOUND;
3458 }
3459
3460 boolean newTask = false;
3461
3462 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003463 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003464 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3465 // todo: should do better management of integers.
3466 mCurTask++;
3467 if (mCurTask <= 0) {
3468 mCurTask = 1;
3469 }
3470 r.task = new TaskRecord(mCurTask, r.info, intent,
3471 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3472 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3473 + " in new task " + r.task);
3474 newTask = true;
3475 addRecentTask(r.task);
3476
3477 } else if (sourceRecord != null) {
3478 if (!addingToTask &&
3479 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3480 // In this case, we are adding the activity to an existing
3481 // task, but the caller has asked to clear that task if the
3482 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003483 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003484 sourceRecord.task.taskId, r, true);
3485 if (top != null) {
3486 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3487 deliverNewIntentLocked(top, r.intent);
3488 // For paranoia, make sure we have correctly
3489 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003490 if (doResume) {
3491 resumeTopActivityLocked(null);
3492 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003493 return START_DELIVERED_TO_TOP;
3494 }
3495 } else if (!addingToTask &&
3496 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3497 // In this case, we are launching an activity in our own task
3498 // that may already be running somewhere in the history, and
3499 // we want to shuffle it to the front of the stack if so.
3500 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3501 if (where >= 0) {
3502 HistoryRecord top = moveActivityToFrontLocked(where);
3503 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3504 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003505 if (doResume) {
3506 resumeTopActivityLocked(null);
3507 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003508 return START_DELIVERED_TO_TOP;
3509 }
3510 }
3511 // An existing activity is starting this new activity, so we want
3512 // to keep the new one in the same task as the one that is starting
3513 // it.
3514 r.task = sourceRecord.task;
3515 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3516 + " in existing task " + r.task);
3517
3518 } else {
3519 // This not being started from an existing activity, and not part
3520 // of a new task... just put it in the top task, though these days
3521 // this case should never happen.
3522 final int N = mHistory.size();
3523 HistoryRecord prev =
3524 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3525 r.task = prev != null
3526 ? prev.task
3527 : new TaskRecord(mCurTask, r.info, intent,
3528 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3529 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3530 + " in new guessed " + r.task);
3531 }
3532 if (newTask) {
3533 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3534 }
3535 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003536 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003537 return START_SUCCESS;
3538 }
3539
3540 public final int startActivity(IApplicationThread caller,
3541 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3542 int grantedMode, IBinder resultTo,
3543 String resultWho, int requestCode, boolean onlyIfNeeded,
3544 boolean debug) {
3545 // Refuse possible leaked file descriptors
3546 if (intent != null && intent.hasFileDescriptors()) {
3547 throw new IllegalArgumentException("File descriptors passed in Intent");
3548 }
3549
The Android Open Source Project4df24232009-03-05 14:34:35 -08003550 final boolean componentSpecified = intent.getComponent() != null;
3551
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003552 // Don't modify the client's object!
3553 intent = new Intent(intent);
3554
3555 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003556 ActivityInfo aInfo;
3557 try {
3558 ResolveInfo rInfo =
3559 ActivityThread.getPackageManager().resolveIntent(
3560 intent, resolvedType,
3561 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003562 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003563 aInfo = rInfo != null ? rInfo.activityInfo : null;
3564 } catch (RemoteException e) {
3565 aInfo = null;
3566 }
3567
3568 if (aInfo != null) {
3569 // Store the found target back into the intent, because now that
3570 // we have it we never want to do this again. For example, if the
3571 // user navigates back to this point in the history, we should
3572 // always restart the exact same activity.
3573 intent.setComponent(new ComponentName(
3574 aInfo.applicationInfo.packageName, aInfo.name));
3575
3576 // Don't debug things in the system process
3577 if (debug) {
3578 if (!aInfo.processName.equals("system")) {
3579 setDebugApp(aInfo.processName, true, false);
3580 }
3581 }
3582 }
3583
3584 synchronized(this) {
3585 final long origId = Binder.clearCallingIdentity();
3586 int res = startActivityLocked(caller, intent, resolvedType,
3587 grantedUriPermissions, grantedMode, aInfo,
3588 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003589 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003590 Binder.restoreCallingIdentity(origId);
3591 return res;
3592 }
3593 }
3594
3595 public boolean startNextMatchingActivity(IBinder callingActivity,
3596 Intent intent) {
3597 // Refuse possible leaked file descriptors
3598 if (intent != null && intent.hasFileDescriptors() == true) {
3599 throw new IllegalArgumentException("File descriptors passed in Intent");
3600 }
3601
3602 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003603 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003604 if (index < 0) {
3605 return false;
3606 }
3607 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3608 if (r.app == null || r.app.thread == null) {
3609 // The caller is not running... d'oh!
3610 return false;
3611 }
3612 intent = new Intent(intent);
3613 // The caller is not allowed to change the data.
3614 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3615 // And we are resetting to find the next component...
3616 intent.setComponent(null);
3617
3618 ActivityInfo aInfo = null;
3619 try {
3620 List<ResolveInfo> resolves =
3621 ActivityThread.getPackageManager().queryIntentActivities(
3622 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003623 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003624
3625 // Look for the original activity in the list...
3626 final int N = resolves != null ? resolves.size() : 0;
3627 for (int i=0; i<N; i++) {
3628 ResolveInfo rInfo = resolves.get(i);
3629 if (rInfo.activityInfo.packageName.equals(r.packageName)
3630 && rInfo.activityInfo.name.equals(r.info.name)) {
3631 // We found the current one... the next matching is
3632 // after it.
3633 i++;
3634 if (i<N) {
3635 aInfo = resolves.get(i).activityInfo;
3636 }
3637 break;
3638 }
3639 }
3640 } catch (RemoteException e) {
3641 }
3642
3643 if (aInfo == null) {
3644 // Nobody who is next!
3645 return false;
3646 }
3647
3648 intent.setComponent(new ComponentName(
3649 aInfo.applicationInfo.packageName, aInfo.name));
3650 intent.setFlags(intent.getFlags()&~(
3651 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3652 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3653 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3654 Intent.FLAG_ACTIVITY_NEW_TASK));
3655
3656 // Okay now we need to start the new activity, replacing the
3657 // currently running activity. This is a little tricky because
3658 // we want to start the new one as if the current one is finished,
3659 // but not finish the current one first so that there is no flicker.
3660 // And thus...
3661 final boolean wasFinishing = r.finishing;
3662 r.finishing = true;
3663
3664 // Propagate reply information over to the new activity.
3665 final HistoryRecord resultTo = r.resultTo;
3666 final String resultWho = r.resultWho;
3667 final int requestCode = r.requestCode;
3668 r.resultTo = null;
3669 if (resultTo != null) {
3670 resultTo.removeResultsLocked(r, resultWho, requestCode);
3671 }
3672
3673 final long origId = Binder.clearCallingIdentity();
3674 // XXX we are not dealing with propagating grantedUriPermissions...
3675 // those are not yet exposed to user code, so there is no need.
3676 int res = startActivityLocked(r.app.thread, intent,
3677 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003678 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003679 Binder.restoreCallingIdentity(origId);
3680
3681 r.finishing = wasFinishing;
3682 if (res != START_SUCCESS) {
3683 return false;
3684 }
3685 return true;
3686 }
3687 }
3688
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003689 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003690 Intent intent, String resolvedType, IBinder resultTo,
3691 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003692
3693 // This is so super not safe, that only the system (or okay root)
3694 // can do it.
3695 final int callingUid = Binder.getCallingUid();
3696 if (callingUid != 0 && callingUid != Process.myUid()) {
3697 throw new SecurityException(
3698 "startActivityInPackage only available to the system");
3699 }
3700
The Android Open Source Project4df24232009-03-05 14:34:35 -08003701 final boolean componentSpecified = intent.getComponent() != null;
3702
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003703 // Don't modify the client's object!
3704 intent = new Intent(intent);
3705
3706 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003707 ActivityInfo aInfo;
3708 try {
3709 ResolveInfo rInfo =
3710 ActivityThread.getPackageManager().resolveIntent(
3711 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003712 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003713 aInfo = rInfo != null ? rInfo.activityInfo : null;
3714 } catch (RemoteException e) {
3715 aInfo = null;
3716 }
3717
3718 if (aInfo != null) {
3719 // Store the found target back into the intent, because now that
3720 // we have it we never want to do this again. For example, if the
3721 // user navigates back to this point in the history, we should
3722 // always restart the exact same activity.
3723 intent.setComponent(new ComponentName(
3724 aInfo.applicationInfo.packageName, aInfo.name));
3725 }
3726
3727 synchronized(this) {
3728 return startActivityLocked(null, intent, resolvedType,
3729 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003730 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003731 }
3732 }
3733
3734 private final void addRecentTask(TaskRecord task) {
3735 // Remove any existing entries that are the same kind of task.
3736 int N = mRecentTasks.size();
3737 for (int i=0; i<N; i++) {
3738 TaskRecord tr = mRecentTasks.get(i);
3739 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3740 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3741 mRecentTasks.remove(i);
3742 i--;
3743 N--;
3744 if (task.intent == null) {
3745 // If the new recent task we are adding is not fully
3746 // specified, then replace it with the existing recent task.
3747 task = tr;
3748 }
3749 }
3750 }
3751 if (N >= MAX_RECENT_TASKS) {
3752 mRecentTasks.remove(N-1);
3753 }
3754 mRecentTasks.add(0, task);
3755 }
3756
3757 public void setRequestedOrientation(IBinder token,
3758 int requestedOrientation) {
3759 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003760 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003761 if (index < 0) {
3762 return;
3763 }
3764 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3765 final long origId = Binder.clearCallingIdentity();
3766 mWindowManager.setAppOrientation(r, requestedOrientation);
3767 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003768 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003769 r.mayFreezeScreenLocked(r.app) ? r : null);
3770 if (config != null) {
3771 r.frozenBeforeDestroy = true;
3772 if (!updateConfigurationLocked(config, r)) {
3773 resumeTopActivityLocked(null);
3774 }
3775 }
3776 Binder.restoreCallingIdentity(origId);
3777 }
3778 }
3779
3780 public int getRequestedOrientation(IBinder token) {
3781 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003782 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003783 if (index < 0) {
3784 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3785 }
3786 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3787 return mWindowManager.getAppOrientation(r);
3788 }
3789 }
3790
3791 private final void stopActivityLocked(HistoryRecord r) {
3792 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3793 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3794 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3795 if (!r.finishing) {
3796 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3797 "no-history");
3798 }
3799 } else if (r.app != null && r.app.thread != null) {
3800 if (mFocusedActivity == r) {
3801 setFocusedActivityLocked(topRunningActivityLocked(null));
3802 }
3803 r.resumeKeyDispatchingLocked();
3804 try {
3805 r.stopped = false;
3806 r.state = ActivityState.STOPPING;
3807 if (DEBUG_VISBILITY) Log.v(
3808 TAG, "Stopping visible=" + r.visible + " for " + r);
3809 if (!r.visible) {
3810 mWindowManager.setAppVisibility(r, false);
3811 }
3812 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3813 } catch (Exception e) {
3814 // Maybe just ignore exceptions here... if the process
3815 // has crashed, our death notification will clean things
3816 // up.
3817 Log.w(TAG, "Exception thrown during pause", e);
3818 // Just in case, assume it to be stopped.
3819 r.stopped = true;
3820 r.state = ActivityState.STOPPED;
3821 if (r.configDestroy) {
3822 destroyActivityLocked(r, true);
3823 }
3824 }
3825 }
3826 }
3827
3828 /**
3829 * @return Returns true if the activity is being finished, false if for
3830 * some reason it is being left as-is.
3831 */
3832 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3833 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003834 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003835 TAG, "Finishing activity: token=" + token
3836 + ", result=" + resultCode + ", data=" + resultData);
3837
Dianne Hackborn75b03852009-06-12 15:43:26 -07003838 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003839 if (index < 0) {
3840 return false;
3841 }
3842 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3843
3844 // Is this the last activity left?
3845 boolean lastActivity = true;
3846 for (int i=mHistory.size()-1; i>=0; i--) {
3847 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3848 if (!p.finishing && p != r) {
3849 lastActivity = false;
3850 break;
3851 }
3852 }
3853
3854 // If this is the last activity, but it is the home activity, then
3855 // just don't finish it.
3856 if (lastActivity) {
3857 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3858 return false;
3859 }
3860 }
3861
3862 finishActivityLocked(r, index, resultCode, resultData, reason);
3863 return true;
3864 }
3865
3866 /**
3867 * @return Returns true if this activity has been removed from the history
3868 * list, or false if it is still in the list and will be removed later.
3869 */
3870 private final boolean finishActivityLocked(HistoryRecord r, int index,
3871 int resultCode, Intent resultData, String reason) {
3872 if (r.finishing) {
3873 Log.w(TAG, "Duplicate finish request for " + r);
3874 return false;
3875 }
3876
3877 r.finishing = true;
3878 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3879 System.identityHashCode(r),
3880 r.task.taskId, r.shortComponentName, reason);
3881 r.task.numActivities--;
3882 if (r.frontOfTask && index < (mHistory.size()-1)) {
3883 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3884 if (next.task == r.task) {
3885 next.frontOfTask = true;
3886 }
3887 }
3888
3889 r.pauseKeyDispatchingLocked();
3890 if (mFocusedActivity == r) {
3891 setFocusedActivityLocked(topRunningActivityLocked(null));
3892 }
3893
3894 // send the result
3895 HistoryRecord resultTo = r.resultTo;
3896 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003897 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3898 + " who=" + r.resultWho + " req=" + r.requestCode
3899 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003900 if (r.info.applicationInfo.uid > 0) {
3901 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3902 r.packageName, resultData, r);
3903 }
3904 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3905 resultData);
3906 r.resultTo = null;
3907 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003908 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003909
3910 // Make sure this HistoryRecord is not holding on to other resources,
3911 // because clients have remote IPC references to this object so we
3912 // can't assume that will go away and want to avoid circular IPC refs.
3913 r.results = null;
3914 r.pendingResults = null;
3915 r.newIntents = null;
3916 r.icicle = null;
3917
3918 if (mPendingThumbnails.size() > 0) {
3919 // There are clients waiting to receive thumbnails so, in case
3920 // this is an activity that someone is waiting for, add it
3921 // to the pending list so we can correctly update the clients.
3922 mCancelledThumbnails.add(r);
3923 }
3924
3925 if (mResumedActivity == r) {
3926 boolean endTask = index <= 0
3927 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3928 if (DEBUG_TRANSITION) Log.v(TAG,
3929 "Prepare close transition: finishing " + r);
3930 mWindowManager.prepareAppTransition(endTask
3931 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3932 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3933
3934 // Tell window manager to prepare for this one to be removed.
3935 mWindowManager.setAppVisibility(r, false);
3936
3937 if (mPausingActivity == null) {
3938 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3939 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3940 startPausingLocked(false, false);
3941 }
3942
3943 } else if (r.state != ActivityState.PAUSING) {
3944 // If the activity is PAUSING, we will complete the finish once
3945 // it is done pausing; else we can just directly finish it here.
3946 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3947 return finishCurrentActivityLocked(r, index,
3948 FINISH_AFTER_PAUSE) == null;
3949 } else {
3950 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3951 }
3952
3953 return false;
3954 }
3955
3956 private static final int FINISH_IMMEDIATELY = 0;
3957 private static final int FINISH_AFTER_PAUSE = 1;
3958 private static final int FINISH_AFTER_VISIBLE = 2;
3959
3960 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3961 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003962 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003963 if (index < 0) {
3964 return null;
3965 }
3966
3967 return finishCurrentActivityLocked(r, index, mode);
3968 }
3969
3970 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3971 int index, int mode) {
3972 // First things first: if this activity is currently visible,
3973 // and the resumed activity is not yet visible, then hold off on
3974 // finishing until the resumed one becomes visible.
3975 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3976 if (!mStoppingActivities.contains(r)) {
3977 mStoppingActivities.add(r);
3978 if (mStoppingActivities.size() > 3) {
3979 // If we already have a few activities waiting to stop,
3980 // then give up on things going idle and start clearing
3981 // them out.
3982 Message msg = Message.obtain();
3983 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3984 mHandler.sendMessage(msg);
3985 }
3986 }
3987 r.state = ActivityState.STOPPING;
3988 updateOomAdjLocked();
3989 return r;
3990 }
3991
3992 // make sure the record is cleaned out of other places.
3993 mStoppingActivities.remove(r);
3994 mWaitingVisibleActivities.remove(r);
3995 if (mResumedActivity == r) {
3996 mResumedActivity = null;
3997 }
3998 final ActivityState prevState = r.state;
3999 r.state = ActivityState.FINISHING;
4000
4001 if (mode == FINISH_IMMEDIATELY
4002 || prevState == ActivityState.STOPPED
4003 || prevState == ActivityState.INITIALIZING) {
4004 // If this activity is already stopped, we can just finish
4005 // it right now.
4006 return destroyActivityLocked(r, true) ? null : r;
4007 } else {
4008 // Need to go through the full pause cycle to get this
4009 // activity into the stopped state and then finish it.
4010 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4011 mFinishingActivities.add(r);
4012 resumeTopActivityLocked(null);
4013 }
4014 return r;
4015 }
4016
4017 /**
4018 * This is the internal entry point for handling Activity.finish().
4019 *
4020 * @param token The Binder token referencing the Activity we want to finish.
4021 * @param resultCode Result code, if any, from this Activity.
4022 * @param resultData Result data (Intent), if any, from this Activity.
4023 *
4024 * @result Returns true if the activity successfully finished, or false if it is still running.
4025 */
4026 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4027 // Refuse possible leaked file descriptors
4028 if (resultData != null && resultData.hasFileDescriptors() == true) {
4029 throw new IllegalArgumentException("File descriptors passed in Intent");
4030 }
4031
4032 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004033 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004034 // Find the first activity that is not finishing.
4035 HistoryRecord next = topRunningActivityLocked(token, 0);
4036 if (next != null) {
4037 // ask watcher if this is allowed
4038 boolean resumeOK = true;
4039 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004040 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004041 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004042 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004043 }
4044
4045 if (!resumeOK) {
4046 return false;
4047 }
4048 }
4049 }
4050 final long origId = Binder.clearCallingIdentity();
4051 boolean res = requestFinishActivityLocked(token, resultCode,
4052 resultData, "app-request");
4053 Binder.restoreCallingIdentity(origId);
4054 return res;
4055 }
4056 }
4057
4058 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4059 String resultWho, int requestCode, int resultCode, Intent data) {
4060
4061 if (callingUid > 0) {
4062 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4063 data, r);
4064 }
4065
The Android Open Source Project10592532009-03-18 17:39:46 -07004066 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4067 + " : who=" + resultWho + " req=" + requestCode
4068 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004069 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4070 try {
4071 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4072 list.add(new ResultInfo(resultWho, requestCode,
4073 resultCode, data));
4074 r.app.thread.scheduleSendResult(r, list);
4075 return;
4076 } catch (Exception e) {
4077 Log.w(TAG, "Exception thrown sending result to " + r, e);
4078 }
4079 }
4080
4081 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4082 }
4083
4084 public final void finishSubActivity(IBinder token, String resultWho,
4085 int requestCode) {
4086 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004087 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004088 if (index < 0) {
4089 return;
4090 }
4091 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4092
4093 final long origId = Binder.clearCallingIdentity();
4094
4095 int i;
4096 for (i=mHistory.size()-1; i>=0; i--) {
4097 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4098 if (r.resultTo == self && r.requestCode == requestCode) {
4099 if ((r.resultWho == null && resultWho == null) ||
4100 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4101 finishActivityLocked(r, i,
4102 Activity.RESULT_CANCELED, null, "request-sub");
4103 }
4104 }
4105 }
4106
4107 Binder.restoreCallingIdentity(origId);
4108 }
4109 }
4110
4111 /**
4112 * Perform clean-up of service connections in an activity record.
4113 */
4114 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4115 // Throw away any services that have been bound by this activity.
4116 if (r.connections != null) {
4117 Iterator<ConnectionRecord> it = r.connections.iterator();
4118 while (it.hasNext()) {
4119 ConnectionRecord c = it.next();
4120 removeConnectionLocked(c, null, r);
4121 }
4122 r.connections = null;
4123 }
4124 }
4125
4126 /**
4127 * Perform the common clean-up of an activity record. This is called both
4128 * as part of destroyActivityLocked() (when destroying the client-side
4129 * representation) and cleaning things up as a result of its hosting
4130 * processing going away, in which case there is no remaining client-side
4131 * state to destroy so only the cleanup here is needed.
4132 */
4133 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4134 if (mResumedActivity == r) {
4135 mResumedActivity = null;
4136 }
4137 if (mFocusedActivity == r) {
4138 mFocusedActivity = null;
4139 }
4140
4141 r.configDestroy = false;
4142 r.frozenBeforeDestroy = false;
4143
4144 // Make sure this record is no longer in the pending finishes list.
4145 // This could happen, for example, if we are trimming activities
4146 // down to the max limit while they are still waiting to finish.
4147 mFinishingActivities.remove(r);
4148 mWaitingVisibleActivities.remove(r);
4149
4150 // Remove any pending results.
4151 if (r.finishing && r.pendingResults != null) {
4152 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4153 PendingIntentRecord rec = apr.get();
4154 if (rec != null) {
4155 cancelIntentSenderLocked(rec, false);
4156 }
4157 }
4158 r.pendingResults = null;
4159 }
4160
4161 if (cleanServices) {
4162 cleanUpActivityServicesLocked(r);
4163 }
4164
4165 if (mPendingThumbnails.size() > 0) {
4166 // There are clients waiting to receive thumbnails so, in case
4167 // this is an activity that someone is waiting for, add it
4168 // to the pending list so we can correctly update the clients.
4169 mCancelledThumbnails.add(r);
4170 }
4171
4172 // Get rid of any pending idle timeouts.
4173 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4174 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4175 }
4176
4177 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4178 if (r.state != ActivityState.DESTROYED) {
4179 mHistory.remove(r);
4180 r.inHistory = false;
4181 r.state = ActivityState.DESTROYED;
4182 mWindowManager.removeAppToken(r);
4183 if (VALIDATE_TOKENS) {
4184 mWindowManager.validateAppTokens(mHistory);
4185 }
4186 cleanUpActivityServicesLocked(r);
4187 removeActivityUriPermissionsLocked(r);
4188 }
4189 }
4190
4191 /**
4192 * Destroy the current CLIENT SIDE instance of an activity. This may be
4193 * called both when actually finishing an activity, or when performing
4194 * a configuration switch where we destroy the current client-side object
4195 * but then create a new client-side object for this same HistoryRecord.
4196 */
4197 private final boolean destroyActivityLocked(HistoryRecord r,
4198 boolean removeFromApp) {
4199 if (DEBUG_SWITCH) Log.v(
4200 TAG, "Removing activity: token=" + r
4201 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4202 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4203 System.identityHashCode(r),
4204 r.task.taskId, r.shortComponentName);
4205
4206 boolean removedFromHistory = false;
4207
4208 cleanUpActivityLocked(r, false);
4209
4210 if (r.app != null) {
4211 if (removeFromApp) {
4212 int idx = r.app.activities.indexOf(r);
4213 if (idx >= 0) {
4214 r.app.activities.remove(idx);
4215 }
4216 if (r.persistent) {
4217 decPersistentCountLocked(r.app);
4218 }
4219 }
4220
4221 boolean skipDestroy = false;
4222
4223 try {
4224 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4225 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4226 r.configChangeFlags);
4227 } catch (Exception e) {
4228 // We can just ignore exceptions here... if the process
4229 // has crashed, our death notification will clean things
4230 // up.
4231 //Log.w(TAG, "Exception thrown during finish", e);
4232 if (r.finishing) {
4233 removeActivityFromHistoryLocked(r);
4234 removedFromHistory = true;
4235 skipDestroy = true;
4236 }
4237 }
4238
4239 r.app = null;
4240 r.nowVisible = false;
4241
4242 if (r.finishing && !skipDestroy) {
4243 r.state = ActivityState.DESTROYING;
4244 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4245 msg.obj = r;
4246 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4247 } else {
4248 r.state = ActivityState.DESTROYED;
4249 }
4250 } else {
4251 // remove this record from the history.
4252 if (r.finishing) {
4253 removeActivityFromHistoryLocked(r);
4254 removedFromHistory = true;
4255 } else {
4256 r.state = ActivityState.DESTROYED;
4257 }
4258 }
4259
4260 r.configChangeFlags = 0;
4261
4262 if (!mLRUActivities.remove(r)) {
4263 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4264 }
4265
4266 return removedFromHistory;
4267 }
4268
4269 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4270 ProcessRecord app)
4271 {
4272 int i = list.size();
4273 if (localLOGV) Log.v(
4274 TAG, "Removing app " + app + " from list " + list
4275 + " with " + i + " entries");
4276 while (i > 0) {
4277 i--;
4278 HistoryRecord r = (HistoryRecord)list.get(i);
4279 if (localLOGV) Log.v(
4280 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4281 if (r.app == app) {
4282 if (localLOGV) Log.v(TAG, "Removing this entry!");
4283 list.remove(i);
4284 }
4285 }
4286 }
4287
4288 /**
4289 * Main function for removing an existing process from the activity manager
4290 * as a result of that process going away. Clears out all connections
4291 * to the process.
4292 */
4293 private final void handleAppDiedLocked(ProcessRecord app,
4294 boolean restarting) {
4295 cleanUpApplicationRecordLocked(app, restarting, -1);
4296 if (!restarting) {
4297 mLRUProcesses.remove(app);
4298 }
4299
4300 // Just in case...
4301 if (mPausingActivity != null && mPausingActivity.app == app) {
4302 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4303 mPausingActivity = null;
4304 }
4305 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4306 mLastPausedActivity = null;
4307 }
4308
4309 // Remove this application's activities from active lists.
4310 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4311 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4312 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4313 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4314
4315 boolean atTop = true;
4316 boolean hasVisibleActivities = false;
4317
4318 // Clean out the history list.
4319 int i = mHistory.size();
4320 if (localLOGV) Log.v(
4321 TAG, "Removing app " + app + " from history with " + i + " entries");
4322 while (i > 0) {
4323 i--;
4324 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4325 if (localLOGV) Log.v(
4326 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4327 if (r.app == app) {
4328 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4329 if (localLOGV) Log.v(
4330 TAG, "Removing this entry! frozen=" + r.haveState
4331 + " finishing=" + r.finishing);
4332 mHistory.remove(i);
4333
4334 r.inHistory = false;
4335 mWindowManager.removeAppToken(r);
4336 if (VALIDATE_TOKENS) {
4337 mWindowManager.validateAppTokens(mHistory);
4338 }
4339 removeActivityUriPermissionsLocked(r);
4340
4341 } else {
4342 // We have the current state for this activity, so
4343 // it can be restarted later when needed.
4344 if (localLOGV) Log.v(
4345 TAG, "Keeping entry, setting app to null");
4346 if (r.visible) {
4347 hasVisibleActivities = true;
4348 }
4349 r.app = null;
4350 r.nowVisible = false;
4351 if (!r.haveState) {
4352 r.icicle = null;
4353 }
4354 }
4355
4356 cleanUpActivityLocked(r, true);
4357 r.state = ActivityState.STOPPED;
4358 }
4359 atTop = false;
4360 }
4361
4362 app.activities.clear();
4363
4364 if (app.instrumentationClass != null) {
4365 Log.w(TAG, "Crash of app " + app.processName
4366 + " running instrumentation " + app.instrumentationClass);
4367 Bundle info = new Bundle();
4368 info.putString("shortMsg", "Process crashed.");
4369 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4370 }
4371
4372 if (!restarting) {
4373 if (!resumeTopActivityLocked(null)) {
4374 // If there was nothing to resume, and we are not already
4375 // restarting this process, but there is a visible activity that
4376 // is hosted by the process... then make sure all visible
4377 // activities are running, taking care of restarting this
4378 // process.
4379 if (hasVisibleActivities) {
4380 ensureActivitiesVisibleLocked(null, 0);
4381 }
4382 }
4383 }
4384 }
4385
4386 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4387 IBinder threadBinder = thread.asBinder();
4388
4389 // Find the application record.
4390 int count = mLRUProcesses.size();
4391 int i;
4392 for (i=0; i<count; i++) {
4393 ProcessRecord rec = mLRUProcesses.get(i);
4394 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4395 return i;
4396 }
4397 }
4398 return -1;
4399 }
4400
4401 private final ProcessRecord getRecordForAppLocked(
4402 IApplicationThread thread) {
4403 if (thread == null) {
4404 return null;
4405 }
4406
4407 int appIndex = getLRURecordIndexForAppLocked(thread);
4408 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4409 }
4410
4411 private final void appDiedLocked(ProcessRecord app, int pid,
4412 IApplicationThread thread) {
4413
4414 mProcDeaths[0]++;
4415
4416 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4417 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4418 + ") has died.");
4419 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4420 if (localLOGV) Log.v(
4421 TAG, "Dying app: " + app + ", pid: " + pid
4422 + ", thread: " + thread.asBinder());
4423 boolean doLowMem = app.instrumentationClass == null;
4424 handleAppDiedLocked(app, false);
4425
4426 if (doLowMem) {
4427 // If there are no longer any background processes running,
4428 // and the app that died was not running instrumentation,
4429 // then tell everyone we are now low on memory.
4430 boolean haveBg = false;
4431 int count = mLRUProcesses.size();
4432 int i;
4433 for (i=0; i<count; i++) {
4434 ProcessRecord rec = mLRUProcesses.get(i);
4435 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4436 haveBg = true;
4437 break;
4438 }
4439 }
4440
4441 if (!haveBg) {
4442 Log.i(TAG, "Low Memory: No more background processes.");
4443 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004444 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004445 for (i=0; i<count; i++) {
4446 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004447 if (rec.thread != null &&
4448 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4449 // The low memory report is overriding any current
4450 // state for a GC request. Make sure to do
4451 // visible/foreground processes first.
4452 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4453 rec.lastRequestedGc = 0;
4454 } else {
4455 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004456 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004457 rec.reportLowMemory = true;
4458 rec.lastLowMemory = now;
4459 mProcessesToGc.remove(rec);
4460 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004461 }
4462 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004463 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004464 }
4465 }
4466 } else if (Config.LOGD) {
4467 Log.d(TAG, "Received spurious death notification for thread "
4468 + thread.asBinder());
4469 }
4470 }
4471
4472 final String readFile(String filename) {
4473 try {
4474 FileInputStream fs = new FileInputStream(filename);
4475 byte[] inp = new byte[8192];
4476 int size = fs.read(inp);
4477 fs.close();
4478 return new String(inp, 0, 0, size);
4479 } catch (java.io.IOException e) {
4480 }
4481 return "";
4482 }
4483
4484 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004485 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004486 if (app.notResponding || app.crashing) {
4487 return;
4488 }
4489
4490 // Log the ANR to the event log.
4491 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4492
4493 // If we are on a secure build and the application is not interesting to the user (it is
4494 // not visible or in the background), just kill it instead of displaying a dialog.
4495 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4496 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4497 Process.killProcess(app.pid);
4498 return;
4499 }
4500
4501 // DeviceMonitor.start();
4502
4503 String processInfo = null;
4504 if (MONITOR_CPU_USAGE) {
4505 updateCpuStatsNow();
4506 synchronized (mProcessStatsThread) {
4507 processInfo = mProcessStats.printCurrentState();
4508 }
4509 }
4510
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004511 StringBuilder info = mStringBuilder;
4512 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004513 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004514 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004515 if (reportedActivity != null && reportedActivity.app != null) {
4516 info.append(" (last in ");
4517 info.append(reportedActivity.app.processName);
4518 info.append(")");
4519 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004520 if (annotation != null) {
4521 info.append("\nAnnotation: ");
4522 info.append(annotation);
4523 }
4524 if (MONITOR_CPU_USAGE) {
4525 info.append("\nCPU usage:\n");
4526 info.append(processInfo);
4527 }
4528 Log.i(TAG, info.toString());
4529
4530 // The application is not responding. Dump as many thread traces as we can.
4531 boolean fileDump = prepareTraceFile(true);
4532 if (!fileDump) {
4533 // Dumping traces to the log, just dump the process that isn't responding so
4534 // we don't overflow the log
4535 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4536 } else {
4537 // Dumping traces to a file so dump all active processes we know about
4538 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004539 // First, these are the most important processes.
4540 final int[] imppids = new int[3];
4541 int i=0;
4542 imppids[0] = app.pid;
4543 i++;
4544 if (reportedActivity != null && reportedActivity.app != null
4545 && reportedActivity.app.thread != null
4546 && reportedActivity.app.pid != app.pid) {
4547 imppids[i] = reportedActivity.app.pid;
4548 i++;
4549 }
4550 imppids[i] = Process.myPid();
4551 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4552 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4553 synchronized (this) {
4554 try {
4555 wait(200);
4556 } catch (InterruptedException e) {
4557 }
4558 }
4559 }
4560 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004561 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004562 boolean done = false;
4563 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4564 if (imppids[j] == r.pid) {
4565 done = true;
4566 break;
4567 }
4568 }
4569 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004570 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004571 synchronized (this) {
4572 try {
4573 wait(200);
4574 } catch (InterruptedException e) {
4575 }
4576 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004577 }
4578 }
4579 }
4580 }
4581
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004582 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004583 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004584 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004585 app.pid, info.toString());
4586 if (res != 0) {
4587 if (res < 0) {
4588 // wait until the SIGQUIT has had a chance to process before killing the
4589 // process.
4590 try {
4591 wait(2000);
4592 } catch (InterruptedException e) {
4593 }
4594
4595 Process.killProcess(app.pid);
4596 return;
4597 }
4598 }
4599 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004600 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004601 }
4602 }
4603
4604 makeAppNotRespondingLocked(app,
4605 activity != null ? activity.shortComponentName : null,
4606 annotation != null ? "ANR " + annotation : "ANR",
4607 info.toString(), null);
4608 Message msg = Message.obtain();
4609 HashMap map = new HashMap();
4610 msg.what = SHOW_NOT_RESPONDING_MSG;
4611 msg.obj = map;
4612 map.put("app", app);
4613 if (activity != null) {
4614 map.put("activity", activity);
4615 }
4616
4617 mHandler.sendMessage(msg);
4618 return;
4619 }
4620
4621 /**
4622 * If a stack trace file has been configured, prepare the filesystem
4623 * by creating the directory if it doesn't exist and optionally
4624 * removing the old trace file.
4625 *
4626 * @param removeExisting If set, the existing trace file will be removed.
4627 * @return Returns true if the trace file preparations succeeded
4628 */
4629 public static boolean prepareTraceFile(boolean removeExisting) {
4630 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4631 boolean fileReady = false;
4632 if (!TextUtils.isEmpty(tracesPath)) {
4633 File f = new File(tracesPath);
4634 if (!f.exists()) {
4635 // Ensure the enclosing directory exists
4636 File dir = f.getParentFile();
4637 if (!dir.exists()) {
4638 fileReady = dir.mkdirs();
4639 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004640 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004641 } else if (dir.isDirectory()) {
4642 fileReady = true;
4643 }
4644 } else if (removeExisting) {
4645 // Remove the previous traces file, so we don't fill the disk.
4646 // The VM will recreate it
4647 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4648 fileReady = f.delete();
4649 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004650
4651 if (removeExisting) {
4652 try {
4653 f.createNewFile();
4654 FileUtils.setPermissions(f.getAbsolutePath(),
4655 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4656 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4657 fileReady = true;
4658 } catch (IOException e) {
4659 Log.w(TAG, "Unable to make ANR traces file", e);
4660 }
4661 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004662 }
4663
4664 return fileReady;
4665 }
4666
4667
4668 private final void decPersistentCountLocked(ProcessRecord app)
4669 {
4670 app.persistentActivities--;
4671 if (app.persistentActivities > 0) {
4672 // Still more of 'em...
4673 return;
4674 }
4675 if (app.persistent) {
4676 // Ah, but the application itself is persistent. Whatever!
4677 return;
4678 }
4679
4680 // App is no longer persistent... make sure it and the ones
4681 // following it in the LRU list have the correc oom_adj.
4682 updateOomAdjLocked();
4683 }
4684
4685 public void setPersistent(IBinder token, boolean isPersistent) {
4686 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4687 != PackageManager.PERMISSION_GRANTED) {
4688 String msg = "Permission Denial: setPersistent() from pid="
4689 + Binder.getCallingPid()
4690 + ", uid=" + Binder.getCallingUid()
4691 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4692 Log.w(TAG, msg);
4693 throw new SecurityException(msg);
4694 }
4695
4696 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004697 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004698 if (index < 0) {
4699 return;
4700 }
4701 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4702 ProcessRecord app = r.app;
4703
4704 if (localLOGV) Log.v(
4705 TAG, "Setting persistence " + isPersistent + ": " + r);
4706
4707 if (isPersistent) {
4708 if (r.persistent) {
4709 // Okay okay, I heard you already!
4710 if (localLOGV) Log.v(TAG, "Already persistent!");
4711 return;
4712 }
4713 r.persistent = true;
4714 app.persistentActivities++;
4715 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4716 if (app.persistentActivities > 1) {
4717 // We aren't the first...
4718 if (localLOGV) Log.v(TAG, "Not the first!");
4719 return;
4720 }
4721 if (app.persistent) {
4722 // This would be redundant.
4723 if (localLOGV) Log.v(TAG, "App is persistent!");
4724 return;
4725 }
4726
4727 // App is now persistent... make sure it and the ones
4728 // following it now have the correct oom_adj.
4729 final long origId = Binder.clearCallingIdentity();
4730 updateOomAdjLocked();
4731 Binder.restoreCallingIdentity(origId);
4732
4733 } else {
4734 if (!r.persistent) {
4735 // Okay okay, I heard you already!
4736 return;
4737 }
4738 r.persistent = false;
4739 final long origId = Binder.clearCallingIdentity();
4740 decPersistentCountLocked(app);
4741 Binder.restoreCallingIdentity(origId);
4742
4743 }
4744 }
4745 }
4746
4747 public boolean clearApplicationUserData(final String packageName,
4748 final IPackageDataObserver observer) {
4749 int uid = Binder.getCallingUid();
4750 int pid = Binder.getCallingPid();
4751 long callingId = Binder.clearCallingIdentity();
4752 try {
4753 IPackageManager pm = ActivityThread.getPackageManager();
4754 int pkgUid = -1;
4755 synchronized(this) {
4756 try {
4757 pkgUid = pm.getPackageUid(packageName);
4758 } catch (RemoteException e) {
4759 }
4760 if (pkgUid == -1) {
4761 Log.w(TAG, "Invalid packageName:" + packageName);
4762 return false;
4763 }
4764 if (uid == pkgUid || checkComponentPermission(
4765 android.Manifest.permission.CLEAR_APP_USER_DATA,
4766 pid, uid, -1)
4767 == PackageManager.PERMISSION_GRANTED) {
4768 restartPackageLocked(packageName, pkgUid);
4769 } else {
4770 throw new SecurityException(pid+" does not have permission:"+
4771 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4772 "for process:"+packageName);
4773 }
4774 }
4775
4776 try {
4777 //clear application user data
4778 pm.clearApplicationUserData(packageName, observer);
4779 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4780 Uri.fromParts("package", packageName, null));
4781 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4782 broadcastIntentLocked(null, null, intent,
4783 null, null, 0, null, null, null,
4784 false, false, MY_PID, Process.SYSTEM_UID);
4785 } catch (RemoteException e) {
4786 }
4787 } finally {
4788 Binder.restoreCallingIdentity(callingId);
4789 }
4790 return true;
4791 }
4792
4793 public void restartPackage(final String packageName) {
4794 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4795 != PackageManager.PERMISSION_GRANTED) {
4796 String msg = "Permission Denial: restartPackage() from pid="
4797 + Binder.getCallingPid()
4798 + ", uid=" + Binder.getCallingUid()
4799 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4800 Log.w(TAG, msg);
4801 throw new SecurityException(msg);
4802 }
4803
4804 long callingId = Binder.clearCallingIdentity();
4805 try {
4806 IPackageManager pm = ActivityThread.getPackageManager();
4807 int pkgUid = -1;
4808 synchronized(this) {
4809 try {
4810 pkgUid = pm.getPackageUid(packageName);
4811 } catch (RemoteException e) {
4812 }
4813 if (pkgUid == -1) {
4814 Log.w(TAG, "Invalid packageName: " + packageName);
4815 return;
4816 }
4817 restartPackageLocked(packageName, pkgUid);
4818 }
4819 } finally {
4820 Binder.restoreCallingIdentity(callingId);
4821 }
4822 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004823
4824 /*
4825 * The pkg name and uid have to be specified.
4826 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4827 */
4828 public void killApplicationWithUid(String pkg, int uid) {
4829 if (pkg == null) {
4830 return;
4831 }
4832 // Make sure the uid is valid.
4833 if (uid < 0) {
4834 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4835 return;
4836 }
4837 int callerUid = Binder.getCallingUid();
4838 // Only the system server can kill an application
4839 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004840 // Post an aysnc message to kill the application
4841 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4842 msg.arg1 = uid;
4843 msg.arg2 = 0;
4844 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004845 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004846 } else {
4847 throw new SecurityException(callerUid + " cannot kill pkg: " +
4848 pkg);
4849 }
4850 }
4851
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004852 public void closeSystemDialogs(String reason) {
4853 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4854 if (reason != null) {
4855 intent.putExtra("reason", reason);
4856 }
4857
4858 final int uid = Binder.getCallingUid();
4859 final long origId = Binder.clearCallingIdentity();
4860 synchronized (this) {
4861 int i = mWatchers.beginBroadcast();
4862 while (i > 0) {
4863 i--;
4864 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4865 if (w != null) {
4866 try {
4867 w.closingSystemDialogs(reason);
4868 } catch (RemoteException e) {
4869 }
4870 }
4871 }
4872 mWatchers.finishBroadcast();
4873
4874 broadcastIntentLocked(null, null, intent, null,
4875 null, 0, null, null, null, false, false, -1, uid);
4876 }
4877 Binder.restoreCallingIdentity(origId);
4878 }
4879
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004880 private void restartPackageLocked(final String packageName, int uid) {
4881 uninstallPackageLocked(packageName, uid, false);
4882 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4883 Uri.fromParts("package", packageName, null));
4884 intent.putExtra(Intent.EXTRA_UID, uid);
4885 broadcastIntentLocked(null, null, intent,
4886 null, null, 0, null, null, null,
4887 false, false, MY_PID, Process.SYSTEM_UID);
4888 }
4889
4890 private final void uninstallPackageLocked(String name, int uid,
4891 boolean callerWillRestart) {
4892 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4893
4894 int i, N;
4895
4896 final String procNamePrefix = name + ":";
4897 if (uid < 0) {
4898 try {
4899 uid = ActivityThread.getPackageManager().getPackageUid(name);
4900 } catch (RemoteException e) {
4901 }
4902 }
4903
4904 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4905 while (badApps.hasNext()) {
4906 SparseArray<Long> ba = badApps.next();
4907 if (ba.get(uid) != null) {
4908 badApps.remove();
4909 }
4910 }
4911
4912 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4913
4914 // Remove all processes this package may have touched: all with the
4915 // same UID (except for the system or root user), and all whose name
4916 // matches the package name.
4917 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4918 final int NA = apps.size();
4919 for (int ia=0; ia<NA; ia++) {
4920 ProcessRecord app = apps.valueAt(ia);
4921 if (app.removed) {
4922 procs.add(app);
4923 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4924 || app.processName.equals(name)
4925 || app.processName.startsWith(procNamePrefix)) {
4926 app.removed = true;
4927 procs.add(app);
4928 }
4929 }
4930 }
4931
4932 N = procs.size();
4933 for (i=0; i<N; i++) {
4934 removeProcessLocked(procs.get(i), callerWillRestart);
4935 }
4936
4937 for (i=mHistory.size()-1; i>=0; i--) {
4938 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4939 if (r.packageName.equals(name)) {
4940 if (Config.LOGD) Log.d(
4941 TAG, " Force finishing activity "
4942 + r.intent.getComponent().flattenToShortString());
4943 if (r.app != null) {
4944 r.app.removed = true;
4945 }
4946 r.app = null;
4947 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4948 }
4949 }
4950
4951 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4952 for (ServiceRecord service : mServices.values()) {
4953 if (service.packageName.equals(name)) {
4954 if (service.app != null) {
4955 service.app.removed = true;
4956 }
4957 service.app = null;
4958 services.add(service);
4959 }
4960 }
4961
4962 N = services.size();
4963 for (i=0; i<N; i++) {
4964 bringDownServiceLocked(services.get(i), true);
4965 }
4966
4967 resumeTopActivityLocked(null);
4968 }
4969
4970 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4971 final String name = app.processName;
4972 final int uid = app.info.uid;
4973 if (Config.LOGD) Log.d(
4974 TAG, "Force removing process " + app + " (" + name
4975 + "/" + uid + ")");
4976
4977 mProcessNames.remove(name, uid);
4978 boolean needRestart = false;
4979 if (app.pid > 0 && app.pid != MY_PID) {
4980 int pid = app.pid;
4981 synchronized (mPidsSelfLocked) {
4982 mPidsSelfLocked.remove(pid);
4983 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4984 }
4985 handleAppDiedLocked(app, true);
4986 mLRUProcesses.remove(app);
4987 Process.killProcess(pid);
4988
4989 if (app.persistent) {
4990 if (!callerWillRestart) {
4991 addAppLocked(app.info);
4992 } else {
4993 needRestart = true;
4994 }
4995 }
4996 } else {
4997 mRemovedProcesses.add(app);
4998 }
4999
5000 return needRestart;
5001 }
5002
5003 private final void processStartTimedOutLocked(ProcessRecord app) {
5004 final int pid = app.pid;
5005 boolean gone = false;
5006 synchronized (mPidsSelfLocked) {
5007 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5008 if (knownApp != null && knownApp.thread == null) {
5009 mPidsSelfLocked.remove(pid);
5010 gone = true;
5011 }
5012 }
5013
5014 if (gone) {
5015 Log.w(TAG, "Process " + app + " failed to attach");
5016 mProcessNames.remove(app.processName, app.info.uid);
5017 Process.killProcess(pid);
5018 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5019 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5020 mPendingBroadcast = null;
5021 scheduleBroadcastsLocked();
5022 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005023 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5024 Log.w(TAG, "Unattached app died before backup, skipping");
5025 try {
5026 IBackupManager bm = IBackupManager.Stub.asInterface(
5027 ServiceManager.getService(Context.BACKUP_SERVICE));
5028 bm.agentDisconnected(app.info.packageName);
5029 } catch (RemoteException e) {
5030 // Can't happen; the backup manager is local
5031 }
5032 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005033 } else {
5034 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5035 }
5036 }
5037
5038 private final boolean attachApplicationLocked(IApplicationThread thread,
5039 int pid) {
5040
5041 // Find the application record that is being attached... either via
5042 // the pid if we are running in multiple processes, or just pull the
5043 // next app record if we are emulating process with anonymous threads.
5044 ProcessRecord app;
5045 if (pid != MY_PID && pid >= 0) {
5046 synchronized (mPidsSelfLocked) {
5047 app = mPidsSelfLocked.get(pid);
5048 }
5049 } else if (mStartingProcesses.size() > 0) {
5050 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005051 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005052 } else {
5053 app = null;
5054 }
5055
5056 if (app == null) {
5057 Log.w(TAG, "No pending application record for pid " + pid
5058 + " (IApplicationThread " + thread + "); dropping process");
5059 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5060 if (pid > 0 && pid != MY_PID) {
5061 Process.killProcess(pid);
5062 } else {
5063 try {
5064 thread.scheduleExit();
5065 } catch (Exception e) {
5066 // Ignore exceptions.
5067 }
5068 }
5069 return false;
5070 }
5071
5072 // If this application record is still attached to a previous
5073 // process, clean it up now.
5074 if (app.thread != null) {
5075 handleAppDiedLocked(app, true);
5076 }
5077
5078 // Tell the process all about itself.
5079
5080 if (localLOGV) Log.v(
5081 TAG, "Binding process pid " + pid + " to record " + app);
5082
5083 String processName = app.processName;
5084 try {
5085 thread.asBinder().linkToDeath(new AppDeathRecipient(
5086 app, pid, thread), 0);
5087 } catch (RemoteException e) {
5088 app.resetPackageList();
5089 startProcessLocked(app, "link fail", processName);
5090 return false;
5091 }
5092
5093 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5094
5095 app.thread = thread;
5096 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005097 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005098 app.forcingToForeground = null;
5099 app.foregroundServices = false;
5100 app.debugging = false;
5101
5102 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5103
5104 List providers = generateApplicationProvidersLocked(app);
5105
5106 if (localLOGV) Log.v(
5107 TAG, "New app record " + app
5108 + " thread=" + thread.asBinder() + " pid=" + pid);
5109 try {
5110 int testMode = IApplicationThread.DEBUG_OFF;
5111 if (mDebugApp != null && mDebugApp.equals(processName)) {
5112 testMode = mWaitForDebugger
5113 ? IApplicationThread.DEBUG_WAIT
5114 : IApplicationThread.DEBUG_ON;
5115 app.debugging = true;
5116 if (mDebugTransient) {
5117 mDebugApp = mOrigDebugApp;
5118 mWaitForDebugger = mOrigWaitForDebugger;
5119 }
5120 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005121 // If the app is being launched for restore or full backup, set it up specially
5122 boolean isRestrictedBackupMode = false;
5123 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5124 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5125 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5126 }
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005127 ensurePackageDexOpt(app.instrumentationInfo != null
5128 ? app.instrumentationInfo.packageName
5129 : app.info.packageName);
5130 if (app.instrumentationClass != null) {
5131 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005132 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07005133 thread.bindApplication(processName, app.instrumentationInfo != null
5134 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005135 app.instrumentationClass, app.instrumentationProfileFile,
5136 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07005137 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005138 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005139 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005140 } catch (Exception e) {
5141 // todo: Yikes! What should we do? For now we will try to
5142 // start another process, but that could easily get us in
5143 // an infinite loop of restarting processes...
5144 Log.w(TAG, "Exception thrown during bind!", e);
5145
5146 app.resetPackageList();
5147 startProcessLocked(app, "bind fail", processName);
5148 return false;
5149 }
5150
5151 // Remove this record from the list of starting applications.
5152 mPersistentStartingProcesses.remove(app);
5153 mProcessesOnHold.remove(app);
5154
5155 boolean badApp = false;
5156 boolean didSomething = false;
5157
5158 // See if the top visible activity is waiting to run in this process...
5159 HistoryRecord hr = topRunningActivityLocked(null);
5160 if (hr != null) {
5161 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5162 && processName.equals(hr.processName)) {
5163 try {
5164 if (realStartActivityLocked(hr, app, true, true)) {
5165 didSomething = true;
5166 }
5167 } catch (Exception e) {
5168 Log.w(TAG, "Exception in new application when starting activity "
5169 + hr.intent.getComponent().flattenToShortString(), e);
5170 badApp = true;
5171 }
5172 } else {
5173 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5174 }
5175 }
5176
5177 // Find any services that should be running in this process...
5178 if (!badApp && mPendingServices.size() > 0) {
5179 ServiceRecord sr = null;
5180 try {
5181 for (int i=0; i<mPendingServices.size(); i++) {
5182 sr = mPendingServices.get(i);
5183 if (app.info.uid != sr.appInfo.uid
5184 || !processName.equals(sr.processName)) {
5185 continue;
5186 }
5187
5188 mPendingServices.remove(i);
5189 i--;
5190 realStartServiceLocked(sr, app);
5191 didSomething = true;
5192 }
5193 } catch (Exception e) {
5194 Log.w(TAG, "Exception in new application when starting service "
5195 + sr.shortName, e);
5196 badApp = true;
5197 }
5198 }
5199
5200 // Check if the next broadcast receiver is in this process...
5201 BroadcastRecord br = mPendingBroadcast;
5202 if (!badApp && br != null && br.curApp == app) {
5203 try {
5204 mPendingBroadcast = null;
5205 processCurBroadcastLocked(br, app);
5206 didSomething = true;
5207 } catch (Exception e) {
5208 Log.w(TAG, "Exception in new application when starting receiver "
5209 + br.curComponent.flattenToShortString(), e);
5210 badApp = true;
5211 logBroadcastReceiverDiscard(br);
5212 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5213 br.resultExtras, br.resultAbort, true);
5214 scheduleBroadcastsLocked();
5215 }
5216 }
5217
Christopher Tate181fafa2009-05-14 11:12:14 -07005218 // Check whether the next backup agent is in this process...
5219 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5220 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005221 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005222 try {
5223 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5224 } catch (Exception e) {
5225 Log.w(TAG, "Exception scheduling backup agent creation: ");
5226 e.printStackTrace();
5227 }
5228 }
5229
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005230 if (badApp) {
5231 // todo: Also need to kill application to deal with all
5232 // kinds of exceptions.
5233 handleAppDiedLocked(app, false);
5234 return false;
5235 }
5236
5237 if (!didSomething) {
5238 updateOomAdjLocked();
5239 }
5240
5241 return true;
5242 }
5243
5244 public final void attachApplication(IApplicationThread thread) {
5245 synchronized (this) {
5246 int callingPid = Binder.getCallingPid();
5247 final long origId = Binder.clearCallingIdentity();
5248 attachApplicationLocked(thread, callingPid);
5249 Binder.restoreCallingIdentity(origId);
5250 }
5251 }
5252
5253 public final void activityIdle(IBinder token) {
5254 final long origId = Binder.clearCallingIdentity();
5255 activityIdleInternal(token, false);
5256 Binder.restoreCallingIdentity(origId);
5257 }
5258
5259 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5260 boolean remove) {
5261 int N = mStoppingActivities.size();
5262 if (N <= 0) return null;
5263
5264 ArrayList<HistoryRecord> stops = null;
5265
5266 final boolean nowVisible = mResumedActivity != null
5267 && mResumedActivity.nowVisible
5268 && !mResumedActivity.waitingVisible;
5269 for (int i=0; i<N; i++) {
5270 HistoryRecord s = mStoppingActivities.get(i);
5271 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5272 + nowVisible + " waitingVisible=" + s.waitingVisible
5273 + " finishing=" + s.finishing);
5274 if (s.waitingVisible && nowVisible) {
5275 mWaitingVisibleActivities.remove(s);
5276 s.waitingVisible = false;
5277 if (s.finishing) {
5278 // If this activity is finishing, it is sitting on top of
5279 // everyone else but we now know it is no longer needed...
5280 // so get rid of it. Otherwise, we need to go through the
5281 // normal flow and hide it once we determine that it is
5282 // hidden by the activities in front of it.
5283 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5284 mWindowManager.setAppVisibility(s, false);
5285 }
5286 }
5287 if (!s.waitingVisible && remove) {
5288 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5289 if (stops == null) {
5290 stops = new ArrayList<HistoryRecord>();
5291 }
5292 stops.add(s);
5293 mStoppingActivities.remove(i);
5294 N--;
5295 i--;
5296 }
5297 }
5298
5299 return stops;
5300 }
5301
5302 void enableScreenAfterBoot() {
5303 mWindowManager.enableScreenAfterBoot();
5304 }
5305
5306 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5307 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5308
5309 ArrayList<HistoryRecord> stops = null;
5310 ArrayList<HistoryRecord> finishes = null;
5311 ArrayList<HistoryRecord> thumbnails = null;
5312 int NS = 0;
5313 int NF = 0;
5314 int NT = 0;
5315 IApplicationThread sendThumbnail = null;
5316 boolean booting = false;
5317 boolean enableScreen = false;
5318
5319 synchronized (this) {
5320 if (token != null) {
5321 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5322 }
5323
5324 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005325 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005326 if (index >= 0) {
5327 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5328
5329 // No longer need to keep the device awake.
5330 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5331 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5332 mLaunchingActivity.release();
5333 }
5334
5335 // We are now idle. If someone is waiting for a thumbnail from
5336 // us, we can now deliver.
5337 r.idle = true;
5338 scheduleAppGcsLocked();
5339 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5340 sendThumbnail = r.app.thread;
5341 r.thumbnailNeeded = false;
5342 }
5343
5344 // If this activity is fullscreen, set up to hide those under it.
5345
5346 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5347 ensureActivitiesVisibleLocked(null, 0);
5348
5349 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5350 if (!mBooted && !fromTimeout) {
5351 mBooted = true;
5352 enableScreen = true;
5353 }
5354 }
5355
5356 // Atomically retrieve all of the other things to do.
5357 stops = processStoppingActivitiesLocked(true);
5358 NS = stops != null ? stops.size() : 0;
5359 if ((NF=mFinishingActivities.size()) > 0) {
5360 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5361 mFinishingActivities.clear();
5362 }
5363 if ((NT=mCancelledThumbnails.size()) > 0) {
5364 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5365 mCancelledThumbnails.clear();
5366 }
5367
5368 booting = mBooting;
5369 mBooting = false;
5370 }
5371
5372 int i;
5373
5374 // Send thumbnail if requested.
5375 if (sendThumbnail != null) {
5376 try {
5377 sendThumbnail.requestThumbnail(token);
5378 } catch (Exception e) {
5379 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5380 sendPendingThumbnail(null, token, null, null, true);
5381 }
5382 }
5383
5384 // Stop any activities that are scheduled to do so but have been
5385 // waiting for the next one to start.
5386 for (i=0; i<NS; i++) {
5387 HistoryRecord r = (HistoryRecord)stops.get(i);
5388 synchronized (this) {
5389 if (r.finishing) {
5390 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5391 } else {
5392 stopActivityLocked(r);
5393 }
5394 }
5395 }
5396
5397 // Finish any activities that are scheduled to do so but have been
5398 // waiting for the next one to start.
5399 for (i=0; i<NF; i++) {
5400 HistoryRecord r = (HistoryRecord)finishes.get(i);
5401 synchronized (this) {
5402 destroyActivityLocked(r, true);
5403 }
5404 }
5405
5406 // Report back to any thumbnail receivers.
5407 for (i=0; i<NT; i++) {
5408 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5409 sendPendingThumbnail(r, null, null, null, true);
5410 }
5411
5412 if (booting) {
5413 // Ensure that any processes we had put on hold are now started
5414 // up.
5415 final int NP = mProcessesOnHold.size();
5416 if (NP > 0) {
5417 ArrayList<ProcessRecord> procs =
5418 new ArrayList<ProcessRecord>(mProcessesOnHold);
5419 for (int ip=0; ip<NP; ip++) {
5420 this.startProcessLocked(procs.get(ip), "on-hold", null);
5421 }
5422 }
5423 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5424 // Tell anyone interested that we are done booting!
5425 synchronized (this) {
5426 broadcastIntentLocked(null, null,
5427 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5428 null, null, 0, null, null,
5429 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5430 false, false, MY_PID, Process.SYSTEM_UID);
5431 }
5432 }
5433 }
5434
5435 trimApplications();
5436 //dump();
5437 //mWindowManager.dump();
5438
5439 if (enableScreen) {
5440 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5441 SystemClock.uptimeMillis());
5442 enableScreenAfterBoot();
5443 }
5444 }
5445
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005446 final void ensureScreenEnabled() {
5447 boolean enableScreen;
5448 synchronized (this) {
5449 enableScreen = !mBooted;
5450 mBooted = true;
5451 }
5452
5453 if (enableScreen) {
5454 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5455 SystemClock.uptimeMillis());
5456 enableScreenAfterBoot();
5457 }
5458 }
5459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005460 public final void activityPaused(IBinder token, Bundle icicle) {
5461 // Refuse possible leaked file descriptors
5462 if (icicle != null && icicle.hasFileDescriptors()) {
5463 throw new IllegalArgumentException("File descriptors passed in Bundle");
5464 }
5465
5466 final long origId = Binder.clearCallingIdentity();
5467 activityPaused(token, icicle, false);
5468 Binder.restoreCallingIdentity(origId);
5469 }
5470
5471 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5472 if (DEBUG_PAUSE) Log.v(
5473 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5474 + ", timeout=" + timeout);
5475
5476 HistoryRecord r = null;
5477
5478 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005479 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005480 if (index >= 0) {
5481 r = (HistoryRecord)mHistory.get(index);
5482 if (!timeout) {
5483 r.icicle = icicle;
5484 r.haveState = true;
5485 }
5486 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5487 if (mPausingActivity == r) {
5488 r.state = ActivityState.PAUSED;
5489 completePauseLocked();
5490 } else {
5491 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5492 System.identityHashCode(r), r.shortComponentName,
5493 mPausingActivity != null
5494 ? mPausingActivity.shortComponentName : "(none)");
5495 }
5496 }
5497 }
5498 }
5499
5500 public final void activityStopped(IBinder token, Bitmap thumbnail,
5501 CharSequence description) {
5502 if (localLOGV) Log.v(
5503 TAG, "Activity stopped: token=" + token);
5504
5505 HistoryRecord r = null;
5506
5507 final long origId = Binder.clearCallingIdentity();
5508
5509 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005510 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005511 if (index >= 0) {
5512 r = (HistoryRecord)mHistory.get(index);
5513 r.thumbnail = thumbnail;
5514 r.description = description;
5515 r.stopped = true;
5516 r.state = ActivityState.STOPPED;
5517 if (!r.finishing) {
5518 if (r.configDestroy) {
5519 destroyActivityLocked(r, true);
5520 resumeTopActivityLocked(null);
5521 }
5522 }
5523 }
5524 }
5525
5526 if (r != null) {
5527 sendPendingThumbnail(r, null, null, null, false);
5528 }
5529
5530 trimApplications();
5531
5532 Binder.restoreCallingIdentity(origId);
5533 }
5534
5535 public final void activityDestroyed(IBinder token) {
5536 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5537 synchronized (this) {
5538 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5539
Dianne Hackborn75b03852009-06-12 15:43:26 -07005540 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005541 if (index >= 0) {
5542 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5543 if (r.state == ActivityState.DESTROYING) {
5544 final long origId = Binder.clearCallingIdentity();
5545 removeActivityFromHistoryLocked(r);
5546 Binder.restoreCallingIdentity(origId);
5547 }
5548 }
5549 }
5550 }
5551
5552 public String getCallingPackage(IBinder token) {
5553 synchronized (this) {
5554 HistoryRecord r = getCallingRecordLocked(token);
5555 return r != null && r.app != null ? r.app.processName : null;
5556 }
5557 }
5558
5559 public ComponentName getCallingActivity(IBinder token) {
5560 synchronized (this) {
5561 HistoryRecord r = getCallingRecordLocked(token);
5562 return r != null ? r.intent.getComponent() : null;
5563 }
5564 }
5565
5566 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005567 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005568 if (index >= 0) {
5569 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5570 if (r != null) {
5571 return r.resultTo;
5572 }
5573 }
5574 return null;
5575 }
5576
5577 public ComponentName getActivityClassForToken(IBinder token) {
5578 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005579 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005580 if (index >= 0) {
5581 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5582 return r.intent.getComponent();
5583 }
5584 return null;
5585 }
5586 }
5587
5588 public String getPackageForToken(IBinder token) {
5589 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005590 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005591 if (index >= 0) {
5592 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5593 return r.packageName;
5594 }
5595 return null;
5596 }
5597 }
5598
5599 public IIntentSender getIntentSender(int type,
5600 String packageName, IBinder token, String resultWho,
5601 int requestCode, Intent intent, String resolvedType, int flags) {
5602 // Refuse possible leaked file descriptors
5603 if (intent != null && intent.hasFileDescriptors() == true) {
5604 throw new IllegalArgumentException("File descriptors passed in Intent");
5605 }
5606
5607 synchronized(this) {
5608 int callingUid = Binder.getCallingUid();
5609 try {
5610 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5611 Process.supportsProcesses()) {
5612 int uid = ActivityThread.getPackageManager()
5613 .getPackageUid(packageName);
5614 if (uid != Binder.getCallingUid()) {
5615 String msg = "Permission Denial: getIntentSender() from pid="
5616 + Binder.getCallingPid()
5617 + ", uid=" + Binder.getCallingUid()
5618 + ", (need uid=" + uid + ")"
5619 + " is not allowed to send as package " + packageName;
5620 Log.w(TAG, msg);
5621 throw new SecurityException(msg);
5622 }
5623 }
5624 } catch (RemoteException e) {
5625 throw new SecurityException(e);
5626 }
5627 HistoryRecord activity = null;
5628 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005629 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005630 if (index < 0) {
5631 return null;
5632 }
5633 activity = (HistoryRecord)mHistory.get(index);
5634 if (activity.finishing) {
5635 return null;
5636 }
5637 }
5638
5639 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5640 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5641 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5642 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5643 |PendingIntent.FLAG_UPDATE_CURRENT);
5644
5645 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5646 type, packageName, activity, resultWho,
5647 requestCode, intent, resolvedType, flags);
5648 WeakReference<PendingIntentRecord> ref;
5649 ref = mIntentSenderRecords.get(key);
5650 PendingIntentRecord rec = ref != null ? ref.get() : null;
5651 if (rec != null) {
5652 if (!cancelCurrent) {
5653 if (updateCurrent) {
5654 rec.key.requestIntent.replaceExtras(intent);
5655 }
5656 return rec;
5657 }
5658 rec.canceled = true;
5659 mIntentSenderRecords.remove(key);
5660 }
5661 if (noCreate) {
5662 return rec;
5663 }
5664 rec = new PendingIntentRecord(this, key, callingUid);
5665 mIntentSenderRecords.put(key, rec.ref);
5666 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5667 if (activity.pendingResults == null) {
5668 activity.pendingResults
5669 = new HashSet<WeakReference<PendingIntentRecord>>();
5670 }
5671 activity.pendingResults.add(rec.ref);
5672 }
5673 return rec;
5674 }
5675 }
5676
5677 public void cancelIntentSender(IIntentSender sender) {
5678 if (!(sender instanceof PendingIntentRecord)) {
5679 return;
5680 }
5681 synchronized(this) {
5682 PendingIntentRecord rec = (PendingIntentRecord)sender;
5683 try {
5684 int uid = ActivityThread.getPackageManager()
5685 .getPackageUid(rec.key.packageName);
5686 if (uid != Binder.getCallingUid()) {
5687 String msg = "Permission Denial: cancelIntentSender() from pid="
5688 + Binder.getCallingPid()
5689 + ", uid=" + Binder.getCallingUid()
5690 + " is not allowed to cancel packges "
5691 + rec.key.packageName;
5692 Log.w(TAG, msg);
5693 throw new SecurityException(msg);
5694 }
5695 } catch (RemoteException e) {
5696 throw new SecurityException(e);
5697 }
5698 cancelIntentSenderLocked(rec, true);
5699 }
5700 }
5701
5702 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5703 rec.canceled = true;
5704 mIntentSenderRecords.remove(rec.key);
5705 if (cleanActivity && rec.key.activity != null) {
5706 rec.key.activity.pendingResults.remove(rec.ref);
5707 }
5708 }
5709
5710 public String getPackageForIntentSender(IIntentSender pendingResult) {
5711 if (!(pendingResult instanceof PendingIntentRecord)) {
5712 return null;
5713 }
5714 synchronized(this) {
5715 try {
5716 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5717 return res.key.packageName;
5718 } catch (ClassCastException e) {
5719 }
5720 }
5721 return null;
5722 }
5723
5724 public void setProcessLimit(int max) {
5725 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5726 "setProcessLimit()");
5727 mProcessLimit = max;
5728 }
5729
5730 public int getProcessLimit() {
5731 return mProcessLimit;
5732 }
5733
5734 void foregroundTokenDied(ForegroundToken token) {
5735 synchronized (ActivityManagerService.this) {
5736 synchronized (mPidsSelfLocked) {
5737 ForegroundToken cur
5738 = mForegroundProcesses.get(token.pid);
5739 if (cur != token) {
5740 return;
5741 }
5742 mForegroundProcesses.remove(token.pid);
5743 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5744 if (pr == null) {
5745 return;
5746 }
5747 pr.forcingToForeground = null;
5748 pr.foregroundServices = false;
5749 }
5750 updateOomAdjLocked();
5751 }
5752 }
5753
5754 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5755 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5756 "setProcessForeground()");
5757 synchronized(this) {
5758 boolean changed = false;
5759
5760 synchronized (mPidsSelfLocked) {
5761 ProcessRecord pr = mPidsSelfLocked.get(pid);
5762 if (pr == null) {
5763 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5764 return;
5765 }
5766 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5767 if (oldToken != null) {
5768 oldToken.token.unlinkToDeath(oldToken, 0);
5769 mForegroundProcesses.remove(pid);
5770 pr.forcingToForeground = null;
5771 changed = true;
5772 }
5773 if (isForeground && token != null) {
5774 ForegroundToken newToken = new ForegroundToken() {
5775 public void binderDied() {
5776 foregroundTokenDied(this);
5777 }
5778 };
5779 newToken.pid = pid;
5780 newToken.token = token;
5781 try {
5782 token.linkToDeath(newToken, 0);
5783 mForegroundProcesses.put(pid, newToken);
5784 pr.forcingToForeground = token;
5785 changed = true;
5786 } catch (RemoteException e) {
5787 // If the process died while doing this, we will later
5788 // do the cleanup with the process death link.
5789 }
5790 }
5791 }
5792
5793 if (changed) {
5794 updateOomAdjLocked();
5795 }
5796 }
5797 }
5798
5799 // =========================================================
5800 // PERMISSIONS
5801 // =========================================================
5802
5803 static class PermissionController extends IPermissionController.Stub {
5804 ActivityManagerService mActivityManagerService;
5805 PermissionController(ActivityManagerService activityManagerService) {
5806 mActivityManagerService = activityManagerService;
5807 }
5808
5809 public boolean checkPermission(String permission, int pid, int uid) {
5810 return mActivityManagerService.checkPermission(permission, pid,
5811 uid) == PackageManager.PERMISSION_GRANTED;
5812 }
5813 }
5814
5815 /**
5816 * This can be called with or without the global lock held.
5817 */
5818 int checkComponentPermission(String permission, int pid, int uid,
5819 int reqUid) {
5820 // We might be performing an operation on behalf of an indirect binder
5821 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5822 // client identity accordingly before proceeding.
5823 Identity tlsIdentity = sCallerIdentity.get();
5824 if (tlsIdentity != null) {
5825 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5826 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5827 uid = tlsIdentity.uid;
5828 pid = tlsIdentity.pid;
5829 }
5830
5831 // Root, system server and our own process get to do everything.
5832 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5833 !Process.supportsProcesses()) {
5834 return PackageManager.PERMISSION_GRANTED;
5835 }
5836 // If the target requires a specific UID, always fail for others.
5837 if (reqUid >= 0 && uid != reqUid) {
5838 return PackageManager.PERMISSION_DENIED;
5839 }
5840 if (permission == null) {
5841 return PackageManager.PERMISSION_GRANTED;
5842 }
5843 try {
5844 return ActivityThread.getPackageManager()
5845 .checkUidPermission(permission, uid);
5846 } catch (RemoteException e) {
5847 // Should never happen, but if it does... deny!
5848 Log.e(TAG, "PackageManager is dead?!?", e);
5849 }
5850 return PackageManager.PERMISSION_DENIED;
5851 }
5852
5853 /**
5854 * As the only public entry point for permissions checking, this method
5855 * can enforce the semantic that requesting a check on a null global
5856 * permission is automatically denied. (Internally a null permission
5857 * string is used when calling {@link #checkComponentPermission} in cases
5858 * when only uid-based security is needed.)
5859 *
5860 * This can be called with or without the global lock held.
5861 */
5862 public int checkPermission(String permission, int pid, int uid) {
5863 if (permission == null) {
5864 return PackageManager.PERMISSION_DENIED;
5865 }
5866 return checkComponentPermission(permission, pid, uid, -1);
5867 }
5868
5869 /**
5870 * Binder IPC calls go through the public entry point.
5871 * This can be called with or without the global lock held.
5872 */
5873 int checkCallingPermission(String permission) {
5874 return checkPermission(permission,
5875 Binder.getCallingPid(),
5876 Binder.getCallingUid());
5877 }
5878
5879 /**
5880 * This can be called with or without the global lock held.
5881 */
5882 void enforceCallingPermission(String permission, String func) {
5883 if (checkCallingPermission(permission)
5884 == PackageManager.PERMISSION_GRANTED) {
5885 return;
5886 }
5887
5888 String msg = "Permission Denial: " + func + " from pid="
5889 + Binder.getCallingPid()
5890 + ", uid=" + Binder.getCallingUid()
5891 + " requires " + permission;
5892 Log.w(TAG, msg);
5893 throw new SecurityException(msg);
5894 }
5895
5896 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5897 ProviderInfo pi, int uid, int modeFlags) {
5898 try {
5899 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5900 if ((pi.readPermission != null) &&
5901 (pm.checkUidPermission(pi.readPermission, uid)
5902 != PackageManager.PERMISSION_GRANTED)) {
5903 return false;
5904 }
5905 }
5906 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5907 if ((pi.writePermission != null) &&
5908 (pm.checkUidPermission(pi.writePermission, uid)
5909 != PackageManager.PERMISSION_GRANTED)) {
5910 return false;
5911 }
5912 }
5913 return true;
5914 } catch (RemoteException e) {
5915 return false;
5916 }
5917 }
5918
5919 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5920 int modeFlags) {
5921 // Root gets to do everything.
5922 if (uid == 0 || !Process.supportsProcesses()) {
5923 return true;
5924 }
5925 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5926 if (perms == null) return false;
5927 UriPermission perm = perms.get(uri);
5928 if (perm == null) return false;
5929 return (modeFlags&perm.modeFlags) == modeFlags;
5930 }
5931
5932 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5933 // Another redirected-binder-call permissions check as in
5934 // {@link checkComponentPermission}.
5935 Identity tlsIdentity = sCallerIdentity.get();
5936 if (tlsIdentity != null) {
5937 uid = tlsIdentity.uid;
5938 pid = tlsIdentity.pid;
5939 }
5940
5941 // Our own process gets to do everything.
5942 if (pid == MY_PID) {
5943 return PackageManager.PERMISSION_GRANTED;
5944 }
5945 synchronized(this) {
5946 return checkUriPermissionLocked(uri, uid, modeFlags)
5947 ? PackageManager.PERMISSION_GRANTED
5948 : PackageManager.PERMISSION_DENIED;
5949 }
5950 }
5951
5952 private void grantUriPermissionLocked(int callingUid,
5953 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5954 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5955 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5956 if (modeFlags == 0) {
5957 return;
5958 }
5959
5960 final IPackageManager pm = ActivityThread.getPackageManager();
5961
5962 // If this is not a content: uri, we can't do anything with it.
5963 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5964 return;
5965 }
5966
5967 String name = uri.getAuthority();
5968 ProviderInfo pi = null;
5969 ContentProviderRecord cpr
5970 = (ContentProviderRecord)mProvidersByName.get(name);
5971 if (cpr != null) {
5972 pi = cpr.info;
5973 } else {
5974 try {
5975 pi = pm.resolveContentProvider(name,
5976 PackageManager.GET_URI_PERMISSION_PATTERNS);
5977 } catch (RemoteException ex) {
5978 }
5979 }
5980 if (pi == null) {
5981 Log.w(TAG, "No content provider found for: " + name);
5982 return;
5983 }
5984
5985 int targetUid;
5986 try {
5987 targetUid = pm.getPackageUid(targetPkg);
5988 if (targetUid < 0) {
5989 return;
5990 }
5991 } catch (RemoteException ex) {
5992 return;
5993 }
5994
5995 // First... does the target actually need this permission?
5996 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5997 // No need to grant the target this permission.
5998 return;
5999 }
6000
6001 // Second... maybe someone else has already granted the
6002 // permission?
6003 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6004 // No need to grant the target this permission.
6005 return;
6006 }
6007
6008 // Third... is the provider allowing granting of URI permissions?
6009 if (!pi.grantUriPermissions) {
6010 throw new SecurityException("Provider " + pi.packageName
6011 + "/" + pi.name
6012 + " does not allow granting of Uri permissions (uri "
6013 + uri + ")");
6014 }
6015 if (pi.uriPermissionPatterns != null) {
6016 final int N = pi.uriPermissionPatterns.length;
6017 boolean allowed = false;
6018 for (int i=0; i<N; i++) {
6019 if (pi.uriPermissionPatterns[i] != null
6020 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6021 allowed = true;
6022 break;
6023 }
6024 }
6025 if (!allowed) {
6026 throw new SecurityException("Provider " + pi.packageName
6027 + "/" + pi.name
6028 + " does not allow granting of permission to path of Uri "
6029 + uri);
6030 }
6031 }
6032
6033 // Fourth... does the caller itself have permission to access
6034 // this uri?
6035 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6036 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6037 throw new SecurityException("Uid " + callingUid
6038 + " does not have permission to uri " + uri);
6039 }
6040 }
6041
6042 // Okay! So here we are: the caller has the assumed permission
6043 // to the uri, and the target doesn't. Let's now give this to
6044 // the target.
6045
6046 HashMap<Uri, UriPermission> targetUris
6047 = mGrantedUriPermissions.get(targetUid);
6048 if (targetUris == null) {
6049 targetUris = new HashMap<Uri, UriPermission>();
6050 mGrantedUriPermissions.put(targetUid, targetUris);
6051 }
6052
6053 UriPermission perm = targetUris.get(uri);
6054 if (perm == null) {
6055 perm = new UriPermission(targetUid, uri);
6056 targetUris.put(uri, perm);
6057
6058 }
6059 perm.modeFlags |= modeFlags;
6060 if (activity == null) {
6061 perm.globalModeFlags |= modeFlags;
6062 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6063 perm.readActivities.add(activity);
6064 if (activity.readUriPermissions == null) {
6065 activity.readUriPermissions = new HashSet<UriPermission>();
6066 }
6067 activity.readUriPermissions.add(perm);
6068 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6069 perm.writeActivities.add(activity);
6070 if (activity.writeUriPermissions == null) {
6071 activity.writeUriPermissions = new HashSet<UriPermission>();
6072 }
6073 activity.writeUriPermissions.add(perm);
6074 }
6075 }
6076
6077 private void grantUriPermissionFromIntentLocked(int callingUid,
6078 String targetPkg, Intent intent, HistoryRecord activity) {
6079 if (intent == null) {
6080 return;
6081 }
6082 Uri data = intent.getData();
6083 if (data == null) {
6084 return;
6085 }
6086 grantUriPermissionLocked(callingUid, targetPkg, data,
6087 intent.getFlags(), activity);
6088 }
6089
6090 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6091 Uri uri, int modeFlags) {
6092 synchronized(this) {
6093 final ProcessRecord r = getRecordForAppLocked(caller);
6094 if (r == null) {
6095 throw new SecurityException("Unable to find app for caller "
6096 + caller
6097 + " when granting permission to uri " + uri);
6098 }
6099 if (targetPkg == null) {
6100 Log.w(TAG, "grantUriPermission: null target");
6101 return;
6102 }
6103 if (uri == null) {
6104 Log.w(TAG, "grantUriPermission: null uri");
6105 return;
6106 }
6107
6108 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6109 null);
6110 }
6111 }
6112
6113 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6114 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6115 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6116 HashMap<Uri, UriPermission> perms
6117 = mGrantedUriPermissions.get(perm.uid);
6118 if (perms != null) {
6119 perms.remove(perm.uri);
6120 if (perms.size() == 0) {
6121 mGrantedUriPermissions.remove(perm.uid);
6122 }
6123 }
6124 }
6125 }
6126
6127 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6128 if (activity.readUriPermissions != null) {
6129 for (UriPermission perm : activity.readUriPermissions) {
6130 perm.readActivities.remove(activity);
6131 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6132 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6133 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6134 removeUriPermissionIfNeededLocked(perm);
6135 }
6136 }
6137 }
6138 if (activity.writeUriPermissions != null) {
6139 for (UriPermission perm : activity.writeUriPermissions) {
6140 perm.writeActivities.remove(activity);
6141 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6142 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6143 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6144 removeUriPermissionIfNeededLocked(perm);
6145 }
6146 }
6147 }
6148 }
6149
6150 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6151 int modeFlags) {
6152 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6153 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6154 if (modeFlags == 0) {
6155 return;
6156 }
6157
6158 final IPackageManager pm = ActivityThread.getPackageManager();
6159
6160 final String authority = uri.getAuthority();
6161 ProviderInfo pi = null;
6162 ContentProviderRecord cpr
6163 = (ContentProviderRecord)mProvidersByName.get(authority);
6164 if (cpr != null) {
6165 pi = cpr.info;
6166 } else {
6167 try {
6168 pi = pm.resolveContentProvider(authority,
6169 PackageManager.GET_URI_PERMISSION_PATTERNS);
6170 } catch (RemoteException ex) {
6171 }
6172 }
6173 if (pi == null) {
6174 Log.w(TAG, "No content provider found for: " + authority);
6175 return;
6176 }
6177
6178 // Does the caller have this permission on the URI?
6179 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6180 // Right now, if you are not the original owner of the permission,
6181 // you are not allowed to revoke it.
6182 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6183 throw new SecurityException("Uid " + callingUid
6184 + " does not have permission to uri " + uri);
6185 //}
6186 }
6187
6188 // Go through all of the permissions and remove any that match.
6189 final List<String> SEGMENTS = uri.getPathSegments();
6190 if (SEGMENTS != null) {
6191 final int NS = SEGMENTS.size();
6192 int N = mGrantedUriPermissions.size();
6193 for (int i=0; i<N; i++) {
6194 HashMap<Uri, UriPermission> perms
6195 = mGrantedUriPermissions.valueAt(i);
6196 Iterator<UriPermission> it = perms.values().iterator();
6197 toploop:
6198 while (it.hasNext()) {
6199 UriPermission perm = it.next();
6200 Uri targetUri = perm.uri;
6201 if (!authority.equals(targetUri.getAuthority())) {
6202 continue;
6203 }
6204 List<String> targetSegments = targetUri.getPathSegments();
6205 if (targetSegments == null) {
6206 continue;
6207 }
6208 if (targetSegments.size() < NS) {
6209 continue;
6210 }
6211 for (int j=0; j<NS; j++) {
6212 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6213 continue toploop;
6214 }
6215 }
6216 perm.clearModes(modeFlags);
6217 if (perm.modeFlags == 0) {
6218 it.remove();
6219 }
6220 }
6221 if (perms.size() == 0) {
6222 mGrantedUriPermissions.remove(
6223 mGrantedUriPermissions.keyAt(i));
6224 N--;
6225 i--;
6226 }
6227 }
6228 }
6229 }
6230
6231 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6232 int modeFlags) {
6233 synchronized(this) {
6234 final ProcessRecord r = getRecordForAppLocked(caller);
6235 if (r == null) {
6236 throw new SecurityException("Unable to find app for caller "
6237 + caller
6238 + " when revoking permission to uri " + uri);
6239 }
6240 if (uri == null) {
6241 Log.w(TAG, "revokeUriPermission: null uri");
6242 return;
6243 }
6244
6245 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6246 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6247 if (modeFlags == 0) {
6248 return;
6249 }
6250
6251 final IPackageManager pm = ActivityThread.getPackageManager();
6252
6253 final String authority = uri.getAuthority();
6254 ProviderInfo pi = null;
6255 ContentProviderRecord cpr
6256 = (ContentProviderRecord)mProvidersByName.get(authority);
6257 if (cpr != null) {
6258 pi = cpr.info;
6259 } else {
6260 try {
6261 pi = pm.resolveContentProvider(authority,
6262 PackageManager.GET_URI_PERMISSION_PATTERNS);
6263 } catch (RemoteException ex) {
6264 }
6265 }
6266 if (pi == null) {
6267 Log.w(TAG, "No content provider found for: " + authority);
6268 return;
6269 }
6270
6271 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6272 }
6273 }
6274
6275 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6276 synchronized (this) {
6277 ProcessRecord app =
6278 who != null ? getRecordForAppLocked(who) : null;
6279 if (app == null) return;
6280
6281 Message msg = Message.obtain();
6282 msg.what = WAIT_FOR_DEBUGGER_MSG;
6283 msg.obj = app;
6284 msg.arg1 = waiting ? 1 : 0;
6285 mHandler.sendMessage(msg);
6286 }
6287 }
6288
6289 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6290 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006291 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006292 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006293 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006294 }
6295
6296 // =========================================================
6297 // TASK MANAGEMENT
6298 // =========================================================
6299
6300 public List getTasks(int maxNum, int flags,
6301 IThumbnailReceiver receiver) {
6302 ArrayList list = new ArrayList();
6303
6304 PendingThumbnailsRecord pending = null;
6305 IApplicationThread topThumbnail = null;
6306 HistoryRecord topRecord = null;
6307
6308 synchronized(this) {
6309 if (localLOGV) Log.v(
6310 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6311 + ", receiver=" + receiver);
6312
6313 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6314 != PackageManager.PERMISSION_GRANTED) {
6315 if (receiver != null) {
6316 // If the caller wants to wait for pending thumbnails,
6317 // it ain't gonna get them.
6318 try {
6319 receiver.finished();
6320 } catch (RemoteException ex) {
6321 }
6322 }
6323 String msg = "Permission Denial: getTasks() from pid="
6324 + Binder.getCallingPid()
6325 + ", uid=" + Binder.getCallingUid()
6326 + " requires " + android.Manifest.permission.GET_TASKS;
6327 Log.w(TAG, msg);
6328 throw new SecurityException(msg);
6329 }
6330
6331 int pos = mHistory.size()-1;
6332 HistoryRecord next =
6333 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6334 HistoryRecord top = null;
6335 CharSequence topDescription = null;
6336 TaskRecord curTask = null;
6337 int numActivities = 0;
6338 int numRunning = 0;
6339 while (pos >= 0 && maxNum > 0) {
6340 final HistoryRecord r = next;
6341 pos--;
6342 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6343
6344 // Initialize state for next task if needed.
6345 if (top == null ||
6346 (top.state == ActivityState.INITIALIZING
6347 && top.task == r.task)) {
6348 top = r;
6349 topDescription = r.description;
6350 curTask = r.task;
6351 numActivities = numRunning = 0;
6352 }
6353
6354 // Add 'r' into the current task.
6355 numActivities++;
6356 if (r.app != null && r.app.thread != null) {
6357 numRunning++;
6358 }
6359 if (topDescription == null) {
6360 topDescription = r.description;
6361 }
6362
6363 if (localLOGV) Log.v(
6364 TAG, r.intent.getComponent().flattenToShortString()
6365 + ": task=" + r.task);
6366
6367 // If the next one is a different task, generate a new
6368 // TaskInfo entry for what we have.
6369 if (next == null || next.task != curTask) {
6370 ActivityManager.RunningTaskInfo ci
6371 = new ActivityManager.RunningTaskInfo();
6372 ci.id = curTask.taskId;
6373 ci.baseActivity = r.intent.getComponent();
6374 ci.topActivity = top.intent.getComponent();
6375 ci.thumbnail = top.thumbnail;
6376 ci.description = topDescription;
6377 ci.numActivities = numActivities;
6378 ci.numRunning = numRunning;
6379 //System.out.println(
6380 // "#" + maxNum + ": " + " descr=" + ci.description);
6381 if (ci.thumbnail == null && receiver != null) {
6382 if (localLOGV) Log.v(
6383 TAG, "State=" + top.state + "Idle=" + top.idle
6384 + " app=" + top.app
6385 + " thr=" + (top.app != null ? top.app.thread : null));
6386 if (top.state == ActivityState.RESUMED
6387 || top.state == ActivityState.PAUSING) {
6388 if (top.idle && top.app != null
6389 && top.app.thread != null) {
6390 topRecord = top;
6391 topThumbnail = top.app.thread;
6392 } else {
6393 top.thumbnailNeeded = true;
6394 }
6395 }
6396 if (pending == null) {
6397 pending = new PendingThumbnailsRecord(receiver);
6398 }
6399 pending.pendingRecords.add(top);
6400 }
6401 list.add(ci);
6402 maxNum--;
6403 top = null;
6404 }
6405 }
6406
6407 if (pending != null) {
6408 mPendingThumbnails.add(pending);
6409 }
6410 }
6411
6412 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6413
6414 if (topThumbnail != null) {
6415 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6416 try {
6417 topThumbnail.requestThumbnail(topRecord);
6418 } catch (Exception e) {
6419 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6420 sendPendingThumbnail(null, topRecord, null, null, true);
6421 }
6422 }
6423
6424 if (pending == null && receiver != null) {
6425 // In this case all thumbnails were available and the client
6426 // is being asked to be told when the remaining ones come in...
6427 // which is unusually, since the top-most currently running
6428 // activity should never have a canned thumbnail! Oh well.
6429 try {
6430 receiver.finished();
6431 } catch (RemoteException ex) {
6432 }
6433 }
6434
6435 return list;
6436 }
6437
6438 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6439 int flags) {
6440 synchronized (this) {
6441 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6442 "getRecentTasks()");
6443
6444 final int N = mRecentTasks.size();
6445 ArrayList<ActivityManager.RecentTaskInfo> res
6446 = new ArrayList<ActivityManager.RecentTaskInfo>(
6447 maxNum < N ? maxNum : N);
6448 for (int i=0; i<N && maxNum > 0; i++) {
6449 TaskRecord tr = mRecentTasks.get(i);
6450 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6451 || (tr.intent == null)
6452 || ((tr.intent.getFlags()
6453 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6454 ActivityManager.RecentTaskInfo rti
6455 = new ActivityManager.RecentTaskInfo();
6456 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6457 rti.baseIntent = new Intent(
6458 tr.intent != null ? tr.intent : tr.affinityIntent);
6459 rti.origActivity = tr.origActivity;
6460 res.add(rti);
6461 maxNum--;
6462 }
6463 }
6464 return res;
6465 }
6466 }
6467
6468 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6469 int j;
6470 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6471 TaskRecord jt = startTask;
6472
6473 // First look backwards
6474 for (j=startIndex-1; j>=0; j--) {
6475 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6476 if (r.task != jt) {
6477 jt = r.task;
6478 if (affinity.equals(jt.affinity)) {
6479 return j;
6480 }
6481 }
6482 }
6483
6484 // Now look forwards
6485 final int N = mHistory.size();
6486 jt = startTask;
6487 for (j=startIndex+1; j<N; j++) {
6488 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6489 if (r.task != jt) {
6490 if (affinity.equals(jt.affinity)) {
6491 return j;
6492 }
6493 jt = r.task;
6494 }
6495 }
6496
6497 // Might it be at the top?
6498 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6499 return N-1;
6500 }
6501
6502 return -1;
6503 }
6504
6505 /**
6506 * Perform a reset of the given task, if needed as part of launching it.
6507 * Returns the new HistoryRecord at the top of the task.
6508 */
6509 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6510 HistoryRecord newActivity) {
6511 boolean forceReset = (newActivity.info.flags
6512 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6513 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6514 if ((newActivity.info.flags
6515 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6516 forceReset = true;
6517 }
6518 }
6519
6520 final TaskRecord task = taskTop.task;
6521
6522 // We are going to move through the history list so that we can look
6523 // at each activity 'target' with 'below' either the interesting
6524 // activity immediately below it in the stack or null.
6525 HistoryRecord target = null;
6526 int targetI = 0;
6527 int taskTopI = -1;
6528 int replyChainEnd = -1;
6529 int lastReparentPos = -1;
6530 for (int i=mHistory.size()-1; i>=-1; i--) {
6531 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6532
6533 if (below != null && below.finishing) {
6534 continue;
6535 }
6536 if (target == null) {
6537 target = below;
6538 targetI = i;
6539 // If we were in the middle of a reply chain before this
6540 // task, it doesn't appear like the root of the chain wants
6541 // anything interesting, so drop it.
6542 replyChainEnd = -1;
6543 continue;
6544 }
6545
6546 final int flags = target.info.flags;
6547
6548 final boolean finishOnTaskLaunch =
6549 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6550 final boolean allowTaskReparenting =
6551 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6552
6553 if (target.task == task) {
6554 // We are inside of the task being reset... we'll either
6555 // finish this activity, push it out for another task,
6556 // or leave it as-is. We only do this
6557 // for activities that are not the root of the task (since
6558 // if we finish the root, we may no longer have the task!).
6559 if (taskTopI < 0) {
6560 taskTopI = targetI;
6561 }
6562 if (below != null && below.task == task) {
6563 final boolean clearWhenTaskReset =
6564 (target.intent.getFlags()
6565 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006566 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006567 // If this activity is sending a reply to a previous
6568 // activity, we can't do anything with it now until
6569 // we reach the start of the reply chain.
6570 // XXX note that we are assuming the result is always
6571 // to the previous activity, which is almost always
6572 // the case but we really shouldn't count on.
6573 if (replyChainEnd < 0) {
6574 replyChainEnd = targetI;
6575 }
Ed Heyl73798232009-03-24 21:32:21 -07006576 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006577 && target.taskAffinity != null
6578 && !target.taskAffinity.equals(task.affinity)) {
6579 // If this activity has an affinity for another
6580 // task, then we need to move it out of here. We will
6581 // move it as far out of the way as possible, to the
6582 // bottom of the activity stack. This also keeps it
6583 // correctly ordered with any activities we previously
6584 // moved.
6585 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6586 if (target.taskAffinity != null
6587 && target.taskAffinity.equals(p.task.affinity)) {
6588 // If the activity currently at the bottom has the
6589 // same task affinity as the one we are moving,
6590 // then merge it into the same task.
6591 target.task = p.task;
6592 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6593 + " out to bottom task " + p.task);
6594 } else {
6595 mCurTask++;
6596 if (mCurTask <= 0) {
6597 mCurTask = 1;
6598 }
6599 target.task = new TaskRecord(mCurTask, target.info, null,
6600 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6601 target.task.affinityIntent = target.intent;
6602 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6603 + " out to new task " + target.task);
6604 }
6605 mWindowManager.setAppGroupId(target, task.taskId);
6606 if (replyChainEnd < 0) {
6607 replyChainEnd = targetI;
6608 }
6609 int dstPos = 0;
6610 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6611 p = (HistoryRecord)mHistory.get(srcPos);
6612 if (p.finishing) {
6613 continue;
6614 }
6615 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6616 + " out to target's task " + target.task);
6617 task.numActivities--;
6618 p.task = target.task;
6619 target.task.numActivities++;
6620 mHistory.remove(srcPos);
6621 mHistory.add(dstPos, p);
6622 mWindowManager.moveAppToken(dstPos, p);
6623 mWindowManager.setAppGroupId(p, p.task.taskId);
6624 dstPos++;
6625 if (VALIDATE_TOKENS) {
6626 mWindowManager.validateAppTokens(mHistory);
6627 }
6628 i++;
6629 }
6630 if (taskTop == p) {
6631 taskTop = below;
6632 }
6633 if (taskTopI == replyChainEnd) {
6634 taskTopI = -1;
6635 }
6636 replyChainEnd = -1;
6637 addRecentTask(target.task);
6638 } else if (forceReset || finishOnTaskLaunch
6639 || clearWhenTaskReset) {
6640 // If the activity should just be removed -- either
6641 // because it asks for it, or the task should be
6642 // cleared -- then finish it and anything that is
6643 // part of its reply chain.
6644 if (clearWhenTaskReset) {
6645 // In this case, we want to finish this activity
6646 // and everything above it, so be sneaky and pretend
6647 // like these are all in the reply chain.
6648 replyChainEnd = targetI+1;
6649 while (replyChainEnd < mHistory.size() &&
6650 ((HistoryRecord)mHistory.get(
6651 replyChainEnd)).task == task) {
6652 replyChainEnd++;
6653 }
6654 replyChainEnd--;
6655 } else if (replyChainEnd < 0) {
6656 replyChainEnd = targetI;
6657 }
6658 HistoryRecord p = null;
6659 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6660 p = (HistoryRecord)mHistory.get(srcPos);
6661 if (p.finishing) {
6662 continue;
6663 }
6664 if (finishActivityLocked(p, srcPos,
6665 Activity.RESULT_CANCELED, null, "reset")) {
6666 replyChainEnd--;
6667 srcPos--;
6668 }
6669 }
6670 if (taskTop == p) {
6671 taskTop = below;
6672 }
6673 if (taskTopI == replyChainEnd) {
6674 taskTopI = -1;
6675 }
6676 replyChainEnd = -1;
6677 } else {
6678 // If we were in the middle of a chain, well the
6679 // activity that started it all doesn't want anything
6680 // special, so leave it all as-is.
6681 replyChainEnd = -1;
6682 }
6683 } else {
6684 // Reached the bottom of the task -- any reply chain
6685 // should be left as-is.
6686 replyChainEnd = -1;
6687 }
6688
6689 } else if (target.resultTo != null) {
6690 // If this activity is sending a reply to a previous
6691 // activity, we can't do anything with it now until
6692 // we reach the start of the reply chain.
6693 // XXX note that we are assuming the result is always
6694 // to the previous activity, which is almost always
6695 // the case but we really shouldn't count on.
6696 if (replyChainEnd < 0) {
6697 replyChainEnd = targetI;
6698 }
6699
6700 } else if (taskTopI >= 0 && allowTaskReparenting
6701 && task.affinity != null
6702 && task.affinity.equals(target.taskAffinity)) {
6703 // We are inside of another task... if this activity has
6704 // an affinity for our task, then either remove it if we are
6705 // clearing or move it over to our task. Note that
6706 // we currently punt on the case where we are resetting a
6707 // task that is not at the top but who has activities above
6708 // with an affinity to it... this is really not a normal
6709 // case, and we will need to later pull that task to the front
6710 // and usually at that point we will do the reset and pick
6711 // up those remaining activities. (This only happens if
6712 // someone starts an activity in a new task from an activity
6713 // in a task that is not currently on top.)
6714 if (forceReset || finishOnTaskLaunch) {
6715 if (replyChainEnd < 0) {
6716 replyChainEnd = targetI;
6717 }
6718 HistoryRecord p = null;
6719 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6720 p = (HistoryRecord)mHistory.get(srcPos);
6721 if (p.finishing) {
6722 continue;
6723 }
6724 if (finishActivityLocked(p, srcPos,
6725 Activity.RESULT_CANCELED, null, "reset")) {
6726 taskTopI--;
6727 lastReparentPos--;
6728 replyChainEnd--;
6729 srcPos--;
6730 }
6731 }
6732 replyChainEnd = -1;
6733 } else {
6734 if (replyChainEnd < 0) {
6735 replyChainEnd = targetI;
6736 }
6737 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6738 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6739 if (p.finishing) {
6740 continue;
6741 }
6742 if (lastReparentPos < 0) {
6743 lastReparentPos = taskTopI;
6744 taskTop = p;
6745 } else {
6746 lastReparentPos--;
6747 }
6748 mHistory.remove(srcPos);
6749 p.task.numActivities--;
6750 p.task = task;
6751 mHistory.add(lastReparentPos, p);
6752 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6753 + " in to resetting task " + task);
6754 task.numActivities++;
6755 mWindowManager.moveAppToken(lastReparentPos, p);
6756 mWindowManager.setAppGroupId(p, p.task.taskId);
6757 if (VALIDATE_TOKENS) {
6758 mWindowManager.validateAppTokens(mHistory);
6759 }
6760 }
6761 replyChainEnd = -1;
6762
6763 // Now we've moved it in to place... but what if this is
6764 // a singleTop activity and we have put it on top of another
6765 // instance of the same activity? Then we drop the instance
6766 // below so it remains singleTop.
6767 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6768 for (int j=lastReparentPos-1; j>=0; j--) {
6769 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6770 if (p.finishing) {
6771 continue;
6772 }
6773 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6774 if (finishActivityLocked(p, j,
6775 Activity.RESULT_CANCELED, null, "replace")) {
6776 taskTopI--;
6777 lastReparentPos--;
6778 }
6779 }
6780 }
6781 }
6782 }
6783 }
6784
6785 target = below;
6786 targetI = i;
6787 }
6788
6789 return taskTop;
6790 }
6791
6792 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006793 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006794 */
6795 public void moveTaskToFront(int task) {
6796 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6797 "moveTaskToFront()");
6798
6799 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006800 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6801 Binder.getCallingUid(), "Task to front")) {
6802 return;
6803 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006804 final long origId = Binder.clearCallingIdentity();
6805 try {
6806 int N = mRecentTasks.size();
6807 for (int i=0; i<N; i++) {
6808 TaskRecord tr = mRecentTasks.get(i);
6809 if (tr.taskId == task) {
6810 moveTaskToFrontLocked(tr);
6811 return;
6812 }
6813 }
6814 for (int i=mHistory.size()-1; i>=0; i--) {
6815 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6816 if (hr.task.taskId == task) {
6817 moveTaskToFrontLocked(hr.task);
6818 return;
6819 }
6820 }
6821 } finally {
6822 Binder.restoreCallingIdentity(origId);
6823 }
6824 }
6825 }
6826
6827 private final void moveTaskToFrontLocked(TaskRecord tr) {
6828 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6829
6830 final int task = tr.taskId;
6831 int top = mHistory.size()-1;
6832
6833 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6834 // nothing to do!
6835 return;
6836 }
6837
6838 if (DEBUG_TRANSITION) Log.v(TAG,
6839 "Prepare to front transition: task=" + tr);
6840 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6841
6842 ArrayList moved = new ArrayList();
6843
6844 // Applying the affinities may have removed entries from the history,
6845 // so get the size again.
6846 top = mHistory.size()-1;
6847 int pos = top;
6848
6849 // Shift all activities with this task up to the top
6850 // of the stack, keeping them in the same internal order.
6851 while (pos >= 0) {
6852 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6853 if (localLOGV) Log.v(
6854 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6855 boolean first = true;
6856 if (r.task.taskId == task) {
6857 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6858 mHistory.remove(pos);
6859 mHistory.add(top, r);
6860 moved.add(0, r);
6861 top--;
6862 if (first) {
6863 addRecentTask(r.task);
6864 first = false;
6865 }
6866 }
6867 pos--;
6868 }
6869
6870 mWindowManager.moveAppTokensToTop(moved);
6871 if (VALIDATE_TOKENS) {
6872 mWindowManager.validateAppTokens(mHistory);
6873 }
6874
6875 finishTaskMove(task);
6876 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6877 }
6878
6879 private final void finishTaskMove(int task) {
6880 resumeTopActivityLocked(null);
6881 }
6882
6883 public void moveTaskToBack(int task) {
6884 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6885 "moveTaskToBack()");
6886
6887 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006888 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6889 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6890 Binder.getCallingUid(), "Task to back")) {
6891 return;
6892 }
6893 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006894 final long origId = Binder.clearCallingIdentity();
6895 moveTaskToBackLocked(task);
6896 Binder.restoreCallingIdentity(origId);
6897 }
6898 }
6899
6900 /**
6901 * Moves an activity, and all of the other activities within the same task, to the bottom
6902 * of the history stack. The activity's order within the task is unchanged.
6903 *
6904 * @param token A reference to the activity we wish to move
6905 * @param nonRoot If false then this only works if the activity is the root
6906 * of a task; if true it will work for any activity in a task.
6907 * @return Returns true if the move completed, false if not.
6908 */
6909 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6910 synchronized(this) {
6911 final long origId = Binder.clearCallingIdentity();
6912 int taskId = getTaskForActivityLocked(token, !nonRoot);
6913 if (taskId >= 0) {
6914 return moveTaskToBackLocked(taskId);
6915 }
6916 Binder.restoreCallingIdentity(origId);
6917 }
6918 return false;
6919 }
6920
6921 /**
6922 * Worker method for rearranging history stack. Implements the function of moving all
6923 * activities for a specific task (gathering them if disjoint) into a single group at the
6924 * bottom of the stack.
6925 *
6926 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6927 * to premeptively cancel the move.
6928 *
6929 * @param task The taskId to collect and move to the bottom.
6930 * @return Returns true if the move completed, false if not.
6931 */
6932 private final boolean moveTaskToBackLocked(int task) {
6933 Log.i(TAG, "moveTaskToBack: " + task);
6934
6935 // If we have a watcher, preflight the move before committing to it. First check
6936 // for *other* available tasks, but if none are available, then try again allowing the
6937 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006938 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006939 HistoryRecord next = topRunningActivityLocked(null, task);
6940 if (next == null) {
6941 next = topRunningActivityLocked(null, 0);
6942 }
6943 if (next != null) {
6944 // ask watcher if this is allowed
6945 boolean moveOK = true;
6946 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006947 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006948 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006949 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006950 }
6951 if (!moveOK) {
6952 return false;
6953 }
6954 }
6955 }
6956
6957 ArrayList moved = new ArrayList();
6958
6959 if (DEBUG_TRANSITION) Log.v(TAG,
6960 "Prepare to back transition: task=" + task);
6961 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6962
6963 final int N = mHistory.size();
6964 int bottom = 0;
6965 int pos = 0;
6966
6967 // Shift all activities with this task down to the bottom
6968 // of the stack, keeping them in the same internal order.
6969 while (pos < N) {
6970 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6971 if (localLOGV) Log.v(
6972 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6973 if (r.task.taskId == task) {
6974 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6975 mHistory.remove(pos);
6976 mHistory.add(bottom, r);
6977 moved.add(r);
6978 bottom++;
6979 }
6980 pos++;
6981 }
6982
6983 mWindowManager.moveAppTokensToBottom(moved);
6984 if (VALIDATE_TOKENS) {
6985 mWindowManager.validateAppTokens(mHistory);
6986 }
6987
6988 finishTaskMove(task);
6989 return true;
6990 }
6991
6992 public void moveTaskBackwards(int task) {
6993 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6994 "moveTaskBackwards()");
6995
6996 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006997 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6998 Binder.getCallingUid(), "Task backwards")) {
6999 return;
7000 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007001 final long origId = Binder.clearCallingIdentity();
7002 moveTaskBackwardsLocked(task);
7003 Binder.restoreCallingIdentity(origId);
7004 }
7005 }
7006
7007 private final void moveTaskBackwardsLocked(int task) {
7008 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7009 }
7010
7011 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7012 synchronized(this) {
7013 return getTaskForActivityLocked(token, onlyRoot);
7014 }
7015 }
7016
7017 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7018 final int N = mHistory.size();
7019 TaskRecord lastTask = null;
7020 for (int i=0; i<N; i++) {
7021 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7022 if (r == token) {
7023 if (!onlyRoot || lastTask != r.task) {
7024 return r.task.taskId;
7025 }
7026 return -1;
7027 }
7028 lastTask = r.task;
7029 }
7030
7031 return -1;
7032 }
7033
7034 /**
7035 * Returns the top activity in any existing task matching the given
7036 * Intent. Returns null if no such task is found.
7037 */
7038 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7039 ComponentName cls = intent.getComponent();
7040 if (info.targetActivity != null) {
7041 cls = new ComponentName(info.packageName, info.targetActivity);
7042 }
7043
7044 TaskRecord cp = null;
7045
7046 final int N = mHistory.size();
7047 for (int i=(N-1); i>=0; i--) {
7048 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7049 if (!r.finishing && r.task != cp
7050 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7051 cp = r.task;
7052 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7053 // + "/aff=" + r.task.affinity + " to new cls="
7054 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7055 if (r.task.affinity != null) {
7056 if (r.task.affinity.equals(info.taskAffinity)) {
7057 //Log.i(TAG, "Found matching affinity!");
7058 return r;
7059 }
7060 } else if (r.task.intent != null
7061 && r.task.intent.getComponent().equals(cls)) {
7062 //Log.i(TAG, "Found matching class!");
7063 //dump();
7064 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7065 return r;
7066 } else if (r.task.affinityIntent != null
7067 && r.task.affinityIntent.getComponent().equals(cls)) {
7068 //Log.i(TAG, "Found matching class!");
7069 //dump();
7070 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7071 return r;
7072 }
7073 }
7074 }
7075
7076 return null;
7077 }
7078
7079 /**
7080 * Returns the first activity (starting from the top of the stack) that
7081 * is the same as the given activity. Returns null if no such activity
7082 * is found.
7083 */
7084 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7085 ComponentName cls = intent.getComponent();
7086 if (info.targetActivity != null) {
7087 cls = new ComponentName(info.packageName, info.targetActivity);
7088 }
7089
7090 final int N = mHistory.size();
7091 for (int i=(N-1); i>=0; i--) {
7092 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7093 if (!r.finishing) {
7094 if (r.intent.getComponent().equals(cls)) {
7095 //Log.i(TAG, "Found matching class!");
7096 //dump();
7097 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7098 return r;
7099 }
7100 }
7101 }
7102
7103 return null;
7104 }
7105
7106 public void finishOtherInstances(IBinder token, ComponentName className) {
7107 synchronized(this) {
7108 final long origId = Binder.clearCallingIdentity();
7109
7110 int N = mHistory.size();
7111 TaskRecord lastTask = null;
7112 for (int i=0; i<N; i++) {
7113 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7114 if (r.realActivity.equals(className)
7115 && r != token && lastTask != r.task) {
7116 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7117 null, "others")) {
7118 i--;
7119 N--;
7120 }
7121 }
7122 lastTask = r.task;
7123 }
7124
7125 Binder.restoreCallingIdentity(origId);
7126 }
7127 }
7128
7129 // =========================================================
7130 // THUMBNAILS
7131 // =========================================================
7132
7133 public void reportThumbnail(IBinder token,
7134 Bitmap thumbnail, CharSequence description) {
7135 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7136 final long origId = Binder.clearCallingIdentity();
7137 sendPendingThumbnail(null, token, thumbnail, description, true);
7138 Binder.restoreCallingIdentity(origId);
7139 }
7140
7141 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7142 Bitmap thumbnail, CharSequence description, boolean always) {
7143 TaskRecord task = null;
7144 ArrayList receivers = null;
7145
7146 //System.out.println("Send pending thumbnail: " + r);
7147
7148 synchronized(this) {
7149 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007150 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007151 if (index < 0) {
7152 return;
7153 }
7154 r = (HistoryRecord)mHistory.get(index);
7155 }
7156 if (thumbnail == null) {
7157 thumbnail = r.thumbnail;
7158 description = r.description;
7159 }
7160 if (thumbnail == null && !always) {
7161 // If there is no thumbnail, and this entry is not actually
7162 // going away, then abort for now and pick up the next
7163 // thumbnail we get.
7164 return;
7165 }
7166 task = r.task;
7167
7168 int N = mPendingThumbnails.size();
7169 int i=0;
7170 while (i<N) {
7171 PendingThumbnailsRecord pr =
7172 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7173 //System.out.println("Looking in " + pr.pendingRecords);
7174 if (pr.pendingRecords.remove(r)) {
7175 if (receivers == null) {
7176 receivers = new ArrayList();
7177 }
7178 receivers.add(pr);
7179 if (pr.pendingRecords.size() == 0) {
7180 pr.finished = true;
7181 mPendingThumbnails.remove(i);
7182 N--;
7183 continue;
7184 }
7185 }
7186 i++;
7187 }
7188 }
7189
7190 if (receivers != null) {
7191 final int N = receivers.size();
7192 for (int i=0; i<N; i++) {
7193 try {
7194 PendingThumbnailsRecord pr =
7195 (PendingThumbnailsRecord)receivers.get(i);
7196 pr.receiver.newThumbnail(
7197 task != null ? task.taskId : -1, thumbnail, description);
7198 if (pr.finished) {
7199 pr.receiver.finished();
7200 }
7201 } catch (Exception e) {
7202 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7203 }
7204 }
7205 }
7206 }
7207
7208 // =========================================================
7209 // CONTENT PROVIDERS
7210 // =========================================================
7211
7212 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7213 List providers = null;
7214 try {
7215 providers = ActivityThread.getPackageManager().
7216 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007217 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007218 } catch (RemoteException ex) {
7219 }
7220 if (providers != null) {
7221 final int N = providers.size();
7222 for (int i=0; i<N; i++) {
7223 ProviderInfo cpi =
7224 (ProviderInfo)providers.get(i);
7225 ContentProviderRecord cpr =
7226 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7227 if (cpr == null) {
7228 cpr = new ContentProviderRecord(cpi, app.info);
7229 mProvidersByClass.put(cpi.name, cpr);
7230 }
7231 app.pubProviders.put(cpi.name, cpr);
7232 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007233 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007234 }
7235 }
7236 return providers;
7237 }
7238
7239 private final String checkContentProviderPermissionLocked(
7240 ProviderInfo cpi, ProcessRecord r, int mode) {
7241 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7242 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7243 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7244 cpi.exported ? -1 : cpi.applicationInfo.uid)
7245 == PackageManager.PERMISSION_GRANTED
7246 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7247 return null;
7248 }
7249 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7250 cpi.exported ? -1 : cpi.applicationInfo.uid)
7251 == PackageManager.PERMISSION_GRANTED) {
7252 return null;
7253 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007254
7255 PathPermission[] pps = cpi.pathPermissions;
7256 if (pps != null) {
7257 int i = pps.length;
7258 while (i > 0) {
7259 i--;
7260 PathPermission pp = pps[i];
7261 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7262 cpi.exported ? -1 : cpi.applicationInfo.uid)
7263 == PackageManager.PERMISSION_GRANTED
7264 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7265 return null;
7266 }
7267 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7268 cpi.exported ? -1 : cpi.applicationInfo.uid)
7269 == PackageManager.PERMISSION_GRANTED) {
7270 return null;
7271 }
7272 }
7273 }
7274
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007275 String msg = "Permission Denial: opening provider " + cpi.name
7276 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7277 + ", uid=" + callingUid + ") requires "
7278 + cpi.readPermission + " or " + cpi.writePermission;
7279 Log.w(TAG, msg);
7280 return msg;
7281 }
7282
7283 private final ContentProviderHolder getContentProviderImpl(
7284 IApplicationThread caller, String name) {
7285 ContentProviderRecord cpr;
7286 ProviderInfo cpi = null;
7287
7288 synchronized(this) {
7289 ProcessRecord r = null;
7290 if (caller != null) {
7291 r = getRecordForAppLocked(caller);
7292 if (r == null) {
7293 throw new SecurityException(
7294 "Unable to find app for caller " + caller
7295 + " (pid=" + Binder.getCallingPid()
7296 + ") when getting content provider " + name);
7297 }
7298 }
7299
7300 // First check if this content provider has been published...
7301 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7302 if (cpr != null) {
7303 cpi = cpr.info;
7304 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7305 return new ContentProviderHolder(cpi,
7306 cpi.readPermission != null
7307 ? cpi.readPermission : cpi.writePermission);
7308 }
7309
7310 if (r != null && cpr.canRunHere(r)) {
7311 // This provider has been published or is in the process
7312 // of being published... but it is also allowed to run
7313 // in the caller's process, so don't make a connection
7314 // and just let the caller instantiate its own instance.
7315 if (cpr.provider != null) {
7316 // don't give caller the provider object, it needs
7317 // to make its own.
7318 cpr = new ContentProviderRecord(cpr);
7319 }
7320 return cpr;
7321 }
7322
7323 final long origId = Binder.clearCallingIdentity();
7324
7325 // In this case the provider is a single instance, so we can
7326 // return it right away.
7327 if (r != null) {
7328 r.conProviders.add(cpr);
7329 cpr.clients.add(r);
7330 } else {
7331 cpr.externals++;
7332 }
7333
7334 if (cpr.app != null) {
7335 updateOomAdjLocked(cpr.app);
7336 }
7337
7338 Binder.restoreCallingIdentity(origId);
7339
7340 } else {
7341 try {
7342 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007343 resolveContentProvider(name,
7344 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007345 } catch (RemoteException ex) {
7346 }
7347 if (cpi == null) {
7348 return null;
7349 }
7350
7351 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7352 return new ContentProviderHolder(cpi,
7353 cpi.readPermission != null
7354 ? cpi.readPermission : cpi.writePermission);
7355 }
7356
7357 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7358 final boolean firstClass = cpr == null;
7359 if (firstClass) {
7360 try {
7361 ApplicationInfo ai =
7362 ActivityThread.getPackageManager().
7363 getApplicationInfo(
7364 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007365 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007366 if (ai == null) {
7367 Log.w(TAG, "No package info for content provider "
7368 + cpi.name);
7369 return null;
7370 }
7371 cpr = new ContentProviderRecord(cpi, ai);
7372 } catch (RemoteException ex) {
7373 // pm is in same process, this will never happen.
7374 }
7375 }
7376
7377 if (r != null && cpr.canRunHere(r)) {
7378 // If this is a multiprocess provider, then just return its
7379 // info and allow the caller to instantiate it. Only do
7380 // this if the provider is the same user as the caller's
7381 // process, or can run as root (so can be in any process).
7382 return cpr;
7383 }
7384
7385 if (false) {
7386 RuntimeException e = new RuntimeException("foo");
7387 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7388 // + " pruid " + ai.uid + "): " + cpi.className, e);
7389 }
7390
7391 // This is single process, and our app is now connecting to it.
7392 // See if we are already in the process of launching this
7393 // provider.
7394 final int N = mLaunchingProviders.size();
7395 int i;
7396 for (i=0; i<N; i++) {
7397 if (mLaunchingProviders.get(i) == cpr) {
7398 break;
7399 }
7400 if (false) {
7401 final ContentProviderRecord rec =
7402 (ContentProviderRecord)mLaunchingProviders.get(i);
7403 if (rec.info.name.equals(cpr.info.name)) {
7404 cpr = rec;
7405 break;
7406 }
7407 }
7408 }
7409
7410 // If the provider is not already being launched, then get it
7411 // started.
7412 if (i >= N) {
7413 final long origId = Binder.clearCallingIdentity();
7414 ProcessRecord proc = startProcessLocked(cpi.processName,
7415 cpr.appInfo, false, 0, "content provider",
7416 new ComponentName(cpi.applicationInfo.packageName,
7417 cpi.name));
7418 if (proc == null) {
7419 Log.w(TAG, "Unable to launch app "
7420 + cpi.applicationInfo.packageName + "/"
7421 + cpi.applicationInfo.uid + " for provider "
7422 + name + ": process is bad");
7423 return null;
7424 }
7425 cpr.launchingApp = proc;
7426 mLaunchingProviders.add(cpr);
7427 Binder.restoreCallingIdentity(origId);
7428 }
7429
7430 // Make sure the provider is published (the same provider class
7431 // may be published under multiple names).
7432 if (firstClass) {
7433 mProvidersByClass.put(cpi.name, cpr);
7434 }
7435 mProvidersByName.put(name, cpr);
7436
7437 if (r != null) {
7438 r.conProviders.add(cpr);
7439 cpr.clients.add(r);
7440 } else {
7441 cpr.externals++;
7442 }
7443 }
7444 }
7445
7446 // Wait for the provider to be published...
7447 synchronized (cpr) {
7448 while (cpr.provider == null) {
7449 if (cpr.launchingApp == null) {
7450 Log.w(TAG, "Unable to launch app "
7451 + cpi.applicationInfo.packageName + "/"
7452 + cpi.applicationInfo.uid + " for provider "
7453 + name + ": launching app became null");
7454 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7455 cpi.applicationInfo.packageName,
7456 cpi.applicationInfo.uid, name);
7457 return null;
7458 }
7459 try {
7460 cpr.wait();
7461 } catch (InterruptedException ex) {
7462 }
7463 }
7464 }
7465 return cpr;
7466 }
7467
7468 public final ContentProviderHolder getContentProvider(
7469 IApplicationThread caller, String name) {
7470 if (caller == null) {
7471 String msg = "null IApplicationThread when getting content provider "
7472 + name;
7473 Log.w(TAG, msg);
7474 throw new SecurityException(msg);
7475 }
7476
7477 return getContentProviderImpl(caller, name);
7478 }
7479
7480 private ContentProviderHolder getContentProviderExternal(String name) {
7481 return getContentProviderImpl(null, name);
7482 }
7483
7484 /**
7485 * Drop a content provider from a ProcessRecord's bookkeeping
7486 * @param cpr
7487 */
7488 public void removeContentProvider(IApplicationThread caller, String name) {
7489 synchronized (this) {
7490 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7491 if(cpr == null) {
7492 //remove from mProvidersByClass
7493 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7494 return;
7495 }
7496 final ProcessRecord r = getRecordForAppLocked(caller);
7497 if (r == null) {
7498 throw new SecurityException(
7499 "Unable to find app for caller " + caller +
7500 " when removing content provider " + name);
7501 }
7502 //update content provider record entry info
7503 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7504 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7505 r.info.processName+" from process "+localCpr.appInfo.processName);
7506 if(localCpr.appInfo.processName == r.info.processName) {
7507 //should not happen. taken care of as a local provider
7508 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7509 return;
7510 } else {
7511 localCpr.clients.remove(r);
7512 r.conProviders.remove(localCpr);
7513 }
7514 updateOomAdjLocked();
7515 }
7516 }
7517
7518 private void removeContentProviderExternal(String name) {
7519 synchronized (this) {
7520 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7521 if(cpr == null) {
7522 //remove from mProvidersByClass
7523 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7524 return;
7525 }
7526
7527 //update content provider record entry info
7528 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7529 localCpr.externals--;
7530 if (localCpr.externals < 0) {
7531 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7532 }
7533 updateOomAdjLocked();
7534 }
7535 }
7536
7537 public final void publishContentProviders(IApplicationThread caller,
7538 List<ContentProviderHolder> providers) {
7539 if (providers == null) {
7540 return;
7541 }
7542
7543 synchronized(this) {
7544 final ProcessRecord r = getRecordForAppLocked(caller);
7545 if (r == null) {
7546 throw new SecurityException(
7547 "Unable to find app for caller " + caller
7548 + " (pid=" + Binder.getCallingPid()
7549 + ") when publishing content providers");
7550 }
7551
7552 final long origId = Binder.clearCallingIdentity();
7553
7554 final int N = providers.size();
7555 for (int i=0; i<N; i++) {
7556 ContentProviderHolder src = providers.get(i);
7557 if (src == null || src.info == null || src.provider == null) {
7558 continue;
7559 }
7560 ContentProviderRecord dst =
7561 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7562 if (dst != null) {
7563 mProvidersByClass.put(dst.info.name, dst);
7564 String names[] = dst.info.authority.split(";");
7565 for (int j = 0; j < names.length; j++) {
7566 mProvidersByName.put(names[j], dst);
7567 }
7568
7569 int NL = mLaunchingProviders.size();
7570 int j;
7571 for (j=0; j<NL; j++) {
7572 if (mLaunchingProviders.get(j) == dst) {
7573 mLaunchingProviders.remove(j);
7574 j--;
7575 NL--;
7576 }
7577 }
7578 synchronized (dst) {
7579 dst.provider = src.provider;
7580 dst.app = r;
7581 dst.notifyAll();
7582 }
7583 updateOomAdjLocked(r);
7584 }
7585 }
7586
7587 Binder.restoreCallingIdentity(origId);
7588 }
7589 }
7590
7591 public static final void installSystemProviders() {
7592 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7593 List providers = mSelf.generateApplicationProvidersLocked(app);
7594 mSystemThread.installSystemProviders(providers);
7595 }
7596
7597 // =========================================================
7598 // GLOBAL MANAGEMENT
7599 // =========================================================
7600
7601 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7602 ApplicationInfo info, String customProcess) {
7603 String proc = customProcess != null ? customProcess : info.processName;
7604 BatteryStatsImpl.Uid.Proc ps = null;
7605 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7606 synchronized (stats) {
7607 ps = stats.getProcessStatsLocked(info.uid, proc);
7608 }
7609 return new ProcessRecord(ps, thread, info, proc);
7610 }
7611
7612 final ProcessRecord addAppLocked(ApplicationInfo info) {
7613 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7614
7615 if (app == null) {
7616 app = newProcessRecordLocked(null, info, null);
7617 mProcessNames.put(info.processName, info.uid, app);
7618 updateLRUListLocked(app, true);
7619 }
7620
7621 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7622 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7623 app.persistent = true;
7624 app.maxAdj = CORE_SERVER_ADJ;
7625 }
7626 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7627 mPersistentStartingProcesses.add(app);
7628 startProcessLocked(app, "added application", app.processName);
7629 }
7630
7631 return app;
7632 }
7633
7634 public void unhandledBack() {
7635 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7636 "unhandledBack()");
7637
7638 synchronized(this) {
7639 int count = mHistory.size();
7640 if (Config.LOGD) Log.d(
7641 TAG, "Performing unhandledBack(): stack size = " + count);
7642 if (count > 1) {
7643 final long origId = Binder.clearCallingIdentity();
7644 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7645 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7646 Binder.restoreCallingIdentity(origId);
7647 }
7648 }
7649 }
7650
7651 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7652 String name = uri.getAuthority();
7653 ContentProviderHolder cph = getContentProviderExternal(name);
7654 ParcelFileDescriptor pfd = null;
7655 if (cph != null) {
7656 // We record the binder invoker's uid in thread-local storage before
7657 // going to the content provider to open the file. Later, in the code
7658 // that handles all permissions checks, we look for this uid and use
7659 // that rather than the Activity Manager's own uid. The effect is that
7660 // we do the check against the caller's permissions even though it looks
7661 // to the content provider like the Activity Manager itself is making
7662 // the request.
7663 sCallerIdentity.set(new Identity(
7664 Binder.getCallingPid(), Binder.getCallingUid()));
7665 try {
7666 pfd = cph.provider.openFile(uri, "r");
7667 } catch (FileNotFoundException e) {
7668 // do nothing; pfd will be returned null
7669 } finally {
7670 // Ensure that whatever happens, we clean up the identity state
7671 sCallerIdentity.remove();
7672 }
7673
7674 // We've got the fd now, so we're done with the provider.
7675 removeContentProviderExternal(name);
7676 } else {
7677 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7678 }
7679 return pfd;
7680 }
7681
7682 public void goingToSleep() {
7683 synchronized(this) {
7684 mSleeping = true;
7685 mWindowManager.setEventDispatching(false);
7686
7687 if (mResumedActivity != null) {
7688 pauseIfSleepingLocked();
7689 } else {
7690 Log.w(TAG, "goingToSleep with no resumed activity!");
7691 }
7692 }
7693 }
7694
Dianne Hackborn55280a92009-05-07 15:53:46 -07007695 public boolean shutdown(int timeout) {
7696 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7697 != PackageManager.PERMISSION_GRANTED) {
7698 throw new SecurityException("Requires permission "
7699 + android.Manifest.permission.SHUTDOWN);
7700 }
7701
7702 boolean timedout = false;
7703
7704 synchronized(this) {
7705 mShuttingDown = true;
7706 mWindowManager.setEventDispatching(false);
7707
7708 if (mResumedActivity != null) {
7709 pauseIfSleepingLocked();
7710 final long endTime = System.currentTimeMillis() + timeout;
7711 while (mResumedActivity != null || mPausingActivity != null) {
7712 long delay = endTime - System.currentTimeMillis();
7713 if (delay <= 0) {
7714 Log.w(TAG, "Activity manager shutdown timed out");
7715 timedout = true;
7716 break;
7717 }
7718 try {
7719 this.wait();
7720 } catch (InterruptedException e) {
7721 }
7722 }
7723 }
7724 }
7725
7726 mUsageStatsService.shutdown();
7727 mBatteryStatsService.shutdown();
7728
7729 return timedout;
7730 }
7731
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007732 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007733 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007734 if (!mGoingToSleep.isHeld()) {
7735 mGoingToSleep.acquire();
7736 if (mLaunchingActivity.isHeld()) {
7737 mLaunchingActivity.release();
7738 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7739 }
7740 }
7741
7742 // If we are not currently pausing an activity, get the current
7743 // one to pause. If we are pausing one, we will just let that stuff
7744 // run and release the wake lock when all done.
7745 if (mPausingActivity == null) {
7746 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7747 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7748 startPausingLocked(false, true);
7749 }
7750 }
7751 }
7752
7753 public void wakingUp() {
7754 synchronized(this) {
7755 if (mGoingToSleep.isHeld()) {
7756 mGoingToSleep.release();
7757 }
7758 mWindowManager.setEventDispatching(true);
7759 mSleeping = false;
7760 resumeTopActivityLocked(null);
7761 }
7762 }
7763
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007764 public void stopAppSwitches() {
7765 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7766 != PackageManager.PERMISSION_GRANTED) {
7767 throw new SecurityException("Requires permission "
7768 + android.Manifest.permission.STOP_APP_SWITCHES);
7769 }
7770
7771 synchronized(this) {
7772 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7773 + APP_SWITCH_DELAY_TIME;
7774 mDidAppSwitch = false;
7775 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7776 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7777 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7778 }
7779 }
7780
7781 public void resumeAppSwitches() {
7782 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7783 != PackageManager.PERMISSION_GRANTED) {
7784 throw new SecurityException("Requires permission "
7785 + android.Manifest.permission.STOP_APP_SWITCHES);
7786 }
7787
7788 synchronized(this) {
7789 // Note that we don't execute any pending app switches... we will
7790 // let those wait until either the timeout, or the next start
7791 // activity request.
7792 mAppSwitchesAllowedTime = 0;
7793 }
7794 }
7795
7796 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7797 String name) {
7798 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7799 return true;
7800 }
7801
7802 final int perm = checkComponentPermission(
7803 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7804 callingUid, -1);
7805 if (perm == PackageManager.PERMISSION_GRANTED) {
7806 return true;
7807 }
7808
7809 Log.w(TAG, name + " request from " + callingUid + " stopped");
7810 return false;
7811 }
7812
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007813 public void setDebugApp(String packageName, boolean waitForDebugger,
7814 boolean persistent) {
7815 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7816 "setDebugApp()");
7817
7818 // Note that this is not really thread safe if there are multiple
7819 // callers into it at the same time, but that's not a situation we
7820 // care about.
7821 if (persistent) {
7822 final ContentResolver resolver = mContext.getContentResolver();
7823 Settings.System.putString(
7824 resolver, Settings.System.DEBUG_APP,
7825 packageName);
7826 Settings.System.putInt(
7827 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7828 waitForDebugger ? 1 : 0);
7829 }
7830
7831 synchronized (this) {
7832 if (!persistent) {
7833 mOrigDebugApp = mDebugApp;
7834 mOrigWaitForDebugger = mWaitForDebugger;
7835 }
7836 mDebugApp = packageName;
7837 mWaitForDebugger = waitForDebugger;
7838 mDebugTransient = !persistent;
7839 if (packageName != null) {
7840 final long origId = Binder.clearCallingIdentity();
7841 uninstallPackageLocked(packageName, -1, false);
7842 Binder.restoreCallingIdentity(origId);
7843 }
7844 }
7845 }
7846
7847 public void setAlwaysFinish(boolean enabled) {
7848 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7849 "setAlwaysFinish()");
7850
7851 Settings.System.putInt(
7852 mContext.getContentResolver(),
7853 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7854
7855 synchronized (this) {
7856 mAlwaysFinishActivities = enabled;
7857 }
7858 }
7859
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007860 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007861 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007862 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007863 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007864 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007865 }
7866 }
7867
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007868 public void registerActivityWatcher(IActivityWatcher watcher) {
7869 mWatchers.register(watcher);
7870 }
7871
7872 public void unregisterActivityWatcher(IActivityWatcher watcher) {
7873 mWatchers.unregister(watcher);
7874 }
7875
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007876 public final void enterSafeMode() {
7877 synchronized(this) {
7878 // It only makes sense to do this before the system is ready
7879 // and started launching other packages.
7880 if (!mSystemReady) {
7881 try {
7882 ActivityThread.getPackageManager().enterSafeMode();
7883 } catch (RemoteException e) {
7884 }
7885
7886 View v = LayoutInflater.from(mContext).inflate(
7887 com.android.internal.R.layout.safe_mode, null);
7888 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7889 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7890 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7891 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7892 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7893 lp.format = v.getBackground().getOpacity();
7894 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7895 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7896 ((WindowManager)mContext.getSystemService(
7897 Context.WINDOW_SERVICE)).addView(v, lp);
7898 }
7899 }
7900 }
7901
7902 public void noteWakeupAlarm(IIntentSender sender) {
7903 if (!(sender instanceof PendingIntentRecord)) {
7904 return;
7905 }
7906 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7907 synchronized (stats) {
7908 if (mBatteryStatsService.isOnBattery()) {
7909 mBatteryStatsService.enforceCallingPermission();
7910 PendingIntentRecord rec = (PendingIntentRecord)sender;
7911 int MY_UID = Binder.getCallingUid();
7912 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7913 BatteryStatsImpl.Uid.Pkg pkg =
7914 stats.getPackageStatsLocked(uid, rec.key.packageName);
7915 pkg.incWakeupsLocked();
7916 }
7917 }
7918 }
7919
7920 public boolean killPidsForMemory(int[] pids) {
7921 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7922 throw new SecurityException("killPidsForMemory only available to the system");
7923 }
7924
7925 // XXX Note: don't acquire main activity lock here, because the window
7926 // manager calls in with its locks held.
7927
7928 boolean killed = false;
7929 synchronized (mPidsSelfLocked) {
7930 int[] types = new int[pids.length];
7931 int worstType = 0;
7932 for (int i=0; i<pids.length; i++) {
7933 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7934 if (proc != null) {
7935 int type = proc.setAdj;
7936 types[i] = type;
7937 if (type > worstType) {
7938 worstType = type;
7939 }
7940 }
7941 }
7942
7943 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7944 // then constrain it so we will kill all hidden procs.
7945 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7946 worstType = HIDDEN_APP_MIN_ADJ;
7947 }
7948 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7949 for (int i=0; i<pids.length; i++) {
7950 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7951 if (proc == null) {
7952 continue;
7953 }
7954 int adj = proc.setAdj;
7955 if (adj >= worstType) {
7956 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7957 + adj + ")");
7958 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7959 proc.processName, adj);
7960 killed = true;
7961 Process.killProcess(pids[i]);
7962 }
7963 }
7964 }
7965 return killed;
7966 }
7967
7968 public void reportPss(IApplicationThread caller, int pss) {
7969 Watchdog.PssRequestor req;
7970 String name;
7971 ProcessRecord callerApp;
7972 synchronized (this) {
7973 if (caller == null) {
7974 return;
7975 }
7976 callerApp = getRecordForAppLocked(caller);
7977 if (callerApp == null) {
7978 return;
7979 }
7980 callerApp.lastPss = pss;
7981 req = callerApp;
7982 name = callerApp.processName;
7983 }
7984 Watchdog.getInstance().reportPss(req, name, pss);
7985 if (!callerApp.persistent) {
7986 removeRequestedPss(callerApp);
7987 }
7988 }
7989
7990 public void requestPss(Runnable completeCallback) {
7991 ArrayList<ProcessRecord> procs;
7992 synchronized (this) {
7993 mRequestPssCallback = completeCallback;
7994 mRequestPssList.clear();
7995 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7996 ProcessRecord proc = mLRUProcesses.get(i);
7997 if (!proc.persistent) {
7998 mRequestPssList.add(proc);
7999 }
8000 }
8001 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8002 }
8003
8004 int oldPri = Process.getThreadPriority(Process.myTid());
8005 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8006 for (int i=procs.size()-1; i>=0; i--) {
8007 ProcessRecord proc = procs.get(i);
8008 proc.lastPss = 0;
8009 proc.requestPss();
8010 }
8011 Process.setThreadPriority(oldPri);
8012 }
8013
8014 void removeRequestedPss(ProcessRecord proc) {
8015 Runnable callback = null;
8016 synchronized (this) {
8017 if (mRequestPssList.remove(proc)) {
8018 if (mRequestPssList.size() == 0) {
8019 callback = mRequestPssCallback;
8020 mRequestPssCallback = null;
8021 }
8022 }
8023 }
8024
8025 if (callback != null) {
8026 callback.run();
8027 }
8028 }
8029
8030 public void collectPss(Watchdog.PssStats stats) {
8031 stats.mEmptyPss = 0;
8032 stats.mEmptyCount = 0;
8033 stats.mBackgroundPss = 0;
8034 stats.mBackgroundCount = 0;
8035 stats.mServicePss = 0;
8036 stats.mServiceCount = 0;
8037 stats.mVisiblePss = 0;
8038 stats.mVisibleCount = 0;
8039 stats.mForegroundPss = 0;
8040 stats.mForegroundCount = 0;
8041 stats.mNoPssCount = 0;
8042 synchronized (this) {
8043 int i;
8044 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8045 ? mProcDeaths.length : stats.mProcDeaths.length;
8046 int aggr = 0;
8047 for (i=0; i<NPD; i++) {
8048 aggr += mProcDeaths[i];
8049 stats.mProcDeaths[i] = aggr;
8050 }
8051 while (i<stats.mProcDeaths.length) {
8052 stats.mProcDeaths[i] = 0;
8053 i++;
8054 }
8055
8056 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8057 ProcessRecord proc = mLRUProcesses.get(i);
8058 if (proc.persistent) {
8059 continue;
8060 }
8061 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8062 if (proc.lastPss == 0) {
8063 stats.mNoPssCount++;
8064 continue;
8065 }
8066 if (proc.setAdj == EMPTY_APP_ADJ) {
8067 stats.mEmptyPss += proc.lastPss;
8068 stats.mEmptyCount++;
8069 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8070 stats.mEmptyPss += proc.lastPss;
8071 stats.mEmptyCount++;
8072 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8073 stats.mBackgroundPss += proc.lastPss;
8074 stats.mBackgroundCount++;
8075 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8076 stats.mVisiblePss += proc.lastPss;
8077 stats.mVisibleCount++;
8078 } else {
8079 stats.mForegroundPss += proc.lastPss;
8080 stats.mForegroundCount++;
8081 }
8082 }
8083 }
8084 }
8085
8086 public final void startRunning(String pkg, String cls, String action,
8087 String data) {
8088 synchronized(this) {
8089 if (mStartRunning) {
8090 return;
8091 }
8092 mStartRunning = true;
8093 mTopComponent = pkg != null && cls != null
8094 ? new ComponentName(pkg, cls) : null;
8095 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8096 mTopData = data;
8097 if (!mSystemReady) {
8098 return;
8099 }
8100 }
8101
8102 systemReady();
8103 }
8104
8105 private void retrieveSettings() {
8106 final ContentResolver resolver = mContext.getContentResolver();
8107 String debugApp = Settings.System.getString(
8108 resolver, Settings.System.DEBUG_APP);
8109 boolean waitForDebugger = Settings.System.getInt(
8110 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8111 boolean alwaysFinishActivities = Settings.System.getInt(
8112 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8113
8114 Configuration configuration = new Configuration();
8115 Settings.System.getConfiguration(resolver, configuration);
8116
8117 synchronized (this) {
8118 mDebugApp = mOrigDebugApp = debugApp;
8119 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8120 mAlwaysFinishActivities = alwaysFinishActivities;
8121 // This happens before any activities are started, so we can
8122 // change mConfiguration in-place.
8123 mConfiguration.updateFrom(configuration);
8124 }
8125 }
8126
8127 public boolean testIsSystemReady() {
8128 // no need to synchronize(this) just to read & return the value
8129 return mSystemReady;
8130 }
8131
8132 public void systemReady() {
8133 // In the simulator, startRunning will never have been called, which
8134 // normally sets a few crucial variables. Do it here instead.
8135 if (!Process.supportsProcesses()) {
8136 mStartRunning = true;
8137 mTopAction = Intent.ACTION_MAIN;
8138 }
8139
8140 synchronized(this) {
8141 if (mSystemReady) {
8142 return;
8143 }
8144 mSystemReady = true;
8145 if (!mStartRunning) {
8146 return;
8147 }
8148 }
8149
8150 if (Config.LOGD) Log.d(TAG, "Start running!");
8151 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8152 SystemClock.uptimeMillis());
8153
8154 synchronized(this) {
8155 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8156 ResolveInfo ri = mContext.getPackageManager()
8157 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008158 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008159 CharSequence errorMsg = null;
8160 if (ri != null) {
8161 ActivityInfo ai = ri.activityInfo;
8162 ApplicationInfo app = ai.applicationInfo;
8163 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8164 mTopAction = Intent.ACTION_FACTORY_TEST;
8165 mTopData = null;
8166 mTopComponent = new ComponentName(app.packageName,
8167 ai.name);
8168 } else {
8169 errorMsg = mContext.getResources().getText(
8170 com.android.internal.R.string.factorytest_not_system);
8171 }
8172 } else {
8173 errorMsg = mContext.getResources().getText(
8174 com.android.internal.R.string.factorytest_no_action);
8175 }
8176 if (errorMsg != null) {
8177 mTopAction = null;
8178 mTopData = null;
8179 mTopComponent = null;
8180 Message msg = Message.obtain();
8181 msg.what = SHOW_FACTORY_ERROR_MSG;
8182 msg.getData().putCharSequence("msg", errorMsg);
8183 mHandler.sendMessage(msg);
8184 }
8185 }
8186 }
8187
8188 retrieveSettings();
8189
8190 synchronized (this) {
8191 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8192 try {
8193 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008194 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008195 if (apps != null) {
8196 int N = apps.size();
8197 int i;
8198 for (i=0; i<N; i++) {
8199 ApplicationInfo info
8200 = (ApplicationInfo)apps.get(i);
8201 if (info != null &&
8202 !info.packageName.equals("android")) {
8203 addAppLocked(info);
8204 }
8205 }
8206 }
8207 } catch (RemoteException ex) {
8208 // pm is in same process, this will never happen.
8209 }
8210 }
8211
8212 try {
8213 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8214 Message msg = Message.obtain();
8215 msg.what = SHOW_UID_ERROR_MSG;
8216 mHandler.sendMessage(msg);
8217 }
8218 } catch (RemoteException e) {
8219 }
8220
8221 // Start up initial activity.
8222 mBooting = true;
8223 resumeTopActivityLocked(null);
8224 }
8225 }
8226
8227 boolean makeAppCrashingLocked(ProcessRecord app,
8228 String tag, String shortMsg, String longMsg, byte[] crashData) {
8229 app.crashing = true;
8230 app.crashingReport = generateProcessError(app,
8231 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8232 startAppProblemLocked(app);
8233 app.stopFreezingAllLocked();
8234 return handleAppCrashLocked(app);
8235 }
8236
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008237 private ComponentName getErrorReportReceiver(ProcessRecord app) {
8238 IPackageManager pm = ActivityThread.getPackageManager();
8239 try {
8240 // was an installer package name specified when this app was
8241 // installed?
8242 String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
8243 if (installerPackageName == null) {
8244 return null;
8245 }
8246
8247 // is there an Activity in this package that handles ACTION_APP_ERROR?
8248 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
Dianne Hackbornc14b9cc2009-06-17 18:02:12 -07008249 intent.setPackage(installerPackageName);
8250 ResolveInfo info = pm.resolveIntent(intent, null, 0);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008251 if (info == null || info.activityInfo == null) {
8252 return null;
8253 }
8254
8255 return new ComponentName(installerPackageName, info.activityInfo.name);
8256 } catch (RemoteException e) {
8257 // will return null and no error report will be delivered
8258 }
8259 return null;
8260 }
8261
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008262 void makeAppNotRespondingLocked(ProcessRecord app,
8263 String tag, String shortMsg, String longMsg, byte[] crashData) {
8264 app.notResponding = true;
8265 app.notRespondingReport = generateProcessError(app,
8266 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8267 crashData);
8268 startAppProblemLocked(app);
8269 app.stopFreezingAllLocked();
8270 }
8271
8272 /**
8273 * Generate a process error record, suitable for attachment to a ProcessRecord.
8274 *
8275 * @param app The ProcessRecord in which the error occurred.
8276 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8277 * ActivityManager.AppErrorStateInfo
8278 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8279 * @param shortMsg Short message describing the crash.
8280 * @param longMsg Long message describing the crash.
8281 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8282 *
8283 * @return Returns a fully-formed AppErrorStateInfo record.
8284 */
8285 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8286 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8287 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8288
8289 report.condition = condition;
8290 report.processName = app.processName;
8291 report.pid = app.pid;
8292 report.uid = app.info.uid;
8293 report.tag = tag;
8294 report.shortMsg = shortMsg;
8295 report.longMsg = longMsg;
8296 report.crashData = crashData;
8297
8298 return report;
8299 }
8300
8301 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8302 boolean crashed) {
8303 synchronized (this) {
8304 app.crashing = false;
8305 app.crashingReport = null;
8306 app.notResponding = false;
8307 app.notRespondingReport = null;
8308 if (app.anrDialog == fromDialog) {
8309 app.anrDialog = null;
8310 }
8311 if (app.waitDialog == fromDialog) {
8312 app.waitDialog = null;
8313 }
8314 if (app.pid > 0 && app.pid != MY_PID) {
8315 if (crashed) {
8316 handleAppCrashLocked(app);
8317 }
8318 Log.i(ActivityManagerService.TAG, "Killing process "
8319 + app.processName
8320 + " (pid=" + app.pid + ") at user's request");
8321 Process.killProcess(app.pid);
8322 }
8323
8324 }
8325 }
8326
8327 boolean handleAppCrashLocked(ProcessRecord app) {
8328 long now = SystemClock.uptimeMillis();
8329
8330 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8331 app.info.uid);
8332 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8333 // This process loses!
8334 Log.w(TAG, "Process " + app.info.processName
8335 + " has crashed too many times: killing!");
8336 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8337 app.info.processName, app.info.uid);
8338 killServicesLocked(app, false);
8339 for (int i=mHistory.size()-1; i>=0; i--) {
8340 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8341 if (r.app == app) {
8342 if (Config.LOGD) Log.d(
8343 TAG, " Force finishing activity "
8344 + r.intent.getComponent().flattenToShortString());
8345 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8346 }
8347 }
8348 if (!app.persistent) {
8349 // We don't want to start this process again until the user
8350 // explicitly does so... but for persistent process, we really
8351 // need to keep it running. If a persistent process is actually
8352 // repeatedly crashing, then badness for everyone.
8353 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8354 app.info.processName);
8355 mBadProcesses.put(app.info.processName, app.info.uid, now);
8356 app.bad = true;
8357 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8358 app.removed = true;
8359 removeProcessLocked(app, false);
8360 return false;
8361 }
8362 }
8363
8364 // Bump up the crash count of any services currently running in the proc.
8365 if (app.services.size() != 0) {
8366 // Any services running in the application need to be placed
8367 // back in the pending list.
8368 Iterator it = app.services.iterator();
8369 while (it.hasNext()) {
8370 ServiceRecord sr = (ServiceRecord)it.next();
8371 sr.crashCount++;
8372 }
8373 }
8374
8375 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8376 return true;
8377 }
8378
8379 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008380 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008381 skipCurrentReceiverLocked(app);
8382 }
8383
8384 void skipCurrentReceiverLocked(ProcessRecord app) {
8385 boolean reschedule = false;
8386 BroadcastRecord r = app.curReceiver;
8387 if (r != null) {
8388 // The current broadcast is waiting for this app's receiver
8389 // to be finished. Looks like that's not going to happen, so
8390 // let the broadcast continue.
8391 logBroadcastReceiverDiscard(r);
8392 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8393 r.resultExtras, r.resultAbort, true);
8394 reschedule = true;
8395 }
8396 r = mPendingBroadcast;
8397 if (r != null && r.curApp == app) {
8398 if (DEBUG_BROADCAST) Log.v(TAG,
8399 "skip & discard pending app " + r);
8400 logBroadcastReceiverDiscard(r);
8401 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8402 r.resultExtras, r.resultAbort, true);
8403 reschedule = true;
8404 }
8405 if (reschedule) {
8406 scheduleBroadcastsLocked();
8407 }
8408 }
8409
8410 public int handleApplicationError(IBinder app, int flags,
8411 String tag, String shortMsg, String longMsg, byte[] crashData) {
8412 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008413 ProcessRecord r = null;
8414 synchronized (this) {
8415 if (app != null) {
8416 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8417 final int NA = apps.size();
8418 for (int ia=0; ia<NA; ia++) {
8419 ProcessRecord p = apps.valueAt(ia);
8420 if (p.thread != null && p.thread.asBinder() == app) {
8421 r = p;
8422 break;
8423 }
8424 }
8425 }
8426 }
8427
8428 if (r != null) {
8429 // The application has crashed. Send the SIGQUIT to the process so
8430 // that it can dump its state.
8431 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8432 //Log.i(TAG, "Current system threads:");
8433 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8434 }
8435
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008436 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008437 try {
8438 String name = r != null ? r.processName : null;
8439 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008440 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008441 shortMsg, longMsg, crashData)) {
8442 Log.w(TAG, "Force-killing crashed app " + name
8443 + " at watcher's request");
8444 Process.killProcess(pid);
8445 return 0;
8446 }
8447 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008448 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008449 }
8450 }
8451
8452 final long origId = Binder.clearCallingIdentity();
8453
8454 // If this process is running instrumentation, finish it.
8455 if (r != null && r.instrumentationClass != null) {
8456 Log.w(TAG, "Error in app " + r.processName
8457 + " running instrumentation " + r.instrumentationClass + ":");
8458 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8459 if (longMsg != null) Log.w(TAG, " " + longMsg);
8460 Bundle info = new Bundle();
8461 info.putString("shortMsg", shortMsg);
8462 info.putString("longMsg", longMsg);
8463 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8464 Binder.restoreCallingIdentity(origId);
8465 return 0;
8466 }
8467
8468 if (r != null) {
8469 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8470 return 0;
8471 }
8472 } else {
8473 Log.w(TAG, "Some application object " + app + " tag " + tag
8474 + " has crashed, but I don't know who it is.");
8475 Log.w(TAG, "ShortMsg:" + shortMsg);
8476 Log.w(TAG, "LongMsg:" + longMsg);
8477 Binder.restoreCallingIdentity(origId);
8478 return 0;
8479 }
8480
8481 Message msg = Message.obtain();
8482 msg.what = SHOW_ERROR_MSG;
8483 HashMap data = new HashMap();
8484 data.put("result", result);
8485 data.put("app", r);
8486 data.put("flags", flags);
8487 data.put("shortMsg", shortMsg);
8488 data.put("longMsg", longMsg);
8489 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8490 // For system processes, submit crash data to the server.
8491 data.put("crashData", crashData);
8492 }
8493 msg.obj = data;
8494 mHandler.sendMessage(msg);
8495
8496 Binder.restoreCallingIdentity(origId);
8497 }
8498
8499 int res = result.get();
8500
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008501 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008502 synchronized (this) {
8503 if (r != null) {
8504 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8505 SystemClock.uptimeMillis());
8506 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008507 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8508 appErrorIntent = createAppErrorIntentLocked(r);
8509 res = AppErrorDialog.FORCE_QUIT;
8510 }
8511 }
8512
8513 if (appErrorIntent != null) {
8514 try {
8515 mContext.startActivity(appErrorIntent);
8516 } catch (ActivityNotFoundException e) {
8517 Log.w(TAG, "bug report receiver dissappeared", e);
8518 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008519 }
8520
8521 return res;
8522 }
8523
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008524 Intent createAppErrorIntentLocked(ProcessRecord r) {
8525 ApplicationErrorReport report = createAppErrorReportLocked(r);
8526 if (report == null) {
8527 return null;
8528 }
8529 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8530 result.setComponent(r.errorReportReceiver);
8531 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8532 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8533 return result;
8534 }
8535
8536 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8537 if (r.errorReportReceiver == null) {
8538 return null;
8539 }
8540
8541 if (!r.crashing && !r.notResponding) {
8542 return null;
8543 }
8544
8545 try {
8546 ApplicationErrorReport report = new ApplicationErrorReport();
8547 report.packageName = r.info.packageName;
8548 report.installerPackageName = r.errorReportReceiver.getPackageName();
8549 report.processName = r.processName;
8550
8551 if (r.crashing) {
8552 report.type = ApplicationErrorReport.TYPE_CRASH;
8553 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8554
8555 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8556 r.crashingReport.crashData);
8557 DataInputStream dataStream = new DataInputStream(byteStream);
8558 CrashData crashData = new CrashData(dataStream);
8559 ThrowableData throwData = crashData.getThrowableData();
8560
8561 report.time = crashData.getTime();
8562 report.crashInfo.stackTrace = throwData.toString();
8563
Jacek Surazskif829a782009-06-11 22:47:02 +02008564 // Extract the source of the exception, useful for report
8565 // clustering. Also extract the "deepest" non-null exception
8566 // message.
8567 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008568 while (throwData.getCause() != null) {
8569 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008570 String msg = throwData.getMessage();
8571 if (msg != null && msg.length() > 0) {
8572 exceptionMessage = msg;
8573 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008574 }
8575 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008576 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008577 report.crashInfo.exceptionClassName = throwData.getType();
8578 report.crashInfo.throwFileName = trace.getFileName();
8579 report.crashInfo.throwClassName = trace.getClassName();
8580 report.crashInfo.throwMethodName = trace.getMethodName();
8581 } else if (r.notResponding) {
8582 report.type = ApplicationErrorReport.TYPE_ANR;
8583 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8584
8585 report.anrInfo.activity = r.notRespondingReport.tag;
8586 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8587 report.anrInfo.info = r.notRespondingReport.longMsg;
8588 }
8589
8590 return report;
8591 } catch (IOException e) {
8592 // we don't send it
8593 }
8594
8595 return null;
8596 }
8597
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008598 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8599 // assume our apps are happy - lazy create the list
8600 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8601
8602 synchronized (this) {
8603
8604 // iterate across all processes
8605 final int N = mLRUProcesses.size();
8606 for (int i = 0; i < N; i++) {
8607 ProcessRecord app = mLRUProcesses.get(i);
8608 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8609 // This one's in trouble, so we'll generate a report for it
8610 // crashes are higher priority (in case there's a crash *and* an anr)
8611 ActivityManager.ProcessErrorStateInfo report = null;
8612 if (app.crashing) {
8613 report = app.crashingReport;
8614 } else if (app.notResponding) {
8615 report = app.notRespondingReport;
8616 }
8617
8618 if (report != null) {
8619 if (errList == null) {
8620 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8621 }
8622 errList.add(report);
8623 } else {
8624 Log.w(TAG, "Missing app error report, app = " + app.processName +
8625 " crashing = " + app.crashing +
8626 " notResponding = " + app.notResponding);
8627 }
8628 }
8629 }
8630 }
8631
8632 return errList;
8633 }
8634
8635 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8636 // Lazy instantiation of list
8637 List<ActivityManager.RunningAppProcessInfo> runList = null;
8638 synchronized (this) {
8639 // Iterate across all processes
8640 final int N = mLRUProcesses.size();
8641 for (int i = 0; i < N; i++) {
8642 ProcessRecord app = mLRUProcesses.get(i);
8643 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8644 // Generate process state info for running application
8645 ActivityManager.RunningAppProcessInfo currApp =
8646 new ActivityManager.RunningAppProcessInfo(app.processName,
8647 app.pid, app.getPackageList());
8648 int adj = app.curAdj;
8649 if (adj >= CONTENT_PROVIDER_ADJ) {
8650 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8651 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8652 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008653 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8654 } else if (adj >= HOME_APP_ADJ) {
8655 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8656 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008657 } else if (adj >= SECONDARY_SERVER_ADJ) {
8658 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8659 } else if (adj >= VISIBLE_APP_ADJ) {
8660 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8661 } else {
8662 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8663 }
8664 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8665 // + " lru=" + currApp.lru);
8666 if (runList == null) {
8667 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8668 }
8669 runList.add(currApp);
8670 }
8671 }
8672 }
8673 return runList;
8674 }
8675
8676 @Override
8677 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8678 synchronized (this) {
8679 if (checkCallingPermission(android.Manifest.permission.DUMP)
8680 != PackageManager.PERMISSION_GRANTED) {
8681 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8682 + Binder.getCallingPid()
8683 + ", uid=" + Binder.getCallingUid()
8684 + " without permission "
8685 + android.Manifest.permission.DUMP);
8686 return;
8687 }
8688 if (args.length != 0 && "service".equals(args[0])) {
8689 dumpService(fd, pw, args);
8690 return;
8691 }
8692 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008693 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008694 pw.println(" ");
8695 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008696 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008697 if (mWaitingVisibleActivities.size() > 0) {
8698 pw.println(" ");
8699 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008700 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008701 }
8702 if (mStoppingActivities.size() > 0) {
8703 pw.println(" ");
8704 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008705 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008706 }
8707 if (mFinishingActivities.size() > 0) {
8708 pw.println(" ");
8709 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008710 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008711 }
8712
8713 pw.println(" ");
8714 pw.println(" mPausingActivity: " + mPausingActivity);
8715 pw.println(" mResumedActivity: " + mResumedActivity);
8716 pw.println(" mFocusedActivity: " + mFocusedActivity);
8717 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8718
8719 if (mRecentTasks.size() > 0) {
8720 pw.println(" ");
8721 pw.println("Recent tasks in Current Activity Manager State:");
8722
8723 final int N = mRecentTasks.size();
8724 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008725 TaskRecord tr = mRecentTasks.get(i);
8726 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8727 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008728 mRecentTasks.get(i).dump(pw, " ");
8729 }
8730 }
8731
8732 pw.println(" ");
8733 pw.println(" mCurTask: " + mCurTask);
8734
8735 pw.println(" ");
8736 pw.println("Processes in Current Activity Manager State:");
8737
8738 boolean needSep = false;
8739 int numPers = 0;
8740
8741 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8742 final int NA = procs.size();
8743 for (int ia=0; ia<NA; ia++) {
8744 if (!needSep) {
8745 pw.println(" All known processes:");
8746 needSep = true;
8747 }
8748 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008749 pw.print(r.persistent ? " *PERS*" : " *APP*");
8750 pw.print(" UID "); pw.print(procs.keyAt(ia));
8751 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008752 r.dump(pw, " ");
8753 if (r.persistent) {
8754 numPers++;
8755 }
8756 }
8757 }
8758
8759 if (mLRUProcesses.size() > 0) {
8760 if (needSep) pw.println(" ");
8761 needSep = true;
8762 pw.println(" Running processes (most recent first):");
8763 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008764 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008765 needSep = true;
8766 }
8767
8768 synchronized (mPidsSelfLocked) {
8769 if (mPidsSelfLocked.size() > 0) {
8770 if (needSep) pw.println(" ");
8771 needSep = true;
8772 pw.println(" PID mappings:");
8773 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008774 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8775 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008776 }
8777 }
8778 }
8779
8780 if (mForegroundProcesses.size() > 0) {
8781 if (needSep) pw.println(" ");
8782 needSep = true;
8783 pw.println(" Foreground Processes:");
8784 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008785 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8786 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008787 }
8788 }
8789
8790 if (mPersistentStartingProcesses.size() > 0) {
8791 if (needSep) pw.println(" ");
8792 needSep = true;
8793 pw.println(" Persisent processes that are starting:");
8794 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008795 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008796 }
8797
8798 if (mStartingProcesses.size() > 0) {
8799 if (needSep) pw.println(" ");
8800 needSep = true;
8801 pw.println(" Processes that are starting:");
8802 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008803 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008804 }
8805
8806 if (mRemovedProcesses.size() > 0) {
8807 if (needSep) pw.println(" ");
8808 needSep = true;
8809 pw.println(" Processes that are being removed:");
8810 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008811 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008812 }
8813
8814 if (mProcessesOnHold.size() > 0) {
8815 if (needSep) pw.println(" ");
8816 needSep = true;
8817 pw.println(" Processes that are on old until the system is ready:");
8818 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008819 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008820 }
8821
Dianne Hackbornfd12af42009-08-27 00:44:33 -07008822 if (mProcessesToGc.size() > 0) {
8823 if (needSep) pw.println(" ");
8824 needSep = true;
8825 pw.println(" Processes that are waiting to GC:");
8826 long now = SystemClock.uptimeMillis();
8827 for (int i=0; i<mProcessesToGc.size(); i++) {
8828 ProcessRecord proc = mProcessesToGc.get(i);
8829 pw.print(" Process "); pw.println(proc);
8830 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
8831 pw.print(", last gced=");
8832 pw.print(now-proc.lastRequestedGc);
8833 pw.print(" ms ago, last lowMwm=");
8834 pw.print(now-proc.lastLowMemory);
8835 pw.println(" ms ago");
8836
8837 }
8838 }
8839
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008840 if (mProcessCrashTimes.getMap().size() > 0) {
8841 if (needSep) pw.println(" ");
8842 needSep = true;
8843 pw.println(" Time since processes crashed:");
8844 long now = SystemClock.uptimeMillis();
8845 for (Map.Entry<String, SparseArray<Long>> procs
8846 : mProcessCrashTimes.getMap().entrySet()) {
8847 SparseArray<Long> uids = procs.getValue();
8848 final int N = uids.size();
8849 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008850 pw.print(" Process "); pw.print(procs.getKey());
8851 pw.print(" uid "); pw.print(uids.keyAt(i));
8852 pw.print(": last crashed ");
8853 pw.print((now-uids.valueAt(i)));
8854 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008855 }
8856 }
8857 }
8858
8859 if (mBadProcesses.getMap().size() > 0) {
8860 if (needSep) pw.println(" ");
8861 needSep = true;
8862 pw.println(" Bad processes:");
8863 for (Map.Entry<String, SparseArray<Long>> procs
8864 : mBadProcesses.getMap().entrySet()) {
8865 SparseArray<Long> uids = procs.getValue();
8866 final int N = uids.size();
8867 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008868 pw.print(" Bad process "); pw.print(procs.getKey());
8869 pw.print(" uid "); pw.print(uids.keyAt(i));
8870 pw.print(": crashed at time ");
8871 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008872 }
8873 }
8874 }
8875
8876 pw.println(" ");
8877 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008878 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008879 pw.println(" mConfiguration: " + mConfiguration);
8880 pw.println(" mStartRunning=" + mStartRunning
8881 + " mSystemReady=" + mSystemReady
8882 + " mBooting=" + mBooting
8883 + " mBooted=" + mBooted
8884 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008885 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008886 pw.println(" mGoingToSleep=" + mGoingToSleep);
8887 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8888 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8889 + " mDebugTransient=" + mDebugTransient
8890 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8891 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008892 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008893 }
8894 }
8895
8896 /**
8897 * There are three ways to call this:
8898 * - no service specified: dump all the services
8899 * - a flattened component name that matched an existing service was specified as the
8900 * first arg: dump that one service
8901 * - the first arg isn't the flattened component name of an existing service:
8902 * dump all services whose component contains the first arg as a substring
8903 */
8904 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8905 String[] newArgs;
8906 String componentNameString;
8907 ServiceRecord r;
8908 if (args.length == 1) {
8909 componentNameString = null;
8910 newArgs = EMPTY_STRING_ARRAY;
8911 r = null;
8912 } else {
8913 componentNameString = args[1];
8914 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8915 r = componentName != null ? mServices.get(componentName) : null;
8916 newArgs = new String[args.length - 2];
8917 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8918 }
8919
8920 if (r != null) {
8921 dumpService(fd, pw, r, newArgs);
8922 } else {
8923 for (ServiceRecord r1 : mServices.values()) {
8924 if (componentNameString == null
8925 || r1.name.flattenToString().contains(componentNameString)) {
8926 dumpService(fd, pw, r1, newArgs);
8927 }
8928 }
8929 }
8930 }
8931
8932 /**
8933 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8934 * there is a thread associated with the service.
8935 */
8936 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8937 pw.println(" Service " + r.name.flattenToString());
8938 if (r.app != null && r.app.thread != null) {
8939 try {
8940 // flush anything that is already in the PrintWriter since the thread is going
8941 // to write to the file descriptor directly
8942 pw.flush();
8943 r.app.thread.dumpService(fd, r, args);
8944 pw.print("\n");
8945 } catch (RemoteException e) {
8946 pw.println("got a RemoteException while dumping the service");
8947 }
8948 }
8949 }
8950
8951 void dumpBroadcasts(PrintWriter pw) {
8952 synchronized (this) {
8953 if (checkCallingPermission(android.Manifest.permission.DUMP)
8954 != PackageManager.PERMISSION_GRANTED) {
8955 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8956 + Binder.getCallingPid()
8957 + ", uid=" + Binder.getCallingUid()
8958 + " without permission "
8959 + android.Manifest.permission.DUMP);
8960 return;
8961 }
8962 pw.println("Broadcasts in Current Activity Manager State:");
8963
8964 if (mRegisteredReceivers.size() > 0) {
8965 pw.println(" ");
8966 pw.println(" Registered Receivers:");
8967 Iterator it = mRegisteredReceivers.values().iterator();
8968 while (it.hasNext()) {
8969 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008970 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008971 r.dump(pw, " ");
8972 }
8973 }
8974
8975 pw.println(" ");
8976 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008977 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008978
8979 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8980 || mPendingBroadcast != null) {
8981 if (mParallelBroadcasts.size() > 0) {
8982 pw.println(" ");
8983 pw.println(" Active broadcasts:");
8984 }
8985 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8986 pw.println(" Broadcast #" + i + ":");
8987 mParallelBroadcasts.get(i).dump(pw, " ");
8988 }
8989 if (mOrderedBroadcasts.size() > 0) {
8990 pw.println(" ");
8991 pw.println(" Active serialized broadcasts:");
8992 }
8993 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8994 pw.println(" Serialized Broadcast #" + i + ":");
8995 mOrderedBroadcasts.get(i).dump(pw, " ");
8996 }
8997 pw.println(" ");
8998 pw.println(" Pending broadcast:");
8999 if (mPendingBroadcast != null) {
9000 mPendingBroadcast.dump(pw, " ");
9001 } else {
9002 pw.println(" (null)");
9003 }
9004 }
9005
9006 pw.println(" ");
9007 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9008 if (mStickyBroadcasts != null) {
9009 pw.println(" ");
9010 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009011 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009012 for (Map.Entry<String, ArrayList<Intent>> ent
9013 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009014 pw.print(" * Sticky action "); pw.print(ent.getKey());
9015 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009016 ArrayList<Intent> intents = ent.getValue();
9017 final int N = intents.size();
9018 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009019 sb.setLength(0);
9020 sb.append(" Intent: ");
9021 intents.get(i).toShortString(sb, true, false);
9022 pw.println(sb.toString());
9023 Bundle bundle = intents.get(i).getExtras();
9024 if (bundle != null) {
9025 pw.print(" ");
9026 pw.println(bundle.toString());
9027 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009028 }
9029 }
9030 }
9031
9032 pw.println(" ");
9033 pw.println(" mHandler:");
9034 mHandler.dump(new PrintWriterPrinter(pw), " ");
9035 }
9036 }
9037
9038 void dumpServices(PrintWriter pw) {
9039 synchronized (this) {
9040 if (checkCallingPermission(android.Manifest.permission.DUMP)
9041 != PackageManager.PERMISSION_GRANTED) {
9042 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9043 + Binder.getCallingPid()
9044 + ", uid=" + Binder.getCallingUid()
9045 + " without permission "
9046 + android.Manifest.permission.DUMP);
9047 return;
9048 }
9049 pw.println("Services in Current Activity Manager State:");
9050
9051 boolean needSep = false;
9052
9053 if (mServices.size() > 0) {
9054 pw.println(" Active services:");
9055 Iterator<ServiceRecord> it = mServices.values().iterator();
9056 while (it.hasNext()) {
9057 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009058 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009059 r.dump(pw, " ");
9060 }
9061 needSep = true;
9062 }
9063
9064 if (mPendingServices.size() > 0) {
9065 if (needSep) pw.println(" ");
9066 pw.println(" Pending services:");
9067 for (int i=0; i<mPendingServices.size(); i++) {
9068 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009069 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009070 r.dump(pw, " ");
9071 }
9072 needSep = true;
9073 }
9074
9075 if (mRestartingServices.size() > 0) {
9076 if (needSep) pw.println(" ");
9077 pw.println(" Restarting services:");
9078 for (int i=0; i<mRestartingServices.size(); i++) {
9079 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009080 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009081 r.dump(pw, " ");
9082 }
9083 needSep = true;
9084 }
9085
9086 if (mStoppingServices.size() > 0) {
9087 if (needSep) pw.println(" ");
9088 pw.println(" Stopping services:");
9089 for (int i=0; i<mStoppingServices.size(); i++) {
9090 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009091 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009092 r.dump(pw, " ");
9093 }
9094 needSep = true;
9095 }
9096
9097 if (mServiceConnections.size() > 0) {
9098 if (needSep) pw.println(" ");
9099 pw.println(" Connection bindings to services:");
9100 Iterator<ConnectionRecord> it
9101 = mServiceConnections.values().iterator();
9102 while (it.hasNext()) {
9103 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009104 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009105 r.dump(pw, " ");
9106 }
9107 }
9108 }
9109 }
9110
9111 void dumpProviders(PrintWriter pw) {
9112 synchronized (this) {
9113 if (checkCallingPermission(android.Manifest.permission.DUMP)
9114 != PackageManager.PERMISSION_GRANTED) {
9115 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9116 + Binder.getCallingPid()
9117 + ", uid=" + Binder.getCallingUid()
9118 + " without permission "
9119 + android.Manifest.permission.DUMP);
9120 return;
9121 }
9122
9123 pw.println("Content Providers in Current Activity Manager State:");
9124
9125 boolean needSep = false;
9126
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009127 if (mProvidersByClass.size() > 0) {
9128 if (needSep) pw.println(" ");
9129 pw.println(" Published content providers (by class):");
9130 Iterator it = mProvidersByClass.entrySet().iterator();
9131 while (it.hasNext()) {
9132 Map.Entry e = (Map.Entry)it.next();
9133 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009134 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009135 r.dump(pw, " ");
9136 }
9137 needSep = true;
9138 }
9139
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009140 if (mProvidersByName.size() > 0) {
9141 pw.println(" ");
9142 pw.println(" Authority to provider mappings:");
9143 Iterator it = mProvidersByName.entrySet().iterator();
9144 while (it.hasNext()) {
9145 Map.Entry e = (Map.Entry)it.next();
9146 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9147 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9148 pw.println(r);
9149 }
9150 needSep = true;
9151 }
9152
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009153 if (mLaunchingProviders.size() > 0) {
9154 if (needSep) pw.println(" ");
9155 pw.println(" Launching content providers:");
9156 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009157 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9158 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009159 }
9160 needSep = true;
9161 }
9162
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009163 if (mGrantedUriPermissions.size() > 0) {
9164 pw.println();
9165 pw.println("Granted Uri Permissions:");
9166 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9167 int uid = mGrantedUriPermissions.keyAt(i);
9168 HashMap<Uri, UriPermission> perms
9169 = mGrantedUriPermissions.valueAt(i);
9170 pw.print(" * UID "); pw.print(uid);
9171 pw.println(" holds:");
9172 for (UriPermission perm : perms.values()) {
9173 pw.print(" "); pw.println(perm);
9174 perm.dump(pw, " ");
9175 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009176 }
9177 }
9178 }
9179 }
9180
9181 void dumpSenders(PrintWriter pw) {
9182 synchronized (this) {
9183 if (checkCallingPermission(android.Manifest.permission.DUMP)
9184 != PackageManager.PERMISSION_GRANTED) {
9185 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9186 + Binder.getCallingPid()
9187 + ", uid=" + Binder.getCallingUid()
9188 + " without permission "
9189 + android.Manifest.permission.DUMP);
9190 return;
9191 }
9192
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009193 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009194
9195 if (this.mIntentSenderRecords.size() > 0) {
9196 Iterator<WeakReference<PendingIntentRecord>> it
9197 = mIntentSenderRecords.values().iterator();
9198 while (it.hasNext()) {
9199 WeakReference<PendingIntentRecord> ref = it.next();
9200 PendingIntentRecord rec = ref != null ? ref.get(): null;
9201 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009202 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009203 rec.dump(pw, " ");
9204 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009205 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009206 }
9207 }
9208 }
9209 }
9210 }
9211
9212 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009213 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009214 TaskRecord lastTask = null;
9215 for (int i=list.size()-1; i>=0; i--) {
9216 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009217 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009218 if (lastTask != r.task) {
9219 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009220 pw.print(prefix);
9221 pw.print(full ? "* " : " ");
9222 pw.println(lastTask);
9223 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009224 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009225 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009226 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009227 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9228 pw.print(" #"); pw.print(i); pw.print(": ");
9229 pw.println(r);
9230 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009231 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009232 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009233 }
9234 }
9235
9236 private static final int dumpProcessList(PrintWriter pw, List list,
9237 String prefix, String normalLabel, String persistentLabel,
9238 boolean inclOomAdj) {
9239 int numPers = 0;
9240 for (int i=list.size()-1; i>=0; i--) {
9241 ProcessRecord r = (ProcessRecord)list.get(i);
9242 if (false) {
9243 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9244 + " #" + i + ":");
9245 r.dump(pw, prefix + " ");
9246 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009247 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009248 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009249 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9250 if (r.adjSource != null || r.adjTarget != null) {
9251 pw.println(prefix + " " + r.adjTarget
9252 + " used by " + r.adjSource);
9253 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009254 } else {
9255 pw.println(String.format("%s%s #%2d: %s",
9256 prefix, (r.persistent ? persistentLabel : normalLabel),
9257 i, r.toString()));
9258 }
9259 if (r.persistent) {
9260 numPers++;
9261 }
9262 }
9263 return numPers;
9264 }
9265
9266 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9267 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009268 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009269 long uptime = SystemClock.uptimeMillis();
9270 long realtime = SystemClock.elapsedRealtime();
9271
9272 if (isCheckinRequest) {
9273 // short checkin version
9274 pw.println(uptime + "," + realtime);
9275 pw.flush();
9276 } else {
9277 pw.println("Applications Memory Usage (kB):");
9278 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9279 }
9280 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9281 ProcessRecord r = (ProcessRecord)list.get(i);
9282 if (r.thread != null) {
9283 if (!isCheckinRequest) {
9284 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9285 pw.flush();
9286 }
9287 try {
9288 r.thread.asBinder().dump(fd, args);
9289 } catch (RemoteException e) {
9290 if (!isCheckinRequest) {
9291 pw.println("Got RemoteException!");
9292 pw.flush();
9293 }
9294 }
9295 }
9296 }
9297 }
9298
9299 /**
9300 * Searches array of arguments for the specified string
9301 * @param args array of argument strings
9302 * @param value value to search for
9303 * @return true if the value is contained in the array
9304 */
9305 private static boolean scanArgs(String[] args, String value) {
9306 if (args != null) {
9307 for (String arg : args) {
9308 if (value.equals(arg)) {
9309 return true;
9310 }
9311 }
9312 }
9313 return false;
9314 }
9315
Dianne Hackborn75b03852009-06-12 15:43:26 -07009316 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009317 int count = mHistory.size();
9318
9319 // convert the token to an entry in the history.
9320 HistoryRecord r = null;
9321 int index = -1;
9322 for (int i=count-1; i>=0; i--) {
9323 Object o = mHistory.get(i);
9324 if (o == token) {
9325 r = (HistoryRecord)o;
9326 index = i;
9327 break;
9328 }
9329 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009330
9331 return index;
9332 }
9333
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009334 private final void killServicesLocked(ProcessRecord app,
9335 boolean allowRestart) {
9336 // Report disconnected services.
9337 if (false) {
9338 // XXX we are letting the client link to the service for
9339 // death notifications.
9340 if (app.services.size() > 0) {
9341 Iterator it = app.services.iterator();
9342 while (it.hasNext()) {
9343 ServiceRecord r = (ServiceRecord)it.next();
9344 if (r.connections.size() > 0) {
9345 Iterator<ConnectionRecord> jt
9346 = r.connections.values().iterator();
9347 while (jt.hasNext()) {
9348 ConnectionRecord c = jt.next();
9349 if (c.binding.client != app) {
9350 try {
9351 //c.conn.connected(r.className, null);
9352 } catch (Exception e) {
9353 // todo: this should be asynchronous!
9354 Log.w(TAG, "Exception thrown disconnected servce "
9355 + r.shortName
9356 + " from app " + app.processName, e);
9357 }
9358 }
9359 }
9360 }
9361 }
9362 }
9363 }
9364
9365 // Clean up any connections this application has to other services.
9366 if (app.connections.size() > 0) {
9367 Iterator<ConnectionRecord> it = app.connections.iterator();
9368 while (it.hasNext()) {
9369 ConnectionRecord r = it.next();
9370 removeConnectionLocked(r, app, null);
9371 }
9372 }
9373 app.connections.clear();
9374
9375 if (app.services.size() != 0) {
9376 // Any services running in the application need to be placed
9377 // back in the pending list.
9378 Iterator it = app.services.iterator();
9379 while (it.hasNext()) {
9380 ServiceRecord sr = (ServiceRecord)it.next();
9381 synchronized (sr.stats.getBatteryStats()) {
9382 sr.stats.stopLaunchedLocked();
9383 }
9384 sr.app = null;
9385 sr.executeNesting = 0;
9386 mStoppingServices.remove(sr);
9387 if (sr.bindings.size() > 0) {
9388 Iterator<IntentBindRecord> bindings
9389 = sr.bindings.values().iterator();
9390 while (bindings.hasNext()) {
9391 IntentBindRecord b = bindings.next();
9392 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9393 + ": shouldUnbind=" + b.hasBound);
9394 b.binder = null;
9395 b.requested = b.received = b.hasBound = false;
9396 }
9397 }
9398
9399 if (sr.crashCount >= 2) {
9400 Log.w(TAG, "Service crashed " + sr.crashCount
9401 + " times, stopping: " + sr);
9402 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9403 sr.crashCount, sr.shortName, app.pid);
9404 bringDownServiceLocked(sr, true);
9405 } else if (!allowRestart) {
9406 bringDownServiceLocked(sr, true);
9407 } else {
9408 scheduleServiceRestartLocked(sr);
9409 }
9410 }
9411
9412 if (!allowRestart) {
9413 app.services.clear();
9414 }
9415 }
9416
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009417 // Make sure we have no more records on the stopping list.
9418 int i = mStoppingServices.size();
9419 while (i > 0) {
9420 i--;
9421 ServiceRecord sr = mStoppingServices.get(i);
9422 if (sr.app == app) {
9423 mStoppingServices.remove(i);
9424 }
9425 }
9426
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009427 app.executingServices.clear();
9428 }
9429
9430 private final void removeDyingProviderLocked(ProcessRecord proc,
9431 ContentProviderRecord cpr) {
9432 synchronized (cpr) {
9433 cpr.launchingApp = null;
9434 cpr.notifyAll();
9435 }
9436
9437 mProvidersByClass.remove(cpr.info.name);
9438 String names[] = cpr.info.authority.split(";");
9439 for (int j = 0; j < names.length; j++) {
9440 mProvidersByName.remove(names[j]);
9441 }
9442
9443 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9444 while (cit.hasNext()) {
9445 ProcessRecord capp = cit.next();
9446 if (!capp.persistent && capp.thread != null
9447 && capp.pid != 0
9448 && capp.pid != MY_PID) {
9449 Log.i(TAG, "Killing app " + capp.processName
9450 + " (pid " + capp.pid
9451 + ") because provider " + cpr.info.name
9452 + " is in dying process " + proc.processName);
9453 Process.killProcess(capp.pid);
9454 }
9455 }
9456
9457 mLaunchingProviders.remove(cpr);
9458 }
9459
9460 /**
9461 * Main code for cleaning up a process when it has gone away. This is
9462 * called both as a result of the process dying, or directly when stopping
9463 * a process when running in single process mode.
9464 */
9465 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9466 boolean restarting, int index) {
9467 if (index >= 0) {
9468 mLRUProcesses.remove(index);
9469 }
9470
9471 // Dismiss any open dialogs.
9472 if (app.crashDialog != null) {
9473 app.crashDialog.dismiss();
9474 app.crashDialog = null;
9475 }
9476 if (app.anrDialog != null) {
9477 app.anrDialog.dismiss();
9478 app.anrDialog = null;
9479 }
9480 if (app.waitDialog != null) {
9481 app.waitDialog.dismiss();
9482 app.waitDialog = null;
9483 }
9484
9485 app.crashing = false;
9486 app.notResponding = false;
9487
9488 app.resetPackageList();
9489 app.thread = null;
9490 app.forcingToForeground = null;
9491 app.foregroundServices = false;
9492
9493 killServicesLocked(app, true);
9494
9495 boolean restart = false;
9496
9497 int NL = mLaunchingProviders.size();
9498
9499 // Remove published content providers.
9500 if (!app.pubProviders.isEmpty()) {
9501 Iterator it = app.pubProviders.values().iterator();
9502 while (it.hasNext()) {
9503 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9504 cpr.provider = null;
9505 cpr.app = null;
9506
9507 // See if someone is waiting for this provider... in which
9508 // case we don't remove it, but just let it restart.
9509 int i = 0;
9510 if (!app.bad) {
9511 for (; i<NL; i++) {
9512 if (mLaunchingProviders.get(i) == cpr) {
9513 restart = true;
9514 break;
9515 }
9516 }
9517 } else {
9518 i = NL;
9519 }
9520
9521 if (i >= NL) {
9522 removeDyingProviderLocked(app, cpr);
9523 NL = mLaunchingProviders.size();
9524 }
9525 }
9526 app.pubProviders.clear();
9527 }
9528
9529 // Look through the content providers we are waiting to have launched,
9530 // and if any run in this process then either schedule a restart of
9531 // the process or kill the client waiting for it if this process has
9532 // gone bad.
9533 for (int i=0; i<NL; i++) {
9534 ContentProviderRecord cpr = (ContentProviderRecord)
9535 mLaunchingProviders.get(i);
9536 if (cpr.launchingApp == app) {
9537 if (!app.bad) {
9538 restart = true;
9539 } else {
9540 removeDyingProviderLocked(app, cpr);
9541 NL = mLaunchingProviders.size();
9542 }
9543 }
9544 }
9545
9546 // Unregister from connected content providers.
9547 if (!app.conProviders.isEmpty()) {
9548 Iterator it = app.conProviders.iterator();
9549 while (it.hasNext()) {
9550 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9551 cpr.clients.remove(app);
9552 }
9553 app.conProviders.clear();
9554 }
9555
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009556 // At this point there may be remaining entries in mLaunchingProviders
9557 // where we were the only one waiting, so they are no longer of use.
9558 // Look for these and clean up if found.
9559 // XXX Commented out for now. Trying to figure out a way to reproduce
9560 // the actual situation to identify what is actually going on.
9561 if (false) {
9562 for (int i=0; i<NL; i++) {
9563 ContentProviderRecord cpr = (ContentProviderRecord)
9564 mLaunchingProviders.get(i);
9565 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9566 synchronized (cpr) {
9567 cpr.launchingApp = null;
9568 cpr.notifyAll();
9569 }
9570 }
9571 }
9572 }
9573
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009574 skipCurrentReceiverLocked(app);
9575
9576 // Unregister any receivers.
9577 if (app.receivers.size() > 0) {
9578 Iterator<ReceiverList> it = app.receivers.iterator();
9579 while (it.hasNext()) {
9580 removeReceiverLocked(it.next());
9581 }
9582 app.receivers.clear();
9583 }
9584
Christopher Tate181fafa2009-05-14 11:12:14 -07009585 // If the app is undergoing backup, tell the backup manager about it
9586 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9587 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9588 try {
9589 IBackupManager bm = IBackupManager.Stub.asInterface(
9590 ServiceManager.getService(Context.BACKUP_SERVICE));
9591 bm.agentDisconnected(app.info.packageName);
9592 } catch (RemoteException e) {
9593 // can't happen; backup manager is local
9594 }
9595 }
9596
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009597 // If the caller is restarting this app, then leave it in its
9598 // current lists and let the caller take care of it.
9599 if (restarting) {
9600 return;
9601 }
9602
9603 if (!app.persistent) {
9604 if (DEBUG_PROCESSES) Log.v(TAG,
9605 "Removing non-persistent process during cleanup: " + app);
9606 mProcessNames.remove(app.processName, app.info.uid);
9607 } else if (!app.removed) {
9608 // This app is persistent, so we need to keep its record around.
9609 // If it is not already on the pending app list, add it there
9610 // and start a new process for it.
9611 app.thread = null;
9612 app.forcingToForeground = null;
9613 app.foregroundServices = false;
9614 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9615 mPersistentStartingProcesses.add(app);
9616 restart = true;
9617 }
9618 }
9619 mProcessesOnHold.remove(app);
9620
The Android Open Source Project4df24232009-03-05 14:34:35 -08009621 if (app == mHomeProcess) {
9622 mHomeProcess = null;
9623 }
9624
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009625 if (restart) {
9626 // We have components that still need to be running in the
9627 // process, so re-launch it.
9628 mProcessNames.put(app.processName, app.info.uid, app);
9629 startProcessLocked(app, "restart", app.processName);
9630 } else if (app.pid > 0 && app.pid != MY_PID) {
9631 // Goodbye!
9632 synchronized (mPidsSelfLocked) {
9633 mPidsSelfLocked.remove(app.pid);
9634 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9635 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009636 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009637 }
9638 }
9639
9640 // =========================================================
9641 // SERVICES
9642 // =========================================================
9643
9644 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9645 ActivityManager.RunningServiceInfo info =
9646 new ActivityManager.RunningServiceInfo();
9647 info.service = r.name;
9648 if (r.app != null) {
9649 info.pid = r.app.pid;
9650 }
9651 info.process = r.processName;
9652 info.foreground = r.isForeground;
9653 info.activeSince = r.createTime;
9654 info.started = r.startRequested;
9655 info.clientCount = r.connections.size();
9656 info.crashCount = r.crashCount;
9657 info.lastActivityTime = r.lastActivity;
9658 return info;
9659 }
9660
9661 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9662 int flags) {
9663 synchronized (this) {
9664 ArrayList<ActivityManager.RunningServiceInfo> res
9665 = new ArrayList<ActivityManager.RunningServiceInfo>();
9666
9667 if (mServices.size() > 0) {
9668 Iterator<ServiceRecord> it = mServices.values().iterator();
9669 while (it.hasNext() && res.size() < maxNum) {
9670 res.add(makeRunningServiceInfoLocked(it.next()));
9671 }
9672 }
9673
9674 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9675 ServiceRecord r = mRestartingServices.get(i);
9676 ActivityManager.RunningServiceInfo info =
9677 makeRunningServiceInfoLocked(r);
9678 info.restarting = r.nextRestartTime;
9679 res.add(info);
9680 }
9681
9682 return res;
9683 }
9684 }
9685
9686 private final ServiceRecord findServiceLocked(ComponentName name,
9687 IBinder token) {
9688 ServiceRecord r = mServices.get(name);
9689 return r == token ? r : null;
9690 }
9691
9692 private final class ServiceLookupResult {
9693 final ServiceRecord record;
9694 final String permission;
9695
9696 ServiceLookupResult(ServiceRecord _record, String _permission) {
9697 record = _record;
9698 permission = _permission;
9699 }
9700 };
9701
9702 private ServiceLookupResult findServiceLocked(Intent service,
9703 String resolvedType) {
9704 ServiceRecord r = null;
9705 if (service.getComponent() != null) {
9706 r = mServices.get(service.getComponent());
9707 }
9708 if (r == null) {
9709 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9710 r = mServicesByIntent.get(filter);
9711 }
9712
9713 if (r == null) {
9714 try {
9715 ResolveInfo rInfo =
9716 ActivityThread.getPackageManager().resolveService(
9717 service, resolvedType, 0);
9718 ServiceInfo sInfo =
9719 rInfo != null ? rInfo.serviceInfo : null;
9720 if (sInfo == null) {
9721 return null;
9722 }
9723
9724 ComponentName name = new ComponentName(
9725 sInfo.applicationInfo.packageName, sInfo.name);
9726 r = mServices.get(name);
9727 } catch (RemoteException ex) {
9728 // pm is in same process, this will never happen.
9729 }
9730 }
9731 if (r != null) {
9732 int callingPid = Binder.getCallingPid();
9733 int callingUid = Binder.getCallingUid();
9734 if (checkComponentPermission(r.permission,
9735 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9736 != PackageManager.PERMISSION_GRANTED) {
9737 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9738 + " from pid=" + callingPid
9739 + ", uid=" + callingUid
9740 + " requires " + r.permission);
9741 return new ServiceLookupResult(null, r.permission);
9742 }
9743 return new ServiceLookupResult(r, null);
9744 }
9745 return null;
9746 }
9747
9748 private class ServiceRestarter implements Runnable {
9749 private ServiceRecord mService;
9750
9751 void setService(ServiceRecord service) {
9752 mService = service;
9753 }
9754
9755 public void run() {
9756 synchronized(ActivityManagerService.this) {
9757 performServiceRestartLocked(mService);
9758 }
9759 }
9760 }
9761
9762 private ServiceLookupResult retrieveServiceLocked(Intent service,
9763 String resolvedType, int callingPid, int callingUid) {
9764 ServiceRecord r = null;
9765 if (service.getComponent() != null) {
9766 r = mServices.get(service.getComponent());
9767 }
9768 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9769 r = mServicesByIntent.get(filter);
9770 if (r == null) {
9771 try {
9772 ResolveInfo rInfo =
9773 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009774 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009775 ServiceInfo sInfo =
9776 rInfo != null ? rInfo.serviceInfo : null;
9777 if (sInfo == null) {
9778 Log.w(TAG, "Unable to start service " + service +
9779 ": not found");
9780 return null;
9781 }
9782
9783 ComponentName name = new ComponentName(
9784 sInfo.applicationInfo.packageName, sInfo.name);
9785 r = mServices.get(name);
9786 if (r == null) {
9787 filter = new Intent.FilterComparison(service.cloneFilter());
9788 ServiceRestarter res = new ServiceRestarter();
9789 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9790 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9791 synchronized (stats) {
9792 ss = stats.getServiceStatsLocked(
9793 sInfo.applicationInfo.uid, sInfo.packageName,
9794 sInfo.name);
9795 }
9796 r = new ServiceRecord(ss, name, filter, sInfo, res);
9797 res.setService(r);
9798 mServices.put(name, r);
9799 mServicesByIntent.put(filter, r);
9800
9801 // Make sure this component isn't in the pending list.
9802 int N = mPendingServices.size();
9803 for (int i=0; i<N; i++) {
9804 ServiceRecord pr = mPendingServices.get(i);
9805 if (pr.name.equals(name)) {
9806 mPendingServices.remove(i);
9807 i--;
9808 N--;
9809 }
9810 }
9811 }
9812 } catch (RemoteException ex) {
9813 // pm is in same process, this will never happen.
9814 }
9815 }
9816 if (r != null) {
9817 if (checkComponentPermission(r.permission,
9818 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9819 != PackageManager.PERMISSION_GRANTED) {
9820 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9821 + " from pid=" + Binder.getCallingPid()
9822 + ", uid=" + Binder.getCallingUid()
9823 + " requires " + r.permission);
9824 return new ServiceLookupResult(null, r.permission);
9825 }
9826 return new ServiceLookupResult(r, null);
9827 }
9828 return null;
9829 }
9830
9831 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9832 long now = SystemClock.uptimeMillis();
9833 if (r.executeNesting == 0 && r.app != null) {
9834 if (r.app.executingServices.size() == 0) {
9835 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9836 msg.obj = r.app;
9837 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9838 }
9839 r.app.executingServices.add(r);
9840 }
9841 r.executeNesting++;
9842 r.executingStart = now;
9843 }
9844
9845 private final void sendServiceArgsLocked(ServiceRecord r,
9846 boolean oomAdjusted) {
9847 final int N = r.startArgs.size();
9848 if (N == 0) {
9849 return;
9850 }
9851
9852 final int BASEID = r.lastStartId - N + 1;
9853 int i = 0;
9854 while (i < N) {
9855 try {
9856 Intent args = r.startArgs.get(i);
9857 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9858 + r.name + " " + r.intent + " args=" + args);
9859 bumpServiceExecutingLocked(r);
9860 if (!oomAdjusted) {
9861 oomAdjusted = true;
9862 updateOomAdjLocked(r.app);
9863 }
9864 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9865 i++;
9866 } catch (Exception e) {
9867 break;
9868 }
9869 }
9870 if (i == N) {
9871 r.startArgs.clear();
9872 } else {
9873 while (i > 0) {
9874 r.startArgs.remove(0);
9875 i--;
9876 }
9877 }
9878 }
9879
9880 private final boolean requestServiceBindingLocked(ServiceRecord r,
9881 IntentBindRecord i, boolean rebind) {
9882 if (r.app == null || r.app.thread == null) {
9883 // If service is not currently running, can't yet bind.
9884 return false;
9885 }
9886 if ((!i.requested || rebind) && i.apps.size() > 0) {
9887 try {
9888 bumpServiceExecutingLocked(r);
9889 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9890 + ": shouldUnbind=" + i.hasBound);
9891 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9892 if (!rebind) {
9893 i.requested = true;
9894 }
9895 i.hasBound = true;
9896 i.doRebind = false;
9897 } catch (RemoteException e) {
9898 return false;
9899 }
9900 }
9901 return true;
9902 }
9903
9904 private final void requestServiceBindingsLocked(ServiceRecord r) {
9905 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9906 while (bindings.hasNext()) {
9907 IntentBindRecord i = bindings.next();
9908 if (!requestServiceBindingLocked(r, i, false)) {
9909 break;
9910 }
9911 }
9912 }
9913
9914 private final void realStartServiceLocked(ServiceRecord r,
9915 ProcessRecord app) throws RemoteException {
9916 if (app.thread == null) {
9917 throw new RemoteException();
9918 }
9919
9920 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009921 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009922
9923 app.services.add(r);
9924 bumpServiceExecutingLocked(r);
9925 updateLRUListLocked(app, true);
9926
9927 boolean created = false;
9928 try {
9929 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9930 + r.name + " " + r.intent);
9931 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9932 System.identityHashCode(r), r.shortName,
9933 r.intent.getIntent().toString(), r.app.pid);
9934 synchronized (r.stats.getBatteryStats()) {
9935 r.stats.startLaunchedLocked();
9936 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07009937 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009938 app.thread.scheduleCreateService(r, r.serviceInfo);
9939 created = true;
9940 } finally {
9941 if (!created) {
9942 app.services.remove(r);
9943 scheduleServiceRestartLocked(r);
9944 }
9945 }
9946
9947 requestServiceBindingsLocked(r);
9948 sendServiceArgsLocked(r, true);
9949 }
9950
9951 private final void scheduleServiceRestartLocked(ServiceRecord r) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009952 final long now = SystemClock.uptimeMillis();
9953
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009954 r.totalRestartCount++;
9955 if (r.restartDelay == 0) {
9956 r.restartCount++;
9957 r.restartDelay = SERVICE_RESTART_DURATION;
9958 } else {
9959 // If it has been a "reasonably long time" since the service
9960 // was started, then reset our restart duration back to
9961 // the beginning, so we don't infinitely increase the duration
9962 // on a service that just occasionally gets killed (which is
9963 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009964 if (now > (r.restartTime+SERVICE_RESET_RUN_DURATION)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009965 r.restartCount = 1;
9966 r.restartDelay = SERVICE_RESTART_DURATION;
9967 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009968 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009969 }
9970 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009971
9972 r.nextRestartTime = now + r.restartDelay;
9973
9974 // Make sure that we don't end up restarting a bunch of services
9975 // all at the same time.
9976 boolean repeat;
9977 do {
9978 repeat = false;
9979 for (int i=mRestartingServices.size()-1; i>=0; i--) {
9980 ServiceRecord r2 = mRestartingServices.get(i);
9981 if (r2 != r && r.nextRestartTime
9982 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
9983 && r.nextRestartTime
9984 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
9985 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
9986 r.restartDelay = r.nextRestartTime - now;
9987 repeat = true;
9988 break;
9989 }
9990 }
9991 } while (repeat);
9992
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009993 if (!mRestartingServices.contains(r)) {
9994 mRestartingServices.add(r);
9995 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009996
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009997 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009998 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009999 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10000 Log.w(TAG, "Scheduling restart of crashed service "
10001 + r.shortName + " in " + r.restartDelay + "ms");
10002 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10003 r.shortName, r.restartDelay);
10004
10005 Message msg = Message.obtain();
10006 msg.what = SERVICE_ERROR_MSG;
10007 msg.obj = r;
10008 mHandler.sendMessage(msg);
10009 }
10010
10011 final void performServiceRestartLocked(ServiceRecord r) {
10012 if (!mRestartingServices.contains(r)) {
10013 return;
10014 }
10015 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10016 }
10017
10018 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10019 if (r.restartDelay == 0) {
10020 return false;
10021 }
10022 r.resetRestartCounter();
10023 mRestartingServices.remove(r);
10024 mHandler.removeCallbacks(r.restarter);
10025 return true;
10026 }
10027
10028 private final boolean bringUpServiceLocked(ServiceRecord r,
10029 int intentFlags, boolean whileRestarting) {
10030 //Log.i(TAG, "Bring up service:");
10031 //r.dump(" ");
10032
10033 if (r.app != null) {
10034 sendServiceArgsLocked(r, false);
10035 return true;
10036 }
10037
10038 if (!whileRestarting && r.restartDelay > 0) {
10039 // If waiting for a restart, then do nothing.
10040 return true;
10041 }
10042
10043 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10044 + " " + r.intent);
10045
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010046 // We are now bringing the service up, so no longer in the
10047 // restarting state.
10048 mRestartingServices.remove(r);
10049
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010050 final String appName = r.processName;
10051 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10052 if (app != null && app.thread != null) {
10053 try {
10054 realStartServiceLocked(r, app);
10055 return true;
10056 } catch (RemoteException e) {
10057 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10058 }
10059
10060 // If a dead object exception was thrown -- fall through to
10061 // restart the application.
10062 }
10063
10064 if (!mPendingServices.contains(r)) {
10065 // Not running -- get it started, and enqueue this service record
10066 // to be executed when the app comes up.
10067 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10068 "service", r.name) == null) {
10069 Log.w(TAG, "Unable to launch app "
10070 + r.appInfo.packageName + "/"
10071 + r.appInfo.uid + " for service "
10072 + r.intent.getIntent() + ": process is bad");
10073 bringDownServiceLocked(r, true);
10074 return false;
10075 }
10076 mPendingServices.add(r);
10077 }
10078 return true;
10079 }
10080
10081 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10082 //Log.i(TAG, "Bring down service:");
10083 //r.dump(" ");
10084
10085 // Does it still need to run?
10086 if (!force && r.startRequested) {
10087 return;
10088 }
10089 if (r.connections.size() > 0) {
10090 if (!force) {
10091 // XXX should probably keep a count of the number of auto-create
10092 // connections directly in the service.
10093 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10094 while (it.hasNext()) {
10095 ConnectionRecord cr = it.next();
10096 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10097 return;
10098 }
10099 }
10100 }
10101
10102 // Report to all of the connections that the service is no longer
10103 // available.
10104 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10105 while (it.hasNext()) {
10106 ConnectionRecord c = it.next();
10107 try {
10108 // todo: shouldn't be a synchronous call!
10109 c.conn.connected(r.name, null);
10110 } catch (Exception e) {
10111 Log.w(TAG, "Failure disconnecting service " + r.name +
10112 " to connection " + c.conn.asBinder() +
10113 " (in " + c.binding.client.processName + ")", e);
10114 }
10115 }
10116 }
10117
10118 // Tell the service that it has been unbound.
10119 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10120 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10121 while (it.hasNext()) {
10122 IntentBindRecord ibr = it.next();
10123 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10124 + ": hasBound=" + ibr.hasBound);
10125 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10126 try {
10127 bumpServiceExecutingLocked(r);
10128 updateOomAdjLocked(r.app);
10129 ibr.hasBound = false;
10130 r.app.thread.scheduleUnbindService(r,
10131 ibr.intent.getIntent());
10132 } catch (Exception e) {
10133 Log.w(TAG, "Exception when unbinding service "
10134 + r.shortName, e);
10135 serviceDoneExecutingLocked(r, true);
10136 }
10137 }
10138 }
10139 }
10140
10141 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10142 + " " + r.intent);
10143 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10144 System.identityHashCode(r), r.shortName,
10145 (r.app != null) ? r.app.pid : -1);
10146
10147 mServices.remove(r.name);
10148 mServicesByIntent.remove(r.intent);
10149 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10150 r.totalRestartCount = 0;
10151 unscheduleServiceRestartLocked(r);
10152
10153 // Also make sure it is not on the pending list.
10154 int N = mPendingServices.size();
10155 for (int i=0; i<N; i++) {
10156 if (mPendingServices.get(i) == r) {
10157 mPendingServices.remove(i);
10158 if (DEBUG_SERVICE) Log.v(
10159 TAG, "Removed pending service: " + r.shortName);
10160 i--;
10161 N--;
10162 }
10163 }
10164
10165 if (r.app != null) {
10166 synchronized (r.stats.getBatteryStats()) {
10167 r.stats.stopLaunchedLocked();
10168 }
10169 r.app.services.remove(r);
10170 if (r.app.thread != null) {
10171 updateServiceForegroundLocked(r.app, false);
10172 try {
10173 Log.i(TAG, "Stopping service: " + r.shortName);
10174 bumpServiceExecutingLocked(r);
10175 mStoppingServices.add(r);
10176 updateOomAdjLocked(r.app);
10177 r.app.thread.scheduleStopService(r);
10178 } catch (Exception e) {
10179 Log.w(TAG, "Exception when stopping service "
10180 + r.shortName, e);
10181 serviceDoneExecutingLocked(r, true);
10182 }
10183 } else {
10184 if (DEBUG_SERVICE) Log.v(
10185 TAG, "Removed service that has no process: " + r.shortName);
10186 }
10187 } else {
10188 if (DEBUG_SERVICE) Log.v(
10189 TAG, "Removed service that is not running: " + r.shortName);
10190 }
10191 }
10192
10193 ComponentName startServiceLocked(IApplicationThread caller,
10194 Intent service, String resolvedType,
10195 int callingPid, int callingUid) {
10196 synchronized(this) {
10197 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10198 + " type=" + resolvedType + " args=" + service.getExtras());
10199
10200 if (caller != null) {
10201 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10202 if (callerApp == null) {
10203 throw new SecurityException(
10204 "Unable to find app for caller " + caller
10205 + " (pid=" + Binder.getCallingPid()
10206 + ") when starting service " + service);
10207 }
10208 }
10209
10210 ServiceLookupResult res =
10211 retrieveServiceLocked(service, resolvedType,
10212 callingPid, callingUid);
10213 if (res == null) {
10214 return null;
10215 }
10216 if (res.record == null) {
10217 return new ComponentName("!", res.permission != null
10218 ? res.permission : "private to package");
10219 }
10220 ServiceRecord r = res.record;
10221 if (unscheduleServiceRestartLocked(r)) {
10222 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10223 + r.shortName);
10224 }
10225 r.startRequested = true;
10226 r.startArgs.add(service);
10227 r.lastStartId++;
10228 if (r.lastStartId < 1) {
10229 r.lastStartId = 1;
10230 }
10231 r.lastActivity = SystemClock.uptimeMillis();
10232 synchronized (r.stats.getBatteryStats()) {
10233 r.stats.startRunningLocked();
10234 }
10235 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10236 return new ComponentName("!", "Service process is bad");
10237 }
10238 return r.name;
10239 }
10240 }
10241
10242 public ComponentName startService(IApplicationThread caller, Intent service,
10243 String resolvedType) {
10244 // Refuse possible leaked file descriptors
10245 if (service != null && service.hasFileDescriptors() == true) {
10246 throw new IllegalArgumentException("File descriptors passed in Intent");
10247 }
10248
10249 synchronized(this) {
10250 final int callingPid = Binder.getCallingPid();
10251 final int callingUid = Binder.getCallingUid();
10252 final long origId = Binder.clearCallingIdentity();
10253 ComponentName res = startServiceLocked(caller, service,
10254 resolvedType, callingPid, callingUid);
10255 Binder.restoreCallingIdentity(origId);
10256 return res;
10257 }
10258 }
10259
10260 ComponentName startServiceInPackage(int uid,
10261 Intent service, String resolvedType) {
10262 synchronized(this) {
10263 final long origId = Binder.clearCallingIdentity();
10264 ComponentName res = startServiceLocked(null, service,
10265 resolvedType, -1, uid);
10266 Binder.restoreCallingIdentity(origId);
10267 return res;
10268 }
10269 }
10270
10271 public int stopService(IApplicationThread caller, Intent service,
10272 String resolvedType) {
10273 // Refuse possible leaked file descriptors
10274 if (service != null && service.hasFileDescriptors() == true) {
10275 throw new IllegalArgumentException("File descriptors passed in Intent");
10276 }
10277
10278 synchronized(this) {
10279 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10280 + " type=" + resolvedType);
10281
10282 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10283 if (caller != null && callerApp == null) {
10284 throw new SecurityException(
10285 "Unable to find app for caller " + caller
10286 + " (pid=" + Binder.getCallingPid()
10287 + ") when stopping service " + service);
10288 }
10289
10290 // If this service is active, make sure it is stopped.
10291 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10292 if (r != null) {
10293 if (r.record != null) {
10294 synchronized (r.record.stats.getBatteryStats()) {
10295 r.record.stats.stopRunningLocked();
10296 }
10297 r.record.startRequested = false;
10298 final long origId = Binder.clearCallingIdentity();
10299 bringDownServiceLocked(r.record, false);
10300 Binder.restoreCallingIdentity(origId);
10301 return 1;
10302 }
10303 return -1;
10304 }
10305 }
10306
10307 return 0;
10308 }
10309
10310 public IBinder peekService(Intent service, String resolvedType) {
10311 // Refuse possible leaked file descriptors
10312 if (service != null && service.hasFileDescriptors() == true) {
10313 throw new IllegalArgumentException("File descriptors passed in Intent");
10314 }
10315
10316 IBinder ret = null;
10317
10318 synchronized(this) {
10319 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10320
10321 if (r != null) {
10322 // r.record is null if findServiceLocked() failed the caller permission check
10323 if (r.record == null) {
10324 throw new SecurityException(
10325 "Permission Denial: Accessing service " + r.record.name
10326 + " from pid=" + Binder.getCallingPid()
10327 + ", uid=" + Binder.getCallingUid()
10328 + " requires " + r.permission);
10329 }
10330 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10331 if (ib != null) {
10332 ret = ib.binder;
10333 }
10334 }
10335 }
10336
10337 return ret;
10338 }
10339
10340 public boolean stopServiceToken(ComponentName className, IBinder token,
10341 int startId) {
10342 synchronized(this) {
10343 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10344 + " " + token + " startId=" + startId);
10345 ServiceRecord r = findServiceLocked(className, token);
10346 if (r != null && (startId < 0 || r.lastStartId == startId)) {
10347 synchronized (r.stats.getBatteryStats()) {
10348 r.stats.stopRunningLocked();
10349 r.startRequested = false;
10350 }
10351 final long origId = Binder.clearCallingIdentity();
10352 bringDownServiceLocked(r, false);
10353 Binder.restoreCallingIdentity(origId);
10354 return true;
10355 }
10356 }
10357 return false;
10358 }
10359
10360 public void setServiceForeground(ComponentName className, IBinder token,
10361 boolean isForeground) {
10362 synchronized(this) {
10363 ServiceRecord r = findServiceLocked(className, token);
10364 if (r != null) {
10365 if (r.isForeground != isForeground) {
10366 final long origId = Binder.clearCallingIdentity();
10367 r.isForeground = isForeground;
10368 if (r.app != null) {
10369 updateServiceForegroundLocked(r.app, true);
10370 }
10371 Binder.restoreCallingIdentity(origId);
10372 }
10373 }
10374 }
10375 }
10376
10377 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10378 boolean anyForeground = false;
10379 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10380 if (sr.isForeground) {
10381 anyForeground = true;
10382 break;
10383 }
10384 }
10385 if (anyForeground != proc.foregroundServices) {
10386 proc.foregroundServices = anyForeground;
10387 if (oomAdj) {
10388 updateOomAdjLocked();
10389 }
10390 }
10391 }
10392
10393 public int bindService(IApplicationThread caller, IBinder token,
10394 Intent service, String resolvedType,
10395 IServiceConnection connection, int flags) {
10396 // Refuse possible leaked file descriptors
10397 if (service != null && service.hasFileDescriptors() == true) {
10398 throw new IllegalArgumentException("File descriptors passed in Intent");
10399 }
10400
10401 synchronized(this) {
10402 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10403 + " type=" + resolvedType + " conn=" + connection.asBinder()
10404 + " flags=0x" + Integer.toHexString(flags));
10405 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10406 if (callerApp == null) {
10407 throw new SecurityException(
10408 "Unable to find app for caller " + caller
10409 + " (pid=" + Binder.getCallingPid()
10410 + ") when binding service " + service);
10411 }
10412
10413 HistoryRecord activity = null;
10414 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010415 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010416 if (aindex < 0) {
10417 Log.w(TAG, "Binding with unknown activity: " + token);
10418 return 0;
10419 }
10420 activity = (HistoryRecord)mHistory.get(aindex);
10421 }
10422
10423 ServiceLookupResult res =
10424 retrieveServiceLocked(service, resolvedType,
10425 Binder.getCallingPid(), Binder.getCallingUid());
10426 if (res == null) {
10427 return 0;
10428 }
10429 if (res.record == null) {
10430 return -1;
10431 }
10432 ServiceRecord s = res.record;
10433
10434 final long origId = Binder.clearCallingIdentity();
10435
10436 if (unscheduleServiceRestartLocked(s)) {
10437 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10438 + s.shortName);
10439 }
10440
10441 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10442 ConnectionRecord c = new ConnectionRecord(b, activity,
10443 connection, flags);
10444
10445 IBinder binder = connection.asBinder();
10446 s.connections.put(binder, c);
10447 b.connections.add(c);
10448 if (activity != null) {
10449 if (activity.connections == null) {
10450 activity.connections = new HashSet<ConnectionRecord>();
10451 }
10452 activity.connections.add(c);
10453 }
10454 b.client.connections.add(c);
10455 mServiceConnections.put(binder, c);
10456
10457 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10458 s.lastActivity = SystemClock.uptimeMillis();
10459 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10460 return 0;
10461 }
10462 }
10463
10464 if (s.app != null) {
10465 // This could have made the service more important.
10466 updateOomAdjLocked(s.app);
10467 }
10468
10469 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10470 + ": received=" + b.intent.received
10471 + " apps=" + b.intent.apps.size()
10472 + " doRebind=" + b.intent.doRebind);
10473
10474 if (s.app != null && b.intent.received) {
10475 // Service is already running, so we can immediately
10476 // publish the connection.
10477 try {
10478 c.conn.connected(s.name, b.intent.binder);
10479 } catch (Exception e) {
10480 Log.w(TAG, "Failure sending service " + s.shortName
10481 + " to connection " + c.conn.asBinder()
10482 + " (in " + c.binding.client.processName + ")", e);
10483 }
10484
10485 // If this is the first app connected back to this binding,
10486 // and the service had previously asked to be told when
10487 // rebound, then do so.
10488 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10489 requestServiceBindingLocked(s, b.intent, true);
10490 }
10491 } else if (!b.intent.requested) {
10492 requestServiceBindingLocked(s, b.intent, false);
10493 }
10494
10495 Binder.restoreCallingIdentity(origId);
10496 }
10497
10498 return 1;
10499 }
10500
10501 private void removeConnectionLocked(
10502 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10503 IBinder binder = c.conn.asBinder();
10504 AppBindRecord b = c.binding;
10505 ServiceRecord s = b.service;
10506 s.connections.remove(binder);
10507 b.connections.remove(c);
10508 if (c.activity != null && c.activity != skipAct) {
10509 if (c.activity.connections != null) {
10510 c.activity.connections.remove(c);
10511 }
10512 }
10513 if (b.client != skipApp) {
10514 b.client.connections.remove(c);
10515 }
10516 mServiceConnections.remove(binder);
10517
10518 if (b.connections.size() == 0) {
10519 b.intent.apps.remove(b.client);
10520 }
10521
10522 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10523 + ": shouldUnbind=" + b.intent.hasBound);
10524 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10525 && b.intent.hasBound) {
10526 try {
10527 bumpServiceExecutingLocked(s);
10528 updateOomAdjLocked(s.app);
10529 b.intent.hasBound = false;
10530 // Assume the client doesn't want to know about a rebind;
10531 // we will deal with that later if it asks for one.
10532 b.intent.doRebind = false;
10533 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10534 } catch (Exception e) {
10535 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10536 serviceDoneExecutingLocked(s, true);
10537 }
10538 }
10539
10540 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10541 bringDownServiceLocked(s, false);
10542 }
10543 }
10544
10545 public boolean unbindService(IServiceConnection connection) {
10546 synchronized (this) {
10547 IBinder binder = connection.asBinder();
10548 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10549 ConnectionRecord r = mServiceConnections.get(binder);
10550 if (r == null) {
10551 Log.w(TAG, "Unbind failed: could not find connection for "
10552 + connection.asBinder());
10553 return false;
10554 }
10555
10556 final long origId = Binder.clearCallingIdentity();
10557
10558 removeConnectionLocked(r, null, null);
10559
10560 if (r.binding.service.app != null) {
10561 // This could have made the service less important.
10562 updateOomAdjLocked(r.binding.service.app);
10563 }
10564
10565 Binder.restoreCallingIdentity(origId);
10566 }
10567
10568 return true;
10569 }
10570
10571 public void publishService(IBinder token, Intent intent, IBinder service) {
10572 // Refuse possible leaked file descriptors
10573 if (intent != null && intent.hasFileDescriptors() == true) {
10574 throw new IllegalArgumentException("File descriptors passed in Intent");
10575 }
10576
10577 synchronized(this) {
10578 if (!(token instanceof ServiceRecord)) {
10579 throw new IllegalArgumentException("Invalid service token");
10580 }
10581 ServiceRecord r = (ServiceRecord)token;
10582
10583 final long origId = Binder.clearCallingIdentity();
10584
10585 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10586 + " " + intent + ": " + service);
10587 if (r != null) {
10588 Intent.FilterComparison filter
10589 = new Intent.FilterComparison(intent);
10590 IntentBindRecord b = r.bindings.get(filter);
10591 if (b != null && !b.received) {
10592 b.binder = service;
10593 b.requested = true;
10594 b.received = true;
10595 if (r.connections.size() > 0) {
10596 Iterator<ConnectionRecord> it
10597 = r.connections.values().iterator();
10598 while (it.hasNext()) {
10599 ConnectionRecord c = it.next();
10600 if (!filter.equals(c.binding.intent.intent)) {
10601 if (DEBUG_SERVICE) Log.v(
10602 TAG, "Not publishing to: " + c);
10603 if (DEBUG_SERVICE) Log.v(
10604 TAG, "Bound intent: " + c.binding.intent.intent);
10605 if (DEBUG_SERVICE) Log.v(
10606 TAG, "Published intent: " + intent);
10607 continue;
10608 }
10609 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10610 try {
10611 c.conn.connected(r.name, service);
10612 } catch (Exception e) {
10613 Log.w(TAG, "Failure sending service " + r.name +
10614 " to connection " + c.conn.asBinder() +
10615 " (in " + c.binding.client.processName + ")", e);
10616 }
10617 }
10618 }
10619 }
10620
10621 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10622
10623 Binder.restoreCallingIdentity(origId);
10624 }
10625 }
10626 }
10627
10628 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10629 // Refuse possible leaked file descriptors
10630 if (intent != null && intent.hasFileDescriptors() == true) {
10631 throw new IllegalArgumentException("File descriptors passed in Intent");
10632 }
10633
10634 synchronized(this) {
10635 if (!(token instanceof ServiceRecord)) {
10636 throw new IllegalArgumentException("Invalid service token");
10637 }
10638 ServiceRecord r = (ServiceRecord)token;
10639
10640 final long origId = Binder.clearCallingIdentity();
10641
10642 if (r != null) {
10643 Intent.FilterComparison filter
10644 = new Intent.FilterComparison(intent);
10645 IntentBindRecord b = r.bindings.get(filter);
10646 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10647 + " at " + b + ": apps="
10648 + (b != null ? b.apps.size() : 0));
10649 if (b != null) {
10650 if (b.apps.size() > 0) {
10651 // Applications have already bound since the last
10652 // unbind, so just rebind right here.
10653 requestServiceBindingLocked(r, b, true);
10654 } else {
10655 // Note to tell the service the next time there is
10656 // a new client.
10657 b.doRebind = true;
10658 }
10659 }
10660
10661 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10662
10663 Binder.restoreCallingIdentity(origId);
10664 }
10665 }
10666 }
10667
10668 public void serviceDoneExecuting(IBinder token) {
10669 synchronized(this) {
10670 if (!(token instanceof ServiceRecord)) {
10671 throw new IllegalArgumentException("Invalid service token");
10672 }
10673 ServiceRecord r = (ServiceRecord)token;
10674 boolean inStopping = mStoppingServices.contains(token);
10675 if (r != null) {
10676 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10677 + ": nesting=" + r.executeNesting
10678 + ", inStopping=" + inStopping);
10679 if (r != token) {
10680 Log.w(TAG, "Done executing service " + r.name
10681 + " with incorrect token: given " + token
10682 + ", expected " + r);
10683 return;
10684 }
10685
10686 final long origId = Binder.clearCallingIdentity();
10687 serviceDoneExecutingLocked(r, inStopping);
10688 Binder.restoreCallingIdentity(origId);
10689 } else {
10690 Log.w(TAG, "Done executing unknown service " + r.name
10691 + " with token " + token);
10692 }
10693 }
10694 }
10695
10696 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10697 r.executeNesting--;
10698 if (r.executeNesting <= 0 && r.app != null) {
10699 r.app.executingServices.remove(r);
10700 if (r.app.executingServices.size() == 0) {
10701 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10702 }
10703 if (inStopping) {
10704 mStoppingServices.remove(r);
10705 }
10706 updateOomAdjLocked(r.app);
10707 }
10708 }
10709
10710 void serviceTimeout(ProcessRecord proc) {
10711 synchronized(this) {
10712 if (proc.executingServices.size() == 0 || proc.thread == null) {
10713 return;
10714 }
10715 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10716 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10717 ServiceRecord timeout = null;
10718 long nextTime = 0;
10719 while (it.hasNext()) {
10720 ServiceRecord sr = it.next();
10721 if (sr.executingStart < maxTime) {
10722 timeout = sr;
10723 break;
10724 }
10725 if (sr.executingStart > nextTime) {
10726 nextTime = sr.executingStart;
10727 }
10728 }
10729 if (timeout != null && mLRUProcesses.contains(proc)) {
10730 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070010731 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010732 + timeout.name);
10733 } else {
10734 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10735 msg.obj = proc;
10736 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10737 }
10738 }
10739 }
10740
10741 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010742 // BACKUP AND RESTORE
10743 // =========================================================
10744
10745 // Cause the target app to be launched if necessary and its backup agent
10746 // instantiated. The backup agent will invoke backupAgentCreated() on the
10747 // activity manager to announce its creation.
10748 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10749 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10750 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10751
10752 synchronized(this) {
10753 // !!! TODO: currently no check here that we're already bound
10754 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10755 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10756 synchronized (stats) {
10757 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10758 }
10759
10760 BackupRecord r = new BackupRecord(ss, app, backupMode);
10761 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10762 // startProcessLocked() returns existing proc's record if it's already running
10763 ProcessRecord proc = startProcessLocked(app.processName, app,
10764 false, 0, "backup", hostingName);
10765 if (proc == null) {
10766 Log.e(TAG, "Unable to start backup agent process " + r);
10767 return false;
10768 }
10769
10770 r.app = proc;
10771 mBackupTarget = r;
10772 mBackupAppName = app.packageName;
10773
Christopher Tate6fa95972009-06-05 18:43:55 -070010774 // Try not to kill the process during backup
10775 updateOomAdjLocked(proc);
10776
Christopher Tate181fafa2009-05-14 11:12:14 -070010777 // If the process is already attached, schedule the creation of the backup agent now.
10778 // If it is not yet live, this will be done when it attaches to the framework.
10779 if (proc.thread != null) {
10780 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10781 try {
10782 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10783 } catch (RemoteException e) {
10784 // !!! TODO: notify the backup manager that we crashed, or rely on
10785 // death notices, or...?
10786 }
10787 } else {
10788 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10789 }
10790 // Invariants: at this point, the target app process exists and the application
10791 // is either already running or in the process of coming up. mBackupTarget and
10792 // mBackupAppName describe the app, so that when it binds back to the AM we
10793 // know that it's scheduled for a backup-agent operation.
10794 }
10795
10796 return true;
10797 }
10798
10799 // A backup agent has just come up
10800 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10801 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10802 + " = " + agent);
10803
10804 synchronized(this) {
10805 if (!agentPackageName.equals(mBackupAppName)) {
10806 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10807 return;
10808 }
10809
Christopher Tate043dadc2009-06-02 16:11:00 -070010810 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070010811 try {
10812 IBackupManager bm = IBackupManager.Stub.asInterface(
10813 ServiceManager.getService(Context.BACKUP_SERVICE));
10814 bm.agentConnected(agentPackageName, agent);
10815 } catch (RemoteException e) {
10816 // can't happen; the backup manager service is local
10817 } catch (Exception e) {
10818 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10819 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070010820 } finally {
10821 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070010822 }
10823 }
10824 }
10825
10826 // done with this agent
10827 public void unbindBackupAgent(ApplicationInfo appInfo) {
10828 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070010829 if (appInfo == null) {
10830 Log.w(TAG, "unbind backup agent for null app");
10831 return;
10832 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010833
10834 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070010835 if (mBackupAppName == null) {
10836 Log.w(TAG, "Unbinding backup agent with no active backup");
10837 return;
10838 }
10839
Christopher Tate181fafa2009-05-14 11:12:14 -070010840 if (!mBackupAppName.equals(appInfo.packageName)) {
10841 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10842 return;
10843 }
10844
Christopher Tate6fa95972009-06-05 18:43:55 -070010845 ProcessRecord proc = mBackupTarget.app;
10846 mBackupTarget = null;
10847 mBackupAppName = null;
10848
10849 // Not backing this app up any more; reset its OOM adjustment
10850 updateOomAdjLocked(proc);
10851
Christopher Tatec7b31e32009-06-10 15:49:30 -070010852 // If the app crashed during backup, 'thread' will be null here
10853 if (proc.thread != null) {
10854 try {
10855 proc.thread.scheduleDestroyBackupAgent(appInfo);
10856 } catch (Exception e) {
10857 Log.e(TAG, "Exception when unbinding backup agent:");
10858 e.printStackTrace();
10859 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010860 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010861 }
10862 }
10863 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010864 // BROADCASTS
10865 // =========================================================
10866
10867 private final List getStickies(String action, IntentFilter filter,
10868 List cur) {
10869 final ContentResolver resolver = mContext.getContentResolver();
10870 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10871 if (list == null) {
10872 return cur;
10873 }
10874 int N = list.size();
10875 for (int i=0; i<N; i++) {
10876 Intent intent = list.get(i);
10877 if (filter.match(resolver, intent, true, TAG) >= 0) {
10878 if (cur == null) {
10879 cur = new ArrayList<Intent>();
10880 }
10881 cur.add(intent);
10882 }
10883 }
10884 return cur;
10885 }
10886
10887 private final void scheduleBroadcastsLocked() {
10888 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10889 + mBroadcastsScheduled);
10890
10891 if (mBroadcastsScheduled) {
10892 return;
10893 }
10894 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10895 mBroadcastsScheduled = true;
10896 }
10897
10898 public Intent registerReceiver(IApplicationThread caller,
10899 IIntentReceiver receiver, IntentFilter filter, String permission) {
10900 synchronized(this) {
10901 ProcessRecord callerApp = null;
10902 if (caller != null) {
10903 callerApp = getRecordForAppLocked(caller);
10904 if (callerApp == null) {
10905 throw new SecurityException(
10906 "Unable to find app for caller " + caller
10907 + " (pid=" + Binder.getCallingPid()
10908 + ") when registering receiver " + receiver);
10909 }
10910 }
10911
10912 List allSticky = null;
10913
10914 // Look for any matching sticky broadcasts...
10915 Iterator actions = filter.actionsIterator();
10916 if (actions != null) {
10917 while (actions.hasNext()) {
10918 String action = (String)actions.next();
10919 allSticky = getStickies(action, filter, allSticky);
10920 }
10921 } else {
10922 allSticky = getStickies(null, filter, allSticky);
10923 }
10924
10925 // The first sticky in the list is returned directly back to
10926 // the client.
10927 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10928
10929 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10930 + ": " + sticky);
10931
10932 if (receiver == null) {
10933 return sticky;
10934 }
10935
10936 ReceiverList rl
10937 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10938 if (rl == null) {
10939 rl = new ReceiverList(this, callerApp,
10940 Binder.getCallingPid(),
10941 Binder.getCallingUid(), receiver);
10942 if (rl.app != null) {
10943 rl.app.receivers.add(rl);
10944 } else {
10945 try {
10946 receiver.asBinder().linkToDeath(rl, 0);
10947 } catch (RemoteException e) {
10948 return sticky;
10949 }
10950 rl.linkedToDeath = true;
10951 }
10952 mRegisteredReceivers.put(receiver.asBinder(), rl);
10953 }
10954 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10955 rl.add(bf);
10956 if (!bf.debugCheck()) {
10957 Log.w(TAG, "==> For Dynamic broadast");
10958 }
10959 mReceiverResolver.addFilter(bf);
10960
10961 // Enqueue broadcasts for all existing stickies that match
10962 // this filter.
10963 if (allSticky != null) {
10964 ArrayList receivers = new ArrayList();
10965 receivers.add(bf);
10966
10967 int N = allSticky.size();
10968 for (int i=0; i<N; i++) {
10969 Intent intent = (Intent)allSticky.get(i);
10970 BroadcastRecord r = new BroadcastRecord(intent, null,
10971 null, -1, -1, null, receivers, null, 0, null, null,
10972 false);
10973 if (mParallelBroadcasts.size() == 0) {
10974 scheduleBroadcastsLocked();
10975 }
10976 mParallelBroadcasts.add(r);
10977 }
10978 }
10979
10980 return sticky;
10981 }
10982 }
10983
10984 public void unregisterReceiver(IIntentReceiver receiver) {
10985 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10986
10987 boolean doNext = false;
10988
10989 synchronized(this) {
10990 ReceiverList rl
10991 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10992 if (rl != null) {
10993 if (rl.curBroadcast != null) {
10994 BroadcastRecord r = rl.curBroadcast;
10995 doNext = finishReceiverLocked(
10996 receiver.asBinder(), r.resultCode, r.resultData,
10997 r.resultExtras, r.resultAbort, true);
10998 }
10999
11000 if (rl.app != null) {
11001 rl.app.receivers.remove(rl);
11002 }
11003 removeReceiverLocked(rl);
11004 if (rl.linkedToDeath) {
11005 rl.linkedToDeath = false;
11006 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11007 }
11008 }
11009 }
11010
11011 if (!doNext) {
11012 return;
11013 }
11014
11015 final long origId = Binder.clearCallingIdentity();
11016 processNextBroadcast(false);
11017 trimApplications();
11018 Binder.restoreCallingIdentity(origId);
11019 }
11020
11021 void removeReceiverLocked(ReceiverList rl) {
11022 mRegisteredReceivers.remove(rl.receiver.asBinder());
11023 int N = rl.size();
11024 for (int i=0; i<N; i++) {
11025 mReceiverResolver.removeFilter(rl.get(i));
11026 }
11027 }
11028
11029 private final int broadcastIntentLocked(ProcessRecord callerApp,
11030 String callerPackage, Intent intent, String resolvedType,
11031 IIntentReceiver resultTo, int resultCode, String resultData,
11032 Bundle map, String requiredPermission,
11033 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11034 intent = new Intent(intent);
11035
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011036 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011037 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11038 + " ordered=" + ordered);
11039 if ((resultTo != null) && !ordered) {
11040 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11041 }
11042
11043 // Handle special intents: if this broadcast is from the package
11044 // manager about a package being removed, we need to remove all of
11045 // its activities from the history stack.
11046 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11047 intent.getAction());
11048 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11049 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11050 || uidRemoved) {
11051 if (checkComponentPermission(
11052 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11053 callingPid, callingUid, -1)
11054 == PackageManager.PERMISSION_GRANTED) {
11055 if (uidRemoved) {
11056 final Bundle intentExtras = intent.getExtras();
11057 final int uid = intentExtras != null
11058 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11059 if (uid >= 0) {
11060 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11061 synchronized (bs) {
11062 bs.removeUidStatsLocked(uid);
11063 }
11064 }
11065 } else {
11066 Uri data = intent.getData();
11067 String ssp;
11068 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11069 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11070 uninstallPackageLocked(ssp,
11071 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011072 AttributeCache ac = AttributeCache.instance();
11073 if (ac != null) {
11074 ac.removePackage(ssp);
11075 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011076 }
11077 }
11078 }
11079 } else {
11080 String msg = "Permission Denial: " + intent.getAction()
11081 + " broadcast from " + callerPackage + " (pid=" + callingPid
11082 + ", uid=" + callingUid + ")"
11083 + " requires "
11084 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11085 Log.w(TAG, msg);
11086 throw new SecurityException(msg);
11087 }
11088 }
11089
11090 /*
11091 * If this is the time zone changed action, queue up a message that will reset the timezone
11092 * of all currently running processes. This message will get queued up before the broadcast
11093 * happens.
11094 */
11095 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11096 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11097 }
11098
Dianne Hackborn854060af2009-07-09 18:14:31 -070011099 /*
11100 * Prevent non-system code (defined here to be non-persistent
11101 * processes) from sending protected broadcasts.
11102 */
11103 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11104 || callingUid == Process.SHELL_UID || callingUid == 0) {
11105 // Always okay.
11106 } else if (callerApp == null || !callerApp.persistent) {
11107 try {
11108 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11109 intent.getAction())) {
11110 String msg = "Permission Denial: not allowed to send broadcast "
11111 + intent.getAction() + " from pid="
11112 + callingPid + ", uid=" + callingUid;
11113 Log.w(TAG, msg);
11114 throw new SecurityException(msg);
11115 }
11116 } catch (RemoteException e) {
11117 Log.w(TAG, "Remote exception", e);
11118 return BROADCAST_SUCCESS;
11119 }
11120 }
11121
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011122 // Add to the sticky list if requested.
11123 if (sticky) {
11124 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11125 callingPid, callingUid)
11126 != PackageManager.PERMISSION_GRANTED) {
11127 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11128 + callingPid + ", uid=" + callingUid
11129 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11130 Log.w(TAG, msg);
11131 throw new SecurityException(msg);
11132 }
11133 if (requiredPermission != null) {
11134 Log.w(TAG, "Can't broadcast sticky intent " + intent
11135 + " and enforce permission " + requiredPermission);
11136 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11137 }
11138 if (intent.getComponent() != null) {
11139 throw new SecurityException(
11140 "Sticky broadcasts can't target a specific component");
11141 }
11142 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11143 if (list == null) {
11144 list = new ArrayList<Intent>();
11145 mStickyBroadcasts.put(intent.getAction(), list);
11146 }
11147 int N = list.size();
11148 int i;
11149 for (i=0; i<N; i++) {
11150 if (intent.filterEquals(list.get(i))) {
11151 // This sticky already exists, replace it.
11152 list.set(i, new Intent(intent));
11153 break;
11154 }
11155 }
11156 if (i >= N) {
11157 list.add(new Intent(intent));
11158 }
11159 }
11160
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011161 // Figure out who all will receive this broadcast.
11162 List receivers = null;
11163 List<BroadcastFilter> registeredReceivers = null;
11164 try {
11165 if (intent.getComponent() != null) {
11166 // Broadcast is going to one specific receiver class...
11167 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011168 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011169 if (ai != null) {
11170 receivers = new ArrayList();
11171 ResolveInfo ri = new ResolveInfo();
11172 ri.activityInfo = ai;
11173 receivers.add(ri);
11174 }
11175 } else {
11176 // Need to resolve the intent to interested receivers...
11177 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11178 == 0) {
11179 receivers =
11180 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011181 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011182 }
Mihai Preda074edef2009-05-18 17:13:31 +020011183 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011184 }
11185 } catch (RemoteException ex) {
11186 // pm is in same process, this will never happen.
11187 }
11188
11189 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11190 if (!ordered && NR > 0) {
11191 // If we are not serializing this broadcast, then send the
11192 // registered receivers separately so they don't wait for the
11193 // components to be launched.
11194 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11195 callerPackage, callingPid, callingUid, requiredPermission,
11196 registeredReceivers, resultTo, resultCode, resultData, map,
11197 ordered);
11198 if (DEBUG_BROADCAST) Log.v(
11199 TAG, "Enqueueing parallel broadcast " + r
11200 + ": prev had " + mParallelBroadcasts.size());
11201 mParallelBroadcasts.add(r);
11202 scheduleBroadcastsLocked();
11203 registeredReceivers = null;
11204 NR = 0;
11205 }
11206
11207 // Merge into one list.
11208 int ir = 0;
11209 if (receivers != null) {
11210 // A special case for PACKAGE_ADDED: do not allow the package
11211 // being added to see this broadcast. This prevents them from
11212 // using this as a back door to get run as soon as they are
11213 // installed. Maybe in the future we want to have a special install
11214 // broadcast or such for apps, but we'd like to deliberately make
11215 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011216 boolean skip = false;
11217 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011218 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011219 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11220 skip = true;
11221 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11222 skip = true;
11223 }
11224 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011225 ? intent.getData().getSchemeSpecificPart()
11226 : null;
11227 if (skipPackage != null && receivers != null) {
11228 int NT = receivers.size();
11229 for (int it=0; it<NT; it++) {
11230 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11231 if (curt.activityInfo.packageName.equals(skipPackage)) {
11232 receivers.remove(it);
11233 it--;
11234 NT--;
11235 }
11236 }
11237 }
11238
11239 int NT = receivers != null ? receivers.size() : 0;
11240 int it = 0;
11241 ResolveInfo curt = null;
11242 BroadcastFilter curr = null;
11243 while (it < NT && ir < NR) {
11244 if (curt == null) {
11245 curt = (ResolveInfo)receivers.get(it);
11246 }
11247 if (curr == null) {
11248 curr = registeredReceivers.get(ir);
11249 }
11250 if (curr.getPriority() >= curt.priority) {
11251 // Insert this broadcast record into the final list.
11252 receivers.add(it, curr);
11253 ir++;
11254 curr = null;
11255 it++;
11256 NT++;
11257 } else {
11258 // Skip to the next ResolveInfo in the final list.
11259 it++;
11260 curt = null;
11261 }
11262 }
11263 }
11264 while (ir < NR) {
11265 if (receivers == null) {
11266 receivers = new ArrayList();
11267 }
11268 receivers.add(registeredReceivers.get(ir));
11269 ir++;
11270 }
11271
11272 if ((receivers != null && receivers.size() > 0)
11273 || resultTo != null) {
11274 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11275 callerPackage, callingPid, callingUid, requiredPermission,
11276 receivers, resultTo, resultCode, resultData, map, ordered);
11277 if (DEBUG_BROADCAST) Log.v(
11278 TAG, "Enqueueing ordered broadcast " + r
11279 + ": prev had " + mOrderedBroadcasts.size());
11280 if (DEBUG_BROADCAST) {
11281 int seq = r.intent.getIntExtra("seq", -1);
11282 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11283 }
11284 mOrderedBroadcasts.add(r);
11285 scheduleBroadcastsLocked();
11286 }
11287
11288 return BROADCAST_SUCCESS;
11289 }
11290
11291 public final int broadcastIntent(IApplicationThread caller,
11292 Intent intent, String resolvedType, IIntentReceiver resultTo,
11293 int resultCode, String resultData, Bundle map,
11294 String requiredPermission, boolean serialized, boolean sticky) {
11295 // Refuse possible leaked file descriptors
11296 if (intent != null && intent.hasFileDescriptors() == true) {
11297 throw new IllegalArgumentException("File descriptors passed in Intent");
11298 }
11299
11300 synchronized(this) {
11301 if (!mSystemReady) {
11302 // if the caller really truly claims to know what they're doing, go
11303 // ahead and allow the broadcast without launching any receivers
11304 int flags = intent.getFlags();
11305 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11306 intent = new Intent(intent);
11307 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11308 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11309 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11310 + " before boot completion");
11311 throw new IllegalStateException("Cannot broadcast before boot completed");
11312 }
11313 }
11314
11315 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11316 final int callingPid = Binder.getCallingPid();
11317 final int callingUid = Binder.getCallingUid();
11318 final long origId = Binder.clearCallingIdentity();
11319 int res = broadcastIntentLocked(callerApp,
11320 callerApp != null ? callerApp.info.packageName : null,
11321 intent, resolvedType, resultTo,
11322 resultCode, resultData, map, requiredPermission, serialized,
11323 sticky, callingPid, callingUid);
11324 Binder.restoreCallingIdentity(origId);
11325 return res;
11326 }
11327 }
11328
11329 int broadcastIntentInPackage(String packageName, int uid,
11330 Intent intent, String resolvedType, IIntentReceiver resultTo,
11331 int resultCode, String resultData, Bundle map,
11332 String requiredPermission, boolean serialized, boolean sticky) {
11333 synchronized(this) {
11334 final long origId = Binder.clearCallingIdentity();
11335 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11336 resultTo, resultCode, resultData, map, requiredPermission,
11337 serialized, sticky, -1, uid);
11338 Binder.restoreCallingIdentity(origId);
11339 return res;
11340 }
11341 }
11342
11343 public final void unbroadcastIntent(IApplicationThread caller,
11344 Intent intent) {
11345 // Refuse possible leaked file descriptors
11346 if (intent != null && intent.hasFileDescriptors() == true) {
11347 throw new IllegalArgumentException("File descriptors passed in Intent");
11348 }
11349
11350 synchronized(this) {
11351 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11352 != PackageManager.PERMISSION_GRANTED) {
11353 String msg = "Permission Denial: unbroadcastIntent() from pid="
11354 + Binder.getCallingPid()
11355 + ", uid=" + Binder.getCallingUid()
11356 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11357 Log.w(TAG, msg);
11358 throw new SecurityException(msg);
11359 }
11360 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11361 if (list != null) {
11362 int N = list.size();
11363 int i;
11364 for (i=0; i<N; i++) {
11365 if (intent.filterEquals(list.get(i))) {
11366 list.remove(i);
11367 break;
11368 }
11369 }
11370 }
11371 }
11372 }
11373
11374 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11375 String resultData, Bundle resultExtras, boolean resultAbort,
11376 boolean explicit) {
11377 if (mOrderedBroadcasts.size() == 0) {
11378 if (explicit) {
11379 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11380 }
11381 return false;
11382 }
11383 BroadcastRecord r = mOrderedBroadcasts.get(0);
11384 if (r.receiver == null) {
11385 if (explicit) {
11386 Log.w(TAG, "finishReceiver called but none active");
11387 }
11388 return false;
11389 }
11390 if (r.receiver != receiver) {
11391 Log.w(TAG, "finishReceiver called but active receiver is different");
11392 return false;
11393 }
11394 int state = r.state;
11395 r.state = r.IDLE;
11396 if (state == r.IDLE) {
11397 if (explicit) {
11398 Log.w(TAG, "finishReceiver called but state is IDLE");
11399 }
11400 }
11401 r.receiver = null;
11402 r.intent.setComponent(null);
11403 if (r.curApp != null) {
11404 r.curApp.curReceiver = null;
11405 }
11406 if (r.curFilter != null) {
11407 r.curFilter.receiverList.curBroadcast = null;
11408 }
11409 r.curFilter = null;
11410 r.curApp = null;
11411 r.curComponent = null;
11412 r.curReceiver = null;
11413 mPendingBroadcast = null;
11414
11415 r.resultCode = resultCode;
11416 r.resultData = resultData;
11417 r.resultExtras = resultExtras;
11418 r.resultAbort = resultAbort;
11419
11420 // We will process the next receiver right now if this is finishing
11421 // an app receiver (which is always asynchronous) or after we have
11422 // come back from calling a receiver.
11423 return state == BroadcastRecord.APP_RECEIVE
11424 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11425 }
11426
11427 public void finishReceiver(IBinder who, int resultCode, String resultData,
11428 Bundle resultExtras, boolean resultAbort) {
11429 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11430
11431 // Refuse possible leaked file descriptors
11432 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11433 throw new IllegalArgumentException("File descriptors passed in Bundle");
11434 }
11435
11436 boolean doNext;
11437
11438 final long origId = Binder.clearCallingIdentity();
11439
11440 synchronized(this) {
11441 doNext = finishReceiverLocked(
11442 who, resultCode, resultData, resultExtras, resultAbort, true);
11443 }
11444
11445 if (doNext) {
11446 processNextBroadcast(false);
11447 }
11448 trimApplications();
11449
11450 Binder.restoreCallingIdentity(origId);
11451 }
11452
11453 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11454 if (r.nextReceiver > 0) {
11455 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11456 if (curReceiver instanceof BroadcastFilter) {
11457 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11458 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11459 System.identityHashCode(r),
11460 r.intent.getAction(),
11461 r.nextReceiver - 1,
11462 System.identityHashCode(bf));
11463 } else {
11464 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11465 System.identityHashCode(r),
11466 r.intent.getAction(),
11467 r.nextReceiver - 1,
11468 ((ResolveInfo)curReceiver).toString());
11469 }
11470 } else {
11471 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11472 + r);
11473 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11474 System.identityHashCode(r),
11475 r.intent.getAction(),
11476 r.nextReceiver,
11477 "NONE");
11478 }
11479 }
11480
11481 private final void broadcastTimeout() {
11482 synchronized (this) {
11483 if (mOrderedBroadcasts.size() == 0) {
11484 return;
11485 }
11486 long now = SystemClock.uptimeMillis();
11487 BroadcastRecord r = mOrderedBroadcasts.get(0);
11488 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11489 if (DEBUG_BROADCAST) Log.v(TAG,
11490 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11491 + (r.startTime + BROADCAST_TIMEOUT));
11492 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11493 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11494 return;
11495 }
11496
11497 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11498 r.startTime = now;
11499 r.anrCount++;
11500
11501 // Current receiver has passed its expiration date.
11502 if (r.nextReceiver <= 0) {
11503 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11504 return;
11505 }
11506
11507 ProcessRecord app = null;
11508
11509 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11510 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11511 logBroadcastReceiverDiscard(r);
11512 if (curReceiver instanceof BroadcastFilter) {
11513 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11514 if (bf.receiverList.pid != 0
11515 && bf.receiverList.pid != MY_PID) {
11516 synchronized (this.mPidsSelfLocked) {
11517 app = this.mPidsSelfLocked.get(
11518 bf.receiverList.pid);
11519 }
11520 }
11521 } else {
11522 app = r.curApp;
11523 }
11524
11525 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011526 appNotRespondingLocked(app, null, null,
11527 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011528 }
11529
11530 if (mPendingBroadcast == r) {
11531 mPendingBroadcast = null;
11532 }
11533
11534 // Move on to the next receiver.
11535 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11536 r.resultExtras, r.resultAbort, true);
11537 scheduleBroadcastsLocked();
11538 }
11539 }
11540
11541 private final void processCurBroadcastLocked(BroadcastRecord r,
11542 ProcessRecord app) throws RemoteException {
11543 if (app.thread == null) {
11544 throw new RemoteException();
11545 }
11546 r.receiver = app.thread.asBinder();
11547 r.curApp = app;
11548 app.curReceiver = r;
11549 updateLRUListLocked(app, true);
11550
11551 // Tell the application to launch this receiver.
11552 r.intent.setComponent(r.curComponent);
11553
11554 boolean started = false;
11555 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011556 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011557 "Delivering to component " + r.curComponent
11558 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070011559 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011560 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11561 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11562 started = true;
11563 } finally {
11564 if (!started) {
11565 r.receiver = null;
11566 r.curApp = null;
11567 app.curReceiver = null;
11568 }
11569 }
11570
11571 }
11572
11573 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11574 Intent intent, int resultCode, String data,
11575 Bundle extras, boolean ordered) throws RemoteException {
11576 if (app != null && app.thread != null) {
11577 // If we have an app thread, do the call through that so it is
11578 // correctly ordered with other one-way calls.
11579 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11580 data, extras, ordered);
11581 } else {
11582 receiver.performReceive(intent, resultCode, data, extras, ordered);
11583 }
11584 }
11585
11586 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11587 BroadcastFilter filter, boolean ordered) {
11588 boolean skip = false;
11589 if (filter.requiredPermission != null) {
11590 int perm = checkComponentPermission(filter.requiredPermission,
11591 r.callingPid, r.callingUid, -1);
11592 if (perm != PackageManager.PERMISSION_GRANTED) {
11593 Log.w(TAG, "Permission Denial: broadcasting "
11594 + r.intent.toString()
11595 + " from " + r.callerPackage + " (pid="
11596 + r.callingPid + ", uid=" + r.callingUid + ")"
11597 + " requires " + filter.requiredPermission
11598 + " due to registered receiver " + filter);
11599 skip = true;
11600 }
11601 }
11602 if (r.requiredPermission != null) {
11603 int perm = checkComponentPermission(r.requiredPermission,
11604 filter.receiverList.pid, filter.receiverList.uid, -1);
11605 if (perm != PackageManager.PERMISSION_GRANTED) {
11606 Log.w(TAG, "Permission Denial: receiving "
11607 + r.intent.toString()
11608 + " to " + filter.receiverList.app
11609 + " (pid=" + filter.receiverList.pid
11610 + ", uid=" + filter.receiverList.uid + ")"
11611 + " requires " + r.requiredPermission
11612 + " due to sender " + r.callerPackage
11613 + " (uid " + r.callingUid + ")");
11614 skip = true;
11615 }
11616 }
11617
11618 if (!skip) {
11619 // If this is not being sent as an ordered broadcast, then we
11620 // don't want to touch the fields that keep track of the current
11621 // state of ordered broadcasts.
11622 if (ordered) {
11623 r.receiver = filter.receiverList.receiver.asBinder();
11624 r.curFilter = filter;
11625 filter.receiverList.curBroadcast = r;
11626 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011627 if (filter.receiverList.app != null) {
11628 // Bump hosting application to no longer be in background
11629 // scheduling class. Note that we can't do that if there
11630 // isn't an app... but we can only be in that case for
11631 // things that directly call the IActivityManager API, which
11632 // are already core system stuff so don't matter for this.
11633 r.curApp = filter.receiverList.app;
11634 filter.receiverList.app.curReceiver = r;
11635 updateOomAdjLocked();
11636 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011637 }
11638 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011639 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011640 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011641 Log.i(TAG, "Delivering to " + filter.receiverList.app
11642 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011643 }
11644 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11645 new Intent(r.intent), r.resultCode,
11646 r.resultData, r.resultExtras, r.ordered);
11647 if (ordered) {
11648 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11649 }
11650 } catch (RemoteException e) {
11651 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11652 if (ordered) {
11653 r.receiver = null;
11654 r.curFilter = null;
11655 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011656 if (filter.receiverList.app != null) {
11657 filter.receiverList.app.curReceiver = null;
11658 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011659 }
11660 }
11661 }
11662 }
11663
11664 private final void processNextBroadcast(boolean fromMsg) {
11665 synchronized(this) {
11666 BroadcastRecord r;
11667
11668 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11669 + mParallelBroadcasts.size() + " broadcasts, "
11670 + mOrderedBroadcasts.size() + " serialized broadcasts");
11671
11672 updateCpuStats();
11673
11674 if (fromMsg) {
11675 mBroadcastsScheduled = false;
11676 }
11677
11678 // First, deliver any non-serialized broadcasts right away.
11679 while (mParallelBroadcasts.size() > 0) {
11680 r = mParallelBroadcasts.remove(0);
11681 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011682 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
11683 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011684 for (int i=0; i<N; i++) {
11685 Object target = r.receivers.get(i);
11686 if (DEBUG_BROADCAST) Log.v(TAG,
11687 "Delivering non-serialized to registered "
11688 + target + ": " + r);
11689 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11690 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011691 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
11692 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011693 }
11694
11695 // Now take care of the next serialized one...
11696
11697 // If we are waiting for a process to come up to handle the next
11698 // broadcast, then do nothing at this point. Just in case, we
11699 // check that the process we're waiting for still exists.
11700 if (mPendingBroadcast != null) {
11701 Log.i(TAG, "processNextBroadcast: waiting for "
11702 + mPendingBroadcast.curApp);
11703
11704 boolean isDead;
11705 synchronized (mPidsSelfLocked) {
11706 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11707 }
11708 if (!isDead) {
11709 // It's still alive, so keep waiting
11710 return;
11711 } else {
11712 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11713 + " died before responding to broadcast");
11714 mPendingBroadcast = null;
11715 }
11716 }
11717
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011718 boolean looped = false;
11719
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011720 do {
11721 if (mOrderedBroadcasts.size() == 0) {
11722 // No more broadcasts pending, so all done!
11723 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011724 if (looped) {
11725 // If we had finished the last ordered broadcast, then
11726 // make sure all processes have correct oom and sched
11727 // adjustments.
11728 updateOomAdjLocked();
11729 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011730 return;
11731 }
11732 r = mOrderedBroadcasts.get(0);
11733 boolean forceReceive = false;
11734
11735 // Ensure that even if something goes awry with the timeout
11736 // detection, we catch "hung" broadcasts here, discard them,
11737 // and continue to make progress.
11738 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11739 long now = SystemClock.uptimeMillis();
11740 if (r.dispatchTime > 0) {
11741 if ((numReceivers > 0) &&
11742 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11743 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11744 + " now=" + now
11745 + " dispatchTime=" + r.dispatchTime
11746 + " startTime=" + r.startTime
11747 + " intent=" + r.intent
11748 + " numReceivers=" + numReceivers
11749 + " nextReceiver=" + r.nextReceiver
11750 + " state=" + r.state);
11751 broadcastTimeout(); // forcibly finish this broadcast
11752 forceReceive = true;
11753 r.state = BroadcastRecord.IDLE;
11754 }
11755 }
11756
11757 if (r.state != BroadcastRecord.IDLE) {
11758 if (DEBUG_BROADCAST) Log.d(TAG,
11759 "processNextBroadcast() called when not idle (state="
11760 + r.state + ")");
11761 return;
11762 }
11763
11764 if (r.receivers == null || r.nextReceiver >= numReceivers
11765 || r.resultAbort || forceReceive) {
11766 // No more receivers for this broadcast! Send the final
11767 // result if requested...
11768 if (r.resultTo != null) {
11769 try {
11770 if (DEBUG_BROADCAST) {
11771 int seq = r.intent.getIntExtra("seq", -1);
11772 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11773 + " seq=" + seq + " app=" + r.callerApp);
11774 }
11775 performReceive(r.callerApp, r.resultTo,
11776 new Intent(r.intent), r.resultCode,
11777 r.resultData, r.resultExtras, false);
11778 } catch (RemoteException e) {
11779 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11780 }
11781 }
11782
11783 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11784 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11785
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011786 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
11787 + r);
11788
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011789 // ... and on to the next...
11790 mOrderedBroadcasts.remove(0);
11791 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011792 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011793 continue;
11794 }
11795 } while (r == null);
11796
11797 // Get the next receiver...
11798 int recIdx = r.nextReceiver++;
11799
11800 // Keep track of when this receiver started, and make sure there
11801 // is a timeout message pending to kill it if need be.
11802 r.startTime = SystemClock.uptimeMillis();
11803 if (recIdx == 0) {
11804 r.dispatchTime = r.startTime;
11805
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011806 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
11807 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011808 if (DEBUG_BROADCAST) Log.v(TAG,
11809 "Submitting BROADCAST_TIMEOUT_MSG for "
11810 + (r.startTime + BROADCAST_TIMEOUT));
11811 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11812 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11813 }
11814
11815 Object nextReceiver = r.receivers.get(recIdx);
11816 if (nextReceiver instanceof BroadcastFilter) {
11817 // Simple case: this is a registered receiver who gets
11818 // a direct call.
11819 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11820 if (DEBUG_BROADCAST) Log.v(TAG,
11821 "Delivering serialized to registered "
11822 + filter + ": " + r);
11823 deliverToRegisteredReceiver(r, filter, r.ordered);
11824 if (r.receiver == null || !r.ordered) {
11825 // The receiver has already finished, so schedule to
11826 // process the next one.
11827 r.state = BroadcastRecord.IDLE;
11828 scheduleBroadcastsLocked();
11829 }
11830 return;
11831 }
11832
11833 // Hard case: need to instantiate the receiver, possibly
11834 // starting its application process to host it.
11835
11836 ResolveInfo info =
11837 (ResolveInfo)nextReceiver;
11838
11839 boolean skip = false;
11840 int perm = checkComponentPermission(info.activityInfo.permission,
11841 r.callingPid, r.callingUid,
11842 info.activityInfo.exported
11843 ? -1 : info.activityInfo.applicationInfo.uid);
11844 if (perm != PackageManager.PERMISSION_GRANTED) {
11845 Log.w(TAG, "Permission Denial: broadcasting "
11846 + r.intent.toString()
11847 + " from " + r.callerPackage + " (pid=" + r.callingPid
11848 + ", uid=" + r.callingUid + ")"
11849 + " requires " + info.activityInfo.permission
11850 + " due to receiver " + info.activityInfo.packageName
11851 + "/" + info.activityInfo.name);
11852 skip = true;
11853 }
11854 if (r.callingUid != Process.SYSTEM_UID &&
11855 r.requiredPermission != null) {
11856 try {
11857 perm = ActivityThread.getPackageManager().
11858 checkPermission(r.requiredPermission,
11859 info.activityInfo.applicationInfo.packageName);
11860 } catch (RemoteException e) {
11861 perm = PackageManager.PERMISSION_DENIED;
11862 }
11863 if (perm != PackageManager.PERMISSION_GRANTED) {
11864 Log.w(TAG, "Permission Denial: receiving "
11865 + r.intent + " to "
11866 + info.activityInfo.applicationInfo.packageName
11867 + " requires " + r.requiredPermission
11868 + " due to sender " + r.callerPackage
11869 + " (uid " + r.callingUid + ")");
11870 skip = true;
11871 }
11872 }
11873 if (r.curApp != null && r.curApp.crashing) {
11874 // If the target process is crashing, just skip it.
11875 skip = true;
11876 }
11877
11878 if (skip) {
11879 r.receiver = null;
11880 r.curFilter = null;
11881 r.state = BroadcastRecord.IDLE;
11882 scheduleBroadcastsLocked();
11883 return;
11884 }
11885
11886 r.state = BroadcastRecord.APP_RECEIVE;
11887 String targetProcess = info.activityInfo.processName;
11888 r.curComponent = new ComponentName(
11889 info.activityInfo.applicationInfo.packageName,
11890 info.activityInfo.name);
11891 r.curReceiver = info.activityInfo;
11892
11893 // Is this receiver's application already running?
11894 ProcessRecord app = getProcessRecordLocked(targetProcess,
11895 info.activityInfo.applicationInfo.uid);
11896 if (app != null && app.thread != null) {
11897 try {
11898 processCurBroadcastLocked(r, app);
11899 return;
11900 } catch (RemoteException e) {
11901 Log.w(TAG, "Exception when sending broadcast to "
11902 + r.curComponent, e);
11903 }
11904
11905 // If a dead object exception was thrown -- fall through to
11906 // restart the application.
11907 }
11908
11909 // Not running -- get it started, and enqueue this history record
11910 // to be executed when the app comes up.
11911 if ((r.curApp=startProcessLocked(targetProcess,
11912 info.activityInfo.applicationInfo, true,
11913 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11914 "broadcast", r.curComponent)) == null) {
11915 // Ah, this recipient is unavailable. Finish it if necessary,
11916 // and mark the broadcast record as ready for the next.
11917 Log.w(TAG, "Unable to launch app "
11918 + info.activityInfo.applicationInfo.packageName + "/"
11919 + info.activityInfo.applicationInfo.uid + " for broadcast "
11920 + r.intent + ": process is bad");
11921 logBroadcastReceiverDiscard(r);
11922 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11923 r.resultExtras, r.resultAbort, true);
11924 scheduleBroadcastsLocked();
11925 r.state = BroadcastRecord.IDLE;
11926 return;
11927 }
11928
11929 mPendingBroadcast = r;
11930 }
11931 }
11932
11933 // =========================================================
11934 // INSTRUMENTATION
11935 // =========================================================
11936
11937 public boolean startInstrumentation(ComponentName className,
11938 String profileFile, int flags, Bundle arguments,
11939 IInstrumentationWatcher watcher) {
11940 // Refuse possible leaked file descriptors
11941 if (arguments != null && arguments.hasFileDescriptors()) {
11942 throw new IllegalArgumentException("File descriptors passed in Bundle");
11943 }
11944
11945 synchronized(this) {
11946 InstrumentationInfo ii = null;
11947 ApplicationInfo ai = null;
11948 try {
11949 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011950 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011951 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011952 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011953 } catch (PackageManager.NameNotFoundException e) {
11954 }
11955 if (ii == null) {
11956 reportStartInstrumentationFailure(watcher, className,
11957 "Unable to find instrumentation info for: " + className);
11958 return false;
11959 }
11960 if (ai == null) {
11961 reportStartInstrumentationFailure(watcher, className,
11962 "Unable to find instrumentation target package: " + ii.targetPackage);
11963 return false;
11964 }
11965
11966 int match = mContext.getPackageManager().checkSignatures(
11967 ii.targetPackage, ii.packageName);
11968 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11969 String msg = "Permission Denial: starting instrumentation "
11970 + className + " from pid="
11971 + Binder.getCallingPid()
11972 + ", uid=" + Binder.getCallingPid()
11973 + " not allowed because package " + ii.packageName
11974 + " does not have a signature matching the target "
11975 + ii.targetPackage;
11976 reportStartInstrumentationFailure(watcher, className, msg);
11977 throw new SecurityException(msg);
11978 }
11979
11980 final long origId = Binder.clearCallingIdentity();
11981 uninstallPackageLocked(ii.targetPackage, -1, true);
11982 ProcessRecord app = addAppLocked(ai);
11983 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011984 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011985 app.instrumentationProfileFile = profileFile;
11986 app.instrumentationArguments = arguments;
11987 app.instrumentationWatcher = watcher;
11988 app.instrumentationResultClass = className;
11989 Binder.restoreCallingIdentity(origId);
11990 }
11991
11992 return true;
11993 }
11994
11995 /**
11996 * Report errors that occur while attempting to start Instrumentation. Always writes the
11997 * error to the logs, but if somebody is watching, send the report there too. This enables
11998 * the "am" command to report errors with more information.
11999 *
12000 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12001 * @param cn The component name of the instrumentation.
12002 * @param report The error report.
12003 */
12004 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12005 ComponentName cn, String report) {
12006 Log.w(TAG, report);
12007 try {
12008 if (watcher != null) {
12009 Bundle results = new Bundle();
12010 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12011 results.putString("Error", report);
12012 watcher.instrumentationStatus(cn, -1, results);
12013 }
12014 } catch (RemoteException e) {
12015 Log.w(TAG, e);
12016 }
12017 }
12018
12019 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12020 if (app.instrumentationWatcher != null) {
12021 try {
12022 // NOTE: IInstrumentationWatcher *must* be oneway here
12023 app.instrumentationWatcher.instrumentationFinished(
12024 app.instrumentationClass,
12025 resultCode,
12026 results);
12027 } catch (RemoteException e) {
12028 }
12029 }
12030 app.instrumentationWatcher = null;
12031 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012032 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012033 app.instrumentationProfileFile = null;
12034 app.instrumentationArguments = null;
12035
12036 uninstallPackageLocked(app.processName, -1, false);
12037 }
12038
12039 public void finishInstrumentation(IApplicationThread target,
12040 int resultCode, Bundle results) {
12041 // Refuse possible leaked file descriptors
12042 if (results != null && results.hasFileDescriptors()) {
12043 throw new IllegalArgumentException("File descriptors passed in Intent");
12044 }
12045
12046 synchronized(this) {
12047 ProcessRecord app = getRecordForAppLocked(target);
12048 if (app == null) {
12049 Log.w(TAG, "finishInstrumentation: no app for " + target);
12050 return;
12051 }
12052 final long origId = Binder.clearCallingIdentity();
12053 finishInstrumentationLocked(app, resultCode, results);
12054 Binder.restoreCallingIdentity(origId);
12055 }
12056 }
12057
12058 // =========================================================
12059 // CONFIGURATION
12060 // =========================================================
12061
12062 public ConfigurationInfo getDeviceConfigurationInfo() {
12063 ConfigurationInfo config = new ConfigurationInfo();
12064 synchronized (this) {
12065 config.reqTouchScreen = mConfiguration.touchscreen;
12066 config.reqKeyboardType = mConfiguration.keyboard;
12067 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012068 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12069 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012070 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12071 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012072 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12073 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012074 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12075 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012076 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012077 }
12078 return config;
12079 }
12080
12081 public Configuration getConfiguration() {
12082 Configuration ci;
12083 synchronized(this) {
12084 ci = new Configuration(mConfiguration);
12085 }
12086 return ci;
12087 }
12088
12089 public void updateConfiguration(Configuration values) {
12090 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12091 "updateConfiguration()");
12092
12093 synchronized(this) {
12094 if (values == null && mWindowManager != null) {
12095 // sentinel: fetch the current configuration from the window manager
12096 values = mWindowManager.computeNewConfiguration();
12097 }
12098
12099 final long origId = Binder.clearCallingIdentity();
12100 updateConfigurationLocked(values, null);
12101 Binder.restoreCallingIdentity(origId);
12102 }
12103 }
12104
12105 /**
12106 * Do either or both things: (1) change the current configuration, and (2)
12107 * make sure the given activity is running with the (now) current
12108 * configuration. Returns true if the activity has been left running, or
12109 * false if <var>starting</var> is being destroyed to match the new
12110 * configuration.
12111 */
12112 public boolean updateConfigurationLocked(Configuration values,
12113 HistoryRecord starting) {
12114 int changes = 0;
12115
12116 boolean kept = true;
12117
12118 if (values != null) {
12119 Configuration newConfig = new Configuration(mConfiguration);
12120 changes = newConfig.updateFrom(values);
12121 if (changes != 0) {
12122 if (DEBUG_SWITCH) {
12123 Log.i(TAG, "Updating configuration to: " + values);
12124 }
12125
12126 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12127
12128 if (values.locale != null) {
12129 saveLocaleLocked(values.locale,
12130 !values.locale.equals(mConfiguration.locale),
12131 values.userSetLocale);
12132 }
12133
12134 mConfiguration = newConfig;
12135
12136 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12137 msg.obj = new Configuration(mConfiguration);
12138 mHandler.sendMessage(msg);
12139
12140 final int N = mLRUProcesses.size();
12141 for (int i=0; i<N; i++) {
12142 ProcessRecord app = mLRUProcesses.get(i);
12143 try {
12144 if (app.thread != null) {
12145 app.thread.scheduleConfigurationChanged(mConfiguration);
12146 }
12147 } catch (Exception e) {
12148 }
12149 }
12150 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12151 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12152 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012153
12154 AttributeCache ac = AttributeCache.instance();
12155 if (ac != null) {
12156 ac.updateConfiguration(mConfiguration);
12157 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012158 }
12159 }
12160
12161 if (changes != 0 && starting == null) {
12162 // If the configuration changed, and the caller is not already
12163 // in the process of starting an activity, then find the top
12164 // activity to check if its configuration needs to change.
12165 starting = topRunningActivityLocked(null);
12166 }
12167
12168 if (starting != null) {
12169 kept = ensureActivityConfigurationLocked(starting, changes);
12170 if (kept) {
12171 // If this didn't result in the starting activity being
12172 // destroyed, then we need to make sure at this point that all
12173 // other activities are made visible.
12174 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12175 + ", ensuring others are correct.");
12176 ensureActivitiesVisibleLocked(starting, changes);
12177 }
12178 }
12179
12180 return kept;
12181 }
12182
12183 private final boolean relaunchActivityLocked(HistoryRecord r,
12184 int changes, boolean andResume) {
12185 List<ResultInfo> results = null;
12186 List<Intent> newIntents = null;
12187 if (andResume) {
12188 results = r.results;
12189 newIntents = r.newIntents;
12190 }
12191 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12192 + " with results=" + results + " newIntents=" + newIntents
12193 + " andResume=" + andResume);
12194 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12195 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12196 r.task.taskId, r.shortComponentName);
12197
12198 r.startFreezingScreenLocked(r.app, 0);
12199
12200 try {
12201 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12202 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12203 changes, !andResume);
12204 // Note: don't need to call pauseIfSleepingLocked() here, because
12205 // the caller will only pass in 'andResume' if this activity is
12206 // currently resumed, which implies we aren't sleeping.
12207 } catch (RemoteException e) {
12208 return false;
12209 }
12210
12211 if (andResume) {
12212 r.results = null;
12213 r.newIntents = null;
12214 }
12215
12216 return true;
12217 }
12218
12219 /**
12220 * Make sure the given activity matches the current configuration. Returns
12221 * false if the activity had to be destroyed. Returns true if the
12222 * configuration is the same, or the activity will remain running as-is
12223 * for whatever reason. Ensures the HistoryRecord is updated with the
12224 * correct configuration and all other bookkeeping is handled.
12225 */
12226 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12227 int globalChanges) {
12228 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12229
12230 // Short circuit: if the two configurations are the exact same
12231 // object (the common case), then there is nothing to do.
12232 Configuration newConfig = mConfiguration;
12233 if (r.configuration == newConfig) {
12234 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12235 return true;
12236 }
12237
12238 // We don't worry about activities that are finishing.
12239 if (r.finishing) {
12240 if (DEBUG_SWITCH) Log.i(TAG,
12241 "Configuration doesn't matter in finishing " + r);
12242 r.stopFreezingScreenLocked(false);
12243 return true;
12244 }
12245
12246 // Okay we now are going to make this activity have the new config.
12247 // But then we need to figure out how it needs to deal with that.
12248 Configuration oldConfig = r.configuration;
12249 r.configuration = newConfig;
12250
12251 // If the activity isn't currently running, just leave the new
12252 // configuration and it will pick that up next time it starts.
12253 if (r.app == null || r.app.thread == null) {
12254 if (DEBUG_SWITCH) Log.i(TAG,
12255 "Configuration doesn't matter not running " + r);
12256 r.stopFreezingScreenLocked(false);
12257 return true;
12258 }
12259
12260 // If the activity isn't persistent, there is a chance we will
12261 // need to restart it.
12262 if (!r.persistent) {
12263
12264 // Figure out what has changed between the two configurations.
12265 int changes = oldConfig.diff(newConfig);
12266 if (DEBUG_SWITCH) {
12267 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12268 + Integer.toHexString(changes) + ", handles=0x"
12269 + Integer.toHexString(r.info.configChanges));
12270 }
12271 if ((changes&(~r.info.configChanges)) != 0) {
12272 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12273 r.configChangeFlags |= changes;
12274 r.startFreezingScreenLocked(r.app, globalChanges);
12275 if (r.app == null || r.app.thread == null) {
12276 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12277 destroyActivityLocked(r, true);
12278 } else if (r.state == ActivityState.PAUSING) {
12279 // A little annoying: we are waiting for this activity to
12280 // finish pausing. Let's not do anything now, but just
12281 // flag that it needs to be restarted when done pausing.
12282 r.configDestroy = true;
12283 return true;
12284 } else if (r.state == ActivityState.RESUMED) {
12285 // Try to optimize this case: the configuration is changing
12286 // and we need to restart the top, resumed activity.
12287 // Instead of doing the normal handshaking, just say
12288 // "restart!".
12289 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12290 relaunchActivityLocked(r, r.configChangeFlags, true);
12291 r.configChangeFlags = 0;
12292 } else {
12293 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12294 relaunchActivityLocked(r, r.configChangeFlags, false);
12295 r.configChangeFlags = 0;
12296 }
12297
12298 // All done... tell the caller we weren't able to keep this
12299 // activity around.
12300 return false;
12301 }
12302 }
12303
12304 // Default case: the activity can handle this new configuration, so
12305 // hand it over. Note that we don't need to give it the new
12306 // configuration, since we always send configuration changes to all
12307 // process when they happen so it can just use whatever configuration
12308 // it last got.
12309 if (r.app != null && r.app.thread != null) {
12310 try {
12311 r.app.thread.scheduleActivityConfigurationChanged(r);
12312 } catch (RemoteException e) {
12313 // If process died, whatever.
12314 }
12315 }
12316 r.stopFreezingScreenLocked(false);
12317
12318 return true;
12319 }
12320
12321 /**
12322 * Save the locale. You must be inside a synchronized (this) block.
12323 */
12324 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12325 if(isDiff) {
12326 SystemProperties.set("user.language", l.getLanguage());
12327 SystemProperties.set("user.region", l.getCountry());
12328 }
12329
12330 if(isPersist) {
12331 SystemProperties.set("persist.sys.language", l.getLanguage());
12332 SystemProperties.set("persist.sys.country", l.getCountry());
12333 SystemProperties.set("persist.sys.localevar", l.getVariant());
12334 }
12335 }
12336
12337 // =========================================================
12338 // LIFETIME MANAGEMENT
12339 // =========================================================
12340
12341 private final int computeOomAdjLocked(
12342 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12343 if (mAdjSeq == app.adjSeq) {
12344 // This adjustment has already been computed.
12345 return app.curAdj;
12346 }
12347
12348 if (app.thread == null) {
12349 app.adjSeq = mAdjSeq;
12350 return (app.curAdj=EMPTY_APP_ADJ);
12351 }
12352
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012353 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
12354 // The max adjustment doesn't allow this app to be anything
12355 // below foreground, so it is not worth doing work for it.
12356 app.adjType = "fixed";
12357 app.adjSeq = mAdjSeq;
12358 app.curRawAdj = app.maxAdj;
12359 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
12360 return (app.curAdj=app.maxAdj);
12361 }
12362
12363 app.adjSource = null;
12364 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012365
The Android Open Source Project4df24232009-03-05 14:34:35 -080012366 // Determine the importance of the process, starting with most
12367 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012368 int adj;
12369 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012370 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012371 // The last app on the list is the foreground app.
12372 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012373 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012374 } else if (app.instrumentationClass != null) {
12375 // Don't want to kill running instrumentation.
12376 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012377 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012378 } else if (app.persistentActivities > 0) {
12379 // Special persistent activities... shouldn't be used these days.
12380 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012381 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012382 } else if (app.curReceiver != null ||
12383 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12384 // An app that is currently receiving a broadcast also
12385 // counts as being in the foreground.
12386 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012387 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012388 } else if (app.executingServices.size() > 0) {
12389 // An app that is currently executing a service callback also
12390 // counts as being in the foreground.
12391 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012392 app.adjType = "exec-service";
12393 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012394 // The user is aware of this app, so make it visible.
12395 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012396 app.adjType = "foreground-service";
12397 } else if (app.forcingToForeground != null) {
12398 // The user is aware of this app, so make it visible.
12399 adj = VISIBLE_APP_ADJ;
12400 app.adjType = "force-foreground";
12401 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012402 } else if (app == mHomeProcess) {
12403 // This process is hosting what we currently consider to be the
12404 // home app, so we don't want to let it go into the background.
12405 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012406 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012407 } else if ((N=app.activities.size()) != 0) {
12408 // This app is in the background with paused activities.
12409 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012410 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012411 for (int j=0; j<N; j++) {
12412 if (((HistoryRecord)app.activities.get(j)).visible) {
12413 // This app has a visible activity!
12414 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012415 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012416 break;
12417 }
12418 }
12419 } else {
12420 // A very not-needed process.
12421 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012422 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012423 }
12424
The Android Open Source Project4df24232009-03-05 14:34:35 -080012425 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012426 // there are applications dependent on our services or providers, but
12427 // this gives us a baseline and makes sure we don't get into an
12428 // infinite recursion.
12429 app.adjSeq = mAdjSeq;
12430 app.curRawAdj = adj;
12431 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12432
Christopher Tate6fa95972009-06-05 18:43:55 -070012433 if (mBackupTarget != null && app == mBackupTarget.app) {
12434 // If possible we want to avoid killing apps while they're being backed up
12435 if (adj > BACKUP_APP_ADJ) {
12436 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12437 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012438 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070012439 }
12440 }
12441
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012442 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12443 // If this process has active services running in it, we would
12444 // like to avoid killing it unless it would prevent the current
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012445 // application from running. By default we put the process in
12446 // with the rest of the background processes; as we scan through
12447 // its services we may bump it up from there.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012448 if (adj > hiddenAdj) {
12449 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012450 app.adjType = "bg-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012451 }
12452 final long now = SystemClock.uptimeMillis();
12453 // This process is more important if the top activity is
12454 // bound to the service.
12455 Iterator jt = app.services.iterator();
12456 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12457 ServiceRecord s = (ServiceRecord)jt.next();
12458 if (s.startRequested) {
12459 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12460 // This service has seen some activity within
12461 // recent memory, so we will keep its process ahead
12462 // of the background processes.
12463 if (adj > SECONDARY_SERVER_ADJ) {
12464 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012465 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012466 }
12467 }
12468 }
12469 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12470 Iterator<ConnectionRecord> kt
12471 = s.connections.values().iterator();
12472 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12473 // XXX should compute this based on the max of
12474 // all connected clients.
12475 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012476 if (cr.binding.client == app) {
12477 // Binding to ourself is not interesting.
12478 continue;
12479 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012480 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12481 ProcessRecord client = cr.binding.client;
12482 int myHiddenAdj = hiddenAdj;
12483 if (myHiddenAdj > client.hiddenAdj) {
12484 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12485 myHiddenAdj = client.hiddenAdj;
12486 } else {
12487 myHiddenAdj = VISIBLE_APP_ADJ;
12488 }
12489 }
12490 int clientAdj = computeOomAdjLocked(
12491 client, myHiddenAdj, TOP_APP);
12492 if (adj > clientAdj) {
12493 adj = clientAdj > VISIBLE_APP_ADJ
12494 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012495 app.adjType = "service";
12496 app.adjSource = cr.binding.client;
12497 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012498 }
12499 }
12500 HistoryRecord a = cr.activity;
12501 //if (a != null) {
12502 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12503 //}
12504 if (a != null && adj > FOREGROUND_APP_ADJ &&
12505 (a.state == ActivityState.RESUMED
12506 || a.state == ActivityState.PAUSING)) {
12507 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012508 app.adjType = "service";
12509 app.adjSource = a;
12510 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012511 }
12512 }
12513 }
12514 }
12515 }
12516
12517 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12518 // If this process has published any content providers, then
12519 // its adjustment makes it at least as important as any of the
12520 // processes using those providers, and no less important than
12521 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12522 if (adj > CONTENT_PROVIDER_ADJ) {
12523 adj = CONTENT_PROVIDER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012524 app.adjType = "pub-providers";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012525 }
12526 Iterator jt = app.pubProviders.values().iterator();
12527 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12528 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12529 if (cpr.clients.size() != 0) {
12530 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12531 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12532 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012533 if (client == app) {
12534 // Being our own client is not interesting.
12535 continue;
12536 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012537 int myHiddenAdj = hiddenAdj;
12538 if (myHiddenAdj > client.hiddenAdj) {
12539 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12540 myHiddenAdj = client.hiddenAdj;
12541 } else {
12542 myHiddenAdj = FOREGROUND_APP_ADJ;
12543 }
12544 }
12545 int clientAdj = computeOomAdjLocked(
12546 client, myHiddenAdj, TOP_APP);
12547 if (adj > clientAdj) {
12548 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012549 ? clientAdj : FOREGROUND_APP_ADJ;
12550 app.adjType = "provider";
12551 app.adjSource = client;
12552 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012553 }
12554 }
12555 }
12556 // If the provider has external (non-framework) process
12557 // dependencies, ensure that its adjustment is at least
12558 // FOREGROUND_APP_ADJ.
12559 if (cpr.externals != 0) {
12560 if (adj > FOREGROUND_APP_ADJ) {
12561 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012562 app.adjType = "provider";
12563 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012564 }
12565 }
12566 }
12567 }
12568
12569 app.curRawAdj = adj;
12570
12571 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12572 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12573 if (adj > app.maxAdj) {
12574 adj = app.maxAdj;
12575 }
12576
12577 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012578 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012579 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12580 : Process.THREAD_GROUP_DEFAULT;
12581
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012582 return adj;
12583 }
12584
12585 /**
12586 * Ask a given process to GC right now.
12587 */
12588 final void performAppGcLocked(ProcessRecord app) {
12589 try {
12590 app.lastRequestedGc = SystemClock.uptimeMillis();
12591 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012592 if (app.reportLowMemory) {
12593 app.reportLowMemory = false;
12594 app.thread.scheduleLowMemory();
12595 } else {
12596 app.thread.processInBackground();
12597 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012598 }
12599 } catch (Exception e) {
12600 // whatever.
12601 }
12602 }
12603
12604 /**
12605 * Returns true if things are idle enough to perform GCs.
12606 */
12607 private final boolean canGcNow() {
12608 return mParallelBroadcasts.size() == 0
12609 && mOrderedBroadcasts.size() == 0
12610 && (mSleeping || (mResumedActivity != null &&
12611 mResumedActivity.idle));
12612 }
12613
12614 /**
12615 * Perform GCs on all processes that are waiting for it, but only
12616 * if things are idle.
12617 */
12618 final void performAppGcsLocked() {
12619 final int N = mProcessesToGc.size();
12620 if (N <= 0) {
12621 return;
12622 }
12623 if (canGcNow()) {
12624 while (mProcessesToGc.size() > 0) {
12625 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012626 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
12627 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
12628 <= SystemClock.uptimeMillis()) {
12629 // To avoid spamming the system, we will GC processes one
12630 // at a time, waiting a few seconds between each.
12631 performAppGcLocked(proc);
12632 scheduleAppGcsLocked();
12633 return;
12634 } else {
12635 // It hasn't been long enough since we last GCed this
12636 // process... put it in the list to wait for its time.
12637 addProcessToGcListLocked(proc);
12638 break;
12639 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012640 }
12641 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012642
12643 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012644 }
12645 }
12646
12647 /**
12648 * If all looks good, perform GCs on all processes waiting for them.
12649 */
12650 final void performAppGcsIfAppropriateLocked() {
12651 if (canGcNow()) {
12652 performAppGcsLocked();
12653 return;
12654 }
12655 // Still not idle, wait some more.
12656 scheduleAppGcsLocked();
12657 }
12658
12659 /**
12660 * Schedule the execution of all pending app GCs.
12661 */
12662 final void scheduleAppGcsLocked() {
12663 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012664
12665 if (mProcessesToGc.size() > 0) {
12666 // Schedule a GC for the time to the next process.
12667 ProcessRecord proc = mProcessesToGc.get(0);
12668 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12669
12670 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
12671 long now = SystemClock.uptimeMillis();
12672 if (when < (now+GC_TIMEOUT)) {
12673 when = now + GC_TIMEOUT;
12674 }
12675 mHandler.sendMessageAtTime(msg, when);
12676 }
12677 }
12678
12679 /**
12680 * Add a process to the array of processes waiting to be GCed. Keeps the
12681 * list in sorted order by the last GC time. The process can't already be
12682 * on the list.
12683 */
12684 final void addProcessToGcListLocked(ProcessRecord proc) {
12685 boolean added = false;
12686 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
12687 if (mProcessesToGc.get(i).lastRequestedGc <
12688 proc.lastRequestedGc) {
12689 added = true;
12690 mProcessesToGc.add(i+1, proc);
12691 break;
12692 }
12693 }
12694 if (!added) {
12695 mProcessesToGc.add(0, proc);
12696 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012697 }
12698
12699 /**
12700 * Set up to ask a process to GC itself. This will either do it
12701 * immediately, or put it on the list of processes to gc the next
12702 * time things are idle.
12703 */
12704 final void scheduleAppGcLocked(ProcessRecord app) {
12705 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012706 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012707 return;
12708 }
12709 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012710 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012711 scheduleAppGcsLocked();
12712 }
12713 }
12714
12715 private final boolean updateOomAdjLocked(
12716 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12717 app.hiddenAdj = hiddenAdj;
12718
12719 if (app.thread == null) {
12720 return true;
12721 }
12722
12723 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12724
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012725 if (app.pid != 0 && app.pid != MY_PID) {
12726 if (app.curRawAdj != app.setRawAdj) {
12727 if (app.curRawAdj > FOREGROUND_APP_ADJ
12728 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12729 // If this app is transitioning from foreground to
12730 // non-foreground, have it do a gc.
12731 scheduleAppGcLocked(app);
12732 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12733 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12734 // Likewise do a gc when an app is moving in to the
12735 // background (such as a service stopping).
12736 scheduleAppGcLocked(app);
12737 }
12738 app.setRawAdj = app.curRawAdj;
12739 }
12740 if (adj != app.setAdj) {
12741 if (Process.setOomAdj(app.pid, adj)) {
12742 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12743 TAG, "Set app " + app.processName +
12744 " oom adj to " + adj);
12745 app.setAdj = adj;
12746 } else {
12747 return false;
12748 }
12749 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012750 if (app.setSchedGroup != app.curSchedGroup) {
12751 app.setSchedGroup = app.curSchedGroup;
12752 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12753 "Setting process group of " + app.processName
12754 + " to " + app.curSchedGroup);
12755 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070012756 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012757 try {
12758 Process.setProcessGroup(app.pid, app.curSchedGroup);
12759 } catch (Exception e) {
12760 Log.w(TAG, "Failed setting process group of " + app.pid
12761 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070012762 e.printStackTrace();
12763 } finally {
12764 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012765 }
12766 }
12767 if (false) {
12768 if (app.thread != null) {
12769 try {
12770 app.thread.setSchedulingGroup(app.curSchedGroup);
12771 } catch (RemoteException e) {
12772 }
12773 }
12774 }
12775 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012776 }
12777
12778 return true;
12779 }
12780
12781 private final HistoryRecord resumedAppLocked() {
12782 HistoryRecord resumedActivity = mResumedActivity;
12783 if (resumedActivity == null || resumedActivity.app == null) {
12784 resumedActivity = mPausingActivity;
12785 if (resumedActivity == null || resumedActivity.app == null) {
12786 resumedActivity = topRunningActivityLocked(null);
12787 }
12788 }
12789 return resumedActivity;
12790 }
12791
12792 private final boolean updateOomAdjLocked(ProcessRecord app) {
12793 final HistoryRecord TOP_ACT = resumedAppLocked();
12794 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12795 int curAdj = app.curAdj;
12796 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12797 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12798
12799 mAdjSeq++;
12800
12801 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12802 if (res) {
12803 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12804 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12805 if (nowHidden != wasHidden) {
12806 // Changed to/from hidden state, so apps after it in the LRU
12807 // list may also be changed.
12808 updateOomAdjLocked();
12809 }
12810 }
12811 return res;
12812 }
12813
12814 private final boolean updateOomAdjLocked() {
12815 boolean didOomAdj = true;
12816 final HistoryRecord TOP_ACT = resumedAppLocked();
12817 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12818
12819 if (false) {
12820 RuntimeException e = new RuntimeException();
12821 e.fillInStackTrace();
12822 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12823 }
12824
12825 mAdjSeq++;
12826
12827 // First try updating the OOM adjustment for each of the
12828 // application processes based on their current state.
12829 int i = mLRUProcesses.size();
12830 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12831 while (i > 0) {
12832 i--;
12833 ProcessRecord app = mLRUProcesses.get(i);
12834 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12835 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12836 && app.curAdj == curHiddenAdj) {
12837 curHiddenAdj++;
12838 }
12839 } else {
12840 didOomAdj = false;
12841 }
12842 }
12843
12844 // todo: for now pretend like OOM ADJ didn't work, because things
12845 // aren't behaving as expected on Linux -- it's not killing processes.
12846 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12847 }
12848
12849 private final void trimApplications() {
12850 synchronized (this) {
12851 int i;
12852
12853 // First remove any unused application processes whose package
12854 // has been removed.
12855 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12856 final ProcessRecord app = mRemovedProcesses.get(i);
12857 if (app.activities.size() == 0
12858 && app.curReceiver == null && app.services.size() == 0) {
12859 Log.i(
12860 TAG, "Exiting empty application process "
12861 + app.processName + " ("
12862 + (app.thread != null ? app.thread.asBinder() : null)
12863 + ")\n");
12864 if (app.pid > 0 && app.pid != MY_PID) {
12865 Process.killProcess(app.pid);
12866 } else {
12867 try {
12868 app.thread.scheduleExit();
12869 } catch (Exception e) {
12870 // Ignore exceptions.
12871 }
12872 }
12873 cleanUpApplicationRecordLocked(app, false, -1);
12874 mRemovedProcesses.remove(i);
12875
12876 if (app.persistent) {
12877 if (app.persistent) {
12878 addAppLocked(app.info);
12879 }
12880 }
12881 }
12882 }
12883
12884 // Now try updating the OOM adjustment for each of the
12885 // application processes based on their current state.
12886 // If the setOomAdj() API is not supported, then go with our
12887 // back-up plan...
12888 if (!updateOomAdjLocked()) {
12889
12890 // Count how many processes are running services.
12891 int numServiceProcs = 0;
12892 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12893 final ProcessRecord app = mLRUProcesses.get(i);
12894
12895 if (app.persistent || app.services.size() != 0
12896 || app.curReceiver != null
12897 || app.persistentActivities > 0) {
12898 // Don't count processes holding services against our
12899 // maximum process count.
12900 if (localLOGV) Log.v(
12901 TAG, "Not trimming app " + app + " with services: "
12902 + app.services);
12903 numServiceProcs++;
12904 }
12905 }
12906
12907 int curMaxProcs = mProcessLimit;
12908 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12909 if (mAlwaysFinishActivities) {
12910 curMaxProcs = 1;
12911 }
12912 curMaxProcs += numServiceProcs;
12913
12914 // Quit as many processes as we can to get down to the desired
12915 // process count. First remove any processes that no longer
12916 // have activites running in them.
12917 for ( i=0;
12918 i<mLRUProcesses.size()
12919 && mLRUProcesses.size() > curMaxProcs;
12920 i++) {
12921 final ProcessRecord app = mLRUProcesses.get(i);
12922 // Quit an application only if it is not currently
12923 // running any activities.
12924 if (!app.persistent && app.activities.size() == 0
12925 && app.curReceiver == null && app.services.size() == 0) {
12926 Log.i(
12927 TAG, "Exiting empty application process "
12928 + app.processName + " ("
12929 + (app.thread != null ? app.thread.asBinder() : null)
12930 + ")\n");
12931 if (app.pid > 0 && app.pid != MY_PID) {
12932 Process.killProcess(app.pid);
12933 } else {
12934 try {
12935 app.thread.scheduleExit();
12936 } catch (Exception e) {
12937 // Ignore exceptions.
12938 }
12939 }
12940 // todo: For now we assume the application is not buggy
12941 // or evil, and will quit as a result of our request.
12942 // Eventually we need to drive this off of the death
12943 // notification, and kill the process if it takes too long.
12944 cleanUpApplicationRecordLocked(app, false, i);
12945 i--;
12946 }
12947 }
12948
12949 // If we still have too many processes, now from the least
12950 // recently used process we start finishing activities.
12951 if (Config.LOGV) Log.v(
12952 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12953 " of " + curMaxProcs + " processes");
12954 for ( i=0;
12955 i<mLRUProcesses.size()
12956 && mLRUProcesses.size() > curMaxProcs;
12957 i++) {
12958 final ProcessRecord app = mLRUProcesses.get(i);
12959 // Quit the application only if we have a state saved for
12960 // all of its activities.
12961 boolean canQuit = !app.persistent && app.curReceiver == null
12962 && app.services.size() == 0
12963 && app.persistentActivities == 0;
12964 int NUMA = app.activities.size();
12965 int j;
12966 if (Config.LOGV) Log.v(
12967 TAG, "Looking to quit " + app.processName);
12968 for (j=0; j<NUMA && canQuit; j++) {
12969 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12970 if (Config.LOGV) Log.v(
12971 TAG, " " + r.intent.getComponent().flattenToShortString()
12972 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12973 canQuit = (r.haveState || !r.stateNotNeeded)
12974 && !r.visible && r.stopped;
12975 }
12976 if (canQuit) {
12977 // Finish all of the activities, and then the app itself.
12978 for (j=0; j<NUMA; j++) {
12979 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12980 if (!r.finishing) {
12981 destroyActivityLocked(r, false);
12982 }
12983 r.resultTo = null;
12984 }
12985 Log.i(TAG, "Exiting application process "
12986 + app.processName + " ("
12987 + (app.thread != null ? app.thread.asBinder() : null)
12988 + ")\n");
12989 if (app.pid > 0 && app.pid != MY_PID) {
12990 Process.killProcess(app.pid);
12991 } else {
12992 try {
12993 app.thread.scheduleExit();
12994 } catch (Exception e) {
12995 // Ignore exceptions.
12996 }
12997 }
12998 // todo: For now we assume the application is not buggy
12999 // or evil, and will quit as a result of our request.
13000 // Eventually we need to drive this off of the death
13001 // notification, and kill the process if it takes too long.
13002 cleanUpApplicationRecordLocked(app, false, i);
13003 i--;
13004 //dump();
13005 }
13006 }
13007
13008 }
13009
13010 int curMaxActivities = MAX_ACTIVITIES;
13011 if (mAlwaysFinishActivities) {
13012 curMaxActivities = 1;
13013 }
13014
13015 // Finally, if there are too many activities now running, try to
13016 // finish as many as we can to get back down to the limit.
13017 for ( i=0;
13018 i<mLRUActivities.size()
13019 && mLRUActivities.size() > curMaxActivities;
13020 i++) {
13021 final HistoryRecord r
13022 = (HistoryRecord)mLRUActivities.get(i);
13023
13024 // We can finish this one if we have its icicle saved and
13025 // it is not persistent.
13026 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13027 && r.stopped && !r.persistent && !r.finishing) {
13028 final int origSize = mLRUActivities.size();
13029 destroyActivityLocked(r, true);
13030
13031 // This will remove it from the LRU list, so keep
13032 // our index at the same value. Note that this check to
13033 // see if the size changes is just paranoia -- if
13034 // something unexpected happens, we don't want to end up
13035 // in an infinite loop.
13036 if (origSize > mLRUActivities.size()) {
13037 i--;
13038 }
13039 }
13040 }
13041 }
13042 }
13043
13044 /** This method sends the specified signal to each of the persistent apps */
13045 public void signalPersistentProcesses(int sig) throws RemoteException {
13046 if (sig != Process.SIGNAL_USR1) {
13047 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13048 }
13049
13050 synchronized (this) {
13051 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13052 != PackageManager.PERMISSION_GRANTED) {
13053 throw new SecurityException("Requires permission "
13054 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13055 }
13056
13057 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13058 ProcessRecord r = mLRUProcesses.get(i);
13059 if (r.thread != null && r.persistent) {
13060 Process.sendSignal(r.pid, sig);
13061 }
13062 }
13063 }
13064 }
13065
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013066 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013067 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013068
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013069 try {
13070 synchronized (this) {
13071 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13072 // its own permission.
13073 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13074 != PackageManager.PERMISSION_GRANTED) {
13075 throw new SecurityException("Requires permission "
13076 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013077 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013078
13079 if (start && fd == null) {
13080 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013081 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013082
13083 ProcessRecord proc = null;
13084 try {
13085 int pid = Integer.parseInt(process);
13086 synchronized (mPidsSelfLocked) {
13087 proc = mPidsSelfLocked.get(pid);
13088 }
13089 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013090 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013091
13092 if (proc == null) {
13093 HashMap<String, SparseArray<ProcessRecord>> all
13094 = mProcessNames.getMap();
13095 SparseArray<ProcessRecord> procs = all.get(process);
13096 if (procs != null && procs.size() > 0) {
13097 proc = procs.valueAt(0);
13098 }
13099 }
13100
13101 if (proc == null || proc.thread == null) {
13102 throw new IllegalArgumentException("Unknown process: " + process);
13103 }
13104
13105 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13106 if (isSecure) {
13107 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13108 throw new SecurityException("Process not debuggable: " + proc);
13109 }
13110 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013111
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013112 proc.thread.profilerControl(start, path, fd);
13113 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013114 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013115 }
13116 } catch (RemoteException e) {
13117 throw new IllegalStateException("Process disappeared");
13118 } finally {
13119 if (fd != null) {
13120 try {
13121 fd.close();
13122 } catch (IOException e) {
13123 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013124 }
13125 }
13126 }
13127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013128 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13129 public void monitor() {
13130 synchronized (this) { }
13131 }
13132}