blob: 867d8a6e6dc4cfedba654a323f38d070e776400b [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
19import com.android.internal.os.BatteryStatsImpl;
Dianne Hackbornde7faf62009-06-30 13:27:30 -070020import com.android.server.AttributeCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import com.android.server.IntentResolver;
22import com.android.server.ProcessMap;
23import com.android.server.ProcessStats;
24import com.android.server.SystemServer;
25import com.android.server.Watchdog;
26import com.android.server.WindowManagerService;
27
28import android.app.Activity;
29import android.app.ActivityManager;
30import android.app.ActivityManagerNative;
31import android.app.ActivityThread;
32import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020033import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.app.Dialog;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070035import android.app.IActivityController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.app.IActivityWatcher;
37import android.app.IApplicationThread;
38import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.app.IServiceConnection;
40import android.app.IThumbnailReceiver;
41import android.app.Instrumentation;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070042import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.app.PendingIntent;
44import android.app.ResultInfo;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070045import android.app.Service;
Christopher Tate181fafa2009-05-14 11:12:14 -070046import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020047import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.ComponentName;
49import android.content.ContentResolver;
50import android.content.Context;
51import android.content.Intent;
52import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070053import android.content.IIntentReceiver;
54import android.content.IIntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.content.pm.ActivityInfo;
56import android.content.pm.ApplicationInfo;
57import android.content.pm.ConfigurationInfo;
58import android.content.pm.IPackageDataObserver;
59import android.content.pm.IPackageManager;
60import android.content.pm.InstrumentationInfo;
61import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070062import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.content.pm.ProviderInfo;
64import android.content.pm.ResolveInfo;
65import android.content.pm.ServiceInfo;
66import android.content.res.Configuration;
67import android.graphics.Bitmap;
68import android.net.Uri;
69import android.os.Binder;
70import android.os.Bundle;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070071import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.os.Environment;
73import android.os.FileUtils;
74import android.os.Handler;
75import android.os.IBinder;
76import android.os.IPermissionController;
77import android.os.Looper;
78import android.os.Message;
79import android.os.Parcel;
80import android.os.ParcelFileDescriptor;
81import android.os.PowerManager;
82import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070083import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084import android.os.RemoteException;
85import android.os.ServiceManager;
86import android.os.SystemClock;
87import android.os.SystemProperties;
88import android.provider.Checkin;
89import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020090import android.server.data.CrashData;
91import android.server.data.StackTraceElementData;
92import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093import android.text.TextUtils;
94import android.util.Config;
95import android.util.EventLog;
96import android.util.Log;
97import android.util.PrintWriterPrinter;
98import android.util.SparseArray;
99import android.view.Gravity;
100import android.view.LayoutInflater;
101import android.view.View;
102import android.view.WindowManager;
103import android.view.WindowManagerPolicy;
104
105import dalvik.system.Zygote;
106
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200107import java.io.ByteArrayInputStream;
108import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109import java.io.File;
110import java.io.FileDescriptor;
111import java.io.FileInputStream;
112import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200113import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114import java.io.PrintWriter;
115import java.lang.IllegalStateException;
116import java.lang.ref.WeakReference;
117import java.util.ArrayList;
118import java.util.HashMap;
119import java.util.HashSet;
120import java.util.Iterator;
121import java.util.List;
122import java.util.Locale;
123import java.util.Map;
124
125public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
126 static final String TAG = "ActivityManager";
127 static final boolean DEBUG = false;
128 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
129 static final boolean DEBUG_SWITCH = localLOGV || false;
130 static final boolean DEBUG_TASKS = localLOGV || false;
131 static final boolean DEBUG_PAUSE = localLOGV || false;
132 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
133 static final boolean DEBUG_TRANSITION = localLOGV || false;
134 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700135 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 static final boolean DEBUG_SERVICE = localLOGV || false;
137 static final boolean DEBUG_VISBILITY = localLOGV || false;
138 static final boolean DEBUG_PROCESSES = localLOGV || false;
139 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700140 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700141 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 static final boolean VALIDATE_TOKENS = false;
143 static final boolean SHOW_ACTIVITY_START_TIME = true;
144
145 // Control over CPU and battery monitoring.
146 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
147 static final boolean MONITOR_CPU_USAGE = true;
148 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
149 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
150 static final boolean MONITOR_THREAD_CPU_USAGE = false;
151
152 // Event log tags
153 static final int LOG_CONFIGURATION_CHANGED = 2719;
154 static final int LOG_CPU = 2721;
155 static final int LOG_AM_FINISH_ACTIVITY = 30001;
156 static final int LOG_TASK_TO_FRONT = 30002;
157 static final int LOG_AM_NEW_INTENT = 30003;
158 static final int LOG_AM_CREATE_TASK = 30004;
159 static final int LOG_AM_CREATE_ACTIVITY = 30005;
160 static final int LOG_AM_RESTART_ACTIVITY = 30006;
161 static final int LOG_AM_RESUME_ACTIVITY = 30007;
162 static final int LOG_ANR = 30008;
163 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
164 static final int LOG_AM_PROCESS_BOUND = 30010;
165 static final int LOG_AM_PROCESS_DIED = 30011;
166 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
167 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
168 static final int LOG_AM_PROCESS_START = 30014;
169 static final int LOG_AM_PROCESS_BAD = 30015;
170 static final int LOG_AM_PROCESS_GOOD = 30016;
171 static final int LOG_AM_LOW_MEMORY = 30017;
172 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
173 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
174 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
175 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
176 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
177 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
178 static final int LOG_AM_CREATE_SERVICE = 30030;
179 static final int LOG_AM_DESTROY_SERVICE = 30031;
180 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
181 static final int LOG_AM_DROP_PROCESS = 30033;
182 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
183 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
184 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
185
186 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
187 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
188
Dianne Hackborn1655be42009-05-08 14:29:01 -0700189 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700190 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700191
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 private static final String SYSTEM_SECURE = "ro.secure";
193
194 // This is the maximum number of application processes we would like
195 // to have running. Due to the asynchronous nature of things, we can
196 // temporarily go beyond this limit.
197 static final int MAX_PROCESSES = 2;
198
199 // Set to false to leave processes running indefinitely, relying on
200 // the kernel killing them as resources are required.
201 static final boolean ENFORCE_PROCESS_LIMIT = false;
202
203 // This is the maximum number of activities that we would like to have
204 // running at a given time.
205 static final int MAX_ACTIVITIES = 20;
206
207 // Maximum number of recent tasks that we can remember.
208 static final int MAX_RECENT_TASKS = 20;
209
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700210 // Amount of time after a call to stopAppSwitches() during which we will
211 // prevent further untrusted switches from happening.
212 static final long APP_SWITCH_DELAY_TIME = 5*1000;
213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 // How long until we reset a task when the user returns to it. Currently
215 // 30 minutes.
216 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
217
218 // Set to true to disable the icon that is shown while a new activity
219 // is being started.
220 static final boolean SHOW_APP_STARTING_ICON = true;
221
222 // How long we wait until giving up on the last activity to pause. This
223 // is short because it directly impacts the responsiveness of starting the
224 // next activity.
225 static final int PAUSE_TIMEOUT = 500;
226
227 /**
228 * How long we can hold the launch wake lock before giving up.
229 */
230 static final int LAUNCH_TIMEOUT = 10*1000;
231
232 // How long we wait for a launched process to attach to the activity manager
233 // before we decide it's never going to come up for real.
234 static final int PROC_START_TIMEOUT = 10*1000;
235
236 // How long we wait until giving up on the last activity telling us it
237 // is idle.
238 static final int IDLE_TIMEOUT = 10*1000;
239
240 // How long to wait after going idle before forcing apps to GC.
241 static final int GC_TIMEOUT = 5*1000;
242
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700243 // The minimum amount of time between successive GC requests for a process.
244 static final int GC_MIN_INTERVAL = 60*1000;
245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246 // How long we wait until giving up on an activity telling us it has
247 // finished destroying itself.
248 static final int DESTROY_TIMEOUT = 10*1000;
249
250 // How long we allow a receiver to run before giving up on it.
251 static final int BROADCAST_TIMEOUT = 10*1000;
252
253 // How long we wait for a service to finish executing.
254 static final int SERVICE_TIMEOUT = 20*1000;
255
256 // How long a service needs to be running until restarting its process
257 // is no longer considered to be a relaunch of the service.
258 static final int SERVICE_RESTART_DURATION = 5*1000;
259
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700260 // How long a service needs to be running until it will start back at
261 // SERVICE_RESTART_DURATION after being killed.
262 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
263
264 // Multiplying factor to increase restart duration time by, for each time
265 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
266 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
267
268 // The minimum amount of time between restarting services that we allow.
269 // That is, when multiple services are restarting, we won't allow each
270 // to restart less than this amount of time from the last one.
271 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
272
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 // Maximum amount of time for there to be no activity on a service before
274 // we consider it non-essential and allow its process to go on the
275 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700276 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277
278 // How long we wait until we timeout on key dispatching.
279 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
280
281 // The minimum time we allow between crashes, for us to consider this
282 // application to be bad and stop and its services and reject broadcasts.
283 static final int MIN_CRASH_INTERVAL = 60*1000;
284
285 // How long we wait until we timeout on key dispatching during instrumentation.
286 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
287
288 // OOM adjustments for processes in various states:
289
290 // This is a process without anything currently running in it. Definitely
291 // the first to go! Value set in system/rootdir/init.rc on startup.
292 // This value is initalized in the constructor, careful when refering to
293 // this static variable externally.
294 static int EMPTY_APP_ADJ;
295
296 // This is a process with a content provider that does not have any clients
297 // attached to it. If it did have any clients, its adjustment would be the
298 // one for the highest-priority of those processes.
299 static int CONTENT_PROVIDER_ADJ;
300
301 // This is a process only hosting activities that are not visible,
302 // so it can be killed without any disruption. Value set in
303 // system/rootdir/init.rc on startup.
304 final int HIDDEN_APP_MAX_ADJ;
305 static int HIDDEN_APP_MIN_ADJ;
306
The Android Open Source Project4df24232009-03-05 14:34:35 -0800307 // This is a process holding the home application -- we want to try
308 // avoiding killing it, even if it would normally be in the background,
309 // because the user interacts with it so much.
310 final int HOME_APP_ADJ;
311
Christopher Tate6fa95972009-06-05 18:43:55 -0700312 // This is a process currently hosting a backup operation. Killing it
313 // is not entirely fatal but is generally a bad idea.
314 final int BACKUP_APP_ADJ;
315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 // This is a process holding a secondary server -- killing it will not
317 // have much of an impact as far as the user is concerned. Value set in
318 // system/rootdir/init.rc on startup.
319 final int SECONDARY_SERVER_ADJ;
320
321 // This is a process only hosting activities that are visible to the
322 // user, so we'd prefer they don't disappear. Value set in
323 // system/rootdir/init.rc on startup.
324 final int VISIBLE_APP_ADJ;
325
326 // This is the process running the current foreground app. We'd really
327 // rather not kill it! Value set in system/rootdir/init.rc on startup.
328 final int FOREGROUND_APP_ADJ;
329
330 // This is a process running a core server, such as telephony. Definitely
331 // don't want to kill it, but doing so is not completely fatal.
332 static final int CORE_SERVER_ADJ = -12;
333
334 // The system process runs at the default adjustment.
335 static final int SYSTEM_ADJ = -16;
336
337 // Memory pages are 4K.
338 static final int PAGE_SIZE = 4*1024;
339
Jacek Surazski82a73df2009-06-17 14:33:18 +0200340 // System property defining error report receiver for system apps
341 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
342
343 // System property defining default error report receiver
344 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
345
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 // Corresponding memory levels for above adjustments.
347 final int EMPTY_APP_MEM;
348 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800349 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700350 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 final int SECONDARY_SERVER_MEM;
352 final int VISIBLE_APP_MEM;
353 final int FOREGROUND_APP_MEM;
354
355 final int MY_PID;
356
357 static final String[] EMPTY_STRING_ARRAY = new String[0];
358
359 enum ActivityState {
360 INITIALIZING,
361 RESUMED,
362 PAUSING,
363 PAUSED,
364 STOPPING,
365 STOPPED,
366 FINISHING,
367 DESTROYING,
368 DESTROYED
369 }
370
371 /**
372 * The back history of all previous (and possibly still
373 * running) activities. It contains HistoryRecord objects.
374 */
375 final ArrayList mHistory = new ArrayList();
376
377 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700378 * Description of a request to start a new activity, which has been held
379 * due to app switches being disabled.
380 */
381 class PendingActivityLaunch {
382 HistoryRecord r;
383 HistoryRecord sourceRecord;
384 Uri[] grantedUriPermissions;
385 int grantedMode;
386 boolean onlyIfNeeded;
387 }
388
389 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
390 = new ArrayList<PendingActivityLaunch>();
391
392 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 * List of all active broadcasts that are to be executed immediately
394 * (without waiting for another broadcast to finish). Currently this only
395 * contains broadcasts to registered receivers, to avoid spinning up
396 * a bunch of processes to execute IntentReceiver components.
397 */
398 final ArrayList<BroadcastRecord> mParallelBroadcasts
399 = new ArrayList<BroadcastRecord>();
400
401 /**
402 * List of all active broadcasts that are to be executed one at a time.
403 * The object at the top of the list is the currently activity broadcasts;
404 * those after it are waiting for the top to finish..
405 */
406 final ArrayList<BroadcastRecord> mOrderedBroadcasts
407 = new ArrayList<BroadcastRecord>();
408
409 /**
410 * Set when we current have a BROADCAST_INTENT_MSG in flight.
411 */
412 boolean mBroadcastsScheduled = false;
413
414 /**
415 * Set to indicate whether to issue an onUserLeaving callback when a
416 * newly launched activity is being brought in front of us.
417 */
418 boolean mUserLeaving = false;
419
420 /**
421 * When we are in the process of pausing an activity, before starting the
422 * next one, this variable holds the activity that is currently being paused.
423 */
424 HistoryRecord mPausingActivity = null;
425
426 /**
427 * Current activity that is resumed, or null if there is none.
428 */
429 HistoryRecord mResumedActivity = null;
430
431 /**
432 * Activity we have told the window manager to have key focus.
433 */
434 HistoryRecord mFocusedActivity = null;
435
436 /**
437 * This is the last activity that we put into the paused state. This is
438 * used to determine if we need to do an activity transition while sleeping,
439 * when we normally hold the top activity paused.
440 */
441 HistoryRecord mLastPausedActivity = null;
442
443 /**
444 * List of activities that are waiting for a new activity
445 * to become visible before completing whatever operation they are
446 * supposed to do.
447 */
448 final ArrayList mWaitingVisibleActivities = new ArrayList();
449
450 /**
451 * List of activities that are ready to be stopped, but waiting
452 * for the next activity to settle down before doing so. It contains
453 * HistoryRecord objects.
454 */
455 final ArrayList<HistoryRecord> mStoppingActivities
456 = new ArrayList<HistoryRecord>();
457
458 /**
459 * List of intents that were used to start the most recent tasks.
460 */
461 final ArrayList<TaskRecord> mRecentTasks
462 = new ArrayList<TaskRecord>();
463
464 /**
465 * List of activities that are ready to be finished, but waiting
466 * for the previous activity to settle down before doing so. It contains
467 * HistoryRecord objects.
468 */
469 final ArrayList mFinishingActivities = new ArrayList();
470
471 /**
472 * All of the applications we currently have running organized by name.
473 * The keys are strings of the application package name (as
474 * returned by the package manager), and the keys are ApplicationRecord
475 * objects.
476 */
477 final ProcessMap<ProcessRecord> mProcessNames
478 = new ProcessMap<ProcessRecord>();
479
480 /**
481 * The last time that various processes have crashed.
482 */
483 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
484
485 /**
486 * Set of applications that we consider to be bad, and will reject
487 * incoming broadcasts from (which the user has no control over).
488 * Processes are added to this set when they have crashed twice within
489 * a minimum amount of time; they are removed from it when they are
490 * later restarted (hopefully due to some user action). The value is the
491 * time it was added to the list.
492 */
493 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
494
495 /**
496 * All of the processes we currently have running organized by pid.
497 * The keys are the pid running the application.
498 *
499 * <p>NOTE: This object is protected by its own lock, NOT the global
500 * activity manager lock!
501 */
502 final SparseArray<ProcessRecord> mPidsSelfLocked
503 = new SparseArray<ProcessRecord>();
504
505 /**
506 * All of the processes that have been forced to be foreground. The key
507 * is the pid of the caller who requested it (we hold a death
508 * link on it).
509 */
510 abstract class ForegroundToken implements IBinder.DeathRecipient {
511 int pid;
512 IBinder token;
513 }
514 final SparseArray<ForegroundToken> mForegroundProcesses
515 = new SparseArray<ForegroundToken>();
516
517 /**
518 * List of records for processes that someone had tried to start before the
519 * system was ready. We don't start them at that point, but ensure they
520 * are started by the time booting is complete.
521 */
522 final ArrayList<ProcessRecord> mProcessesOnHold
523 = new ArrayList<ProcessRecord>();
524
525 /**
526 * List of records for processes that we have started and are waiting
527 * for them to call back. This is really only needed when running in
528 * single processes mode, in which case we do not have a unique pid for
529 * each process.
530 */
531 final ArrayList<ProcessRecord> mStartingProcesses
532 = new ArrayList<ProcessRecord>();
533
534 /**
535 * List of persistent applications that are in the process
536 * of being started.
537 */
538 final ArrayList<ProcessRecord> mPersistentStartingProcesses
539 = new ArrayList<ProcessRecord>();
540
541 /**
542 * Processes that are being forcibly torn down.
543 */
544 final ArrayList<ProcessRecord> mRemovedProcesses
545 = new ArrayList<ProcessRecord>();
546
547 /**
548 * List of running applications, sorted by recent usage.
549 * The first entry in the list is the least recently used.
550 * It contains ApplicationRecord objects. This list does NOT include
551 * any persistent application records (since we never want to exit them).
552 */
553 final ArrayList<ProcessRecord> mLRUProcesses
554 = new ArrayList<ProcessRecord>();
555
556 /**
557 * List of processes that should gc as soon as things are idle.
558 */
559 final ArrayList<ProcessRecord> mProcessesToGc
560 = new ArrayList<ProcessRecord>();
561
562 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800563 * This is the process holding what we currently consider to be
564 * the "home" activity.
565 */
566 private ProcessRecord mHomeProcess;
567
568 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 * List of running activities, sorted by recent usage.
570 * The first entry in the list is the least recently used.
571 * It contains HistoryRecord objects.
572 */
573 private final ArrayList mLRUActivities = new ArrayList();
574
575 /**
576 * Set of PendingResultRecord objects that are currently active.
577 */
578 final HashSet mPendingResultRecords = new HashSet();
579
580 /**
581 * Set of IntentSenderRecord objects that are currently active.
582 */
583 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
584 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
585
586 /**
587 * Intent broadcast that we have tried to start, but are
588 * waiting for its application's process to be created. We only
589 * need one (instead of a list) because we always process broadcasts
590 * one at a time, so no others can be started while waiting for this
591 * one.
592 */
593 BroadcastRecord mPendingBroadcast = null;
594
595 /**
596 * Keeps track of all IIntentReceivers that have been registered for
597 * broadcasts. Hash keys are the receiver IBinder, hash value is
598 * a ReceiverList.
599 */
600 final HashMap mRegisteredReceivers = new HashMap();
601
602 /**
603 * Resolver for broadcast intents to registered receivers.
604 * Holds BroadcastFilter (subclass of IntentFilter).
605 */
606 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
607 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
608 @Override
609 protected boolean allowFilterResult(
610 BroadcastFilter filter, List<BroadcastFilter> dest) {
611 IBinder target = filter.receiverList.receiver.asBinder();
612 for (int i=dest.size()-1; i>=0; i--) {
613 if (dest.get(i).receiverList.receiver.asBinder() == target) {
614 return false;
615 }
616 }
617 return true;
618 }
619 };
620
621 /**
622 * State of all active sticky broadcasts. Keys are the action of the
623 * sticky Intent, values are an ArrayList of all broadcasted intents with
624 * that action (which should usually be one).
625 */
626 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
627 new HashMap<String, ArrayList<Intent>>();
628
629 /**
630 * All currently running services.
631 */
632 final HashMap<ComponentName, ServiceRecord> mServices =
633 new HashMap<ComponentName, ServiceRecord>();
634
635 /**
636 * All currently running services indexed by the Intent used to start them.
637 */
638 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
639 new HashMap<Intent.FilterComparison, ServiceRecord>();
640
641 /**
642 * All currently bound service connections. Keys are the IBinder of
643 * the client's IServiceConnection.
644 */
645 final HashMap<IBinder, ConnectionRecord> mServiceConnections
646 = new HashMap<IBinder, ConnectionRecord>();
647
648 /**
649 * List of services that we have been asked to start,
650 * but haven't yet been able to. It is used to hold start requests
651 * while waiting for their corresponding application thread to get
652 * going.
653 */
654 final ArrayList<ServiceRecord> mPendingServices
655 = new ArrayList<ServiceRecord>();
656
657 /**
658 * List of services that are scheduled to restart following a crash.
659 */
660 final ArrayList<ServiceRecord> mRestartingServices
661 = new ArrayList<ServiceRecord>();
662
663 /**
664 * List of services that are in the process of being stopped.
665 */
666 final ArrayList<ServiceRecord> mStoppingServices
667 = new ArrayList<ServiceRecord>();
668
669 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700670 * Backup/restore process management
671 */
672 String mBackupAppName = null;
673 BackupRecord mBackupTarget = null;
674
675 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 * List of PendingThumbnailsRecord objects of clients who are still
677 * waiting to receive all of the thumbnails for a task.
678 */
679 final ArrayList mPendingThumbnails = new ArrayList();
680
681 /**
682 * List of HistoryRecord objects that have been finished and must
683 * still report back to a pending thumbnail receiver.
684 */
685 final ArrayList mCancelledThumbnails = new ArrayList();
686
687 /**
688 * All of the currently running global content providers. Keys are a
689 * string containing the provider name and values are a
690 * ContentProviderRecord object containing the data about it. Note
691 * that a single provider may be published under multiple names, so
692 * there may be multiple entries here for a single one in mProvidersByClass.
693 */
694 final HashMap mProvidersByName = new HashMap();
695
696 /**
697 * All of the currently running global content providers. Keys are a
698 * string containing the provider's implementation class and values are a
699 * ContentProviderRecord object containing the data about it.
700 */
701 final HashMap mProvidersByClass = new HashMap();
702
703 /**
704 * List of content providers who have clients waiting for them. The
705 * application is currently being launched and the provider will be
706 * removed from this list once it is published.
707 */
708 final ArrayList mLaunchingProviders = new ArrayList();
709
710 /**
711 * Global set of specific Uri permissions that have been granted.
712 */
713 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
714 = new SparseArray<HashMap<Uri, UriPermission>>();
715
716 /**
717 * Thread-local storage used to carry caller permissions over through
718 * indirect content-provider access.
719 * @see #ActivityManagerService.openContentUri()
720 */
721 private class Identity {
722 public int pid;
723 public int uid;
724
725 Identity(int _pid, int _uid) {
726 pid = _pid;
727 uid = _uid;
728 }
729 }
730 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
731
732 /**
733 * All information we have collected about the runtime performance of
734 * any user id that can impact battery performance.
735 */
736 final BatteryStatsService mBatteryStatsService;
737
738 /**
739 * information about component usage
740 */
741 final UsageStatsService mUsageStatsService;
742
743 /**
744 * Current configuration information. HistoryRecord objects are given
745 * a reference to this object to indicate which configuration they are
746 * currently running in, so this object must be kept immutable.
747 */
748 Configuration mConfiguration = new Configuration();
749
750 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700751 * Hardware-reported OpenGLES version.
752 */
753 final int GL_ES_VERSION;
754
755 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 * List of initialization arguments to pass to all processes when binding applications to them.
757 * For example, references to the commonly used services.
758 */
759 HashMap<String, IBinder> mAppBindArgs;
760
761 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700762 * Temporary to avoid allocations. Protected by main lock.
763 */
764 final StringBuilder mStringBuilder = new StringBuilder(256);
765
766 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 * Used to control how we initialize the service.
768 */
769 boolean mStartRunning = false;
770 ComponentName mTopComponent;
771 String mTopAction;
772 String mTopData;
773 boolean mSystemReady = false;
774 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700775 boolean mWaitingUpdate = false;
776 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777
778 Context mContext;
779
780 int mFactoryTest;
781
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700782 boolean mCheckedForSetup;
783
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700785 * The time at which we will allow normal application switches again,
786 * after a call to {@link #stopAppSwitches()}.
787 */
788 long mAppSwitchesAllowedTime;
789
790 /**
791 * This is set to true after the first switch after mAppSwitchesAllowedTime
792 * is set; any switches after that will clear the time.
793 */
794 boolean mDidAppSwitch;
795
796 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 * Set while we are wanting to sleep, to prevent any
798 * activities from being started/resumed.
799 */
800 boolean mSleeping = false;
801
802 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700803 * Set if we are shutting down the system, similar to sleeping.
804 */
805 boolean mShuttingDown = false;
806
807 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800808 * Set when the system is going to sleep, until we have
809 * successfully paused the current activity and released our wake lock.
810 * At that point the system is allowed to actually sleep.
811 */
812 PowerManager.WakeLock mGoingToSleep;
813
814 /**
815 * We don't want to allow the device to go to sleep while in the process
816 * of launching an activity. This is primarily to allow alarm intent
817 * receivers to launch an activity and get that to run before the device
818 * goes back to sleep.
819 */
820 PowerManager.WakeLock mLaunchingActivity;
821
822 /**
823 * Task identifier that activities are currently being started
824 * in. Incremented each time a new task is created.
825 * todo: Replace this with a TokenSpace class that generates non-repeating
826 * integers that won't wrap.
827 */
828 int mCurTask = 1;
829
830 /**
831 * Current sequence id for oom_adj computation traversal.
832 */
833 int mAdjSeq = 0;
834
835 /**
836 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
837 * is set, indicating the user wants processes started in such a way
838 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
839 * running in each process (thus no pre-initialized process, etc).
840 */
841 boolean mSimpleProcessManagement = false;
842
843 /**
844 * System monitoring: number of processes that died since the last
845 * N procs were started.
846 */
847 int[] mProcDeaths = new int[20];
848
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700849 /**
850 * This is set if we had to do a delayed dexopt of an app before launching
851 * it, to increasing the ANR timeouts in that case.
852 */
853 boolean mDidDexOpt;
854
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 String mDebugApp = null;
856 boolean mWaitForDebugger = false;
857 boolean mDebugTransient = false;
858 String mOrigDebugApp = null;
859 boolean mOrigWaitForDebugger = false;
860 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700861 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800862
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700863 final RemoteCallbackList<IActivityWatcher> mWatchers
864 = new RemoteCallbackList<IActivityWatcher>();
865
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 /**
867 * Callback of last caller to {@link #requestPss}.
868 */
869 Runnable mRequestPssCallback;
870
871 /**
872 * Remaining processes for which we are waiting results from the last
873 * call to {@link #requestPss}.
874 */
875 final ArrayList<ProcessRecord> mRequestPssList
876 = new ArrayList<ProcessRecord>();
877
878 /**
879 * Runtime statistics collection thread. This object's lock is used to
880 * protect all related state.
881 */
882 final Thread mProcessStatsThread;
883
884 /**
885 * Used to collect process stats when showing not responding dialog.
886 * Protected by mProcessStatsThread.
887 */
888 final ProcessStats mProcessStats = new ProcessStats(
889 MONITOR_THREAD_CPU_USAGE);
890 long mLastCpuTime = 0;
891 long mLastWriteTime = 0;
892
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700893 long mInitialStartTime = 0;
894
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800895 /**
896 * Set to true after the system has finished booting.
897 */
898 boolean mBooted = false;
899
900 int mProcessLimit = 0;
901
902 WindowManagerService mWindowManager;
903
904 static ActivityManagerService mSelf;
905 static ActivityThread mSystemThread;
906
907 private final class AppDeathRecipient implements IBinder.DeathRecipient {
908 final ProcessRecord mApp;
909 final int mPid;
910 final IApplicationThread mAppThread;
911
912 AppDeathRecipient(ProcessRecord app, int pid,
913 IApplicationThread thread) {
914 if (localLOGV) Log.v(
915 TAG, "New death recipient " + this
916 + " for thread " + thread.asBinder());
917 mApp = app;
918 mPid = pid;
919 mAppThread = thread;
920 }
921
922 public void binderDied() {
923 if (localLOGV) Log.v(
924 TAG, "Death received in " + this
925 + " for thread " + mAppThread.asBinder());
926 removeRequestedPss(mApp);
927 synchronized(ActivityManagerService.this) {
928 appDiedLocked(mApp, mPid, mAppThread);
929 }
930 }
931 }
932
933 static final int SHOW_ERROR_MSG = 1;
934 static final int SHOW_NOT_RESPONDING_MSG = 2;
935 static final int SHOW_FACTORY_ERROR_MSG = 3;
936 static final int UPDATE_CONFIGURATION_MSG = 4;
937 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
938 static final int WAIT_FOR_DEBUGGER_MSG = 6;
939 static final int BROADCAST_INTENT_MSG = 7;
940 static final int BROADCAST_TIMEOUT_MSG = 8;
941 static final int PAUSE_TIMEOUT_MSG = 9;
942 static final int IDLE_TIMEOUT_MSG = 10;
943 static final int IDLE_NOW_MSG = 11;
944 static final int SERVICE_TIMEOUT_MSG = 12;
945 static final int UPDATE_TIME_ZONE = 13;
946 static final int SHOW_UID_ERROR_MSG = 14;
947 static final int IM_FEELING_LUCKY_MSG = 15;
948 static final int LAUNCH_TIMEOUT_MSG = 16;
949 static final int DESTROY_TIMEOUT_MSG = 17;
950 static final int SERVICE_ERROR_MSG = 18;
951 static final int RESUME_TOP_ACTIVITY_MSG = 19;
952 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700953 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700954 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800955
956 AlertDialog mUidAlert;
957
958 final Handler mHandler = new Handler() {
959 //public Handler() {
960 // if (localLOGV) Log.v(TAG, "Handler started!");
961 //}
962
963 public void handleMessage(Message msg) {
964 switch (msg.what) {
965 case SHOW_ERROR_MSG: {
966 HashMap data = (HashMap) msg.obj;
967 byte[] crashData = (byte[])data.get("crashData");
968 if (crashData != null) {
969 // This needs to be *un*synchronized to avoid deadlock.
970 ContentResolver resolver = mContext.getContentResolver();
971 Checkin.reportCrash(resolver, crashData);
972 }
973 synchronized (ActivityManagerService.this) {
974 ProcessRecord proc = (ProcessRecord)data.get("app");
975 if (proc != null && proc.crashDialog != null) {
976 Log.e(TAG, "App already has crash dialog: " + proc);
977 return;
978 }
979 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700980 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 Dialog d = new AppErrorDialog(
982 mContext, res, proc,
983 (Integer)data.get("flags"),
984 (String)data.get("shortMsg"),
985 (String)data.get("longMsg"));
986 d.show();
987 proc.crashDialog = d;
988 } else {
989 // The device is asleep, so just pretend that the user
990 // saw a crash dialog and hit "force quit".
991 res.set(0);
992 }
993 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700994
995 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 } break;
997 case SHOW_NOT_RESPONDING_MSG: {
998 synchronized (ActivityManagerService.this) {
999 HashMap data = (HashMap) msg.obj;
1000 ProcessRecord proc = (ProcessRecord)data.get("app");
1001 if (proc != null && proc.anrDialog != null) {
1002 Log.e(TAG, "App already has anr dialog: " + proc);
1003 return;
1004 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001005
1006 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1007 null, null, 0, null, null, null,
1008 false, false, MY_PID, Process.SYSTEM_UID);
1009
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1011 mContext, proc, (HistoryRecord)data.get("activity"));
1012 d.show();
1013 proc.anrDialog = d;
1014 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001015
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001016 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 } break;
1018 case SHOW_FACTORY_ERROR_MSG: {
1019 Dialog d = new FactoryErrorDialog(
1020 mContext, msg.getData().getCharSequence("msg"));
1021 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001022 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 } break;
1024 case UPDATE_CONFIGURATION_MSG: {
1025 final ContentResolver resolver = mContext.getContentResolver();
1026 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1027 } break;
1028 case GC_BACKGROUND_PROCESSES_MSG: {
1029 synchronized (ActivityManagerService.this) {
1030 performAppGcsIfAppropriateLocked();
1031 }
1032 } break;
1033 case WAIT_FOR_DEBUGGER_MSG: {
1034 synchronized (ActivityManagerService.this) {
1035 ProcessRecord app = (ProcessRecord)msg.obj;
1036 if (msg.arg1 != 0) {
1037 if (!app.waitedForDebugger) {
1038 Dialog d = new AppWaitingForDebuggerDialog(
1039 ActivityManagerService.this,
1040 mContext, app);
1041 app.waitDialog = d;
1042 app.waitedForDebugger = true;
1043 d.show();
1044 }
1045 } else {
1046 if (app.waitDialog != null) {
1047 app.waitDialog.dismiss();
1048 app.waitDialog = null;
1049 }
1050 }
1051 }
1052 } break;
1053 case BROADCAST_INTENT_MSG: {
1054 if (DEBUG_BROADCAST) Log.v(
1055 TAG, "Received BROADCAST_INTENT_MSG");
1056 processNextBroadcast(true);
1057 } break;
1058 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001059 if (mDidDexOpt) {
1060 mDidDexOpt = false;
1061 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1062 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1063 return;
1064 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 broadcastTimeout();
1066 } break;
1067 case PAUSE_TIMEOUT_MSG: {
1068 IBinder token = (IBinder)msg.obj;
1069 // We don't at this point know if the activity is fullscreen,
1070 // so we need to be conservative and assume it isn't.
1071 Log.w(TAG, "Activity pause timeout for " + token);
1072 activityPaused(token, null, true);
1073 } break;
1074 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001075 if (mDidDexOpt) {
1076 mDidDexOpt = false;
1077 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1078 nmsg.obj = msg.obj;
1079 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1080 return;
1081 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001082 // We don't at this point know if the activity is fullscreen,
1083 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001084 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001085 Log.w(TAG, "Activity idle timeout for " + token);
1086 activityIdleInternal(token, true);
1087 } break;
1088 case DESTROY_TIMEOUT_MSG: {
1089 IBinder token = (IBinder)msg.obj;
1090 // We don't at this point know if the activity is fullscreen,
1091 // so we need to be conservative and assume it isn't.
1092 Log.w(TAG, "Activity destroy timeout for " + token);
1093 activityDestroyed(token);
1094 } break;
1095 case IDLE_NOW_MSG: {
1096 IBinder token = (IBinder)msg.obj;
1097 activityIdle(token);
1098 } break;
1099 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001100 if (mDidDexOpt) {
1101 mDidDexOpt = false;
1102 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1103 nmsg.obj = msg.obj;
1104 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1105 return;
1106 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107 serviceTimeout((ProcessRecord)msg.obj);
1108 } break;
1109 case UPDATE_TIME_ZONE: {
1110 synchronized (ActivityManagerService.this) {
1111 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1112 ProcessRecord r = mLRUProcesses.get(i);
1113 if (r.thread != null) {
1114 try {
1115 r.thread.updateTimeZone();
1116 } catch (RemoteException ex) {
1117 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1118 }
1119 }
1120 }
1121 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001122 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123 case SHOW_UID_ERROR_MSG: {
1124 // XXX This is a temporary dialog, no need to localize.
1125 AlertDialog d = new BaseErrorDialog(mContext);
1126 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1127 d.setCancelable(false);
1128 d.setTitle("System UIDs Inconsistent");
1129 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1130 d.setButton("I'm Feeling Lucky",
1131 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1132 mUidAlert = d;
1133 d.show();
1134 } break;
1135 case IM_FEELING_LUCKY_MSG: {
1136 if (mUidAlert != null) {
1137 mUidAlert.dismiss();
1138 mUidAlert = null;
1139 }
1140 } break;
1141 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001142 if (mDidDexOpt) {
1143 mDidDexOpt = false;
1144 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1145 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1146 return;
1147 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148 synchronized (ActivityManagerService.this) {
1149 if (mLaunchingActivity.isHeld()) {
1150 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1151 mLaunchingActivity.release();
1152 }
1153 }
1154 } break;
1155 case SERVICE_ERROR_MSG: {
1156 ServiceRecord srv = (ServiceRecord)msg.obj;
1157 // This needs to be *un*synchronized to avoid deadlock.
1158 Checkin.logEvent(mContext.getContentResolver(),
1159 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1160 srv.name.toShortString());
1161 } break;
1162 case RESUME_TOP_ACTIVITY_MSG: {
1163 synchronized (ActivityManagerService.this) {
1164 resumeTopActivityLocked(null);
1165 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001166 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001167 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001168 if (mDidDexOpt) {
1169 mDidDexOpt = false;
1170 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1171 nmsg.obj = msg.obj;
1172 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1173 return;
1174 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001175 ProcessRecord app = (ProcessRecord)msg.obj;
1176 synchronized (ActivityManagerService.this) {
1177 processStartTimedOutLocked(app);
1178 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001179 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001180 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1181 synchronized (ActivityManagerService.this) {
1182 doPendingActivityLaunchesLocked(true);
1183 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001184 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001185 case KILL_APPLICATION_MSG: {
1186 synchronized (ActivityManagerService.this) {
1187 int uid = msg.arg1;
1188 boolean restart = (msg.arg2 == 1);
1189 String pkg = (String) msg.obj;
1190 uninstallPackageLocked(pkg, uid, restart);
1191 }
1192 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 }
1194 }
1195 };
1196
1197 public static void setSystemProcess() {
1198 try {
1199 ActivityManagerService m = mSelf;
1200
1201 ServiceManager.addService("activity", m);
1202 ServiceManager.addService("meminfo", new MemBinder(m));
1203 if (MONITOR_CPU_USAGE) {
1204 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1205 }
1206 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1207 ServiceManager.addService("activity.services", new ServicesBinder(m));
1208 ServiceManager.addService("activity.senders", new SendersBinder(m));
1209 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1210 ServiceManager.addService("permission", new PermissionController(m));
1211
1212 ApplicationInfo info =
1213 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001214 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 synchronized (mSelf) {
1216 ProcessRecord app = mSelf.newProcessRecordLocked(
1217 mSystemThread.getApplicationThread(), info,
1218 info.processName);
1219 app.persistent = true;
1220 app.pid = Process.myPid();
1221 app.maxAdj = SYSTEM_ADJ;
1222 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1223 synchronized (mSelf.mPidsSelfLocked) {
1224 mSelf.mPidsSelfLocked.put(app.pid, app);
1225 }
1226 mSelf.updateLRUListLocked(app, true);
1227 }
1228 } catch (PackageManager.NameNotFoundException e) {
1229 throw new RuntimeException(
1230 "Unable to find android system package", e);
1231 }
1232 }
1233
1234 public void setWindowManager(WindowManagerService wm) {
1235 mWindowManager = wm;
1236 }
1237
1238 public static final Context main(int factoryTest) {
1239 AThread thr = new AThread();
1240 thr.start();
1241
1242 synchronized (thr) {
1243 while (thr.mService == null) {
1244 try {
1245 thr.wait();
1246 } catch (InterruptedException e) {
1247 }
1248 }
1249 }
1250
1251 ActivityManagerService m = thr.mService;
1252 mSelf = m;
1253 ActivityThread at = ActivityThread.systemMain();
1254 mSystemThread = at;
1255 Context context = at.getSystemContext();
1256 m.mContext = context;
1257 m.mFactoryTest = factoryTest;
1258 PowerManager pm =
1259 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1260 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1261 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1262 m.mLaunchingActivity.setReferenceCounted(false);
1263
1264 m.mBatteryStatsService.publish(context);
1265 m.mUsageStatsService.publish(context);
1266
1267 synchronized (thr) {
1268 thr.mReady = true;
1269 thr.notifyAll();
1270 }
1271
1272 m.startRunning(null, null, null, null);
1273
1274 return context;
1275 }
1276
1277 public static ActivityManagerService self() {
1278 return mSelf;
1279 }
1280
1281 static class AThread extends Thread {
1282 ActivityManagerService mService;
1283 boolean mReady = false;
1284
1285 public AThread() {
1286 super("ActivityManager");
1287 }
1288
1289 public void run() {
1290 Looper.prepare();
1291
1292 android.os.Process.setThreadPriority(
1293 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1294
1295 ActivityManagerService m = new ActivityManagerService();
1296
1297 synchronized (this) {
1298 mService = m;
1299 notifyAll();
1300 }
1301
1302 synchronized (this) {
1303 while (!mReady) {
1304 try {
1305 wait();
1306 } catch (InterruptedException e) {
1307 }
1308 }
1309 }
1310
1311 Looper.loop();
1312 }
1313 }
1314
1315 static class BroadcastsBinder extends Binder {
1316 ActivityManagerService mActivityManagerService;
1317 BroadcastsBinder(ActivityManagerService activityManagerService) {
1318 mActivityManagerService = activityManagerService;
1319 }
1320
1321 @Override
1322 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1323 mActivityManagerService.dumpBroadcasts(pw);
1324 }
1325 }
1326
1327 static class ServicesBinder extends Binder {
1328 ActivityManagerService mActivityManagerService;
1329 ServicesBinder(ActivityManagerService activityManagerService) {
1330 mActivityManagerService = activityManagerService;
1331 }
1332
1333 @Override
1334 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1335 mActivityManagerService.dumpServices(pw);
1336 }
1337 }
1338
1339 static class SendersBinder extends Binder {
1340 ActivityManagerService mActivityManagerService;
1341 SendersBinder(ActivityManagerService activityManagerService) {
1342 mActivityManagerService = activityManagerService;
1343 }
1344
1345 @Override
1346 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1347 mActivityManagerService.dumpSenders(pw);
1348 }
1349 }
1350
1351 static class ProvidersBinder extends Binder {
1352 ActivityManagerService mActivityManagerService;
1353 ProvidersBinder(ActivityManagerService activityManagerService) {
1354 mActivityManagerService = activityManagerService;
1355 }
1356
1357 @Override
1358 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1359 mActivityManagerService.dumpProviders(pw);
1360 }
1361 }
1362
1363 static class MemBinder extends Binder {
1364 ActivityManagerService mActivityManagerService;
1365 MemBinder(ActivityManagerService activityManagerService) {
1366 mActivityManagerService = activityManagerService;
1367 }
1368
1369 @Override
1370 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1371 ActivityManagerService service = mActivityManagerService;
1372 ArrayList<ProcessRecord> procs;
1373 synchronized (mActivityManagerService) {
1374 if (args != null && args.length > 0
1375 && args[0].charAt(0) != '-') {
1376 procs = new ArrayList<ProcessRecord>();
1377 int pid = -1;
1378 try {
1379 pid = Integer.parseInt(args[0]);
1380 } catch (NumberFormatException e) {
1381
1382 }
1383 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1384 ProcessRecord proc = service.mLRUProcesses.get(i);
1385 if (proc.pid == pid) {
1386 procs.add(proc);
1387 } else if (proc.processName.equals(args[0])) {
1388 procs.add(proc);
1389 }
1390 }
1391 if (procs.size() <= 0) {
1392 pw.println("No process found for: " + args[0]);
1393 return;
1394 }
1395 } else {
1396 procs = service.mLRUProcesses;
1397 }
1398 }
1399 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1400 }
1401 }
1402
1403 static class CpuBinder extends Binder {
1404 ActivityManagerService mActivityManagerService;
1405 CpuBinder(ActivityManagerService activityManagerService) {
1406 mActivityManagerService = activityManagerService;
1407 }
1408
1409 @Override
1410 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1411 synchronized (mActivityManagerService.mProcessStatsThread) {
1412 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1413 }
1414 }
1415 }
1416
1417 private ActivityManagerService() {
1418 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1419 if (v != null && Integer.getInteger(v) != 0) {
1420 mSimpleProcessManagement = true;
1421 }
1422 v = System.getenv("ANDROID_DEBUG_APP");
1423 if (v != null) {
1424 mSimpleProcessManagement = true;
1425 }
1426
1427 MY_PID = Process.myPid();
1428
1429 File dataDir = Environment.getDataDirectory();
1430 File systemDir = new File(dataDir, "system");
1431 systemDir.mkdirs();
1432 mBatteryStatsService = new BatteryStatsService(new File(
1433 systemDir, "batterystats.bin").toString());
1434 mBatteryStatsService.getActiveStatistics().readLocked();
1435 mBatteryStatsService.getActiveStatistics().writeLocked();
1436
1437 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001438 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001439
Jack Palevichb90d28c2009-07-22 15:35:24 -07001440 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1441 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1442
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001443 mConfiguration.makeDefault();
1444 mProcessStats.init();
1445
1446 // Add ourself to the Watchdog monitors.
1447 Watchdog.getInstance().addMonitor(this);
1448
1449 // These values are set in system/rootdir/init.rc on startup.
1450 FOREGROUND_APP_ADJ =
1451 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1452 VISIBLE_APP_ADJ =
1453 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1454 SECONDARY_SERVER_ADJ =
1455 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001456 BACKUP_APP_ADJ =
1457 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001458 HOME_APP_ADJ =
1459 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 HIDDEN_APP_MIN_ADJ =
1461 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1462 CONTENT_PROVIDER_ADJ =
1463 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1464 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1465 EMPTY_APP_ADJ =
1466 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1467 FOREGROUND_APP_MEM =
1468 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1469 VISIBLE_APP_MEM =
1470 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1471 SECONDARY_SERVER_MEM =
1472 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001473 BACKUP_APP_MEM =
1474 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001475 HOME_APP_MEM =
1476 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001477 HIDDEN_APP_MEM =
1478 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1479 EMPTY_APP_MEM =
1480 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1481
1482 mProcessStatsThread = new Thread("ProcessStats") {
1483 public void run() {
1484 while (true) {
1485 try {
1486 try {
1487 synchronized(this) {
1488 final long now = SystemClock.uptimeMillis();
1489 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1490 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1491 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1492 // + ", write delay=" + nextWriteDelay);
1493 if (nextWriteDelay < nextCpuDelay) {
1494 nextCpuDelay = nextWriteDelay;
1495 }
1496 if (nextCpuDelay > 0) {
1497 this.wait(nextCpuDelay);
1498 }
1499 }
1500 } catch (InterruptedException e) {
1501 }
1502
1503 updateCpuStatsNow();
1504 } catch (Exception e) {
1505 Log.e(TAG, "Unexpected exception collecting process stats", e);
1506 }
1507 }
1508 }
1509 };
1510 mProcessStatsThread.start();
1511 }
1512
1513 @Override
1514 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1515 throws RemoteException {
1516 try {
1517 return super.onTransact(code, data, reply, flags);
1518 } catch (RuntimeException e) {
1519 // The activity manager only throws security exceptions, so let's
1520 // log all others.
1521 if (!(e instanceof SecurityException)) {
1522 Log.e(TAG, "Activity Manager Crash", e);
1523 }
1524 throw e;
1525 }
1526 }
1527
1528 void updateCpuStats() {
1529 synchronized (mProcessStatsThread) {
1530 final long now = SystemClock.uptimeMillis();
1531 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1532 mProcessStatsThread.notify();
1533 }
1534 }
1535 }
1536
1537 void updateCpuStatsNow() {
1538 synchronized (mProcessStatsThread) {
1539 final long now = SystemClock.uptimeMillis();
1540 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001541
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001542 if (MONITOR_CPU_USAGE &&
1543 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1544 mLastCpuTime = now;
1545 haveNewCpuStats = true;
1546 mProcessStats.update();
1547 //Log.i(TAG, mProcessStats.printCurrentState());
1548 //Log.i(TAG, "Total CPU usage: "
1549 // + mProcessStats.getTotalCpuPercent() + "%");
1550
1551 // Log the cpu usage if the property is set.
1552 if ("true".equals(SystemProperties.get("events.cpu"))) {
1553 int user = mProcessStats.getLastUserTime();
1554 int system = mProcessStats.getLastSystemTime();
1555 int iowait = mProcessStats.getLastIoWaitTime();
1556 int irq = mProcessStats.getLastIrqTime();
1557 int softIrq = mProcessStats.getLastSoftIrqTime();
1558 int idle = mProcessStats.getLastIdleTime();
1559
1560 int total = user + system + iowait + irq + softIrq + idle;
1561 if (total == 0) total = 1;
1562
1563 EventLog.writeEvent(LOG_CPU,
1564 ((user+system+iowait+irq+softIrq) * 100) / total,
1565 (user * 100) / total,
1566 (system * 100) / total,
1567 (iowait * 100) / total,
1568 (irq * 100) / total,
1569 (softIrq * 100) / total);
1570 }
1571 }
1572
Amith Yamasani819f9282009-06-24 23:18:15 -07001573 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001574 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001575 synchronized(mPidsSelfLocked) {
1576 if (haveNewCpuStats) {
1577 if (mBatteryStatsService.isOnBattery()) {
1578 final int N = mProcessStats.countWorkingStats();
1579 for (int i=0; i<N; i++) {
1580 ProcessStats.Stats st
1581 = mProcessStats.getWorkingStats(i);
1582 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1583 if (pr != null) {
1584 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1585 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001586 } else {
1587 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001588 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001589 if (ps != null) {
1590 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1591 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001592 }
1593 }
1594 }
1595 }
1596 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001597
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001598 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1599 mLastWriteTime = now;
1600 mBatteryStatsService.getActiveStatistics().writeLocked();
1601 }
1602 }
1603 }
1604 }
1605
1606 /**
1607 * Initialize the application bind args. These are passed to each
1608 * process when the bindApplication() IPC is sent to the process. They're
1609 * lazily setup to make sure the services are running when they're asked for.
1610 */
1611 private HashMap<String, IBinder> getCommonServicesLocked() {
1612 if (mAppBindArgs == null) {
1613 mAppBindArgs = new HashMap<String, IBinder>();
1614
1615 // Setup the application init args
1616 mAppBindArgs.put("package", ServiceManager.getService("package"));
1617 mAppBindArgs.put("window", ServiceManager.getService("window"));
1618 mAppBindArgs.put(Context.ALARM_SERVICE,
1619 ServiceManager.getService(Context.ALARM_SERVICE));
1620 }
1621 return mAppBindArgs;
1622 }
1623
1624 private final void setFocusedActivityLocked(HistoryRecord r) {
1625 if (mFocusedActivity != r) {
1626 mFocusedActivity = r;
1627 mWindowManager.setFocusedApp(r, true);
1628 }
1629 }
1630
1631 private final void updateLRUListLocked(ProcessRecord app,
1632 boolean oomAdj) {
1633 // put it on the LRU to keep track of when it should be exited.
1634 int lrui = mLRUProcesses.indexOf(app);
1635 if (lrui >= 0) mLRUProcesses.remove(lrui);
1636 mLRUProcesses.add(app);
1637 //Log.i(TAG, "Putting proc to front: " + app.processName);
1638 if (oomAdj) {
1639 updateOomAdjLocked();
1640 }
1641 }
1642
1643 private final boolean updateLRUListLocked(HistoryRecord r) {
1644 final boolean hadit = mLRUActivities.remove(r);
1645 mLRUActivities.add(r);
1646 return hadit;
1647 }
1648
1649 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1650 int i = mHistory.size()-1;
1651 while (i >= 0) {
1652 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1653 if (!r.finishing && r != notTop) {
1654 return r;
1655 }
1656 i--;
1657 }
1658 return null;
1659 }
1660
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001661 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1662 int i = mHistory.size()-1;
1663 while (i >= 0) {
1664 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1665 if (!r.finishing && !r.delayedResume && r != notTop) {
1666 return r;
1667 }
1668 i--;
1669 }
1670 return null;
1671 }
1672
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001673 /**
1674 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001675 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001676 *
1677 * @param token If non-null, any history records matching this token will be skipped.
1678 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1679 *
1680 * @return Returns the HistoryRecord of the next activity on the stack.
1681 */
1682 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1683 int i = mHistory.size()-1;
1684 while (i >= 0) {
1685 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1686 // Note: the taskId check depends on real taskId fields being non-zero
1687 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1688 return r;
1689 }
1690 i--;
1691 }
1692 return null;
1693 }
1694
1695 private final ProcessRecord getProcessRecordLocked(
1696 String processName, int uid) {
1697 if (uid == Process.SYSTEM_UID) {
1698 // The system gets to run in any process. If there are multiple
1699 // processes with the same uid, just pick the first (this
1700 // should never happen).
1701 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1702 processName);
1703 return procs != null ? procs.valueAt(0) : null;
1704 }
1705 ProcessRecord proc = mProcessNames.get(processName, uid);
1706 return proc;
1707 }
1708
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001709 private void ensurePackageDexOpt(String packageName) {
1710 IPackageManager pm = ActivityThread.getPackageManager();
1711 try {
1712 if (pm.performDexOpt(packageName)) {
1713 mDidDexOpt = true;
1714 }
1715 } catch (RemoteException e) {
1716 }
1717 }
1718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 private boolean isNextTransitionForward() {
1720 int transit = mWindowManager.getPendingAppTransition();
1721 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1722 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1723 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1724 }
1725
1726 private final boolean realStartActivityLocked(HistoryRecord r,
1727 ProcessRecord app, boolean andResume, boolean checkConfig)
1728 throws RemoteException {
1729
1730 r.startFreezingScreenLocked(app, 0);
1731 mWindowManager.setAppVisibility(r, true);
1732
1733 // Have the window manager re-evaluate the orientation of
1734 // the screen based on the new activity order. Note that
1735 // as a result of this, it can call back into the activity
1736 // manager with a new orientation. We don't care about that,
1737 // because the activity is not currently running so we are
1738 // just restarting it anyway.
1739 if (checkConfig) {
1740 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001741 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 r.mayFreezeScreenLocked(app) ? r : null);
1743 updateConfigurationLocked(config, r);
1744 }
1745
1746 r.app = app;
1747
1748 if (localLOGV) Log.v(TAG, "Launching: " + r);
1749
1750 int idx = app.activities.indexOf(r);
1751 if (idx < 0) {
1752 app.activities.add(r);
1753 }
1754 updateLRUListLocked(app, true);
1755
1756 try {
1757 if (app.thread == null) {
1758 throw new RemoteException();
1759 }
1760 List<ResultInfo> results = null;
1761 List<Intent> newIntents = null;
1762 if (andResume) {
1763 results = r.results;
1764 newIntents = r.newIntents;
1765 }
1766 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1767 + " icicle=" + r.icicle
1768 + " with results=" + results + " newIntents=" + newIntents
1769 + " andResume=" + andResume);
1770 if (andResume) {
1771 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1772 System.identityHashCode(r),
1773 r.task.taskId, r.shortComponentName);
1774 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001775 if (r.isHomeActivity) {
1776 mHomeProcess = app;
1777 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001778 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001779 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001780 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001781 r.info, r.icicle, results, newIntents, !andResume,
1782 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001783 } catch (RemoteException e) {
1784 if (r.launchFailed) {
1785 // This is the second time we failed -- finish activity
1786 // and give up.
1787 Log.e(TAG, "Second failure launching "
1788 + r.intent.getComponent().flattenToShortString()
1789 + ", giving up", e);
1790 appDiedLocked(app, app.pid, app.thread);
1791 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1792 "2nd-crash");
1793 return false;
1794 }
1795
1796 // This is the first time we failed -- restart process and
1797 // retry.
1798 app.activities.remove(r);
1799 throw e;
1800 }
1801
1802 r.launchFailed = false;
1803 if (updateLRUListLocked(r)) {
1804 Log.w(TAG, "Activity " + r
1805 + " being launched, but already in LRU list");
1806 }
1807
1808 if (andResume) {
1809 // As part of the process of launching, ActivityThread also performs
1810 // a resume.
1811 r.state = ActivityState.RESUMED;
1812 r.icicle = null;
1813 r.haveState = false;
1814 r.stopped = false;
1815 mResumedActivity = r;
1816 r.task.touchActiveTime();
1817 completeResumeLocked(r);
1818 pauseIfSleepingLocked();
1819 } else {
1820 // This activity is not starting in the resumed state... which
1821 // should look like we asked it to pause+stop (but remain visible),
1822 // and it has done so and reported back the current icicle and
1823 // other state.
1824 r.state = ActivityState.STOPPED;
1825 r.stopped = true;
1826 }
1827
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001828 // Launch the new version setup screen if needed. We do this -after-
1829 // launching the initial activity (that is, home), so that it can have
1830 // a chance to initialize itself while in the background, making the
1831 // switch back to it faster and look better.
1832 startSetupActivityLocked();
1833
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001834 return true;
1835 }
1836
1837 private final void startSpecificActivityLocked(HistoryRecord r,
1838 boolean andResume, boolean checkConfig) {
1839 // Is this activity's application already running?
1840 ProcessRecord app = getProcessRecordLocked(r.processName,
1841 r.info.applicationInfo.uid);
1842
1843 if (r.startTime == 0) {
1844 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001845 if (mInitialStartTime == 0) {
1846 mInitialStartTime = r.startTime;
1847 }
1848 } else if (mInitialStartTime == 0) {
1849 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 }
1851
1852 if (app != null && app.thread != null) {
1853 try {
1854 realStartActivityLocked(r, app, andResume, checkConfig);
1855 return;
1856 } catch (RemoteException e) {
1857 Log.w(TAG, "Exception when starting activity "
1858 + r.intent.getComponent().flattenToShortString(), e);
1859 }
1860
1861 // If a dead object exception was thrown -- fall through to
1862 // restart the application.
1863 }
1864
1865 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001866 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001867 }
1868
1869 private final ProcessRecord startProcessLocked(String processName,
1870 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001871 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001872 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1873 // We don't have to do anything more if:
1874 // (1) There is an existing application record; and
1875 // (2) The caller doesn't think it is dead, OR there is no thread
1876 // object attached to it so we know it couldn't have crashed; and
1877 // (3) There is a pid assigned to it, so it is either starting or
1878 // already running.
1879 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1880 + " app=" + app + " knownToBeDead=" + knownToBeDead
1881 + " thread=" + (app != null ? app.thread : null)
1882 + " pid=" + (app != null ? app.pid : -1));
1883 if (app != null &&
1884 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1885 return app;
1886 }
1887
1888 String hostingNameStr = hostingName != null
1889 ? hostingName.flattenToShortString() : null;
1890
1891 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1892 // If we are in the background, then check to see if this process
1893 // is bad. If so, we will just silently fail.
1894 if (mBadProcesses.get(info.processName, info.uid) != null) {
1895 return null;
1896 }
1897 } else {
1898 // When the user is explicitly starting a process, then clear its
1899 // crash count so that we won't make it bad until they see at
1900 // least one crash dialog again, and make the process good again
1901 // if it had been bad.
1902 mProcessCrashTimes.remove(info.processName, info.uid);
1903 if (mBadProcesses.get(info.processName, info.uid) != null) {
1904 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1905 info.processName);
1906 mBadProcesses.remove(info.processName, info.uid);
1907 if (app != null) {
1908 app.bad = false;
1909 }
1910 }
1911 }
1912
1913 if (app == null) {
1914 app = newProcessRecordLocked(null, info, processName);
1915 mProcessNames.put(processName, info.uid, app);
1916 } else {
1917 // If this is a new package in the process, add the package to the list
1918 app.addPackage(info.packageName);
1919 }
1920
1921 // If the system is not ready yet, then hold off on starting this
1922 // process until it is.
1923 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001924 && !isAllowedWhileBooting(info)
1925 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001926 if (!mProcessesOnHold.contains(app)) {
1927 mProcessesOnHold.add(app);
1928 }
1929 return app;
1930 }
1931
1932 startProcessLocked(app, hostingType, hostingNameStr);
1933 return (app.pid != 0) ? app : null;
1934 }
1935
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001936 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1937 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1938 }
1939
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001940 private final void startProcessLocked(ProcessRecord app,
1941 String hostingType, String hostingNameStr) {
1942 if (app.pid > 0 && app.pid != MY_PID) {
1943 synchronized (mPidsSelfLocked) {
1944 mPidsSelfLocked.remove(app.pid);
1945 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1946 }
1947 app.pid = 0;
1948 }
1949
1950 mProcessesOnHold.remove(app);
1951
1952 updateCpuStats();
1953
1954 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1955 mProcDeaths[0] = 0;
1956
1957 try {
1958 int uid = app.info.uid;
1959 int[] gids = null;
1960 try {
1961 gids = mContext.getPackageManager().getPackageGids(
1962 app.info.packageName);
1963 } catch (PackageManager.NameNotFoundException e) {
1964 Log.w(TAG, "Unable to retrieve gids", e);
1965 }
1966 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1967 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1968 && mTopComponent != null
1969 && app.processName.equals(mTopComponent.getPackageName())) {
1970 uid = 0;
1971 }
1972 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1973 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1974 uid = 0;
1975 }
1976 }
1977 int debugFlags = 0;
1978 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1979 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1980 }
1981 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1982 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1983 }
1984 if ("1".equals(SystemProperties.get("debug.assert"))) {
1985 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1986 }
1987 int pid = Process.start("android.app.ActivityThread",
1988 mSimpleProcessManagement ? app.processName : null, uid, uid,
1989 gids, debugFlags, null);
1990 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1991 synchronized (bs) {
1992 if (bs.isOnBattery()) {
1993 app.batteryStats.incStartsLocked();
1994 }
1995 }
1996
1997 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1998 app.processName, hostingType,
1999 hostingNameStr != null ? hostingNameStr : "");
2000
2001 if (app.persistent) {
2002 Watchdog.getInstance().processStarted(app, app.processName, pid);
2003 }
2004
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07002005 StringBuilder buf = mStringBuilder;
2006 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002007 buf.append("Start proc ");
2008 buf.append(app.processName);
2009 buf.append(" for ");
2010 buf.append(hostingType);
2011 if (hostingNameStr != null) {
2012 buf.append(" ");
2013 buf.append(hostingNameStr);
2014 }
2015 buf.append(": pid=");
2016 buf.append(pid);
2017 buf.append(" uid=");
2018 buf.append(uid);
2019 buf.append(" gids={");
2020 if (gids != null) {
2021 for (int gi=0; gi<gids.length; gi++) {
2022 if (gi != 0) buf.append(", ");
2023 buf.append(gids[gi]);
2024
2025 }
2026 }
2027 buf.append("}");
2028 Log.i(TAG, buf.toString());
2029 if (pid == 0 || pid == MY_PID) {
2030 // Processes are being emulated with threads.
2031 app.pid = MY_PID;
2032 app.removed = false;
2033 mStartingProcesses.add(app);
2034 } else if (pid > 0) {
2035 app.pid = pid;
2036 app.removed = false;
2037 synchronized (mPidsSelfLocked) {
2038 this.mPidsSelfLocked.put(pid, app);
2039 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2040 msg.obj = app;
2041 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2042 }
2043 } else {
2044 app.pid = 0;
2045 RuntimeException e = new RuntimeException(
2046 "Failure starting process " + app.processName
2047 + ": returned pid=" + pid);
2048 Log.e(TAG, e.getMessage(), e);
2049 }
2050 } catch (RuntimeException e) {
2051 // XXX do better error recovery.
2052 app.pid = 0;
2053 Log.e(TAG, "Failure starting process " + app.processName, e);
2054 }
2055 }
2056
2057 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2058 if (mPausingActivity != null) {
2059 RuntimeException e = new RuntimeException();
2060 Log.e(TAG, "Trying to pause when pause is already pending for "
2061 + mPausingActivity, e);
2062 }
2063 HistoryRecord prev = mResumedActivity;
2064 if (prev == null) {
2065 RuntimeException e = new RuntimeException();
2066 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2067 resumeTopActivityLocked(null);
2068 return;
2069 }
2070 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2071 mResumedActivity = null;
2072 mPausingActivity = prev;
2073 mLastPausedActivity = prev;
2074 prev.state = ActivityState.PAUSING;
2075 prev.task.touchActiveTime();
2076
2077 updateCpuStats();
2078
2079 if (prev.app != null && prev.app.thread != null) {
2080 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2081 try {
2082 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2083 System.identityHashCode(prev),
2084 prev.shortComponentName);
2085 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2086 prev.configChangeFlags);
2087 updateUsageStats(prev, false);
2088 } catch (Exception e) {
2089 // Ignore exception, if process died other code will cleanup.
2090 Log.w(TAG, "Exception thrown during pause", e);
2091 mPausingActivity = null;
2092 mLastPausedActivity = null;
2093 }
2094 } else {
2095 mPausingActivity = null;
2096 mLastPausedActivity = null;
2097 }
2098
2099 // If we are not going to sleep, we want to ensure the device is
2100 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002101 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002102 mLaunchingActivity.acquire();
2103 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2104 // To be safe, don't allow the wake lock to be held for too long.
2105 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2106 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2107 }
2108 }
2109
2110
2111 if (mPausingActivity != null) {
2112 // Have the window manager pause its key dispatching until the new
2113 // activity has started. If we're pausing the activity just because
2114 // the screen is being turned off and the UI is sleeping, don't interrupt
2115 // key dispatch; the same activity will pick it up again on wakeup.
2116 if (!uiSleeping) {
2117 prev.pauseKeyDispatchingLocked();
2118 } else {
2119 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2120 }
2121
2122 // Schedule a pause timeout in case the app doesn't respond.
2123 // We don't give it much time because this directly impacts the
2124 // responsiveness seen by the user.
2125 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2126 msg.obj = prev;
2127 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2128 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2129 } else {
2130 // This activity failed to schedule the
2131 // pause, so just treat it as being paused now.
2132 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2133 resumeTopActivityLocked(null);
2134 }
2135 }
2136
2137 private final void completePauseLocked() {
2138 HistoryRecord prev = mPausingActivity;
2139 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2140
2141 if (prev != null) {
2142 if (prev.finishing) {
2143 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2144 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2145 } else if (prev.app != null) {
2146 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2147 if (prev.waitingVisible) {
2148 prev.waitingVisible = false;
2149 mWaitingVisibleActivities.remove(prev);
2150 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2151 TAG, "Complete pause, no longer waiting: " + prev);
2152 }
2153 if (prev.configDestroy) {
2154 // The previous is being paused because the configuration
2155 // is changing, which means it is actually stopping...
2156 // To juggle the fact that we are also starting a new
2157 // instance right now, we need to first completely stop
2158 // the current instance before starting the new one.
2159 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2160 destroyActivityLocked(prev, true);
2161 } else {
2162 mStoppingActivities.add(prev);
2163 if (mStoppingActivities.size() > 3) {
2164 // If we already have a few activities waiting to stop,
2165 // then give up on things going idle and start clearing
2166 // them out.
2167 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2168 Message msg = Message.obtain();
2169 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2170 mHandler.sendMessage(msg);
2171 }
2172 }
2173 } else {
2174 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2175 prev = null;
2176 }
2177 mPausingActivity = null;
2178 }
2179
Dianne Hackborn55280a92009-05-07 15:53:46 -07002180 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002181 resumeTopActivityLocked(prev);
2182 } else {
2183 if (mGoingToSleep.isHeld()) {
2184 mGoingToSleep.release();
2185 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002186 if (mShuttingDown) {
2187 notifyAll();
2188 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002189 }
2190
2191 if (prev != null) {
2192 prev.resumeKeyDispatchingLocked();
2193 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002194
2195 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2196 long diff = 0;
2197 synchronized (mProcessStatsThread) {
2198 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2199 }
2200 if (diff > 0) {
2201 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2202 synchronized (bsi) {
2203 BatteryStatsImpl.Uid.Proc ps =
2204 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2205 prev.info.packageName);
2206 if (ps != null) {
2207 ps.addForegroundTimeLocked(diff);
2208 }
2209 }
2210 }
2211 }
2212 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002213 }
2214
2215 /**
2216 * Once we know that we have asked an application to put an activity in
2217 * the resumed state (either by launching it or explicitly telling it),
2218 * this function updates the rest of our state to match that fact.
2219 */
2220 private final void completeResumeLocked(HistoryRecord next) {
2221 next.idle = false;
2222 next.results = null;
2223 next.newIntents = null;
2224
2225 // schedule an idle timeout in case the app doesn't do it for us.
2226 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2227 msg.obj = next;
2228 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2229
2230 if (false) {
2231 // The activity was never told to pause, so just keep
2232 // things going as-is. To maintain our own state,
2233 // we need to emulate it coming back and saying it is
2234 // idle.
2235 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2236 msg.obj = next;
2237 mHandler.sendMessage(msg);
2238 }
2239
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002240 reportResumedActivity(next);
2241
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002242 next.thumbnail = null;
2243 setFocusedActivityLocked(next);
2244 next.resumeKeyDispatchingLocked();
2245 ensureActivitiesVisibleLocked(null, 0);
2246 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002247
2248 // Mark the point when the activity is resuming
2249 // TODO: To be more accurate, the mark should be before the onCreate,
2250 // not after the onResume. But for subsequent starts, onResume is fine.
2251 if (next.app != null) {
2252 synchronized (mProcessStatsThread) {
2253 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2254 }
2255 } else {
2256 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2257 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002258 }
2259
2260 /**
2261 * Make sure that all activities that need to be visible (that is, they
2262 * currently can be seen by the user) actually are.
2263 */
2264 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2265 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2266 if (DEBUG_VISBILITY) Log.v(
2267 TAG, "ensureActivitiesVisible behind " + top
2268 + " configChanges=0x" + Integer.toHexString(configChanges));
2269
2270 // If the top activity is not fullscreen, then we need to
2271 // make sure any activities under it are now visible.
2272 final int count = mHistory.size();
2273 int i = count-1;
2274 while (mHistory.get(i) != top) {
2275 i--;
2276 }
2277 HistoryRecord r;
2278 boolean behindFullscreen = false;
2279 for (; i>=0; i--) {
2280 r = (HistoryRecord)mHistory.get(i);
2281 if (DEBUG_VISBILITY) Log.v(
2282 TAG, "Make visible? " + r + " finishing=" + r.finishing
2283 + " state=" + r.state);
2284 if (r.finishing) {
2285 continue;
2286 }
2287
2288 final boolean doThisProcess = onlyThisProcess == null
2289 || onlyThisProcess.equals(r.processName);
2290
2291 // First: if this is not the current activity being started, make
2292 // sure it matches the current configuration.
2293 if (r != starting && doThisProcess) {
2294 ensureActivityConfigurationLocked(r, 0);
2295 }
2296
2297 if (r.app == null || r.app.thread == null) {
2298 if (onlyThisProcess == null
2299 || onlyThisProcess.equals(r.processName)) {
2300 // This activity needs to be visible, but isn't even
2301 // running... get it started, but don't resume it
2302 // at this point.
2303 if (DEBUG_VISBILITY) Log.v(
2304 TAG, "Start and freeze screen for " + r);
2305 if (r != starting) {
2306 r.startFreezingScreenLocked(r.app, configChanges);
2307 }
2308 if (!r.visible) {
2309 if (DEBUG_VISBILITY) Log.v(
2310 TAG, "Starting and making visible: " + r);
2311 mWindowManager.setAppVisibility(r, true);
2312 }
2313 if (r != starting) {
2314 startSpecificActivityLocked(r, false, false);
2315 }
2316 }
2317
2318 } else if (r.visible) {
2319 // If this activity is already visible, then there is nothing
2320 // else to do here.
2321 if (DEBUG_VISBILITY) Log.v(
2322 TAG, "Skipping: already visible at " + r);
2323 r.stopFreezingScreenLocked(false);
2324
2325 } else if (onlyThisProcess == null) {
2326 // This activity is not currently visible, but is running.
2327 // Tell it to become visible.
2328 r.visible = true;
2329 if (r.state != ActivityState.RESUMED && r != starting) {
2330 // If this activity is paused, tell it
2331 // to now show its window.
2332 if (DEBUG_VISBILITY) Log.v(
2333 TAG, "Making visible and scheduling visibility: " + r);
2334 try {
2335 mWindowManager.setAppVisibility(r, true);
2336 r.app.thread.scheduleWindowVisibility(r, true);
2337 r.stopFreezingScreenLocked(false);
2338 } catch (Exception e) {
2339 // Just skip on any failure; we'll make it
2340 // visible when it next restarts.
2341 Log.w(TAG, "Exception thrown making visibile: "
2342 + r.intent.getComponent(), e);
2343 }
2344 }
2345 }
2346
2347 // Aggregate current change flags.
2348 configChanges |= r.configChangeFlags;
2349
2350 if (r.fullscreen) {
2351 // At this point, nothing else needs to be shown
2352 if (DEBUG_VISBILITY) Log.v(
2353 TAG, "Stopping: fullscreen at " + r);
2354 behindFullscreen = true;
2355 i--;
2356 break;
2357 }
2358 }
2359
2360 // Now for any activities that aren't visible to the user, make
2361 // sure they no longer are keeping the screen frozen.
2362 while (i >= 0) {
2363 r = (HistoryRecord)mHistory.get(i);
2364 if (DEBUG_VISBILITY) Log.v(
2365 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2366 + " state=" + r.state
2367 + " behindFullscreen=" + behindFullscreen);
2368 if (!r.finishing) {
2369 if (behindFullscreen) {
2370 if (r.visible) {
2371 if (DEBUG_VISBILITY) Log.v(
2372 TAG, "Making invisible: " + r);
2373 r.visible = false;
2374 try {
2375 mWindowManager.setAppVisibility(r, false);
2376 if ((r.state == ActivityState.STOPPING
2377 || r.state == ActivityState.STOPPED)
2378 && r.app != null && r.app.thread != null) {
2379 if (DEBUG_VISBILITY) Log.v(
2380 TAG, "Scheduling invisibility: " + r);
2381 r.app.thread.scheduleWindowVisibility(r, false);
2382 }
2383 } catch (Exception e) {
2384 // Just skip on any failure; we'll make it
2385 // visible when it next restarts.
2386 Log.w(TAG, "Exception thrown making hidden: "
2387 + r.intent.getComponent(), e);
2388 }
2389 } else {
2390 if (DEBUG_VISBILITY) Log.v(
2391 TAG, "Already invisible: " + r);
2392 }
2393 } else if (r.fullscreen) {
2394 if (DEBUG_VISBILITY) Log.v(
2395 TAG, "Now behindFullscreen: " + r);
2396 behindFullscreen = true;
2397 }
2398 }
2399 i--;
2400 }
2401 }
2402
2403 /**
2404 * Version of ensureActivitiesVisible that can easily be called anywhere.
2405 */
2406 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2407 int configChanges) {
2408 HistoryRecord r = topRunningActivityLocked(null);
2409 if (r != null) {
2410 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2411 }
2412 }
2413
2414 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2415 if (resumed) {
2416 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2417 } else {
2418 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2419 }
2420 }
2421
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002422 private boolean startHomeActivityLocked() {
2423 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2424 && mTopAction == null) {
2425 // We are running in factory test mode, but unable to find
2426 // the factory test app, so just sit around displaying the
2427 // error message and don't try to start anything.
2428 return false;
2429 }
2430 Intent intent = new Intent(
2431 mTopAction,
2432 mTopData != null ? Uri.parse(mTopData) : null);
2433 intent.setComponent(mTopComponent);
2434 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2435 intent.addCategory(Intent.CATEGORY_HOME);
2436 }
2437 ActivityInfo aInfo =
2438 intent.resolveActivityInfo(mContext.getPackageManager(),
2439 STOCK_PM_FLAGS);
2440 if (aInfo != null) {
2441 intent.setComponent(new ComponentName(
2442 aInfo.applicationInfo.packageName, aInfo.name));
2443 // Don't do this if the home app is currently being
2444 // instrumented.
2445 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2446 aInfo.applicationInfo.uid);
2447 if (app == null || app.instrumentationClass == null) {
2448 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2449 startActivityLocked(null, intent, null, null, 0, aInfo,
2450 null, null, 0, 0, 0, false, false);
2451 }
2452 }
2453
2454
2455 return true;
2456 }
2457
2458 /**
2459 * Starts the "new version setup screen" if appropriate.
2460 */
2461 private void startSetupActivityLocked() {
2462 // Only do this once per boot.
2463 if (mCheckedForSetup) {
2464 return;
2465 }
2466
2467 // We will show this screen if the current one is a different
2468 // version than the last one shown, and we are not running in
2469 // low-level factory test mode.
2470 final ContentResolver resolver = mContext.getContentResolver();
2471 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2472 Settings.Secure.getInt(resolver,
2473 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2474 mCheckedForSetup = true;
2475
2476 // See if we should be showing the platform update setup UI.
2477 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2478 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2479 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2480
2481 // We don't allow third party apps to replace this.
2482 ResolveInfo ri = null;
2483 for (int i=0; ris != null && i<ris.size(); i++) {
2484 if ((ris.get(i).activityInfo.applicationInfo.flags
2485 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2486 ri = ris.get(i);
2487 break;
2488 }
2489 }
2490
2491 if (ri != null) {
2492 String vers = ri.activityInfo.metaData != null
2493 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2494 : null;
2495 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2496 vers = ri.activityInfo.applicationInfo.metaData.getString(
2497 Intent.METADATA_SETUP_VERSION);
2498 }
2499 String lastVers = Settings.Secure.getString(
2500 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2501 if (vers != null && !vers.equals(lastVers)) {
2502 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2503 intent.setComponent(new ComponentName(
2504 ri.activityInfo.packageName, ri.activityInfo.name));
2505 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2506 null, null, 0, 0, 0, false, false);
2507 }
2508 }
2509 }
2510 }
2511
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002512 private void reportResumedActivity(HistoryRecord r) {
2513 //Log.i(TAG, "**** REPORT RESUME: " + r);
2514
2515 final int identHash = System.identityHashCode(r);
2516 updateUsageStats(r, true);
2517
2518 int i = mWatchers.beginBroadcast();
2519 while (i > 0) {
2520 i--;
2521 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2522 if (w != null) {
2523 try {
2524 w.activityResuming(identHash);
2525 } catch (RemoteException e) {
2526 }
2527 }
2528 }
2529 mWatchers.finishBroadcast();
2530 }
2531
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002532 /**
2533 * Ensure that the top activity in the stack is resumed.
2534 *
2535 * @param prev The previously resumed activity, for when in the process
2536 * of pausing; can be null to call from elsewhere.
2537 *
2538 * @return Returns true if something is being resumed, or false if
2539 * nothing happened.
2540 */
2541 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2542 // Find the first activity that is not finishing.
2543 HistoryRecord next = topRunningActivityLocked(null);
2544
2545 // Remember how we'll process this pause/resume situation, and ensure
2546 // that the state is reset however we wind up proceeding.
2547 final boolean userLeaving = mUserLeaving;
2548 mUserLeaving = false;
2549
2550 if (next == null) {
2551 // There are no more activities! Let's just start up the
2552 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002553 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002554 }
2555
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002556 next.delayedResume = false;
2557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002558 // If the top activity is the resumed one, nothing to do.
2559 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2560 // Make sure we have executed any pending transitions, since there
2561 // should be nothing left to do at this point.
2562 mWindowManager.executeAppTransition();
2563 return false;
2564 }
2565
2566 // If we are sleeping, and there is no resumed activity, and the top
2567 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002568 if ((mSleeping || mShuttingDown)
2569 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002570 // Make sure we have executed any pending transitions, since there
2571 // should be nothing left to do at this point.
2572 mWindowManager.executeAppTransition();
2573 return false;
2574 }
2575
2576 // The activity may be waiting for stop, but that is no longer
2577 // appropriate for it.
2578 mStoppingActivities.remove(next);
2579 mWaitingVisibleActivities.remove(next);
2580
2581 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2582
2583 // If we are currently pausing an activity, then don't do anything
2584 // until that is done.
2585 if (mPausingActivity != null) {
2586 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2587 return false;
2588 }
2589
2590 // We need to start pausing the current activity so the top one
2591 // can be resumed...
2592 if (mResumedActivity != null) {
2593 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2594 startPausingLocked(userLeaving, false);
2595 return true;
2596 }
2597
2598 if (prev != null && prev != next) {
2599 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2600 prev.waitingVisible = true;
2601 mWaitingVisibleActivities.add(prev);
2602 if (DEBUG_SWITCH) Log.v(
2603 TAG, "Resuming top, waiting visible to hide: " + prev);
2604 } else {
2605 // The next activity is already visible, so hide the previous
2606 // activity's windows right now so we can show the new one ASAP.
2607 // We only do this if the previous is finishing, which should mean
2608 // it is on top of the one being resumed so hiding it quickly
2609 // is good. Otherwise, we want to do the normal route of allowing
2610 // the resumed activity to be shown so we can decide if the
2611 // previous should actually be hidden depending on whether the
2612 // new one is found to be full-screen or not.
2613 if (prev.finishing) {
2614 mWindowManager.setAppVisibility(prev, false);
2615 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2616 + prev + ", waitingVisible="
2617 + (prev != null ? prev.waitingVisible : null)
2618 + ", nowVisible=" + next.nowVisible);
2619 } else {
2620 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2621 + prev + ", waitingVisible="
2622 + (prev != null ? prev.waitingVisible : null)
2623 + ", nowVisible=" + next.nowVisible);
2624 }
2625 }
2626 }
2627
2628 // We are starting up the next activity, so tell the window manager
2629 // that the previous one will be hidden soon. This way it can know
2630 // to ignore it when computing the desired screen orientation.
2631 if (prev != null) {
2632 if (prev.finishing) {
2633 if (DEBUG_TRANSITION) Log.v(TAG,
2634 "Prepare close transition: prev=" + prev);
2635 mWindowManager.prepareAppTransition(prev.task == next.task
2636 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2637 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2638 mWindowManager.setAppWillBeHidden(prev);
2639 mWindowManager.setAppVisibility(prev, false);
2640 } else {
2641 if (DEBUG_TRANSITION) Log.v(TAG,
2642 "Prepare open transition: prev=" + prev);
2643 mWindowManager.prepareAppTransition(prev.task == next.task
2644 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2645 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2646 }
2647 if (false) {
2648 mWindowManager.setAppWillBeHidden(prev);
2649 mWindowManager.setAppVisibility(prev, false);
2650 }
2651 } else if (mHistory.size() > 1) {
2652 if (DEBUG_TRANSITION) Log.v(TAG,
2653 "Prepare open transition: no previous");
2654 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2655 }
2656
2657 if (next.app != null && next.app.thread != null) {
2658 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2659
2660 // This activity is now becoming visible.
2661 mWindowManager.setAppVisibility(next, true);
2662
2663 HistoryRecord lastResumedActivity = mResumedActivity;
2664 ActivityState lastState = next.state;
2665
2666 updateCpuStats();
2667
2668 next.state = ActivityState.RESUMED;
2669 mResumedActivity = next;
2670 next.task.touchActiveTime();
2671 updateLRUListLocked(next.app, true);
2672 updateLRUListLocked(next);
2673
2674 // Have the window manager re-evaluate the orientation of
2675 // the screen based on the new activity order.
2676 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002677 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002678 next.mayFreezeScreenLocked(next.app) ? next : null);
2679 if (config != null) {
2680 next.frozenBeforeDestroy = true;
2681 }
2682 if (!updateConfigurationLocked(config, next)) {
2683 // The configuration update wasn't able to keep the existing
2684 // instance of the activity, and instead started a new one.
2685 // We should be all done, but let's just make sure our activity
2686 // is still at the top and schedule another run if something
2687 // weird happened.
2688 HistoryRecord nextNext = topRunningActivityLocked(null);
2689 if (DEBUG_SWITCH) Log.i(TAG,
2690 "Activity config changed during resume: " + next
2691 + ", new next: " + nextNext);
2692 if (nextNext != next) {
2693 // Do over!
2694 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2695 }
2696 mWindowManager.executeAppTransition();
2697 return true;
2698 }
2699
2700 try {
2701 // Deliver all pending results.
2702 ArrayList a = next.results;
2703 if (a != null) {
2704 final int N = a.size();
2705 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002706 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002707 TAG, "Delivering results to " + next
2708 + ": " + a);
2709 next.app.thread.scheduleSendResult(next, a);
2710 }
2711 }
2712
2713 if (next.newIntents != null) {
2714 next.app.thread.scheduleNewIntent(next.newIntents, next);
2715 }
2716
2717 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2718 System.identityHashCode(next),
2719 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002720
2721 next.app.thread.scheduleResumeActivity(next,
2722 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002724 pauseIfSleepingLocked();
2725
2726 } catch (Exception e) {
2727 // Whoops, need to restart this activity!
2728 next.state = lastState;
2729 mResumedActivity = lastResumedActivity;
2730 if (Config.LOGD) Log.d(TAG,
2731 "Restarting because process died: " + next);
2732 if (!next.hasBeenLaunched) {
2733 next.hasBeenLaunched = true;
2734 } else {
2735 if (SHOW_APP_STARTING_ICON) {
2736 mWindowManager.setAppStartingWindow(
2737 next, next.packageName, next.theme,
2738 next.nonLocalizedLabel,
2739 next.labelRes, next.icon, null, true);
2740 }
2741 }
2742 startSpecificActivityLocked(next, true, false);
2743 return true;
2744 }
2745
2746 // From this point on, if something goes wrong there is no way
2747 // to recover the activity.
2748 try {
2749 next.visible = true;
2750 completeResumeLocked(next);
2751 } catch (Exception e) {
2752 // If any exception gets thrown, toss away this
2753 // activity and try the next one.
2754 Log.w(TAG, "Exception thrown during resume of " + next, e);
2755 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2756 "resume-exception");
2757 return true;
2758 }
2759
2760 // Didn't need to use the icicle, and it is now out of date.
2761 next.icicle = null;
2762 next.haveState = false;
2763 next.stopped = false;
2764
2765 } else {
2766 // Whoops, need to restart this activity!
2767 if (!next.hasBeenLaunched) {
2768 next.hasBeenLaunched = true;
2769 } else {
2770 if (SHOW_APP_STARTING_ICON) {
2771 mWindowManager.setAppStartingWindow(
2772 next, next.packageName, next.theme,
2773 next.nonLocalizedLabel,
2774 next.labelRes, next.icon, null, true);
2775 }
2776 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2777 }
2778 startSpecificActivityLocked(next, true, true);
2779 }
2780
2781 return true;
2782 }
2783
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002784 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2785 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002786 final int NH = mHistory.size();
2787
2788 int addPos = -1;
2789
2790 if (!newTask) {
2791 // If starting in an existing task, find where that is...
2792 HistoryRecord next = null;
2793 boolean startIt = true;
2794 for (int i = NH-1; i >= 0; i--) {
2795 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2796 if (p.finishing) {
2797 continue;
2798 }
2799 if (p.task == r.task) {
2800 // Here it is! Now, if this is not yet visible to the
2801 // user, then just add it without starting; it will
2802 // get started when the user navigates back to it.
2803 addPos = i+1;
2804 if (!startIt) {
2805 mHistory.add(addPos, r);
2806 r.inHistory = true;
2807 r.task.numActivities++;
2808 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2809 r.info.screenOrientation, r.fullscreen);
2810 if (VALIDATE_TOKENS) {
2811 mWindowManager.validateAppTokens(mHistory);
2812 }
2813 return;
2814 }
2815 break;
2816 }
2817 if (p.fullscreen) {
2818 startIt = false;
2819 }
2820 next = p;
2821 }
2822 }
2823
2824 // Place a new activity at top of stack, so it is next to interact
2825 // with the user.
2826 if (addPos < 0) {
2827 addPos = mHistory.size();
2828 }
2829
2830 // If we are not placing the new activity frontmost, we do not want
2831 // to deliver the onUserLeaving callback to the actual frontmost
2832 // activity
2833 if (addPos < NH) {
2834 mUserLeaving = false;
2835 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2836 }
2837
2838 // Slot the activity into the history stack and proceed
2839 mHistory.add(addPos, r);
2840 r.inHistory = true;
2841 r.frontOfTask = newTask;
2842 r.task.numActivities++;
2843 if (NH > 0) {
2844 // We want to show the starting preview window if we are
2845 // switching to a new task, or the next activity's process is
2846 // not currently running.
2847 boolean showStartingIcon = newTask;
2848 ProcessRecord proc = r.app;
2849 if (proc == null) {
2850 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2851 }
2852 if (proc == null || proc.thread == null) {
2853 showStartingIcon = true;
2854 }
2855 if (DEBUG_TRANSITION) Log.v(TAG,
2856 "Prepare open transition: starting " + r);
2857 mWindowManager.prepareAppTransition(newTask
2858 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2859 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2860 mWindowManager.addAppToken(
2861 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2862 boolean doShow = true;
2863 if (newTask) {
2864 // Even though this activity is starting fresh, we still need
2865 // to reset it to make sure we apply affinities to move any
2866 // existing activities from other tasks in to it.
2867 // If the caller has requested that the target task be
2868 // reset, then do so.
2869 if ((r.intent.getFlags()
2870 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2871 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002872 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002873 }
2874 }
2875 if (SHOW_APP_STARTING_ICON && doShow) {
2876 // Figure out if we are transitioning from another activity that is
2877 // "has the same starting icon" as the next one. This allows the
2878 // window manager to keep the previous window it had previously
2879 // created, if it still had one.
2880 HistoryRecord prev = mResumedActivity;
2881 if (prev != null) {
2882 // We don't want to reuse the previous starting preview if:
2883 // (1) The current activity is in a different task.
2884 if (prev.task != r.task) prev = null;
2885 // (2) The current activity is already displayed.
2886 else if (prev.nowVisible) prev = null;
2887 }
2888 mWindowManager.setAppStartingWindow(
2889 r, r.packageName, r.theme, r.nonLocalizedLabel,
2890 r.labelRes, r.icon, prev, showStartingIcon);
2891 }
2892 } else {
2893 // If this is the first activity, don't do any fancy animations,
2894 // because there is nothing for it to animate on top of.
2895 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2896 r.info.screenOrientation, r.fullscreen);
2897 }
2898 if (VALIDATE_TOKENS) {
2899 mWindowManager.validateAppTokens(mHistory);
2900 }
2901
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002902 if (doResume) {
2903 resumeTopActivityLocked(null);
2904 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002905 }
2906
2907 /**
2908 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002909 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2910 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002911 * an instance of that activity in the stack and, if found, finish all
2912 * activities on top of it and return the instance.
2913 *
2914 * @param newR Description of the new activity being started.
2915 * @return Returns the old activity that should be continue to be used,
2916 * or null if none was found.
2917 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002918 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002919 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002920 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002921
2922 // First find the requested task.
2923 while (i > 0) {
2924 i--;
2925 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2926 if (r.task.taskId == taskId) {
2927 i++;
2928 break;
2929 }
2930 }
2931
2932 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002933 while (i > 0) {
2934 i--;
2935 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2936 if (r.finishing) {
2937 continue;
2938 }
2939 if (r.task.taskId != taskId) {
2940 return null;
2941 }
2942 if (r.realActivity.equals(newR.realActivity)) {
2943 // Here it is! Now finish everything in front...
2944 HistoryRecord ret = r;
2945 if (doClear) {
2946 while (i < (mHistory.size()-1)) {
2947 i++;
2948 r = (HistoryRecord)mHistory.get(i);
2949 if (r.finishing) {
2950 continue;
2951 }
2952 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2953 null, "clear")) {
2954 i--;
2955 }
2956 }
2957 }
2958
2959 // Finally, if this is a normal launch mode (that is, not
2960 // expecting onNewIntent()), then we will finish the current
2961 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002962 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
2963 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002964 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002965 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002966 if (index >= 0) {
2967 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2968 null, "clear");
2969 }
2970 return null;
2971 }
2972 }
2973
2974 return ret;
2975 }
2976 }
2977
2978 return null;
2979 }
2980
2981 /**
2982 * Find the activity in the history stack within the given task. Returns
2983 * the index within the history at which it's found, or < 0 if not found.
2984 */
2985 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2986 int i = mHistory.size();
2987 while (i > 0) {
2988 i--;
2989 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2990 if (candidate.task.taskId != task) {
2991 break;
2992 }
2993 if (candidate.realActivity.equals(r.realActivity)) {
2994 return i;
2995 }
2996 }
2997
2998 return -1;
2999 }
3000
3001 /**
3002 * Reorder the history stack so that the activity at the given index is
3003 * brought to the front.
3004 */
3005 private final HistoryRecord moveActivityToFrontLocked(int where) {
3006 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3007 int top = mHistory.size();
3008 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3009 mHistory.add(top, newTop);
3010 oldTop.frontOfTask = false;
3011 newTop.frontOfTask = true;
3012 return newTop;
3013 }
3014
3015 /**
3016 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3017 * method will be called at the proper time.
3018 */
3019 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3020 boolean sent = false;
3021 if (r.state == ActivityState.RESUMED
3022 && r.app != null && r.app.thread != null) {
3023 try {
3024 ArrayList<Intent> ar = new ArrayList<Intent>();
3025 ar.add(new Intent(intent));
3026 r.app.thread.scheduleNewIntent(ar, r);
3027 sent = true;
3028 } catch (Exception e) {
3029 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3030 }
3031 }
3032 if (!sent) {
3033 r.addNewIntentLocked(new Intent(intent));
3034 }
3035 }
3036
3037 private final void logStartActivity(int tag, HistoryRecord r,
3038 TaskRecord task) {
3039 EventLog.writeEvent(tag,
3040 System.identityHashCode(r), task.taskId,
3041 r.shortComponentName, r.intent.getAction(),
3042 r.intent.getType(), r.intent.getDataString(),
3043 r.intent.getFlags());
3044 }
3045
3046 private final int startActivityLocked(IApplicationThread caller,
3047 Intent intent, String resolvedType,
3048 Uri[] grantedUriPermissions,
3049 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3050 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003051 int callingPid, int callingUid, boolean onlyIfNeeded,
3052 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003053 Log.i(TAG, "Starting activity: " + intent);
3054
3055 HistoryRecord sourceRecord = null;
3056 HistoryRecord resultRecord = null;
3057 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003058 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003059 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003060 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3061 if (index >= 0) {
3062 sourceRecord = (HistoryRecord)mHistory.get(index);
3063 if (requestCode >= 0 && !sourceRecord.finishing) {
3064 resultRecord = sourceRecord;
3065 }
3066 }
3067 }
3068
3069 int launchFlags = intent.getFlags();
3070
3071 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3072 && sourceRecord != null) {
3073 // Transfer the result target from the source activity to the new
3074 // one being started, including any failures.
3075 if (requestCode >= 0) {
3076 return START_FORWARD_AND_REQUEST_CONFLICT;
3077 }
3078 resultRecord = sourceRecord.resultTo;
3079 resultWho = sourceRecord.resultWho;
3080 requestCode = sourceRecord.requestCode;
3081 sourceRecord.resultTo = null;
3082 if (resultRecord != null) {
3083 resultRecord.removeResultsLocked(
3084 sourceRecord, resultWho, requestCode);
3085 }
3086 }
3087
3088 int err = START_SUCCESS;
3089
3090 if (intent.getComponent() == null) {
3091 // We couldn't find a class that can handle the given Intent.
3092 // That's the end of that!
3093 err = START_INTENT_NOT_RESOLVED;
3094 }
3095
3096 if (err == START_SUCCESS && aInfo == null) {
3097 // We couldn't find the specific class specified in the Intent.
3098 // Also the end of the line.
3099 err = START_CLASS_NOT_FOUND;
3100 }
3101
3102 ProcessRecord callerApp = null;
3103 if (err == START_SUCCESS && caller != null) {
3104 callerApp = getRecordForAppLocked(caller);
3105 if (callerApp != null) {
3106 callingPid = callerApp.pid;
3107 callingUid = callerApp.info.uid;
3108 } else {
3109 Log.w(TAG, "Unable to find app for caller " + caller
3110 + " (pid=" + callingPid + ") when starting: "
3111 + intent.toString());
3112 err = START_PERMISSION_DENIED;
3113 }
3114 }
3115
3116 if (err != START_SUCCESS) {
3117 if (resultRecord != null) {
3118 sendActivityResultLocked(-1,
3119 resultRecord, resultWho, requestCode,
3120 Activity.RESULT_CANCELED, null);
3121 }
3122 return err;
3123 }
3124
3125 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3126 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3127 if (perm != PackageManager.PERMISSION_GRANTED) {
3128 if (resultRecord != null) {
3129 sendActivityResultLocked(-1,
3130 resultRecord, resultWho, requestCode,
3131 Activity.RESULT_CANCELED, null);
3132 }
3133 String msg = "Permission Denial: starting " + intent.toString()
3134 + " from " + callerApp + " (pid=" + callingPid
3135 + ", uid=" + callingUid + ")"
3136 + " requires " + aInfo.permission;
3137 Log.w(TAG, msg);
3138 throw new SecurityException(msg);
3139 }
3140
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003141 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003142 boolean abort = false;
3143 try {
3144 // The Intent we give to the watcher has the extra data
3145 // stripped off, since it can contain private information.
3146 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003147 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003148 aInfo.applicationInfo.packageName);
3149 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003150 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003151 }
3152
3153 if (abort) {
3154 if (resultRecord != null) {
3155 sendActivityResultLocked(-1,
3156 resultRecord, resultWho, requestCode,
3157 Activity.RESULT_CANCELED, null);
3158 }
3159 // We pretend to the caller that it was really started, but
3160 // they will just get a cancel result.
3161 return START_SUCCESS;
3162 }
3163 }
3164
3165 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3166 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003167 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003168
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003169 if (mResumedActivity == null
3170 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3171 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3172 PendingActivityLaunch pal = new PendingActivityLaunch();
3173 pal.r = r;
3174 pal.sourceRecord = sourceRecord;
3175 pal.grantedUriPermissions = grantedUriPermissions;
3176 pal.grantedMode = grantedMode;
3177 pal.onlyIfNeeded = onlyIfNeeded;
3178 mPendingActivityLaunches.add(pal);
3179 return START_SWITCHES_CANCELED;
3180 }
3181 }
3182
3183 if (mDidAppSwitch) {
3184 // This is the second allowed switch since we stopped switches,
3185 // so now just generally allow switches. Use case: user presses
3186 // home (switches disabled, switch to home, mDidAppSwitch now true);
3187 // user taps a home icon (coming from home so allowed, we hit here
3188 // and now allow anyone to switch again).
3189 mAppSwitchesAllowedTime = 0;
3190 } else {
3191 mDidAppSwitch = true;
3192 }
3193
3194 doPendingActivityLaunchesLocked(false);
3195
3196 return startActivityUncheckedLocked(r, sourceRecord,
3197 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3198 }
3199
3200 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3201 final int N = mPendingActivityLaunches.size();
3202 if (N <= 0) {
3203 return;
3204 }
3205 for (int i=0; i<N; i++) {
3206 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3207 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3208 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3209 doResume && i == (N-1));
3210 }
3211 mPendingActivityLaunches.clear();
3212 }
3213
3214 private final int startActivityUncheckedLocked(HistoryRecord r,
3215 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3216 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3217 final Intent intent = r.intent;
3218 final int callingUid = r.launchedFromUid;
3219
3220 int launchFlags = intent.getFlags();
3221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003222 // We'll invoke onUserLeaving before onPause only if the launching
3223 // activity did not explicitly state that this is an automated launch.
3224 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3225 if (DEBUG_USER_LEAVING) Log.v(TAG,
3226 "startActivity() => mUserLeaving=" + mUserLeaving);
3227
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003228 // If the caller has asked not to resume at this point, we make note
3229 // of this in the record so that we can skip it when trying to find
3230 // the top running activity.
3231 if (!doResume) {
3232 r.delayedResume = true;
3233 }
3234
3235 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3236 != 0 ? r : null;
3237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003238 // If the onlyIfNeeded flag is set, then we can do this if the activity
3239 // being launched is the same as the one making the call... or, as
3240 // a special case, if we do not know the caller then we count the
3241 // current top activity as the caller.
3242 if (onlyIfNeeded) {
3243 HistoryRecord checkedCaller = sourceRecord;
3244 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003245 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003246 }
3247 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3248 // Caller is not the same as launcher, so always needed.
3249 onlyIfNeeded = false;
3250 }
3251 }
3252
3253 if (grantedUriPermissions != null && callingUid > 0) {
3254 for (int i=0; i<grantedUriPermissions.length; i++) {
3255 grantUriPermissionLocked(callingUid, r.packageName,
3256 grantedUriPermissions[i], grantedMode, r);
3257 }
3258 }
3259
3260 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3261 intent, r);
3262
3263 if (sourceRecord == null) {
3264 // This activity is not being started from another... in this
3265 // case we -always- start a new task.
3266 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3267 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3268 + intent);
3269 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3270 }
3271 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3272 // The original activity who is starting us is running as a single
3273 // instance... this new activity it is starting must go on its
3274 // own task.
3275 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3276 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3277 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3278 // The activity being started is a single instance... it always
3279 // gets launched into its own task.
3280 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3281 }
3282
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003283 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003284 // For whatever reason this activity is being launched into a new
3285 // task... yet the caller has requested a result back. Well, that
3286 // is pretty messed up, so instead immediately send back a cancel
3287 // and let the new task continue launched as normal without a
3288 // dependency on its originator.
3289 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3290 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003291 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003292 Activity.RESULT_CANCELED, null);
3293 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003294 }
3295
3296 boolean addingToTask = false;
3297 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3298 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3299 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3300 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3301 // If bring to front is requested, and no result is requested, and
3302 // we can find a task that was started with this same
3303 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003304 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003305 // See if there is a task to bring to the front. If this is
3306 // a SINGLE_INSTANCE activity, there can be one and only one
3307 // instance of it in the history, and it is always in its own
3308 // unique task, so we do a special search.
3309 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3310 ? findTaskLocked(intent, r.info)
3311 : findActivityLocked(intent, r.info);
3312 if (taskTop != null) {
3313 if (taskTop.task.intent == null) {
3314 // This task was started because of movement of
3315 // the activity based on affinity... now that we
3316 // are actually launching it, we can assign the
3317 // base intent.
3318 taskTop.task.setIntent(intent, r.info);
3319 }
3320 // If the target task is not in the front, then we need
3321 // to bring it to the front... except... well, with
3322 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3323 // to have the same behavior as if a new instance was
3324 // being started, which means not bringing it to the front
3325 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003326 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003327 if (curTop.task != taskTop.task) {
3328 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3329 boolean callerAtFront = sourceRecord == null
3330 || curTop.task == sourceRecord.task;
3331 if (callerAtFront) {
3332 // We really do want to push this one into the
3333 // user's face, right now.
3334 moveTaskToFrontLocked(taskTop.task);
3335 }
3336 }
3337 // If the caller has requested that the target task be
3338 // reset, then do so.
3339 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3340 taskTop = resetTaskIfNeededLocked(taskTop, r);
3341 }
3342 if (onlyIfNeeded) {
3343 // We don't need to start a new activity, and
3344 // the client said not to do anything if that
3345 // is the case, so this is it! And for paranoia, make
3346 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003347 if (doResume) {
3348 resumeTopActivityLocked(null);
3349 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003350 return START_RETURN_INTENT_TO_CALLER;
3351 }
3352 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3353 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3354 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3355 // In this situation we want to remove all activities
3356 // from the task up to the one being started. In most
3357 // cases this means we are resetting the task to its
3358 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003359 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003360 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003361 if (top != null) {
3362 if (top.frontOfTask) {
3363 // Activity aliases may mean we use different
3364 // intents for the top activity, so make sure
3365 // the task now has the identity of the new
3366 // intent.
3367 top.task.setIntent(r.intent, r.info);
3368 }
3369 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3370 deliverNewIntentLocked(top, r.intent);
3371 } else {
3372 // A special case: we need to
3373 // start the activity because it is not currently
3374 // running, and the caller has asked to clear the
3375 // current task to have this activity at the top.
3376 addingToTask = true;
3377 // Now pretend like this activity is being started
3378 // by the top of its task, so it is put in the
3379 // right place.
3380 sourceRecord = taskTop;
3381 }
3382 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3383 // In this case the top activity on the task is the
3384 // same as the one being launched, so we take that
3385 // as a request to bring the task to the foreground.
3386 // If the top activity in the task is the root
3387 // activity, deliver this new intent to it if it
3388 // desires.
3389 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3390 && taskTop.realActivity.equals(r.realActivity)) {
3391 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3392 if (taskTop.frontOfTask) {
3393 taskTop.task.setIntent(r.intent, r.info);
3394 }
3395 deliverNewIntentLocked(taskTop, r.intent);
3396 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3397 // In this case we are launching the root activity
3398 // of the task, but with a different intent. We
3399 // should start a new instance on top.
3400 addingToTask = true;
3401 sourceRecord = taskTop;
3402 }
3403 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3404 // In this case an activity is being launched in to an
3405 // existing task, without resetting that task. This
3406 // is typically the situation of launching an activity
3407 // from a notification or shortcut. We want to place
3408 // the new activity on top of the current task.
3409 addingToTask = true;
3410 sourceRecord = taskTop;
3411 } else if (!taskTop.task.rootWasReset) {
3412 // In this case we are launching in to an existing task
3413 // that has not yet been started from its front door.
3414 // The current task has been brought to the front.
3415 // Ideally, we'd probably like to place this new task
3416 // at the bottom of its stack, but that's a little hard
3417 // to do with the current organization of the code so
3418 // for now we'll just drop it.
3419 taskTop.task.setIntent(r.intent, r.info);
3420 }
3421 if (!addingToTask) {
3422 // We didn't do anything... but it was needed (a.k.a., client
3423 // don't use that intent!) And for paranoia, make
3424 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003425 if (doResume) {
3426 resumeTopActivityLocked(null);
3427 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003428 return START_TASK_TO_FRONT;
3429 }
3430 }
3431 }
3432 }
3433
3434 //String uri = r.intent.toURI();
3435 //Intent intent2 = new Intent(uri);
3436 //Log.i(TAG, "Given intent: " + r.intent);
3437 //Log.i(TAG, "URI is: " + uri);
3438 //Log.i(TAG, "To intent: " + intent2);
3439
3440 if (r.packageName != null) {
3441 // If the activity being launched is the same as the one currently
3442 // at the top, then we need to check if it should only be launched
3443 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003444 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3445 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003446 if (top.realActivity.equals(r.realActivity)) {
3447 if (top.app != null && top.app.thread != null) {
3448 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3449 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3450 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3451 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3452 // For paranoia, make sure we have correctly
3453 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003454 if (doResume) {
3455 resumeTopActivityLocked(null);
3456 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003457 if (onlyIfNeeded) {
3458 // We don't need to start a new activity, and
3459 // the client said not to do anything if that
3460 // is the case, so this is it!
3461 return START_RETURN_INTENT_TO_CALLER;
3462 }
3463 deliverNewIntentLocked(top, r.intent);
3464 return START_DELIVERED_TO_TOP;
3465 }
3466 }
3467 }
3468 }
3469
3470 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003471 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003472 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003473 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003474 Activity.RESULT_CANCELED, null);
3475 }
3476 return START_CLASS_NOT_FOUND;
3477 }
3478
3479 boolean newTask = false;
3480
3481 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003482 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003483 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3484 // todo: should do better management of integers.
3485 mCurTask++;
3486 if (mCurTask <= 0) {
3487 mCurTask = 1;
3488 }
3489 r.task = new TaskRecord(mCurTask, r.info, intent,
3490 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3491 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3492 + " in new task " + r.task);
3493 newTask = true;
3494 addRecentTask(r.task);
3495
3496 } else if (sourceRecord != null) {
3497 if (!addingToTask &&
3498 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3499 // In this case, we are adding the activity to an existing
3500 // task, but the caller has asked to clear that task if the
3501 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003502 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003503 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003504 if (top != null) {
3505 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3506 deliverNewIntentLocked(top, r.intent);
3507 // For paranoia, make sure we have correctly
3508 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003509 if (doResume) {
3510 resumeTopActivityLocked(null);
3511 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003512 return START_DELIVERED_TO_TOP;
3513 }
3514 } else if (!addingToTask &&
3515 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3516 // In this case, we are launching an activity in our own task
3517 // that may already be running somewhere in the history, and
3518 // we want to shuffle it to the front of the stack if so.
3519 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3520 if (where >= 0) {
3521 HistoryRecord top = moveActivityToFrontLocked(where);
3522 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3523 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003524 if (doResume) {
3525 resumeTopActivityLocked(null);
3526 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003527 return START_DELIVERED_TO_TOP;
3528 }
3529 }
3530 // An existing activity is starting this new activity, so we want
3531 // to keep the new one in the same task as the one that is starting
3532 // it.
3533 r.task = sourceRecord.task;
3534 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3535 + " in existing task " + r.task);
3536
3537 } else {
3538 // This not being started from an existing activity, and not part
3539 // of a new task... just put it in the top task, though these days
3540 // this case should never happen.
3541 final int N = mHistory.size();
3542 HistoryRecord prev =
3543 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3544 r.task = prev != null
3545 ? prev.task
3546 : new TaskRecord(mCurTask, r.info, intent,
3547 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3548 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3549 + " in new guessed " + r.task);
3550 }
3551 if (newTask) {
3552 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3553 }
3554 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003555 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003556 return START_SUCCESS;
3557 }
3558
3559 public final int startActivity(IApplicationThread caller,
3560 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3561 int grantedMode, IBinder resultTo,
3562 String resultWho, int requestCode, boolean onlyIfNeeded,
3563 boolean debug) {
3564 // Refuse possible leaked file descriptors
3565 if (intent != null && intent.hasFileDescriptors()) {
3566 throw new IllegalArgumentException("File descriptors passed in Intent");
3567 }
3568
The Android Open Source Project4df24232009-03-05 14:34:35 -08003569 final boolean componentSpecified = intent.getComponent() != null;
3570
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003571 // Don't modify the client's object!
3572 intent = new Intent(intent);
3573
3574 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003575 ActivityInfo aInfo;
3576 try {
3577 ResolveInfo rInfo =
3578 ActivityThread.getPackageManager().resolveIntent(
3579 intent, resolvedType,
3580 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003581 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003582 aInfo = rInfo != null ? rInfo.activityInfo : null;
3583 } catch (RemoteException e) {
3584 aInfo = null;
3585 }
3586
3587 if (aInfo != null) {
3588 // Store the found target back into the intent, because now that
3589 // we have it we never want to do this again. For example, if the
3590 // user navigates back to this point in the history, we should
3591 // always restart the exact same activity.
3592 intent.setComponent(new ComponentName(
3593 aInfo.applicationInfo.packageName, aInfo.name));
3594
3595 // Don't debug things in the system process
3596 if (debug) {
3597 if (!aInfo.processName.equals("system")) {
3598 setDebugApp(aInfo.processName, true, false);
3599 }
3600 }
3601 }
3602
3603 synchronized(this) {
3604 final long origId = Binder.clearCallingIdentity();
3605 int res = startActivityLocked(caller, intent, resolvedType,
3606 grantedUriPermissions, grantedMode, aInfo,
3607 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003608 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003609 Binder.restoreCallingIdentity(origId);
3610 return res;
3611 }
3612 }
3613
3614 public boolean startNextMatchingActivity(IBinder callingActivity,
3615 Intent intent) {
3616 // Refuse possible leaked file descriptors
3617 if (intent != null && intent.hasFileDescriptors() == true) {
3618 throw new IllegalArgumentException("File descriptors passed in Intent");
3619 }
3620
3621 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003622 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003623 if (index < 0) {
3624 return false;
3625 }
3626 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3627 if (r.app == null || r.app.thread == null) {
3628 // The caller is not running... d'oh!
3629 return false;
3630 }
3631 intent = new Intent(intent);
3632 // The caller is not allowed to change the data.
3633 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3634 // And we are resetting to find the next component...
3635 intent.setComponent(null);
3636
3637 ActivityInfo aInfo = null;
3638 try {
3639 List<ResolveInfo> resolves =
3640 ActivityThread.getPackageManager().queryIntentActivities(
3641 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003642 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003643
3644 // Look for the original activity in the list...
3645 final int N = resolves != null ? resolves.size() : 0;
3646 for (int i=0; i<N; i++) {
3647 ResolveInfo rInfo = resolves.get(i);
3648 if (rInfo.activityInfo.packageName.equals(r.packageName)
3649 && rInfo.activityInfo.name.equals(r.info.name)) {
3650 // We found the current one... the next matching is
3651 // after it.
3652 i++;
3653 if (i<N) {
3654 aInfo = resolves.get(i).activityInfo;
3655 }
3656 break;
3657 }
3658 }
3659 } catch (RemoteException e) {
3660 }
3661
3662 if (aInfo == null) {
3663 // Nobody who is next!
3664 return false;
3665 }
3666
3667 intent.setComponent(new ComponentName(
3668 aInfo.applicationInfo.packageName, aInfo.name));
3669 intent.setFlags(intent.getFlags()&~(
3670 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3671 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3672 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3673 Intent.FLAG_ACTIVITY_NEW_TASK));
3674
3675 // Okay now we need to start the new activity, replacing the
3676 // currently running activity. This is a little tricky because
3677 // we want to start the new one as if the current one is finished,
3678 // but not finish the current one first so that there is no flicker.
3679 // And thus...
3680 final boolean wasFinishing = r.finishing;
3681 r.finishing = true;
3682
3683 // Propagate reply information over to the new activity.
3684 final HistoryRecord resultTo = r.resultTo;
3685 final String resultWho = r.resultWho;
3686 final int requestCode = r.requestCode;
3687 r.resultTo = null;
3688 if (resultTo != null) {
3689 resultTo.removeResultsLocked(r, resultWho, requestCode);
3690 }
3691
3692 final long origId = Binder.clearCallingIdentity();
3693 // XXX we are not dealing with propagating grantedUriPermissions...
3694 // those are not yet exposed to user code, so there is no need.
3695 int res = startActivityLocked(r.app.thread, intent,
3696 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003697 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003698 Binder.restoreCallingIdentity(origId);
3699
3700 r.finishing = wasFinishing;
3701 if (res != START_SUCCESS) {
3702 return false;
3703 }
3704 return true;
3705 }
3706 }
3707
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003708 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003709 Intent intent, String resolvedType, IBinder resultTo,
3710 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003711
3712 // This is so super not safe, that only the system (or okay root)
3713 // can do it.
3714 final int callingUid = Binder.getCallingUid();
3715 if (callingUid != 0 && callingUid != Process.myUid()) {
3716 throw new SecurityException(
3717 "startActivityInPackage only available to the system");
3718 }
3719
The Android Open Source Project4df24232009-03-05 14:34:35 -08003720 final boolean componentSpecified = intent.getComponent() != null;
3721
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003722 // Don't modify the client's object!
3723 intent = new Intent(intent);
3724
3725 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003726 ActivityInfo aInfo;
3727 try {
3728 ResolveInfo rInfo =
3729 ActivityThread.getPackageManager().resolveIntent(
3730 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003731 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003732 aInfo = rInfo != null ? rInfo.activityInfo : null;
3733 } catch (RemoteException e) {
3734 aInfo = null;
3735 }
3736
3737 if (aInfo != null) {
3738 // Store the found target back into the intent, because now that
3739 // we have it we never want to do this again. For example, if the
3740 // user navigates back to this point in the history, we should
3741 // always restart the exact same activity.
3742 intent.setComponent(new ComponentName(
3743 aInfo.applicationInfo.packageName, aInfo.name));
3744 }
3745
3746 synchronized(this) {
3747 return startActivityLocked(null, intent, resolvedType,
3748 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003749 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003750 }
3751 }
3752
3753 private final void addRecentTask(TaskRecord task) {
3754 // Remove any existing entries that are the same kind of task.
3755 int N = mRecentTasks.size();
3756 for (int i=0; i<N; i++) {
3757 TaskRecord tr = mRecentTasks.get(i);
3758 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3759 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3760 mRecentTasks.remove(i);
3761 i--;
3762 N--;
3763 if (task.intent == null) {
3764 // If the new recent task we are adding is not fully
3765 // specified, then replace it with the existing recent task.
3766 task = tr;
3767 }
3768 }
3769 }
3770 if (N >= MAX_RECENT_TASKS) {
3771 mRecentTasks.remove(N-1);
3772 }
3773 mRecentTasks.add(0, task);
3774 }
3775
3776 public void setRequestedOrientation(IBinder token,
3777 int requestedOrientation) {
3778 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003779 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003780 if (index < 0) {
3781 return;
3782 }
3783 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3784 final long origId = Binder.clearCallingIdentity();
3785 mWindowManager.setAppOrientation(r, requestedOrientation);
3786 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003787 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003788 r.mayFreezeScreenLocked(r.app) ? r : null);
3789 if (config != null) {
3790 r.frozenBeforeDestroy = true;
3791 if (!updateConfigurationLocked(config, r)) {
3792 resumeTopActivityLocked(null);
3793 }
3794 }
3795 Binder.restoreCallingIdentity(origId);
3796 }
3797 }
3798
3799 public int getRequestedOrientation(IBinder token) {
3800 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003801 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003802 if (index < 0) {
3803 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3804 }
3805 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3806 return mWindowManager.getAppOrientation(r);
3807 }
3808 }
3809
3810 private final void stopActivityLocked(HistoryRecord r) {
3811 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3812 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3813 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3814 if (!r.finishing) {
3815 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3816 "no-history");
3817 }
3818 } else if (r.app != null && r.app.thread != null) {
3819 if (mFocusedActivity == r) {
3820 setFocusedActivityLocked(topRunningActivityLocked(null));
3821 }
3822 r.resumeKeyDispatchingLocked();
3823 try {
3824 r.stopped = false;
3825 r.state = ActivityState.STOPPING;
3826 if (DEBUG_VISBILITY) Log.v(
3827 TAG, "Stopping visible=" + r.visible + " for " + r);
3828 if (!r.visible) {
3829 mWindowManager.setAppVisibility(r, false);
3830 }
3831 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3832 } catch (Exception e) {
3833 // Maybe just ignore exceptions here... if the process
3834 // has crashed, our death notification will clean things
3835 // up.
3836 Log.w(TAG, "Exception thrown during pause", e);
3837 // Just in case, assume it to be stopped.
3838 r.stopped = true;
3839 r.state = ActivityState.STOPPED;
3840 if (r.configDestroy) {
3841 destroyActivityLocked(r, true);
3842 }
3843 }
3844 }
3845 }
3846
3847 /**
3848 * @return Returns true if the activity is being finished, false if for
3849 * some reason it is being left as-is.
3850 */
3851 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3852 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003853 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003854 TAG, "Finishing activity: token=" + token
3855 + ", result=" + resultCode + ", data=" + resultData);
3856
Dianne Hackborn75b03852009-06-12 15:43:26 -07003857 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003858 if (index < 0) {
3859 return false;
3860 }
3861 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3862
3863 // Is this the last activity left?
3864 boolean lastActivity = true;
3865 for (int i=mHistory.size()-1; i>=0; i--) {
3866 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3867 if (!p.finishing && p != r) {
3868 lastActivity = false;
3869 break;
3870 }
3871 }
3872
3873 // If this is the last activity, but it is the home activity, then
3874 // just don't finish it.
3875 if (lastActivity) {
3876 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3877 return false;
3878 }
3879 }
3880
3881 finishActivityLocked(r, index, resultCode, resultData, reason);
3882 return true;
3883 }
3884
3885 /**
3886 * @return Returns true if this activity has been removed from the history
3887 * list, or false if it is still in the list and will be removed later.
3888 */
3889 private final boolean finishActivityLocked(HistoryRecord r, int index,
3890 int resultCode, Intent resultData, String reason) {
3891 if (r.finishing) {
3892 Log.w(TAG, "Duplicate finish request for " + r);
3893 return false;
3894 }
3895
3896 r.finishing = true;
3897 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3898 System.identityHashCode(r),
3899 r.task.taskId, r.shortComponentName, reason);
3900 r.task.numActivities--;
3901 if (r.frontOfTask && index < (mHistory.size()-1)) {
3902 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3903 if (next.task == r.task) {
3904 next.frontOfTask = true;
3905 }
3906 }
3907
3908 r.pauseKeyDispatchingLocked();
3909 if (mFocusedActivity == r) {
3910 setFocusedActivityLocked(topRunningActivityLocked(null));
3911 }
3912
3913 // send the result
3914 HistoryRecord resultTo = r.resultTo;
3915 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003916 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3917 + " who=" + r.resultWho + " req=" + r.requestCode
3918 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003919 if (r.info.applicationInfo.uid > 0) {
3920 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3921 r.packageName, resultData, r);
3922 }
3923 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3924 resultData);
3925 r.resultTo = null;
3926 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003927 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003928
3929 // Make sure this HistoryRecord is not holding on to other resources,
3930 // because clients have remote IPC references to this object so we
3931 // can't assume that will go away and want to avoid circular IPC refs.
3932 r.results = null;
3933 r.pendingResults = null;
3934 r.newIntents = null;
3935 r.icicle = null;
3936
3937 if (mPendingThumbnails.size() > 0) {
3938 // There are clients waiting to receive thumbnails so, in case
3939 // this is an activity that someone is waiting for, add it
3940 // to the pending list so we can correctly update the clients.
3941 mCancelledThumbnails.add(r);
3942 }
3943
3944 if (mResumedActivity == r) {
3945 boolean endTask = index <= 0
3946 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3947 if (DEBUG_TRANSITION) Log.v(TAG,
3948 "Prepare close transition: finishing " + r);
3949 mWindowManager.prepareAppTransition(endTask
3950 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3951 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3952
3953 // Tell window manager to prepare for this one to be removed.
3954 mWindowManager.setAppVisibility(r, false);
3955
3956 if (mPausingActivity == null) {
3957 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3958 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3959 startPausingLocked(false, false);
3960 }
3961
3962 } else if (r.state != ActivityState.PAUSING) {
3963 // If the activity is PAUSING, we will complete the finish once
3964 // it is done pausing; else we can just directly finish it here.
3965 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3966 return finishCurrentActivityLocked(r, index,
3967 FINISH_AFTER_PAUSE) == null;
3968 } else {
3969 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3970 }
3971
3972 return false;
3973 }
3974
3975 private static final int FINISH_IMMEDIATELY = 0;
3976 private static final int FINISH_AFTER_PAUSE = 1;
3977 private static final int FINISH_AFTER_VISIBLE = 2;
3978
3979 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3980 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003981 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003982 if (index < 0) {
3983 return null;
3984 }
3985
3986 return finishCurrentActivityLocked(r, index, mode);
3987 }
3988
3989 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3990 int index, int mode) {
3991 // First things first: if this activity is currently visible,
3992 // and the resumed activity is not yet visible, then hold off on
3993 // finishing until the resumed one becomes visible.
3994 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3995 if (!mStoppingActivities.contains(r)) {
3996 mStoppingActivities.add(r);
3997 if (mStoppingActivities.size() > 3) {
3998 // If we already have a few activities waiting to stop,
3999 // then give up on things going idle and start clearing
4000 // them out.
4001 Message msg = Message.obtain();
4002 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4003 mHandler.sendMessage(msg);
4004 }
4005 }
4006 r.state = ActivityState.STOPPING;
4007 updateOomAdjLocked();
4008 return r;
4009 }
4010
4011 // make sure the record is cleaned out of other places.
4012 mStoppingActivities.remove(r);
4013 mWaitingVisibleActivities.remove(r);
4014 if (mResumedActivity == r) {
4015 mResumedActivity = null;
4016 }
4017 final ActivityState prevState = r.state;
4018 r.state = ActivityState.FINISHING;
4019
4020 if (mode == FINISH_IMMEDIATELY
4021 || prevState == ActivityState.STOPPED
4022 || prevState == ActivityState.INITIALIZING) {
4023 // If this activity is already stopped, we can just finish
4024 // it right now.
4025 return destroyActivityLocked(r, true) ? null : r;
4026 } else {
4027 // Need to go through the full pause cycle to get this
4028 // activity into the stopped state and then finish it.
4029 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4030 mFinishingActivities.add(r);
4031 resumeTopActivityLocked(null);
4032 }
4033 return r;
4034 }
4035
4036 /**
4037 * This is the internal entry point for handling Activity.finish().
4038 *
4039 * @param token The Binder token referencing the Activity we want to finish.
4040 * @param resultCode Result code, if any, from this Activity.
4041 * @param resultData Result data (Intent), if any, from this Activity.
4042 *
4043 * @result Returns true if the activity successfully finished, or false if it is still running.
4044 */
4045 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4046 // Refuse possible leaked file descriptors
4047 if (resultData != null && resultData.hasFileDescriptors() == true) {
4048 throw new IllegalArgumentException("File descriptors passed in Intent");
4049 }
4050
4051 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004052 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004053 // Find the first activity that is not finishing.
4054 HistoryRecord next = topRunningActivityLocked(token, 0);
4055 if (next != null) {
4056 // ask watcher if this is allowed
4057 boolean resumeOK = true;
4058 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004059 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004060 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004061 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004062 }
4063
4064 if (!resumeOK) {
4065 return false;
4066 }
4067 }
4068 }
4069 final long origId = Binder.clearCallingIdentity();
4070 boolean res = requestFinishActivityLocked(token, resultCode,
4071 resultData, "app-request");
4072 Binder.restoreCallingIdentity(origId);
4073 return res;
4074 }
4075 }
4076
4077 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4078 String resultWho, int requestCode, int resultCode, Intent data) {
4079
4080 if (callingUid > 0) {
4081 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4082 data, r);
4083 }
4084
The Android Open Source Project10592532009-03-18 17:39:46 -07004085 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4086 + " : who=" + resultWho + " req=" + requestCode
4087 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004088 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4089 try {
4090 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4091 list.add(new ResultInfo(resultWho, requestCode,
4092 resultCode, data));
4093 r.app.thread.scheduleSendResult(r, list);
4094 return;
4095 } catch (Exception e) {
4096 Log.w(TAG, "Exception thrown sending result to " + r, e);
4097 }
4098 }
4099
4100 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4101 }
4102
4103 public final void finishSubActivity(IBinder token, String resultWho,
4104 int requestCode) {
4105 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004106 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004107 if (index < 0) {
4108 return;
4109 }
4110 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4111
4112 final long origId = Binder.clearCallingIdentity();
4113
4114 int i;
4115 for (i=mHistory.size()-1; i>=0; i--) {
4116 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4117 if (r.resultTo == self && r.requestCode == requestCode) {
4118 if ((r.resultWho == null && resultWho == null) ||
4119 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4120 finishActivityLocked(r, i,
4121 Activity.RESULT_CANCELED, null, "request-sub");
4122 }
4123 }
4124 }
4125
4126 Binder.restoreCallingIdentity(origId);
4127 }
4128 }
4129
4130 /**
4131 * Perform clean-up of service connections in an activity record.
4132 */
4133 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4134 // Throw away any services that have been bound by this activity.
4135 if (r.connections != null) {
4136 Iterator<ConnectionRecord> it = r.connections.iterator();
4137 while (it.hasNext()) {
4138 ConnectionRecord c = it.next();
4139 removeConnectionLocked(c, null, r);
4140 }
4141 r.connections = null;
4142 }
4143 }
4144
4145 /**
4146 * Perform the common clean-up of an activity record. This is called both
4147 * as part of destroyActivityLocked() (when destroying the client-side
4148 * representation) and cleaning things up as a result of its hosting
4149 * processing going away, in which case there is no remaining client-side
4150 * state to destroy so only the cleanup here is needed.
4151 */
4152 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4153 if (mResumedActivity == r) {
4154 mResumedActivity = null;
4155 }
4156 if (mFocusedActivity == r) {
4157 mFocusedActivity = null;
4158 }
4159
4160 r.configDestroy = false;
4161 r.frozenBeforeDestroy = false;
4162
4163 // Make sure this record is no longer in the pending finishes list.
4164 // This could happen, for example, if we are trimming activities
4165 // down to the max limit while they are still waiting to finish.
4166 mFinishingActivities.remove(r);
4167 mWaitingVisibleActivities.remove(r);
4168
4169 // Remove any pending results.
4170 if (r.finishing && r.pendingResults != null) {
4171 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4172 PendingIntentRecord rec = apr.get();
4173 if (rec != null) {
4174 cancelIntentSenderLocked(rec, false);
4175 }
4176 }
4177 r.pendingResults = null;
4178 }
4179
4180 if (cleanServices) {
4181 cleanUpActivityServicesLocked(r);
4182 }
4183
4184 if (mPendingThumbnails.size() > 0) {
4185 // There are clients waiting to receive thumbnails so, in case
4186 // this is an activity that someone is waiting for, add it
4187 // to the pending list so we can correctly update the clients.
4188 mCancelledThumbnails.add(r);
4189 }
4190
4191 // Get rid of any pending idle timeouts.
4192 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4193 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4194 }
4195
4196 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4197 if (r.state != ActivityState.DESTROYED) {
4198 mHistory.remove(r);
4199 r.inHistory = false;
4200 r.state = ActivityState.DESTROYED;
4201 mWindowManager.removeAppToken(r);
4202 if (VALIDATE_TOKENS) {
4203 mWindowManager.validateAppTokens(mHistory);
4204 }
4205 cleanUpActivityServicesLocked(r);
4206 removeActivityUriPermissionsLocked(r);
4207 }
4208 }
4209
4210 /**
4211 * Destroy the current CLIENT SIDE instance of an activity. This may be
4212 * called both when actually finishing an activity, or when performing
4213 * a configuration switch where we destroy the current client-side object
4214 * but then create a new client-side object for this same HistoryRecord.
4215 */
4216 private final boolean destroyActivityLocked(HistoryRecord r,
4217 boolean removeFromApp) {
4218 if (DEBUG_SWITCH) Log.v(
4219 TAG, "Removing activity: token=" + r
4220 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4221 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4222 System.identityHashCode(r),
4223 r.task.taskId, r.shortComponentName);
4224
4225 boolean removedFromHistory = false;
4226
4227 cleanUpActivityLocked(r, false);
4228
4229 if (r.app != null) {
4230 if (removeFromApp) {
4231 int idx = r.app.activities.indexOf(r);
4232 if (idx >= 0) {
4233 r.app.activities.remove(idx);
4234 }
4235 if (r.persistent) {
4236 decPersistentCountLocked(r.app);
4237 }
4238 }
4239
4240 boolean skipDestroy = false;
4241
4242 try {
4243 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4244 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4245 r.configChangeFlags);
4246 } catch (Exception e) {
4247 // We can just ignore exceptions here... if the process
4248 // has crashed, our death notification will clean things
4249 // up.
4250 //Log.w(TAG, "Exception thrown during finish", e);
4251 if (r.finishing) {
4252 removeActivityFromHistoryLocked(r);
4253 removedFromHistory = true;
4254 skipDestroy = true;
4255 }
4256 }
4257
4258 r.app = null;
4259 r.nowVisible = false;
4260
4261 if (r.finishing && !skipDestroy) {
4262 r.state = ActivityState.DESTROYING;
4263 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4264 msg.obj = r;
4265 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4266 } else {
4267 r.state = ActivityState.DESTROYED;
4268 }
4269 } else {
4270 // remove this record from the history.
4271 if (r.finishing) {
4272 removeActivityFromHistoryLocked(r);
4273 removedFromHistory = true;
4274 } else {
4275 r.state = ActivityState.DESTROYED;
4276 }
4277 }
4278
4279 r.configChangeFlags = 0;
4280
4281 if (!mLRUActivities.remove(r)) {
4282 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4283 }
4284
4285 return removedFromHistory;
4286 }
4287
4288 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4289 ProcessRecord app)
4290 {
4291 int i = list.size();
4292 if (localLOGV) Log.v(
4293 TAG, "Removing app " + app + " from list " + list
4294 + " with " + i + " entries");
4295 while (i > 0) {
4296 i--;
4297 HistoryRecord r = (HistoryRecord)list.get(i);
4298 if (localLOGV) Log.v(
4299 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4300 if (r.app == app) {
4301 if (localLOGV) Log.v(TAG, "Removing this entry!");
4302 list.remove(i);
4303 }
4304 }
4305 }
4306
4307 /**
4308 * Main function for removing an existing process from the activity manager
4309 * as a result of that process going away. Clears out all connections
4310 * to the process.
4311 */
4312 private final void handleAppDiedLocked(ProcessRecord app,
4313 boolean restarting) {
4314 cleanUpApplicationRecordLocked(app, restarting, -1);
4315 if (!restarting) {
4316 mLRUProcesses.remove(app);
4317 }
4318
4319 // Just in case...
4320 if (mPausingActivity != null && mPausingActivity.app == app) {
4321 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4322 mPausingActivity = null;
4323 }
4324 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4325 mLastPausedActivity = null;
4326 }
4327
4328 // Remove this application's activities from active lists.
4329 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4330 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4331 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4332 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4333
4334 boolean atTop = true;
4335 boolean hasVisibleActivities = false;
4336
4337 // Clean out the history list.
4338 int i = mHistory.size();
4339 if (localLOGV) Log.v(
4340 TAG, "Removing app " + app + " from history with " + i + " entries");
4341 while (i > 0) {
4342 i--;
4343 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4344 if (localLOGV) Log.v(
4345 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4346 if (r.app == app) {
4347 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4348 if (localLOGV) Log.v(
4349 TAG, "Removing this entry! frozen=" + r.haveState
4350 + " finishing=" + r.finishing);
4351 mHistory.remove(i);
4352
4353 r.inHistory = false;
4354 mWindowManager.removeAppToken(r);
4355 if (VALIDATE_TOKENS) {
4356 mWindowManager.validateAppTokens(mHistory);
4357 }
4358 removeActivityUriPermissionsLocked(r);
4359
4360 } else {
4361 // We have the current state for this activity, so
4362 // it can be restarted later when needed.
4363 if (localLOGV) Log.v(
4364 TAG, "Keeping entry, setting app to null");
4365 if (r.visible) {
4366 hasVisibleActivities = true;
4367 }
4368 r.app = null;
4369 r.nowVisible = false;
4370 if (!r.haveState) {
4371 r.icicle = null;
4372 }
4373 }
4374
4375 cleanUpActivityLocked(r, true);
4376 r.state = ActivityState.STOPPED;
4377 }
4378 atTop = false;
4379 }
4380
4381 app.activities.clear();
4382
4383 if (app.instrumentationClass != null) {
4384 Log.w(TAG, "Crash of app " + app.processName
4385 + " running instrumentation " + app.instrumentationClass);
4386 Bundle info = new Bundle();
4387 info.putString("shortMsg", "Process crashed.");
4388 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4389 }
4390
4391 if (!restarting) {
4392 if (!resumeTopActivityLocked(null)) {
4393 // If there was nothing to resume, and we are not already
4394 // restarting this process, but there is a visible activity that
4395 // is hosted by the process... then make sure all visible
4396 // activities are running, taking care of restarting this
4397 // process.
4398 if (hasVisibleActivities) {
4399 ensureActivitiesVisibleLocked(null, 0);
4400 }
4401 }
4402 }
4403 }
4404
4405 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4406 IBinder threadBinder = thread.asBinder();
4407
4408 // Find the application record.
4409 int count = mLRUProcesses.size();
4410 int i;
4411 for (i=0; i<count; i++) {
4412 ProcessRecord rec = mLRUProcesses.get(i);
4413 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4414 return i;
4415 }
4416 }
4417 return -1;
4418 }
4419
4420 private final ProcessRecord getRecordForAppLocked(
4421 IApplicationThread thread) {
4422 if (thread == null) {
4423 return null;
4424 }
4425
4426 int appIndex = getLRURecordIndexForAppLocked(thread);
4427 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4428 }
4429
4430 private final void appDiedLocked(ProcessRecord app, int pid,
4431 IApplicationThread thread) {
4432
4433 mProcDeaths[0]++;
4434
4435 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4436 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4437 + ") has died.");
4438 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4439 if (localLOGV) Log.v(
4440 TAG, "Dying app: " + app + ", pid: " + pid
4441 + ", thread: " + thread.asBinder());
4442 boolean doLowMem = app.instrumentationClass == null;
4443 handleAppDiedLocked(app, false);
4444
4445 if (doLowMem) {
4446 // If there are no longer any background processes running,
4447 // and the app that died was not running instrumentation,
4448 // then tell everyone we are now low on memory.
4449 boolean haveBg = false;
4450 int count = mLRUProcesses.size();
4451 int i;
4452 for (i=0; i<count; i++) {
4453 ProcessRecord rec = mLRUProcesses.get(i);
4454 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4455 haveBg = true;
4456 break;
4457 }
4458 }
4459
4460 if (!haveBg) {
4461 Log.i(TAG, "Low Memory: No more background processes.");
4462 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004463 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004464 for (i=0; i<count; i++) {
4465 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004466 if (rec.thread != null &&
4467 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4468 // The low memory report is overriding any current
4469 // state for a GC request. Make sure to do
4470 // visible/foreground processes first.
4471 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4472 rec.lastRequestedGc = 0;
4473 } else {
4474 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004475 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004476 rec.reportLowMemory = true;
4477 rec.lastLowMemory = now;
4478 mProcessesToGc.remove(rec);
4479 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004480 }
4481 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004482 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004483 }
4484 }
4485 } else if (Config.LOGD) {
4486 Log.d(TAG, "Received spurious death notification for thread "
4487 + thread.asBinder());
4488 }
4489 }
4490
4491 final String readFile(String filename) {
4492 try {
4493 FileInputStream fs = new FileInputStream(filename);
4494 byte[] inp = new byte[8192];
4495 int size = fs.read(inp);
4496 fs.close();
4497 return new String(inp, 0, 0, size);
4498 } catch (java.io.IOException e) {
4499 }
4500 return "";
4501 }
4502
4503 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004504 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004505 if (app.notResponding || app.crashing) {
4506 return;
4507 }
4508
4509 // Log the ANR to the event log.
4510 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4511
4512 // If we are on a secure build and the application is not interesting to the user (it is
4513 // not visible or in the background), just kill it instead of displaying a dialog.
4514 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4515 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4516 Process.killProcess(app.pid);
4517 return;
4518 }
4519
4520 // DeviceMonitor.start();
4521
4522 String processInfo = null;
4523 if (MONITOR_CPU_USAGE) {
4524 updateCpuStatsNow();
4525 synchronized (mProcessStatsThread) {
4526 processInfo = mProcessStats.printCurrentState();
4527 }
4528 }
4529
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004530 StringBuilder info = mStringBuilder;
4531 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004532 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004533 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004534 if (reportedActivity != null && reportedActivity.app != null) {
4535 info.append(" (last in ");
4536 info.append(reportedActivity.app.processName);
4537 info.append(")");
4538 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004539 if (annotation != null) {
4540 info.append("\nAnnotation: ");
4541 info.append(annotation);
4542 }
4543 if (MONITOR_CPU_USAGE) {
4544 info.append("\nCPU usage:\n");
4545 info.append(processInfo);
4546 }
4547 Log.i(TAG, info.toString());
4548
4549 // The application is not responding. Dump as many thread traces as we can.
4550 boolean fileDump = prepareTraceFile(true);
4551 if (!fileDump) {
4552 // Dumping traces to the log, just dump the process that isn't responding so
4553 // we don't overflow the log
4554 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4555 } else {
4556 // Dumping traces to a file so dump all active processes we know about
4557 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004558 // First, these are the most important processes.
4559 final int[] imppids = new int[3];
4560 int i=0;
4561 imppids[0] = app.pid;
4562 i++;
4563 if (reportedActivity != null && reportedActivity.app != null
4564 && reportedActivity.app.thread != null
4565 && reportedActivity.app.pid != app.pid) {
4566 imppids[i] = reportedActivity.app.pid;
4567 i++;
4568 }
4569 imppids[i] = Process.myPid();
4570 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4571 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4572 synchronized (this) {
4573 try {
4574 wait(200);
4575 } catch (InterruptedException e) {
4576 }
4577 }
4578 }
4579 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004580 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004581 boolean done = false;
4582 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4583 if (imppids[j] == r.pid) {
4584 done = true;
4585 break;
4586 }
4587 }
4588 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004589 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004590 synchronized (this) {
4591 try {
4592 wait(200);
4593 } catch (InterruptedException e) {
4594 }
4595 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004596 }
4597 }
4598 }
4599 }
4600
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004601 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004602 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004603 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004604 app.pid, info.toString());
4605 if (res != 0) {
4606 if (res < 0) {
4607 // wait until the SIGQUIT has had a chance to process before killing the
4608 // process.
4609 try {
4610 wait(2000);
4611 } catch (InterruptedException e) {
4612 }
4613
4614 Process.killProcess(app.pid);
4615 return;
4616 }
4617 }
4618 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004619 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004620 }
4621 }
4622
4623 makeAppNotRespondingLocked(app,
4624 activity != null ? activity.shortComponentName : null,
4625 annotation != null ? "ANR " + annotation : "ANR",
4626 info.toString(), null);
4627 Message msg = Message.obtain();
4628 HashMap map = new HashMap();
4629 msg.what = SHOW_NOT_RESPONDING_MSG;
4630 msg.obj = map;
4631 map.put("app", app);
4632 if (activity != null) {
4633 map.put("activity", activity);
4634 }
4635
4636 mHandler.sendMessage(msg);
4637 return;
4638 }
4639
4640 /**
4641 * If a stack trace file has been configured, prepare the filesystem
4642 * by creating the directory if it doesn't exist and optionally
4643 * removing the old trace file.
4644 *
4645 * @param removeExisting If set, the existing trace file will be removed.
4646 * @return Returns true if the trace file preparations succeeded
4647 */
4648 public static boolean prepareTraceFile(boolean removeExisting) {
4649 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4650 boolean fileReady = false;
4651 if (!TextUtils.isEmpty(tracesPath)) {
4652 File f = new File(tracesPath);
4653 if (!f.exists()) {
4654 // Ensure the enclosing directory exists
4655 File dir = f.getParentFile();
4656 if (!dir.exists()) {
4657 fileReady = dir.mkdirs();
4658 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004659 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004660 } else if (dir.isDirectory()) {
4661 fileReady = true;
4662 }
4663 } else if (removeExisting) {
4664 // Remove the previous traces file, so we don't fill the disk.
4665 // The VM will recreate it
4666 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4667 fileReady = f.delete();
4668 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004669
4670 if (removeExisting) {
4671 try {
4672 f.createNewFile();
4673 FileUtils.setPermissions(f.getAbsolutePath(),
4674 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4675 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4676 fileReady = true;
4677 } catch (IOException e) {
4678 Log.w(TAG, "Unable to make ANR traces file", e);
4679 }
4680 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004681 }
4682
4683 return fileReady;
4684 }
4685
4686
4687 private final void decPersistentCountLocked(ProcessRecord app)
4688 {
4689 app.persistentActivities--;
4690 if (app.persistentActivities > 0) {
4691 // Still more of 'em...
4692 return;
4693 }
4694 if (app.persistent) {
4695 // Ah, but the application itself is persistent. Whatever!
4696 return;
4697 }
4698
4699 // App is no longer persistent... make sure it and the ones
4700 // following it in the LRU list have the correc oom_adj.
4701 updateOomAdjLocked();
4702 }
4703
4704 public void setPersistent(IBinder token, boolean isPersistent) {
4705 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4706 != PackageManager.PERMISSION_GRANTED) {
4707 String msg = "Permission Denial: setPersistent() from pid="
4708 + Binder.getCallingPid()
4709 + ", uid=" + Binder.getCallingUid()
4710 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4711 Log.w(TAG, msg);
4712 throw new SecurityException(msg);
4713 }
4714
4715 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004716 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004717 if (index < 0) {
4718 return;
4719 }
4720 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4721 ProcessRecord app = r.app;
4722
4723 if (localLOGV) Log.v(
4724 TAG, "Setting persistence " + isPersistent + ": " + r);
4725
4726 if (isPersistent) {
4727 if (r.persistent) {
4728 // Okay okay, I heard you already!
4729 if (localLOGV) Log.v(TAG, "Already persistent!");
4730 return;
4731 }
4732 r.persistent = true;
4733 app.persistentActivities++;
4734 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4735 if (app.persistentActivities > 1) {
4736 // We aren't the first...
4737 if (localLOGV) Log.v(TAG, "Not the first!");
4738 return;
4739 }
4740 if (app.persistent) {
4741 // This would be redundant.
4742 if (localLOGV) Log.v(TAG, "App is persistent!");
4743 return;
4744 }
4745
4746 // App is now persistent... make sure it and the ones
4747 // following it now have the correct oom_adj.
4748 final long origId = Binder.clearCallingIdentity();
4749 updateOomAdjLocked();
4750 Binder.restoreCallingIdentity(origId);
4751
4752 } else {
4753 if (!r.persistent) {
4754 // Okay okay, I heard you already!
4755 return;
4756 }
4757 r.persistent = false;
4758 final long origId = Binder.clearCallingIdentity();
4759 decPersistentCountLocked(app);
4760 Binder.restoreCallingIdentity(origId);
4761
4762 }
4763 }
4764 }
4765
4766 public boolean clearApplicationUserData(final String packageName,
4767 final IPackageDataObserver observer) {
4768 int uid = Binder.getCallingUid();
4769 int pid = Binder.getCallingPid();
4770 long callingId = Binder.clearCallingIdentity();
4771 try {
4772 IPackageManager pm = ActivityThread.getPackageManager();
4773 int pkgUid = -1;
4774 synchronized(this) {
4775 try {
4776 pkgUid = pm.getPackageUid(packageName);
4777 } catch (RemoteException e) {
4778 }
4779 if (pkgUid == -1) {
4780 Log.w(TAG, "Invalid packageName:" + packageName);
4781 return false;
4782 }
4783 if (uid == pkgUid || checkComponentPermission(
4784 android.Manifest.permission.CLEAR_APP_USER_DATA,
4785 pid, uid, -1)
4786 == PackageManager.PERMISSION_GRANTED) {
4787 restartPackageLocked(packageName, pkgUid);
4788 } else {
4789 throw new SecurityException(pid+" does not have permission:"+
4790 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4791 "for process:"+packageName);
4792 }
4793 }
4794
4795 try {
4796 //clear application user data
4797 pm.clearApplicationUserData(packageName, observer);
4798 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4799 Uri.fromParts("package", packageName, null));
4800 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4801 broadcastIntentLocked(null, null, intent,
4802 null, null, 0, null, null, null,
4803 false, false, MY_PID, Process.SYSTEM_UID);
4804 } catch (RemoteException e) {
4805 }
4806 } finally {
4807 Binder.restoreCallingIdentity(callingId);
4808 }
4809 return true;
4810 }
4811
4812 public void restartPackage(final String packageName) {
4813 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4814 != PackageManager.PERMISSION_GRANTED) {
4815 String msg = "Permission Denial: restartPackage() from pid="
4816 + Binder.getCallingPid()
4817 + ", uid=" + Binder.getCallingUid()
4818 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4819 Log.w(TAG, msg);
4820 throw new SecurityException(msg);
4821 }
4822
4823 long callingId = Binder.clearCallingIdentity();
4824 try {
4825 IPackageManager pm = ActivityThread.getPackageManager();
4826 int pkgUid = -1;
4827 synchronized(this) {
4828 try {
4829 pkgUid = pm.getPackageUid(packageName);
4830 } catch (RemoteException e) {
4831 }
4832 if (pkgUid == -1) {
4833 Log.w(TAG, "Invalid packageName: " + packageName);
4834 return;
4835 }
4836 restartPackageLocked(packageName, pkgUid);
4837 }
4838 } finally {
4839 Binder.restoreCallingIdentity(callingId);
4840 }
4841 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004842
4843 /*
4844 * The pkg name and uid have to be specified.
4845 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4846 */
4847 public void killApplicationWithUid(String pkg, int uid) {
4848 if (pkg == null) {
4849 return;
4850 }
4851 // Make sure the uid is valid.
4852 if (uid < 0) {
4853 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4854 return;
4855 }
4856 int callerUid = Binder.getCallingUid();
4857 // Only the system server can kill an application
4858 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004859 // Post an aysnc message to kill the application
4860 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4861 msg.arg1 = uid;
4862 msg.arg2 = 0;
4863 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004864 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004865 } else {
4866 throw new SecurityException(callerUid + " cannot kill pkg: " +
4867 pkg);
4868 }
4869 }
4870
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004871 public void closeSystemDialogs(String reason) {
4872 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4873 if (reason != null) {
4874 intent.putExtra("reason", reason);
4875 }
4876
4877 final int uid = Binder.getCallingUid();
4878 final long origId = Binder.clearCallingIdentity();
4879 synchronized (this) {
4880 int i = mWatchers.beginBroadcast();
4881 while (i > 0) {
4882 i--;
4883 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4884 if (w != null) {
4885 try {
4886 w.closingSystemDialogs(reason);
4887 } catch (RemoteException e) {
4888 }
4889 }
4890 }
4891 mWatchers.finishBroadcast();
4892
4893 broadcastIntentLocked(null, null, intent, null,
4894 null, 0, null, null, null, false, false, -1, uid);
4895 }
4896 Binder.restoreCallingIdentity(origId);
4897 }
4898
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004899 public void getProcessMemoryInfo(int pid, Debug.MemoryInfo mi)
4900 throws RemoteException {
4901 ProcessRecord proc;
4902 synchronized (mPidsSelfLocked) {
4903 proc = mPidsSelfLocked.get(pid);
4904 }
4905
4906 if (proc == null) {
4907 throw new RemoteException();
4908 }
4909
4910 IApplicationThread thread = proc.thread;
4911 if (thread == null) {
4912 throw new RemoteException();
4913 }
4914
4915 thread.getMemoryInfo(mi);
4916 }
4917
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004918 private void restartPackageLocked(final String packageName, int uid) {
4919 uninstallPackageLocked(packageName, uid, false);
4920 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4921 Uri.fromParts("package", packageName, null));
4922 intent.putExtra(Intent.EXTRA_UID, uid);
4923 broadcastIntentLocked(null, null, intent,
4924 null, null, 0, null, null, null,
4925 false, false, MY_PID, Process.SYSTEM_UID);
4926 }
4927
4928 private final void uninstallPackageLocked(String name, int uid,
4929 boolean callerWillRestart) {
4930 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4931
4932 int i, N;
4933
4934 final String procNamePrefix = name + ":";
4935 if (uid < 0) {
4936 try {
4937 uid = ActivityThread.getPackageManager().getPackageUid(name);
4938 } catch (RemoteException e) {
4939 }
4940 }
4941
4942 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4943 while (badApps.hasNext()) {
4944 SparseArray<Long> ba = badApps.next();
4945 if (ba.get(uid) != null) {
4946 badApps.remove();
4947 }
4948 }
4949
4950 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4951
4952 // Remove all processes this package may have touched: all with the
4953 // same UID (except for the system or root user), and all whose name
4954 // matches the package name.
4955 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4956 final int NA = apps.size();
4957 for (int ia=0; ia<NA; ia++) {
4958 ProcessRecord app = apps.valueAt(ia);
4959 if (app.removed) {
4960 procs.add(app);
4961 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4962 || app.processName.equals(name)
4963 || app.processName.startsWith(procNamePrefix)) {
4964 app.removed = true;
4965 procs.add(app);
4966 }
4967 }
4968 }
4969
4970 N = procs.size();
4971 for (i=0; i<N; i++) {
4972 removeProcessLocked(procs.get(i), callerWillRestart);
4973 }
4974
4975 for (i=mHistory.size()-1; i>=0; i--) {
4976 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4977 if (r.packageName.equals(name)) {
4978 if (Config.LOGD) Log.d(
4979 TAG, " Force finishing activity "
4980 + r.intent.getComponent().flattenToShortString());
4981 if (r.app != null) {
4982 r.app.removed = true;
4983 }
4984 r.app = null;
4985 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4986 }
4987 }
4988
4989 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4990 for (ServiceRecord service : mServices.values()) {
4991 if (service.packageName.equals(name)) {
4992 if (service.app != null) {
4993 service.app.removed = true;
4994 }
4995 service.app = null;
4996 services.add(service);
4997 }
4998 }
4999
5000 N = services.size();
5001 for (i=0; i<N; i++) {
5002 bringDownServiceLocked(services.get(i), true);
5003 }
5004
5005 resumeTopActivityLocked(null);
5006 }
5007
5008 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5009 final String name = app.processName;
5010 final int uid = app.info.uid;
5011 if (Config.LOGD) Log.d(
5012 TAG, "Force removing process " + app + " (" + name
5013 + "/" + uid + ")");
5014
5015 mProcessNames.remove(name, uid);
5016 boolean needRestart = false;
5017 if (app.pid > 0 && app.pid != MY_PID) {
5018 int pid = app.pid;
5019 synchronized (mPidsSelfLocked) {
5020 mPidsSelfLocked.remove(pid);
5021 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5022 }
5023 handleAppDiedLocked(app, true);
5024 mLRUProcesses.remove(app);
5025 Process.killProcess(pid);
5026
5027 if (app.persistent) {
5028 if (!callerWillRestart) {
5029 addAppLocked(app.info);
5030 } else {
5031 needRestart = true;
5032 }
5033 }
5034 } else {
5035 mRemovedProcesses.add(app);
5036 }
5037
5038 return needRestart;
5039 }
5040
5041 private final void processStartTimedOutLocked(ProcessRecord app) {
5042 final int pid = app.pid;
5043 boolean gone = false;
5044 synchronized (mPidsSelfLocked) {
5045 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5046 if (knownApp != null && knownApp.thread == null) {
5047 mPidsSelfLocked.remove(pid);
5048 gone = true;
5049 }
5050 }
5051
5052 if (gone) {
5053 Log.w(TAG, "Process " + app + " failed to attach");
5054 mProcessNames.remove(app.processName, app.info.uid);
5055 Process.killProcess(pid);
5056 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5057 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5058 mPendingBroadcast = null;
5059 scheduleBroadcastsLocked();
5060 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005061 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5062 Log.w(TAG, "Unattached app died before backup, skipping");
5063 try {
5064 IBackupManager bm = IBackupManager.Stub.asInterface(
5065 ServiceManager.getService(Context.BACKUP_SERVICE));
5066 bm.agentDisconnected(app.info.packageName);
5067 } catch (RemoteException e) {
5068 // Can't happen; the backup manager is local
5069 }
5070 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005071 } else {
5072 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5073 }
5074 }
5075
5076 private final boolean attachApplicationLocked(IApplicationThread thread,
5077 int pid) {
5078
5079 // Find the application record that is being attached... either via
5080 // the pid if we are running in multiple processes, or just pull the
5081 // next app record if we are emulating process with anonymous threads.
5082 ProcessRecord app;
5083 if (pid != MY_PID && pid >= 0) {
5084 synchronized (mPidsSelfLocked) {
5085 app = mPidsSelfLocked.get(pid);
5086 }
5087 } else if (mStartingProcesses.size() > 0) {
5088 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005089 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005090 } else {
5091 app = null;
5092 }
5093
5094 if (app == null) {
5095 Log.w(TAG, "No pending application record for pid " + pid
5096 + " (IApplicationThread " + thread + "); dropping process");
5097 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5098 if (pid > 0 && pid != MY_PID) {
5099 Process.killProcess(pid);
5100 } else {
5101 try {
5102 thread.scheduleExit();
5103 } catch (Exception e) {
5104 // Ignore exceptions.
5105 }
5106 }
5107 return false;
5108 }
5109
5110 // If this application record is still attached to a previous
5111 // process, clean it up now.
5112 if (app.thread != null) {
5113 handleAppDiedLocked(app, true);
5114 }
5115
5116 // Tell the process all about itself.
5117
5118 if (localLOGV) Log.v(
5119 TAG, "Binding process pid " + pid + " to record " + app);
5120
5121 String processName = app.processName;
5122 try {
5123 thread.asBinder().linkToDeath(new AppDeathRecipient(
5124 app, pid, thread), 0);
5125 } catch (RemoteException e) {
5126 app.resetPackageList();
5127 startProcessLocked(app, "link fail", processName);
5128 return false;
5129 }
5130
5131 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5132
5133 app.thread = thread;
5134 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005135 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005136 app.forcingToForeground = null;
5137 app.foregroundServices = false;
5138 app.debugging = false;
5139
5140 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5141
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005142 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5143 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005144
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005145 if (!normalMode) {
5146 Log.i(TAG, "Launching preboot mode app: " + app);
5147 }
5148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005149 if (localLOGV) Log.v(
5150 TAG, "New app record " + app
5151 + " thread=" + thread.asBinder() + " pid=" + pid);
5152 try {
5153 int testMode = IApplicationThread.DEBUG_OFF;
5154 if (mDebugApp != null && mDebugApp.equals(processName)) {
5155 testMode = mWaitForDebugger
5156 ? IApplicationThread.DEBUG_WAIT
5157 : IApplicationThread.DEBUG_ON;
5158 app.debugging = true;
5159 if (mDebugTransient) {
5160 mDebugApp = mOrigDebugApp;
5161 mWaitForDebugger = mOrigWaitForDebugger;
5162 }
5163 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005164
Christopher Tate181fafa2009-05-14 11:12:14 -07005165 // If the app is being launched for restore or full backup, set it up specially
5166 boolean isRestrictedBackupMode = false;
5167 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5168 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5169 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5170 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005171
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005172 ensurePackageDexOpt(app.instrumentationInfo != null
5173 ? app.instrumentationInfo.packageName
5174 : app.info.packageName);
5175 if (app.instrumentationClass != null) {
5176 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005177 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07005178 thread.bindApplication(processName, app.instrumentationInfo != null
5179 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005180 app.instrumentationClass, app.instrumentationProfileFile,
5181 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005182 isRestrictedBackupMode || !normalMode,
5183 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005184 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005185 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005186 } catch (Exception e) {
5187 // todo: Yikes! What should we do? For now we will try to
5188 // start another process, but that could easily get us in
5189 // an infinite loop of restarting processes...
5190 Log.w(TAG, "Exception thrown during bind!", e);
5191
5192 app.resetPackageList();
5193 startProcessLocked(app, "bind fail", processName);
5194 return false;
5195 }
5196
5197 // Remove this record from the list of starting applications.
5198 mPersistentStartingProcesses.remove(app);
5199 mProcessesOnHold.remove(app);
5200
5201 boolean badApp = false;
5202 boolean didSomething = false;
5203
5204 // See if the top visible activity is waiting to run in this process...
5205 HistoryRecord hr = topRunningActivityLocked(null);
5206 if (hr != null) {
5207 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5208 && processName.equals(hr.processName)) {
5209 try {
5210 if (realStartActivityLocked(hr, app, true, true)) {
5211 didSomething = true;
5212 }
5213 } catch (Exception e) {
5214 Log.w(TAG, "Exception in new application when starting activity "
5215 + hr.intent.getComponent().flattenToShortString(), e);
5216 badApp = true;
5217 }
5218 } else {
5219 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5220 }
5221 }
5222
5223 // Find any services that should be running in this process...
5224 if (!badApp && mPendingServices.size() > 0) {
5225 ServiceRecord sr = null;
5226 try {
5227 for (int i=0; i<mPendingServices.size(); i++) {
5228 sr = mPendingServices.get(i);
5229 if (app.info.uid != sr.appInfo.uid
5230 || !processName.equals(sr.processName)) {
5231 continue;
5232 }
5233
5234 mPendingServices.remove(i);
5235 i--;
5236 realStartServiceLocked(sr, app);
5237 didSomething = true;
5238 }
5239 } catch (Exception e) {
5240 Log.w(TAG, "Exception in new application when starting service "
5241 + sr.shortName, e);
5242 badApp = true;
5243 }
5244 }
5245
5246 // Check if the next broadcast receiver is in this process...
5247 BroadcastRecord br = mPendingBroadcast;
5248 if (!badApp && br != null && br.curApp == app) {
5249 try {
5250 mPendingBroadcast = null;
5251 processCurBroadcastLocked(br, app);
5252 didSomething = true;
5253 } catch (Exception e) {
5254 Log.w(TAG, "Exception in new application when starting receiver "
5255 + br.curComponent.flattenToShortString(), e);
5256 badApp = true;
5257 logBroadcastReceiverDiscard(br);
5258 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5259 br.resultExtras, br.resultAbort, true);
5260 scheduleBroadcastsLocked();
5261 }
5262 }
5263
Christopher Tate181fafa2009-05-14 11:12:14 -07005264 // Check whether the next backup agent is in this process...
5265 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5266 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005267 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005268 try {
5269 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5270 } catch (Exception e) {
5271 Log.w(TAG, "Exception scheduling backup agent creation: ");
5272 e.printStackTrace();
5273 }
5274 }
5275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005276 if (badApp) {
5277 // todo: Also need to kill application to deal with all
5278 // kinds of exceptions.
5279 handleAppDiedLocked(app, false);
5280 return false;
5281 }
5282
5283 if (!didSomething) {
5284 updateOomAdjLocked();
5285 }
5286
5287 return true;
5288 }
5289
5290 public final void attachApplication(IApplicationThread thread) {
5291 synchronized (this) {
5292 int callingPid = Binder.getCallingPid();
5293 final long origId = Binder.clearCallingIdentity();
5294 attachApplicationLocked(thread, callingPid);
5295 Binder.restoreCallingIdentity(origId);
5296 }
5297 }
5298
5299 public final void activityIdle(IBinder token) {
5300 final long origId = Binder.clearCallingIdentity();
5301 activityIdleInternal(token, false);
5302 Binder.restoreCallingIdentity(origId);
5303 }
5304
5305 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5306 boolean remove) {
5307 int N = mStoppingActivities.size();
5308 if (N <= 0) return null;
5309
5310 ArrayList<HistoryRecord> stops = null;
5311
5312 final boolean nowVisible = mResumedActivity != null
5313 && mResumedActivity.nowVisible
5314 && !mResumedActivity.waitingVisible;
5315 for (int i=0; i<N; i++) {
5316 HistoryRecord s = mStoppingActivities.get(i);
5317 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5318 + nowVisible + " waitingVisible=" + s.waitingVisible
5319 + " finishing=" + s.finishing);
5320 if (s.waitingVisible && nowVisible) {
5321 mWaitingVisibleActivities.remove(s);
5322 s.waitingVisible = false;
5323 if (s.finishing) {
5324 // If this activity is finishing, it is sitting on top of
5325 // everyone else but we now know it is no longer needed...
5326 // so get rid of it. Otherwise, we need to go through the
5327 // normal flow and hide it once we determine that it is
5328 // hidden by the activities in front of it.
5329 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5330 mWindowManager.setAppVisibility(s, false);
5331 }
5332 }
5333 if (!s.waitingVisible && remove) {
5334 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5335 if (stops == null) {
5336 stops = new ArrayList<HistoryRecord>();
5337 }
5338 stops.add(s);
5339 mStoppingActivities.remove(i);
5340 N--;
5341 i--;
5342 }
5343 }
5344
5345 return stops;
5346 }
5347
5348 void enableScreenAfterBoot() {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005349 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5350 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005351 mWindowManager.enableScreenAfterBoot();
5352 }
5353
5354 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5355 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5356
5357 ArrayList<HistoryRecord> stops = null;
5358 ArrayList<HistoryRecord> finishes = null;
5359 ArrayList<HistoryRecord> thumbnails = null;
5360 int NS = 0;
5361 int NF = 0;
5362 int NT = 0;
5363 IApplicationThread sendThumbnail = null;
5364 boolean booting = false;
5365 boolean enableScreen = false;
5366
5367 synchronized (this) {
5368 if (token != null) {
5369 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5370 }
5371
5372 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005373 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005374 if (index >= 0) {
5375 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5376
5377 // No longer need to keep the device awake.
5378 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5379 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5380 mLaunchingActivity.release();
5381 }
5382
5383 // We are now idle. If someone is waiting for a thumbnail from
5384 // us, we can now deliver.
5385 r.idle = true;
5386 scheduleAppGcsLocked();
5387 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5388 sendThumbnail = r.app.thread;
5389 r.thumbnailNeeded = false;
5390 }
5391
5392 // If this activity is fullscreen, set up to hide those under it.
5393
5394 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5395 ensureActivitiesVisibleLocked(null, 0);
5396
5397 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5398 if (!mBooted && !fromTimeout) {
5399 mBooted = true;
5400 enableScreen = true;
5401 }
5402 }
5403
5404 // Atomically retrieve all of the other things to do.
5405 stops = processStoppingActivitiesLocked(true);
5406 NS = stops != null ? stops.size() : 0;
5407 if ((NF=mFinishingActivities.size()) > 0) {
5408 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5409 mFinishingActivities.clear();
5410 }
5411 if ((NT=mCancelledThumbnails.size()) > 0) {
5412 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5413 mCancelledThumbnails.clear();
5414 }
5415
5416 booting = mBooting;
5417 mBooting = false;
5418 }
5419
5420 int i;
5421
5422 // Send thumbnail if requested.
5423 if (sendThumbnail != null) {
5424 try {
5425 sendThumbnail.requestThumbnail(token);
5426 } catch (Exception e) {
5427 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5428 sendPendingThumbnail(null, token, null, null, true);
5429 }
5430 }
5431
5432 // Stop any activities that are scheduled to do so but have been
5433 // waiting for the next one to start.
5434 for (i=0; i<NS; i++) {
5435 HistoryRecord r = (HistoryRecord)stops.get(i);
5436 synchronized (this) {
5437 if (r.finishing) {
5438 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5439 } else {
5440 stopActivityLocked(r);
5441 }
5442 }
5443 }
5444
5445 // Finish any activities that are scheduled to do so but have been
5446 // waiting for the next one to start.
5447 for (i=0; i<NF; i++) {
5448 HistoryRecord r = (HistoryRecord)finishes.get(i);
5449 synchronized (this) {
5450 destroyActivityLocked(r, true);
5451 }
5452 }
5453
5454 // Report back to any thumbnail receivers.
5455 for (i=0; i<NT; i++) {
5456 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5457 sendPendingThumbnail(r, null, null, null, true);
5458 }
5459
5460 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005461 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005462 }
5463
5464 trimApplications();
5465 //dump();
5466 //mWindowManager.dump();
5467
5468 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005469 enableScreenAfterBoot();
5470 }
5471 }
5472
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005473 final void finishBooting() {
5474 // Ensure that any processes we had put on hold are now started
5475 // up.
5476 final int NP = mProcessesOnHold.size();
5477 if (NP > 0) {
5478 ArrayList<ProcessRecord> procs =
5479 new ArrayList<ProcessRecord>(mProcessesOnHold);
5480 for (int ip=0; ip<NP; ip++) {
5481 this.startProcessLocked(procs.get(ip), "on-hold", null);
5482 }
5483 }
5484 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5485 // Tell anyone interested that we are done booting!
5486 synchronized (this) {
5487 broadcastIntentLocked(null, null,
5488 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5489 null, null, 0, null, null,
5490 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5491 false, false, MY_PID, Process.SYSTEM_UID);
5492 }
5493 }
5494 }
5495
5496 final void ensureBootCompleted() {
5497 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005498 boolean enableScreen;
5499 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005500 booting = mBooting;
5501 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005502 enableScreen = !mBooted;
5503 mBooted = true;
5504 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005505
5506 if (booting) {
5507 finishBooting();
5508 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005509
5510 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005511 enableScreenAfterBoot();
5512 }
5513 }
5514
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005515 public final void activityPaused(IBinder token, Bundle icicle) {
5516 // Refuse possible leaked file descriptors
5517 if (icicle != null && icicle.hasFileDescriptors()) {
5518 throw new IllegalArgumentException("File descriptors passed in Bundle");
5519 }
5520
5521 final long origId = Binder.clearCallingIdentity();
5522 activityPaused(token, icicle, false);
5523 Binder.restoreCallingIdentity(origId);
5524 }
5525
5526 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5527 if (DEBUG_PAUSE) Log.v(
5528 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5529 + ", timeout=" + timeout);
5530
5531 HistoryRecord r = null;
5532
5533 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005534 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005535 if (index >= 0) {
5536 r = (HistoryRecord)mHistory.get(index);
5537 if (!timeout) {
5538 r.icicle = icicle;
5539 r.haveState = true;
5540 }
5541 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5542 if (mPausingActivity == r) {
5543 r.state = ActivityState.PAUSED;
5544 completePauseLocked();
5545 } else {
5546 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5547 System.identityHashCode(r), r.shortComponentName,
5548 mPausingActivity != null
5549 ? mPausingActivity.shortComponentName : "(none)");
5550 }
5551 }
5552 }
5553 }
5554
5555 public final void activityStopped(IBinder token, Bitmap thumbnail,
5556 CharSequence description) {
5557 if (localLOGV) Log.v(
5558 TAG, "Activity stopped: token=" + token);
5559
5560 HistoryRecord r = null;
5561
5562 final long origId = Binder.clearCallingIdentity();
5563
5564 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005565 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005566 if (index >= 0) {
5567 r = (HistoryRecord)mHistory.get(index);
5568 r.thumbnail = thumbnail;
5569 r.description = description;
5570 r.stopped = true;
5571 r.state = ActivityState.STOPPED;
5572 if (!r.finishing) {
5573 if (r.configDestroy) {
5574 destroyActivityLocked(r, true);
5575 resumeTopActivityLocked(null);
5576 }
5577 }
5578 }
5579 }
5580
5581 if (r != null) {
5582 sendPendingThumbnail(r, null, null, null, false);
5583 }
5584
5585 trimApplications();
5586
5587 Binder.restoreCallingIdentity(origId);
5588 }
5589
5590 public final void activityDestroyed(IBinder token) {
5591 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5592 synchronized (this) {
5593 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5594
Dianne Hackborn75b03852009-06-12 15:43:26 -07005595 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005596 if (index >= 0) {
5597 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5598 if (r.state == ActivityState.DESTROYING) {
5599 final long origId = Binder.clearCallingIdentity();
5600 removeActivityFromHistoryLocked(r);
5601 Binder.restoreCallingIdentity(origId);
5602 }
5603 }
5604 }
5605 }
5606
5607 public String getCallingPackage(IBinder token) {
5608 synchronized (this) {
5609 HistoryRecord r = getCallingRecordLocked(token);
5610 return r != null && r.app != null ? r.app.processName : null;
5611 }
5612 }
5613
5614 public ComponentName getCallingActivity(IBinder token) {
5615 synchronized (this) {
5616 HistoryRecord r = getCallingRecordLocked(token);
5617 return r != null ? r.intent.getComponent() : null;
5618 }
5619 }
5620
5621 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005622 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005623 if (index >= 0) {
5624 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5625 if (r != null) {
5626 return r.resultTo;
5627 }
5628 }
5629 return null;
5630 }
5631
5632 public ComponentName getActivityClassForToken(IBinder token) {
5633 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005634 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005635 if (index >= 0) {
5636 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5637 return r.intent.getComponent();
5638 }
5639 return null;
5640 }
5641 }
5642
5643 public String getPackageForToken(IBinder token) {
5644 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005645 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005646 if (index >= 0) {
5647 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5648 return r.packageName;
5649 }
5650 return null;
5651 }
5652 }
5653
5654 public IIntentSender getIntentSender(int type,
5655 String packageName, IBinder token, String resultWho,
5656 int requestCode, Intent intent, String resolvedType, int flags) {
5657 // Refuse possible leaked file descriptors
5658 if (intent != null && intent.hasFileDescriptors() == true) {
5659 throw new IllegalArgumentException("File descriptors passed in Intent");
5660 }
5661
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005662 if (type == INTENT_SENDER_BROADCAST) {
5663 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5664 throw new IllegalArgumentException(
5665 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5666 }
5667 }
5668
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005669 synchronized(this) {
5670 int callingUid = Binder.getCallingUid();
5671 try {
5672 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5673 Process.supportsProcesses()) {
5674 int uid = ActivityThread.getPackageManager()
5675 .getPackageUid(packageName);
5676 if (uid != Binder.getCallingUid()) {
5677 String msg = "Permission Denial: getIntentSender() from pid="
5678 + Binder.getCallingPid()
5679 + ", uid=" + Binder.getCallingUid()
5680 + ", (need uid=" + uid + ")"
5681 + " is not allowed to send as package " + packageName;
5682 Log.w(TAG, msg);
5683 throw new SecurityException(msg);
5684 }
5685 }
5686 } catch (RemoteException e) {
5687 throw new SecurityException(e);
5688 }
5689 HistoryRecord activity = null;
5690 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005691 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005692 if (index < 0) {
5693 return null;
5694 }
5695 activity = (HistoryRecord)mHistory.get(index);
5696 if (activity.finishing) {
5697 return null;
5698 }
5699 }
5700
5701 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5702 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5703 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5704 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5705 |PendingIntent.FLAG_UPDATE_CURRENT);
5706
5707 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5708 type, packageName, activity, resultWho,
5709 requestCode, intent, resolvedType, flags);
5710 WeakReference<PendingIntentRecord> ref;
5711 ref = mIntentSenderRecords.get(key);
5712 PendingIntentRecord rec = ref != null ? ref.get() : null;
5713 if (rec != null) {
5714 if (!cancelCurrent) {
5715 if (updateCurrent) {
5716 rec.key.requestIntent.replaceExtras(intent);
5717 }
5718 return rec;
5719 }
5720 rec.canceled = true;
5721 mIntentSenderRecords.remove(key);
5722 }
5723 if (noCreate) {
5724 return rec;
5725 }
5726 rec = new PendingIntentRecord(this, key, callingUid);
5727 mIntentSenderRecords.put(key, rec.ref);
5728 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5729 if (activity.pendingResults == null) {
5730 activity.pendingResults
5731 = new HashSet<WeakReference<PendingIntentRecord>>();
5732 }
5733 activity.pendingResults.add(rec.ref);
5734 }
5735 return rec;
5736 }
5737 }
5738
5739 public void cancelIntentSender(IIntentSender sender) {
5740 if (!(sender instanceof PendingIntentRecord)) {
5741 return;
5742 }
5743 synchronized(this) {
5744 PendingIntentRecord rec = (PendingIntentRecord)sender;
5745 try {
5746 int uid = ActivityThread.getPackageManager()
5747 .getPackageUid(rec.key.packageName);
5748 if (uid != Binder.getCallingUid()) {
5749 String msg = "Permission Denial: cancelIntentSender() from pid="
5750 + Binder.getCallingPid()
5751 + ", uid=" + Binder.getCallingUid()
5752 + " is not allowed to cancel packges "
5753 + rec.key.packageName;
5754 Log.w(TAG, msg);
5755 throw new SecurityException(msg);
5756 }
5757 } catch (RemoteException e) {
5758 throw new SecurityException(e);
5759 }
5760 cancelIntentSenderLocked(rec, true);
5761 }
5762 }
5763
5764 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5765 rec.canceled = true;
5766 mIntentSenderRecords.remove(rec.key);
5767 if (cleanActivity && rec.key.activity != null) {
5768 rec.key.activity.pendingResults.remove(rec.ref);
5769 }
5770 }
5771
5772 public String getPackageForIntentSender(IIntentSender pendingResult) {
5773 if (!(pendingResult instanceof PendingIntentRecord)) {
5774 return null;
5775 }
5776 synchronized(this) {
5777 try {
5778 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5779 return res.key.packageName;
5780 } catch (ClassCastException e) {
5781 }
5782 }
5783 return null;
5784 }
5785
5786 public void setProcessLimit(int max) {
5787 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5788 "setProcessLimit()");
5789 mProcessLimit = max;
5790 }
5791
5792 public int getProcessLimit() {
5793 return mProcessLimit;
5794 }
5795
5796 void foregroundTokenDied(ForegroundToken token) {
5797 synchronized (ActivityManagerService.this) {
5798 synchronized (mPidsSelfLocked) {
5799 ForegroundToken cur
5800 = mForegroundProcesses.get(token.pid);
5801 if (cur != token) {
5802 return;
5803 }
5804 mForegroundProcesses.remove(token.pid);
5805 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5806 if (pr == null) {
5807 return;
5808 }
5809 pr.forcingToForeground = null;
5810 pr.foregroundServices = false;
5811 }
5812 updateOomAdjLocked();
5813 }
5814 }
5815
5816 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5817 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5818 "setProcessForeground()");
5819 synchronized(this) {
5820 boolean changed = false;
5821
5822 synchronized (mPidsSelfLocked) {
5823 ProcessRecord pr = mPidsSelfLocked.get(pid);
5824 if (pr == null) {
5825 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5826 return;
5827 }
5828 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5829 if (oldToken != null) {
5830 oldToken.token.unlinkToDeath(oldToken, 0);
5831 mForegroundProcesses.remove(pid);
5832 pr.forcingToForeground = null;
5833 changed = true;
5834 }
5835 if (isForeground && token != null) {
5836 ForegroundToken newToken = new ForegroundToken() {
5837 public void binderDied() {
5838 foregroundTokenDied(this);
5839 }
5840 };
5841 newToken.pid = pid;
5842 newToken.token = token;
5843 try {
5844 token.linkToDeath(newToken, 0);
5845 mForegroundProcesses.put(pid, newToken);
5846 pr.forcingToForeground = token;
5847 changed = true;
5848 } catch (RemoteException e) {
5849 // If the process died while doing this, we will later
5850 // do the cleanup with the process death link.
5851 }
5852 }
5853 }
5854
5855 if (changed) {
5856 updateOomAdjLocked();
5857 }
5858 }
5859 }
5860
5861 // =========================================================
5862 // PERMISSIONS
5863 // =========================================================
5864
5865 static class PermissionController extends IPermissionController.Stub {
5866 ActivityManagerService mActivityManagerService;
5867 PermissionController(ActivityManagerService activityManagerService) {
5868 mActivityManagerService = activityManagerService;
5869 }
5870
5871 public boolean checkPermission(String permission, int pid, int uid) {
5872 return mActivityManagerService.checkPermission(permission, pid,
5873 uid) == PackageManager.PERMISSION_GRANTED;
5874 }
5875 }
5876
5877 /**
5878 * This can be called with or without the global lock held.
5879 */
5880 int checkComponentPermission(String permission, int pid, int uid,
5881 int reqUid) {
5882 // We might be performing an operation on behalf of an indirect binder
5883 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5884 // client identity accordingly before proceeding.
5885 Identity tlsIdentity = sCallerIdentity.get();
5886 if (tlsIdentity != null) {
5887 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5888 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5889 uid = tlsIdentity.uid;
5890 pid = tlsIdentity.pid;
5891 }
5892
5893 // Root, system server and our own process get to do everything.
5894 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5895 !Process.supportsProcesses()) {
5896 return PackageManager.PERMISSION_GRANTED;
5897 }
5898 // If the target requires a specific UID, always fail for others.
5899 if (reqUid >= 0 && uid != reqUid) {
5900 return PackageManager.PERMISSION_DENIED;
5901 }
5902 if (permission == null) {
5903 return PackageManager.PERMISSION_GRANTED;
5904 }
5905 try {
5906 return ActivityThread.getPackageManager()
5907 .checkUidPermission(permission, uid);
5908 } catch (RemoteException e) {
5909 // Should never happen, but if it does... deny!
5910 Log.e(TAG, "PackageManager is dead?!?", e);
5911 }
5912 return PackageManager.PERMISSION_DENIED;
5913 }
5914
5915 /**
5916 * As the only public entry point for permissions checking, this method
5917 * can enforce the semantic that requesting a check on a null global
5918 * permission is automatically denied. (Internally a null permission
5919 * string is used when calling {@link #checkComponentPermission} in cases
5920 * when only uid-based security is needed.)
5921 *
5922 * This can be called with or without the global lock held.
5923 */
5924 public int checkPermission(String permission, int pid, int uid) {
5925 if (permission == null) {
5926 return PackageManager.PERMISSION_DENIED;
5927 }
5928 return checkComponentPermission(permission, pid, uid, -1);
5929 }
5930
5931 /**
5932 * Binder IPC calls go through the public entry point.
5933 * This can be called with or without the global lock held.
5934 */
5935 int checkCallingPermission(String permission) {
5936 return checkPermission(permission,
5937 Binder.getCallingPid(),
5938 Binder.getCallingUid());
5939 }
5940
5941 /**
5942 * This can be called with or without the global lock held.
5943 */
5944 void enforceCallingPermission(String permission, String func) {
5945 if (checkCallingPermission(permission)
5946 == PackageManager.PERMISSION_GRANTED) {
5947 return;
5948 }
5949
5950 String msg = "Permission Denial: " + func + " from pid="
5951 + Binder.getCallingPid()
5952 + ", uid=" + Binder.getCallingUid()
5953 + " requires " + permission;
5954 Log.w(TAG, msg);
5955 throw new SecurityException(msg);
5956 }
5957
5958 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5959 ProviderInfo pi, int uid, int modeFlags) {
5960 try {
5961 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5962 if ((pi.readPermission != null) &&
5963 (pm.checkUidPermission(pi.readPermission, uid)
5964 != PackageManager.PERMISSION_GRANTED)) {
5965 return false;
5966 }
5967 }
5968 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5969 if ((pi.writePermission != null) &&
5970 (pm.checkUidPermission(pi.writePermission, uid)
5971 != PackageManager.PERMISSION_GRANTED)) {
5972 return false;
5973 }
5974 }
5975 return true;
5976 } catch (RemoteException e) {
5977 return false;
5978 }
5979 }
5980
5981 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5982 int modeFlags) {
5983 // Root gets to do everything.
5984 if (uid == 0 || !Process.supportsProcesses()) {
5985 return true;
5986 }
5987 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5988 if (perms == null) return false;
5989 UriPermission perm = perms.get(uri);
5990 if (perm == null) return false;
5991 return (modeFlags&perm.modeFlags) == modeFlags;
5992 }
5993
5994 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5995 // Another redirected-binder-call permissions check as in
5996 // {@link checkComponentPermission}.
5997 Identity tlsIdentity = sCallerIdentity.get();
5998 if (tlsIdentity != null) {
5999 uid = tlsIdentity.uid;
6000 pid = tlsIdentity.pid;
6001 }
6002
6003 // Our own process gets to do everything.
6004 if (pid == MY_PID) {
6005 return PackageManager.PERMISSION_GRANTED;
6006 }
6007 synchronized(this) {
6008 return checkUriPermissionLocked(uri, uid, modeFlags)
6009 ? PackageManager.PERMISSION_GRANTED
6010 : PackageManager.PERMISSION_DENIED;
6011 }
6012 }
6013
6014 private void grantUriPermissionLocked(int callingUid,
6015 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6016 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6017 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6018 if (modeFlags == 0) {
6019 return;
6020 }
6021
6022 final IPackageManager pm = ActivityThread.getPackageManager();
6023
6024 // If this is not a content: uri, we can't do anything with it.
6025 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6026 return;
6027 }
6028
6029 String name = uri.getAuthority();
6030 ProviderInfo pi = null;
6031 ContentProviderRecord cpr
6032 = (ContentProviderRecord)mProvidersByName.get(name);
6033 if (cpr != null) {
6034 pi = cpr.info;
6035 } else {
6036 try {
6037 pi = pm.resolveContentProvider(name,
6038 PackageManager.GET_URI_PERMISSION_PATTERNS);
6039 } catch (RemoteException ex) {
6040 }
6041 }
6042 if (pi == null) {
6043 Log.w(TAG, "No content provider found for: " + name);
6044 return;
6045 }
6046
6047 int targetUid;
6048 try {
6049 targetUid = pm.getPackageUid(targetPkg);
6050 if (targetUid < 0) {
6051 return;
6052 }
6053 } catch (RemoteException ex) {
6054 return;
6055 }
6056
6057 // First... does the target actually need this permission?
6058 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6059 // No need to grant the target this permission.
6060 return;
6061 }
6062
6063 // Second... maybe someone else has already granted the
6064 // permission?
6065 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6066 // No need to grant the target this permission.
6067 return;
6068 }
6069
6070 // Third... is the provider allowing granting of URI permissions?
6071 if (!pi.grantUriPermissions) {
6072 throw new SecurityException("Provider " + pi.packageName
6073 + "/" + pi.name
6074 + " does not allow granting of Uri permissions (uri "
6075 + uri + ")");
6076 }
6077 if (pi.uriPermissionPatterns != null) {
6078 final int N = pi.uriPermissionPatterns.length;
6079 boolean allowed = false;
6080 for (int i=0; i<N; i++) {
6081 if (pi.uriPermissionPatterns[i] != null
6082 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6083 allowed = true;
6084 break;
6085 }
6086 }
6087 if (!allowed) {
6088 throw new SecurityException("Provider " + pi.packageName
6089 + "/" + pi.name
6090 + " does not allow granting of permission to path of Uri "
6091 + uri);
6092 }
6093 }
6094
6095 // Fourth... does the caller itself have permission to access
6096 // this uri?
6097 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6098 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6099 throw new SecurityException("Uid " + callingUid
6100 + " does not have permission to uri " + uri);
6101 }
6102 }
6103
6104 // Okay! So here we are: the caller has the assumed permission
6105 // to the uri, and the target doesn't. Let's now give this to
6106 // the target.
6107
6108 HashMap<Uri, UriPermission> targetUris
6109 = mGrantedUriPermissions.get(targetUid);
6110 if (targetUris == null) {
6111 targetUris = new HashMap<Uri, UriPermission>();
6112 mGrantedUriPermissions.put(targetUid, targetUris);
6113 }
6114
6115 UriPermission perm = targetUris.get(uri);
6116 if (perm == null) {
6117 perm = new UriPermission(targetUid, uri);
6118 targetUris.put(uri, perm);
6119
6120 }
6121 perm.modeFlags |= modeFlags;
6122 if (activity == null) {
6123 perm.globalModeFlags |= modeFlags;
6124 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6125 perm.readActivities.add(activity);
6126 if (activity.readUriPermissions == null) {
6127 activity.readUriPermissions = new HashSet<UriPermission>();
6128 }
6129 activity.readUriPermissions.add(perm);
6130 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6131 perm.writeActivities.add(activity);
6132 if (activity.writeUriPermissions == null) {
6133 activity.writeUriPermissions = new HashSet<UriPermission>();
6134 }
6135 activity.writeUriPermissions.add(perm);
6136 }
6137 }
6138
6139 private void grantUriPermissionFromIntentLocked(int callingUid,
6140 String targetPkg, Intent intent, HistoryRecord activity) {
6141 if (intent == null) {
6142 return;
6143 }
6144 Uri data = intent.getData();
6145 if (data == null) {
6146 return;
6147 }
6148 grantUriPermissionLocked(callingUid, targetPkg, data,
6149 intent.getFlags(), activity);
6150 }
6151
6152 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6153 Uri uri, int modeFlags) {
6154 synchronized(this) {
6155 final ProcessRecord r = getRecordForAppLocked(caller);
6156 if (r == null) {
6157 throw new SecurityException("Unable to find app for caller "
6158 + caller
6159 + " when granting permission to uri " + uri);
6160 }
6161 if (targetPkg == null) {
6162 Log.w(TAG, "grantUriPermission: null target");
6163 return;
6164 }
6165 if (uri == null) {
6166 Log.w(TAG, "grantUriPermission: null uri");
6167 return;
6168 }
6169
6170 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6171 null);
6172 }
6173 }
6174
6175 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6176 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6177 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6178 HashMap<Uri, UriPermission> perms
6179 = mGrantedUriPermissions.get(perm.uid);
6180 if (perms != null) {
6181 perms.remove(perm.uri);
6182 if (perms.size() == 0) {
6183 mGrantedUriPermissions.remove(perm.uid);
6184 }
6185 }
6186 }
6187 }
6188
6189 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6190 if (activity.readUriPermissions != null) {
6191 for (UriPermission perm : activity.readUriPermissions) {
6192 perm.readActivities.remove(activity);
6193 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6194 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6195 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6196 removeUriPermissionIfNeededLocked(perm);
6197 }
6198 }
6199 }
6200 if (activity.writeUriPermissions != null) {
6201 for (UriPermission perm : activity.writeUriPermissions) {
6202 perm.writeActivities.remove(activity);
6203 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6204 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6205 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6206 removeUriPermissionIfNeededLocked(perm);
6207 }
6208 }
6209 }
6210 }
6211
6212 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6213 int modeFlags) {
6214 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6215 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6216 if (modeFlags == 0) {
6217 return;
6218 }
6219
6220 final IPackageManager pm = ActivityThread.getPackageManager();
6221
6222 final String authority = uri.getAuthority();
6223 ProviderInfo pi = null;
6224 ContentProviderRecord cpr
6225 = (ContentProviderRecord)mProvidersByName.get(authority);
6226 if (cpr != null) {
6227 pi = cpr.info;
6228 } else {
6229 try {
6230 pi = pm.resolveContentProvider(authority,
6231 PackageManager.GET_URI_PERMISSION_PATTERNS);
6232 } catch (RemoteException ex) {
6233 }
6234 }
6235 if (pi == null) {
6236 Log.w(TAG, "No content provider found for: " + authority);
6237 return;
6238 }
6239
6240 // Does the caller have this permission on the URI?
6241 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6242 // Right now, if you are not the original owner of the permission,
6243 // you are not allowed to revoke it.
6244 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6245 throw new SecurityException("Uid " + callingUid
6246 + " does not have permission to uri " + uri);
6247 //}
6248 }
6249
6250 // Go through all of the permissions and remove any that match.
6251 final List<String> SEGMENTS = uri.getPathSegments();
6252 if (SEGMENTS != null) {
6253 final int NS = SEGMENTS.size();
6254 int N = mGrantedUriPermissions.size();
6255 for (int i=0; i<N; i++) {
6256 HashMap<Uri, UriPermission> perms
6257 = mGrantedUriPermissions.valueAt(i);
6258 Iterator<UriPermission> it = perms.values().iterator();
6259 toploop:
6260 while (it.hasNext()) {
6261 UriPermission perm = it.next();
6262 Uri targetUri = perm.uri;
6263 if (!authority.equals(targetUri.getAuthority())) {
6264 continue;
6265 }
6266 List<String> targetSegments = targetUri.getPathSegments();
6267 if (targetSegments == null) {
6268 continue;
6269 }
6270 if (targetSegments.size() < NS) {
6271 continue;
6272 }
6273 for (int j=0; j<NS; j++) {
6274 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6275 continue toploop;
6276 }
6277 }
6278 perm.clearModes(modeFlags);
6279 if (perm.modeFlags == 0) {
6280 it.remove();
6281 }
6282 }
6283 if (perms.size() == 0) {
6284 mGrantedUriPermissions.remove(
6285 mGrantedUriPermissions.keyAt(i));
6286 N--;
6287 i--;
6288 }
6289 }
6290 }
6291 }
6292
6293 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6294 int modeFlags) {
6295 synchronized(this) {
6296 final ProcessRecord r = getRecordForAppLocked(caller);
6297 if (r == null) {
6298 throw new SecurityException("Unable to find app for caller "
6299 + caller
6300 + " when revoking permission to uri " + uri);
6301 }
6302 if (uri == null) {
6303 Log.w(TAG, "revokeUriPermission: null uri");
6304 return;
6305 }
6306
6307 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6308 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6309 if (modeFlags == 0) {
6310 return;
6311 }
6312
6313 final IPackageManager pm = ActivityThread.getPackageManager();
6314
6315 final String authority = uri.getAuthority();
6316 ProviderInfo pi = null;
6317 ContentProviderRecord cpr
6318 = (ContentProviderRecord)mProvidersByName.get(authority);
6319 if (cpr != null) {
6320 pi = cpr.info;
6321 } else {
6322 try {
6323 pi = pm.resolveContentProvider(authority,
6324 PackageManager.GET_URI_PERMISSION_PATTERNS);
6325 } catch (RemoteException ex) {
6326 }
6327 }
6328 if (pi == null) {
6329 Log.w(TAG, "No content provider found for: " + authority);
6330 return;
6331 }
6332
6333 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6334 }
6335 }
6336
6337 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6338 synchronized (this) {
6339 ProcessRecord app =
6340 who != null ? getRecordForAppLocked(who) : null;
6341 if (app == null) return;
6342
6343 Message msg = Message.obtain();
6344 msg.what = WAIT_FOR_DEBUGGER_MSG;
6345 msg.obj = app;
6346 msg.arg1 = waiting ? 1 : 0;
6347 mHandler.sendMessage(msg);
6348 }
6349 }
6350
6351 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6352 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006353 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006354 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006355 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006356 }
6357
6358 // =========================================================
6359 // TASK MANAGEMENT
6360 // =========================================================
6361
6362 public List getTasks(int maxNum, int flags,
6363 IThumbnailReceiver receiver) {
6364 ArrayList list = new ArrayList();
6365
6366 PendingThumbnailsRecord pending = null;
6367 IApplicationThread topThumbnail = null;
6368 HistoryRecord topRecord = null;
6369
6370 synchronized(this) {
6371 if (localLOGV) Log.v(
6372 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6373 + ", receiver=" + receiver);
6374
6375 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6376 != PackageManager.PERMISSION_GRANTED) {
6377 if (receiver != null) {
6378 // If the caller wants to wait for pending thumbnails,
6379 // it ain't gonna get them.
6380 try {
6381 receiver.finished();
6382 } catch (RemoteException ex) {
6383 }
6384 }
6385 String msg = "Permission Denial: getTasks() from pid="
6386 + Binder.getCallingPid()
6387 + ", uid=" + Binder.getCallingUid()
6388 + " requires " + android.Manifest.permission.GET_TASKS;
6389 Log.w(TAG, msg);
6390 throw new SecurityException(msg);
6391 }
6392
6393 int pos = mHistory.size()-1;
6394 HistoryRecord next =
6395 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6396 HistoryRecord top = null;
6397 CharSequence topDescription = null;
6398 TaskRecord curTask = null;
6399 int numActivities = 0;
6400 int numRunning = 0;
6401 while (pos >= 0 && maxNum > 0) {
6402 final HistoryRecord r = next;
6403 pos--;
6404 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6405
6406 // Initialize state for next task if needed.
6407 if (top == null ||
6408 (top.state == ActivityState.INITIALIZING
6409 && top.task == r.task)) {
6410 top = r;
6411 topDescription = r.description;
6412 curTask = r.task;
6413 numActivities = numRunning = 0;
6414 }
6415
6416 // Add 'r' into the current task.
6417 numActivities++;
6418 if (r.app != null && r.app.thread != null) {
6419 numRunning++;
6420 }
6421 if (topDescription == null) {
6422 topDescription = r.description;
6423 }
6424
6425 if (localLOGV) Log.v(
6426 TAG, r.intent.getComponent().flattenToShortString()
6427 + ": task=" + r.task);
6428
6429 // If the next one is a different task, generate a new
6430 // TaskInfo entry for what we have.
6431 if (next == null || next.task != curTask) {
6432 ActivityManager.RunningTaskInfo ci
6433 = new ActivityManager.RunningTaskInfo();
6434 ci.id = curTask.taskId;
6435 ci.baseActivity = r.intent.getComponent();
6436 ci.topActivity = top.intent.getComponent();
6437 ci.thumbnail = top.thumbnail;
6438 ci.description = topDescription;
6439 ci.numActivities = numActivities;
6440 ci.numRunning = numRunning;
6441 //System.out.println(
6442 // "#" + maxNum + ": " + " descr=" + ci.description);
6443 if (ci.thumbnail == null && receiver != null) {
6444 if (localLOGV) Log.v(
6445 TAG, "State=" + top.state + "Idle=" + top.idle
6446 + " app=" + top.app
6447 + " thr=" + (top.app != null ? top.app.thread : null));
6448 if (top.state == ActivityState.RESUMED
6449 || top.state == ActivityState.PAUSING) {
6450 if (top.idle && top.app != null
6451 && top.app.thread != null) {
6452 topRecord = top;
6453 topThumbnail = top.app.thread;
6454 } else {
6455 top.thumbnailNeeded = true;
6456 }
6457 }
6458 if (pending == null) {
6459 pending = new PendingThumbnailsRecord(receiver);
6460 }
6461 pending.pendingRecords.add(top);
6462 }
6463 list.add(ci);
6464 maxNum--;
6465 top = null;
6466 }
6467 }
6468
6469 if (pending != null) {
6470 mPendingThumbnails.add(pending);
6471 }
6472 }
6473
6474 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6475
6476 if (topThumbnail != null) {
6477 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6478 try {
6479 topThumbnail.requestThumbnail(topRecord);
6480 } catch (Exception e) {
6481 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6482 sendPendingThumbnail(null, topRecord, null, null, true);
6483 }
6484 }
6485
6486 if (pending == null && receiver != null) {
6487 // In this case all thumbnails were available and the client
6488 // is being asked to be told when the remaining ones come in...
6489 // which is unusually, since the top-most currently running
6490 // activity should never have a canned thumbnail! Oh well.
6491 try {
6492 receiver.finished();
6493 } catch (RemoteException ex) {
6494 }
6495 }
6496
6497 return list;
6498 }
6499
6500 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6501 int flags) {
6502 synchronized (this) {
6503 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6504 "getRecentTasks()");
6505
6506 final int N = mRecentTasks.size();
6507 ArrayList<ActivityManager.RecentTaskInfo> res
6508 = new ArrayList<ActivityManager.RecentTaskInfo>(
6509 maxNum < N ? maxNum : N);
6510 for (int i=0; i<N && maxNum > 0; i++) {
6511 TaskRecord tr = mRecentTasks.get(i);
6512 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6513 || (tr.intent == null)
6514 || ((tr.intent.getFlags()
6515 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6516 ActivityManager.RecentTaskInfo rti
6517 = new ActivityManager.RecentTaskInfo();
6518 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6519 rti.baseIntent = new Intent(
6520 tr.intent != null ? tr.intent : tr.affinityIntent);
6521 rti.origActivity = tr.origActivity;
6522 res.add(rti);
6523 maxNum--;
6524 }
6525 }
6526 return res;
6527 }
6528 }
6529
6530 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6531 int j;
6532 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6533 TaskRecord jt = startTask;
6534
6535 // First look backwards
6536 for (j=startIndex-1; j>=0; j--) {
6537 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6538 if (r.task != jt) {
6539 jt = r.task;
6540 if (affinity.equals(jt.affinity)) {
6541 return j;
6542 }
6543 }
6544 }
6545
6546 // Now look forwards
6547 final int N = mHistory.size();
6548 jt = startTask;
6549 for (j=startIndex+1; j<N; j++) {
6550 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6551 if (r.task != jt) {
6552 if (affinity.equals(jt.affinity)) {
6553 return j;
6554 }
6555 jt = r.task;
6556 }
6557 }
6558
6559 // Might it be at the top?
6560 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6561 return N-1;
6562 }
6563
6564 return -1;
6565 }
6566
6567 /**
6568 * Perform a reset of the given task, if needed as part of launching it.
6569 * Returns the new HistoryRecord at the top of the task.
6570 */
6571 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6572 HistoryRecord newActivity) {
6573 boolean forceReset = (newActivity.info.flags
6574 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6575 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6576 if ((newActivity.info.flags
6577 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6578 forceReset = true;
6579 }
6580 }
6581
6582 final TaskRecord task = taskTop.task;
6583
6584 // We are going to move through the history list so that we can look
6585 // at each activity 'target' with 'below' either the interesting
6586 // activity immediately below it in the stack or null.
6587 HistoryRecord target = null;
6588 int targetI = 0;
6589 int taskTopI = -1;
6590 int replyChainEnd = -1;
6591 int lastReparentPos = -1;
6592 for (int i=mHistory.size()-1; i>=-1; i--) {
6593 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6594
6595 if (below != null && below.finishing) {
6596 continue;
6597 }
6598 if (target == null) {
6599 target = below;
6600 targetI = i;
6601 // If we were in the middle of a reply chain before this
6602 // task, it doesn't appear like the root of the chain wants
6603 // anything interesting, so drop it.
6604 replyChainEnd = -1;
6605 continue;
6606 }
6607
6608 final int flags = target.info.flags;
6609
6610 final boolean finishOnTaskLaunch =
6611 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6612 final boolean allowTaskReparenting =
6613 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6614
6615 if (target.task == task) {
6616 // We are inside of the task being reset... we'll either
6617 // finish this activity, push it out for another task,
6618 // or leave it as-is. We only do this
6619 // for activities that are not the root of the task (since
6620 // if we finish the root, we may no longer have the task!).
6621 if (taskTopI < 0) {
6622 taskTopI = targetI;
6623 }
6624 if (below != null && below.task == task) {
6625 final boolean clearWhenTaskReset =
6626 (target.intent.getFlags()
6627 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006628 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006629 // If this activity is sending a reply to a previous
6630 // activity, we can't do anything with it now until
6631 // we reach the start of the reply chain.
6632 // XXX note that we are assuming the result is always
6633 // to the previous activity, which is almost always
6634 // the case but we really shouldn't count on.
6635 if (replyChainEnd < 0) {
6636 replyChainEnd = targetI;
6637 }
Ed Heyl73798232009-03-24 21:32:21 -07006638 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006639 && target.taskAffinity != null
6640 && !target.taskAffinity.equals(task.affinity)) {
6641 // If this activity has an affinity for another
6642 // task, then we need to move it out of here. We will
6643 // move it as far out of the way as possible, to the
6644 // bottom of the activity stack. This also keeps it
6645 // correctly ordered with any activities we previously
6646 // moved.
6647 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6648 if (target.taskAffinity != null
6649 && target.taskAffinity.equals(p.task.affinity)) {
6650 // If the activity currently at the bottom has the
6651 // same task affinity as the one we are moving,
6652 // then merge it into the same task.
6653 target.task = p.task;
6654 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6655 + " out to bottom task " + p.task);
6656 } else {
6657 mCurTask++;
6658 if (mCurTask <= 0) {
6659 mCurTask = 1;
6660 }
6661 target.task = new TaskRecord(mCurTask, target.info, null,
6662 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6663 target.task.affinityIntent = target.intent;
6664 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6665 + " out to new task " + target.task);
6666 }
6667 mWindowManager.setAppGroupId(target, task.taskId);
6668 if (replyChainEnd < 0) {
6669 replyChainEnd = targetI;
6670 }
6671 int dstPos = 0;
6672 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6673 p = (HistoryRecord)mHistory.get(srcPos);
6674 if (p.finishing) {
6675 continue;
6676 }
6677 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6678 + " out to target's task " + target.task);
6679 task.numActivities--;
6680 p.task = target.task;
6681 target.task.numActivities++;
6682 mHistory.remove(srcPos);
6683 mHistory.add(dstPos, p);
6684 mWindowManager.moveAppToken(dstPos, p);
6685 mWindowManager.setAppGroupId(p, p.task.taskId);
6686 dstPos++;
6687 if (VALIDATE_TOKENS) {
6688 mWindowManager.validateAppTokens(mHistory);
6689 }
6690 i++;
6691 }
6692 if (taskTop == p) {
6693 taskTop = below;
6694 }
6695 if (taskTopI == replyChainEnd) {
6696 taskTopI = -1;
6697 }
6698 replyChainEnd = -1;
6699 addRecentTask(target.task);
6700 } else if (forceReset || finishOnTaskLaunch
6701 || clearWhenTaskReset) {
6702 // If the activity should just be removed -- either
6703 // because it asks for it, or the task should be
6704 // cleared -- then finish it and anything that is
6705 // part of its reply chain.
6706 if (clearWhenTaskReset) {
6707 // In this case, we want to finish this activity
6708 // and everything above it, so be sneaky and pretend
6709 // like these are all in the reply chain.
6710 replyChainEnd = targetI+1;
6711 while (replyChainEnd < mHistory.size() &&
6712 ((HistoryRecord)mHistory.get(
6713 replyChainEnd)).task == task) {
6714 replyChainEnd++;
6715 }
6716 replyChainEnd--;
6717 } else if (replyChainEnd < 0) {
6718 replyChainEnd = targetI;
6719 }
6720 HistoryRecord p = null;
6721 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6722 p = (HistoryRecord)mHistory.get(srcPos);
6723 if (p.finishing) {
6724 continue;
6725 }
6726 if (finishActivityLocked(p, srcPos,
6727 Activity.RESULT_CANCELED, null, "reset")) {
6728 replyChainEnd--;
6729 srcPos--;
6730 }
6731 }
6732 if (taskTop == p) {
6733 taskTop = below;
6734 }
6735 if (taskTopI == replyChainEnd) {
6736 taskTopI = -1;
6737 }
6738 replyChainEnd = -1;
6739 } else {
6740 // If we were in the middle of a chain, well the
6741 // activity that started it all doesn't want anything
6742 // special, so leave it all as-is.
6743 replyChainEnd = -1;
6744 }
6745 } else {
6746 // Reached the bottom of the task -- any reply chain
6747 // should be left as-is.
6748 replyChainEnd = -1;
6749 }
6750
6751 } else if (target.resultTo != null) {
6752 // If this activity is sending a reply to a previous
6753 // activity, we can't do anything with it now until
6754 // we reach the start of the reply chain.
6755 // XXX note that we are assuming the result is always
6756 // to the previous activity, which is almost always
6757 // the case but we really shouldn't count on.
6758 if (replyChainEnd < 0) {
6759 replyChainEnd = targetI;
6760 }
6761
6762 } else if (taskTopI >= 0 && allowTaskReparenting
6763 && task.affinity != null
6764 && task.affinity.equals(target.taskAffinity)) {
6765 // We are inside of another task... if this activity has
6766 // an affinity for our task, then either remove it if we are
6767 // clearing or move it over to our task. Note that
6768 // we currently punt on the case where we are resetting a
6769 // task that is not at the top but who has activities above
6770 // with an affinity to it... this is really not a normal
6771 // case, and we will need to later pull that task to the front
6772 // and usually at that point we will do the reset and pick
6773 // up those remaining activities. (This only happens if
6774 // someone starts an activity in a new task from an activity
6775 // in a task that is not currently on top.)
6776 if (forceReset || finishOnTaskLaunch) {
6777 if (replyChainEnd < 0) {
6778 replyChainEnd = targetI;
6779 }
6780 HistoryRecord p = null;
6781 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6782 p = (HistoryRecord)mHistory.get(srcPos);
6783 if (p.finishing) {
6784 continue;
6785 }
6786 if (finishActivityLocked(p, srcPos,
6787 Activity.RESULT_CANCELED, null, "reset")) {
6788 taskTopI--;
6789 lastReparentPos--;
6790 replyChainEnd--;
6791 srcPos--;
6792 }
6793 }
6794 replyChainEnd = -1;
6795 } else {
6796 if (replyChainEnd < 0) {
6797 replyChainEnd = targetI;
6798 }
6799 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6800 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6801 if (p.finishing) {
6802 continue;
6803 }
6804 if (lastReparentPos < 0) {
6805 lastReparentPos = taskTopI;
6806 taskTop = p;
6807 } else {
6808 lastReparentPos--;
6809 }
6810 mHistory.remove(srcPos);
6811 p.task.numActivities--;
6812 p.task = task;
6813 mHistory.add(lastReparentPos, p);
6814 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6815 + " in to resetting task " + task);
6816 task.numActivities++;
6817 mWindowManager.moveAppToken(lastReparentPos, p);
6818 mWindowManager.setAppGroupId(p, p.task.taskId);
6819 if (VALIDATE_TOKENS) {
6820 mWindowManager.validateAppTokens(mHistory);
6821 }
6822 }
6823 replyChainEnd = -1;
6824
6825 // Now we've moved it in to place... but what if this is
6826 // a singleTop activity and we have put it on top of another
6827 // instance of the same activity? Then we drop the instance
6828 // below so it remains singleTop.
6829 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6830 for (int j=lastReparentPos-1; j>=0; j--) {
6831 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6832 if (p.finishing) {
6833 continue;
6834 }
6835 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6836 if (finishActivityLocked(p, j,
6837 Activity.RESULT_CANCELED, null, "replace")) {
6838 taskTopI--;
6839 lastReparentPos--;
6840 }
6841 }
6842 }
6843 }
6844 }
6845 }
6846
6847 target = below;
6848 targetI = i;
6849 }
6850
6851 return taskTop;
6852 }
6853
6854 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006855 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006856 */
6857 public void moveTaskToFront(int task) {
6858 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6859 "moveTaskToFront()");
6860
6861 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006862 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6863 Binder.getCallingUid(), "Task to front")) {
6864 return;
6865 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006866 final long origId = Binder.clearCallingIdentity();
6867 try {
6868 int N = mRecentTasks.size();
6869 for (int i=0; i<N; i++) {
6870 TaskRecord tr = mRecentTasks.get(i);
6871 if (tr.taskId == task) {
6872 moveTaskToFrontLocked(tr);
6873 return;
6874 }
6875 }
6876 for (int i=mHistory.size()-1; i>=0; i--) {
6877 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6878 if (hr.task.taskId == task) {
6879 moveTaskToFrontLocked(hr.task);
6880 return;
6881 }
6882 }
6883 } finally {
6884 Binder.restoreCallingIdentity(origId);
6885 }
6886 }
6887 }
6888
6889 private final void moveTaskToFrontLocked(TaskRecord tr) {
6890 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6891
6892 final int task = tr.taskId;
6893 int top = mHistory.size()-1;
6894
6895 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6896 // nothing to do!
6897 return;
6898 }
6899
6900 if (DEBUG_TRANSITION) Log.v(TAG,
6901 "Prepare to front transition: task=" + tr);
6902 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6903
6904 ArrayList moved = new ArrayList();
6905
6906 // Applying the affinities may have removed entries from the history,
6907 // so get the size again.
6908 top = mHistory.size()-1;
6909 int pos = top;
6910
6911 // Shift all activities with this task up to the top
6912 // of the stack, keeping them in the same internal order.
6913 while (pos >= 0) {
6914 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6915 if (localLOGV) Log.v(
6916 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6917 boolean first = true;
6918 if (r.task.taskId == task) {
6919 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6920 mHistory.remove(pos);
6921 mHistory.add(top, r);
6922 moved.add(0, r);
6923 top--;
6924 if (first) {
6925 addRecentTask(r.task);
6926 first = false;
6927 }
6928 }
6929 pos--;
6930 }
6931
6932 mWindowManager.moveAppTokensToTop(moved);
6933 if (VALIDATE_TOKENS) {
6934 mWindowManager.validateAppTokens(mHistory);
6935 }
6936
6937 finishTaskMove(task);
6938 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6939 }
6940
6941 private final void finishTaskMove(int task) {
6942 resumeTopActivityLocked(null);
6943 }
6944
6945 public void moveTaskToBack(int task) {
6946 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6947 "moveTaskToBack()");
6948
6949 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006950 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6951 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6952 Binder.getCallingUid(), "Task to back")) {
6953 return;
6954 }
6955 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006956 final long origId = Binder.clearCallingIdentity();
6957 moveTaskToBackLocked(task);
6958 Binder.restoreCallingIdentity(origId);
6959 }
6960 }
6961
6962 /**
6963 * Moves an activity, and all of the other activities within the same task, to the bottom
6964 * of the history stack. The activity's order within the task is unchanged.
6965 *
6966 * @param token A reference to the activity we wish to move
6967 * @param nonRoot If false then this only works if the activity is the root
6968 * of a task; if true it will work for any activity in a task.
6969 * @return Returns true if the move completed, false if not.
6970 */
6971 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6972 synchronized(this) {
6973 final long origId = Binder.clearCallingIdentity();
6974 int taskId = getTaskForActivityLocked(token, !nonRoot);
6975 if (taskId >= 0) {
6976 return moveTaskToBackLocked(taskId);
6977 }
6978 Binder.restoreCallingIdentity(origId);
6979 }
6980 return false;
6981 }
6982
6983 /**
6984 * Worker method for rearranging history stack. Implements the function of moving all
6985 * activities for a specific task (gathering them if disjoint) into a single group at the
6986 * bottom of the stack.
6987 *
6988 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6989 * to premeptively cancel the move.
6990 *
6991 * @param task The taskId to collect and move to the bottom.
6992 * @return Returns true if the move completed, false if not.
6993 */
6994 private final boolean moveTaskToBackLocked(int task) {
6995 Log.i(TAG, "moveTaskToBack: " + task);
6996
6997 // If we have a watcher, preflight the move before committing to it. First check
6998 // for *other* available tasks, but if none are available, then try again allowing the
6999 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007000 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007001 HistoryRecord next = topRunningActivityLocked(null, task);
7002 if (next == null) {
7003 next = topRunningActivityLocked(null, 0);
7004 }
7005 if (next != null) {
7006 // ask watcher if this is allowed
7007 boolean moveOK = true;
7008 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007009 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007010 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007011 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007012 }
7013 if (!moveOK) {
7014 return false;
7015 }
7016 }
7017 }
7018
7019 ArrayList moved = new ArrayList();
7020
7021 if (DEBUG_TRANSITION) Log.v(TAG,
7022 "Prepare to back transition: task=" + task);
7023 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
7024
7025 final int N = mHistory.size();
7026 int bottom = 0;
7027 int pos = 0;
7028
7029 // Shift all activities with this task down to the bottom
7030 // of the stack, keeping them in the same internal order.
7031 while (pos < N) {
7032 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7033 if (localLOGV) Log.v(
7034 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7035 if (r.task.taskId == task) {
7036 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7037 mHistory.remove(pos);
7038 mHistory.add(bottom, r);
7039 moved.add(r);
7040 bottom++;
7041 }
7042 pos++;
7043 }
7044
7045 mWindowManager.moveAppTokensToBottom(moved);
7046 if (VALIDATE_TOKENS) {
7047 mWindowManager.validateAppTokens(mHistory);
7048 }
7049
7050 finishTaskMove(task);
7051 return true;
7052 }
7053
7054 public void moveTaskBackwards(int task) {
7055 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7056 "moveTaskBackwards()");
7057
7058 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007059 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7060 Binder.getCallingUid(), "Task backwards")) {
7061 return;
7062 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007063 final long origId = Binder.clearCallingIdentity();
7064 moveTaskBackwardsLocked(task);
7065 Binder.restoreCallingIdentity(origId);
7066 }
7067 }
7068
7069 private final void moveTaskBackwardsLocked(int task) {
7070 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7071 }
7072
7073 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7074 synchronized(this) {
7075 return getTaskForActivityLocked(token, onlyRoot);
7076 }
7077 }
7078
7079 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7080 final int N = mHistory.size();
7081 TaskRecord lastTask = null;
7082 for (int i=0; i<N; i++) {
7083 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7084 if (r == token) {
7085 if (!onlyRoot || lastTask != r.task) {
7086 return r.task.taskId;
7087 }
7088 return -1;
7089 }
7090 lastTask = r.task;
7091 }
7092
7093 return -1;
7094 }
7095
7096 /**
7097 * Returns the top activity in any existing task matching the given
7098 * Intent. Returns null if no such task is found.
7099 */
7100 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7101 ComponentName cls = intent.getComponent();
7102 if (info.targetActivity != null) {
7103 cls = new ComponentName(info.packageName, info.targetActivity);
7104 }
7105
7106 TaskRecord cp = null;
7107
7108 final int N = mHistory.size();
7109 for (int i=(N-1); i>=0; i--) {
7110 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7111 if (!r.finishing && r.task != cp
7112 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7113 cp = r.task;
7114 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7115 // + "/aff=" + r.task.affinity + " to new cls="
7116 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7117 if (r.task.affinity != null) {
7118 if (r.task.affinity.equals(info.taskAffinity)) {
7119 //Log.i(TAG, "Found matching affinity!");
7120 return r;
7121 }
7122 } else if (r.task.intent != null
7123 && r.task.intent.getComponent().equals(cls)) {
7124 //Log.i(TAG, "Found matching class!");
7125 //dump();
7126 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7127 return r;
7128 } else if (r.task.affinityIntent != null
7129 && r.task.affinityIntent.getComponent().equals(cls)) {
7130 //Log.i(TAG, "Found matching class!");
7131 //dump();
7132 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7133 return r;
7134 }
7135 }
7136 }
7137
7138 return null;
7139 }
7140
7141 /**
7142 * Returns the first activity (starting from the top of the stack) that
7143 * is the same as the given activity. Returns null if no such activity
7144 * is found.
7145 */
7146 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7147 ComponentName cls = intent.getComponent();
7148 if (info.targetActivity != null) {
7149 cls = new ComponentName(info.packageName, info.targetActivity);
7150 }
7151
7152 final int N = mHistory.size();
7153 for (int i=(N-1); i>=0; i--) {
7154 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7155 if (!r.finishing) {
7156 if (r.intent.getComponent().equals(cls)) {
7157 //Log.i(TAG, "Found matching class!");
7158 //dump();
7159 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7160 return r;
7161 }
7162 }
7163 }
7164
7165 return null;
7166 }
7167
7168 public void finishOtherInstances(IBinder token, ComponentName className) {
7169 synchronized(this) {
7170 final long origId = Binder.clearCallingIdentity();
7171
7172 int N = mHistory.size();
7173 TaskRecord lastTask = null;
7174 for (int i=0; i<N; i++) {
7175 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7176 if (r.realActivity.equals(className)
7177 && r != token && lastTask != r.task) {
7178 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7179 null, "others")) {
7180 i--;
7181 N--;
7182 }
7183 }
7184 lastTask = r.task;
7185 }
7186
7187 Binder.restoreCallingIdentity(origId);
7188 }
7189 }
7190
7191 // =========================================================
7192 // THUMBNAILS
7193 // =========================================================
7194
7195 public void reportThumbnail(IBinder token,
7196 Bitmap thumbnail, CharSequence description) {
7197 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7198 final long origId = Binder.clearCallingIdentity();
7199 sendPendingThumbnail(null, token, thumbnail, description, true);
7200 Binder.restoreCallingIdentity(origId);
7201 }
7202
7203 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7204 Bitmap thumbnail, CharSequence description, boolean always) {
7205 TaskRecord task = null;
7206 ArrayList receivers = null;
7207
7208 //System.out.println("Send pending thumbnail: " + r);
7209
7210 synchronized(this) {
7211 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007212 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007213 if (index < 0) {
7214 return;
7215 }
7216 r = (HistoryRecord)mHistory.get(index);
7217 }
7218 if (thumbnail == null) {
7219 thumbnail = r.thumbnail;
7220 description = r.description;
7221 }
7222 if (thumbnail == null && !always) {
7223 // If there is no thumbnail, and this entry is not actually
7224 // going away, then abort for now and pick up the next
7225 // thumbnail we get.
7226 return;
7227 }
7228 task = r.task;
7229
7230 int N = mPendingThumbnails.size();
7231 int i=0;
7232 while (i<N) {
7233 PendingThumbnailsRecord pr =
7234 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7235 //System.out.println("Looking in " + pr.pendingRecords);
7236 if (pr.pendingRecords.remove(r)) {
7237 if (receivers == null) {
7238 receivers = new ArrayList();
7239 }
7240 receivers.add(pr);
7241 if (pr.pendingRecords.size() == 0) {
7242 pr.finished = true;
7243 mPendingThumbnails.remove(i);
7244 N--;
7245 continue;
7246 }
7247 }
7248 i++;
7249 }
7250 }
7251
7252 if (receivers != null) {
7253 final int N = receivers.size();
7254 for (int i=0; i<N; i++) {
7255 try {
7256 PendingThumbnailsRecord pr =
7257 (PendingThumbnailsRecord)receivers.get(i);
7258 pr.receiver.newThumbnail(
7259 task != null ? task.taskId : -1, thumbnail, description);
7260 if (pr.finished) {
7261 pr.receiver.finished();
7262 }
7263 } catch (Exception e) {
7264 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7265 }
7266 }
7267 }
7268 }
7269
7270 // =========================================================
7271 // CONTENT PROVIDERS
7272 // =========================================================
7273
7274 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7275 List providers = null;
7276 try {
7277 providers = ActivityThread.getPackageManager().
7278 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007279 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007280 } catch (RemoteException ex) {
7281 }
7282 if (providers != null) {
7283 final int N = providers.size();
7284 for (int i=0; i<N; i++) {
7285 ProviderInfo cpi =
7286 (ProviderInfo)providers.get(i);
7287 ContentProviderRecord cpr =
7288 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7289 if (cpr == null) {
7290 cpr = new ContentProviderRecord(cpi, app.info);
7291 mProvidersByClass.put(cpi.name, cpr);
7292 }
7293 app.pubProviders.put(cpi.name, cpr);
7294 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007295 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007296 }
7297 }
7298 return providers;
7299 }
7300
7301 private final String checkContentProviderPermissionLocked(
7302 ProviderInfo cpi, ProcessRecord r, int mode) {
7303 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7304 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7305 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7306 cpi.exported ? -1 : cpi.applicationInfo.uid)
7307 == PackageManager.PERMISSION_GRANTED
7308 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7309 return null;
7310 }
7311 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7312 cpi.exported ? -1 : cpi.applicationInfo.uid)
7313 == PackageManager.PERMISSION_GRANTED) {
7314 return null;
7315 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007316
7317 PathPermission[] pps = cpi.pathPermissions;
7318 if (pps != null) {
7319 int i = pps.length;
7320 while (i > 0) {
7321 i--;
7322 PathPermission pp = pps[i];
7323 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7324 cpi.exported ? -1 : cpi.applicationInfo.uid)
7325 == PackageManager.PERMISSION_GRANTED
7326 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7327 return null;
7328 }
7329 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7330 cpi.exported ? -1 : cpi.applicationInfo.uid)
7331 == PackageManager.PERMISSION_GRANTED) {
7332 return null;
7333 }
7334 }
7335 }
7336
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007337 String msg = "Permission Denial: opening provider " + cpi.name
7338 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7339 + ", uid=" + callingUid + ") requires "
7340 + cpi.readPermission + " or " + cpi.writePermission;
7341 Log.w(TAG, msg);
7342 return msg;
7343 }
7344
7345 private final ContentProviderHolder getContentProviderImpl(
7346 IApplicationThread caller, String name) {
7347 ContentProviderRecord cpr;
7348 ProviderInfo cpi = null;
7349
7350 synchronized(this) {
7351 ProcessRecord r = null;
7352 if (caller != null) {
7353 r = getRecordForAppLocked(caller);
7354 if (r == null) {
7355 throw new SecurityException(
7356 "Unable to find app for caller " + caller
7357 + " (pid=" + Binder.getCallingPid()
7358 + ") when getting content provider " + name);
7359 }
7360 }
7361
7362 // First check if this content provider has been published...
7363 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7364 if (cpr != null) {
7365 cpi = cpr.info;
7366 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7367 return new ContentProviderHolder(cpi,
7368 cpi.readPermission != null
7369 ? cpi.readPermission : cpi.writePermission);
7370 }
7371
7372 if (r != null && cpr.canRunHere(r)) {
7373 // This provider has been published or is in the process
7374 // of being published... but it is also allowed to run
7375 // in the caller's process, so don't make a connection
7376 // and just let the caller instantiate its own instance.
7377 if (cpr.provider != null) {
7378 // don't give caller the provider object, it needs
7379 // to make its own.
7380 cpr = new ContentProviderRecord(cpr);
7381 }
7382 return cpr;
7383 }
7384
7385 final long origId = Binder.clearCallingIdentity();
7386
7387 // In this case the provider is a single instance, so we can
7388 // return it right away.
7389 if (r != null) {
7390 r.conProviders.add(cpr);
7391 cpr.clients.add(r);
7392 } else {
7393 cpr.externals++;
7394 }
7395
7396 if (cpr.app != null) {
7397 updateOomAdjLocked(cpr.app);
7398 }
7399
7400 Binder.restoreCallingIdentity(origId);
7401
7402 } else {
7403 try {
7404 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007405 resolveContentProvider(name,
7406 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007407 } catch (RemoteException ex) {
7408 }
7409 if (cpi == null) {
7410 return null;
7411 }
7412
7413 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7414 return new ContentProviderHolder(cpi,
7415 cpi.readPermission != null
7416 ? cpi.readPermission : cpi.writePermission);
7417 }
7418
7419 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7420 final boolean firstClass = cpr == null;
7421 if (firstClass) {
7422 try {
7423 ApplicationInfo ai =
7424 ActivityThread.getPackageManager().
7425 getApplicationInfo(
7426 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007427 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007428 if (ai == null) {
7429 Log.w(TAG, "No package info for content provider "
7430 + cpi.name);
7431 return null;
7432 }
7433 cpr = new ContentProviderRecord(cpi, ai);
7434 } catch (RemoteException ex) {
7435 // pm is in same process, this will never happen.
7436 }
7437 }
7438
7439 if (r != null && cpr.canRunHere(r)) {
7440 // If this is a multiprocess provider, then just return its
7441 // info and allow the caller to instantiate it. Only do
7442 // this if the provider is the same user as the caller's
7443 // process, or can run as root (so can be in any process).
7444 return cpr;
7445 }
7446
7447 if (false) {
7448 RuntimeException e = new RuntimeException("foo");
7449 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7450 // + " pruid " + ai.uid + "): " + cpi.className, e);
7451 }
7452
7453 // This is single process, and our app is now connecting to it.
7454 // See if we are already in the process of launching this
7455 // provider.
7456 final int N = mLaunchingProviders.size();
7457 int i;
7458 for (i=0; i<N; i++) {
7459 if (mLaunchingProviders.get(i) == cpr) {
7460 break;
7461 }
7462 if (false) {
7463 final ContentProviderRecord rec =
7464 (ContentProviderRecord)mLaunchingProviders.get(i);
7465 if (rec.info.name.equals(cpr.info.name)) {
7466 cpr = rec;
7467 break;
7468 }
7469 }
7470 }
7471
7472 // If the provider is not already being launched, then get it
7473 // started.
7474 if (i >= N) {
7475 final long origId = Binder.clearCallingIdentity();
7476 ProcessRecord proc = startProcessLocked(cpi.processName,
7477 cpr.appInfo, false, 0, "content provider",
7478 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007479 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007480 if (proc == null) {
7481 Log.w(TAG, "Unable to launch app "
7482 + cpi.applicationInfo.packageName + "/"
7483 + cpi.applicationInfo.uid + " for provider "
7484 + name + ": process is bad");
7485 return null;
7486 }
7487 cpr.launchingApp = proc;
7488 mLaunchingProviders.add(cpr);
7489 Binder.restoreCallingIdentity(origId);
7490 }
7491
7492 // Make sure the provider is published (the same provider class
7493 // may be published under multiple names).
7494 if (firstClass) {
7495 mProvidersByClass.put(cpi.name, cpr);
7496 }
7497 mProvidersByName.put(name, cpr);
7498
7499 if (r != null) {
7500 r.conProviders.add(cpr);
7501 cpr.clients.add(r);
7502 } else {
7503 cpr.externals++;
7504 }
7505 }
7506 }
7507
7508 // Wait for the provider to be published...
7509 synchronized (cpr) {
7510 while (cpr.provider == null) {
7511 if (cpr.launchingApp == null) {
7512 Log.w(TAG, "Unable to launch app "
7513 + cpi.applicationInfo.packageName + "/"
7514 + cpi.applicationInfo.uid + " for provider "
7515 + name + ": launching app became null");
7516 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7517 cpi.applicationInfo.packageName,
7518 cpi.applicationInfo.uid, name);
7519 return null;
7520 }
7521 try {
7522 cpr.wait();
7523 } catch (InterruptedException ex) {
7524 }
7525 }
7526 }
7527 return cpr;
7528 }
7529
7530 public final ContentProviderHolder getContentProvider(
7531 IApplicationThread caller, String name) {
7532 if (caller == null) {
7533 String msg = "null IApplicationThread when getting content provider "
7534 + name;
7535 Log.w(TAG, msg);
7536 throw new SecurityException(msg);
7537 }
7538
7539 return getContentProviderImpl(caller, name);
7540 }
7541
7542 private ContentProviderHolder getContentProviderExternal(String name) {
7543 return getContentProviderImpl(null, name);
7544 }
7545
7546 /**
7547 * Drop a content provider from a ProcessRecord's bookkeeping
7548 * @param cpr
7549 */
7550 public void removeContentProvider(IApplicationThread caller, String name) {
7551 synchronized (this) {
7552 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7553 if(cpr == null) {
7554 //remove from mProvidersByClass
7555 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7556 return;
7557 }
7558 final ProcessRecord r = getRecordForAppLocked(caller);
7559 if (r == null) {
7560 throw new SecurityException(
7561 "Unable to find app for caller " + caller +
7562 " when removing content provider " + name);
7563 }
7564 //update content provider record entry info
7565 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7566 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7567 r.info.processName+" from process "+localCpr.appInfo.processName);
7568 if(localCpr.appInfo.processName == r.info.processName) {
7569 //should not happen. taken care of as a local provider
7570 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7571 return;
7572 } else {
7573 localCpr.clients.remove(r);
7574 r.conProviders.remove(localCpr);
7575 }
7576 updateOomAdjLocked();
7577 }
7578 }
7579
7580 private void removeContentProviderExternal(String name) {
7581 synchronized (this) {
7582 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7583 if(cpr == null) {
7584 //remove from mProvidersByClass
7585 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7586 return;
7587 }
7588
7589 //update content provider record entry info
7590 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7591 localCpr.externals--;
7592 if (localCpr.externals < 0) {
7593 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7594 }
7595 updateOomAdjLocked();
7596 }
7597 }
7598
7599 public final void publishContentProviders(IApplicationThread caller,
7600 List<ContentProviderHolder> providers) {
7601 if (providers == null) {
7602 return;
7603 }
7604
7605 synchronized(this) {
7606 final ProcessRecord r = getRecordForAppLocked(caller);
7607 if (r == null) {
7608 throw new SecurityException(
7609 "Unable to find app for caller " + caller
7610 + " (pid=" + Binder.getCallingPid()
7611 + ") when publishing content providers");
7612 }
7613
7614 final long origId = Binder.clearCallingIdentity();
7615
7616 final int N = providers.size();
7617 for (int i=0; i<N; i++) {
7618 ContentProviderHolder src = providers.get(i);
7619 if (src == null || src.info == null || src.provider == null) {
7620 continue;
7621 }
7622 ContentProviderRecord dst =
7623 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7624 if (dst != null) {
7625 mProvidersByClass.put(dst.info.name, dst);
7626 String names[] = dst.info.authority.split(";");
7627 for (int j = 0; j < names.length; j++) {
7628 mProvidersByName.put(names[j], dst);
7629 }
7630
7631 int NL = mLaunchingProviders.size();
7632 int j;
7633 for (j=0; j<NL; j++) {
7634 if (mLaunchingProviders.get(j) == dst) {
7635 mLaunchingProviders.remove(j);
7636 j--;
7637 NL--;
7638 }
7639 }
7640 synchronized (dst) {
7641 dst.provider = src.provider;
7642 dst.app = r;
7643 dst.notifyAll();
7644 }
7645 updateOomAdjLocked(r);
7646 }
7647 }
7648
7649 Binder.restoreCallingIdentity(origId);
7650 }
7651 }
7652
7653 public static final void installSystemProviders() {
7654 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7655 List providers = mSelf.generateApplicationProvidersLocked(app);
7656 mSystemThread.installSystemProviders(providers);
7657 }
7658
7659 // =========================================================
7660 // GLOBAL MANAGEMENT
7661 // =========================================================
7662
7663 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7664 ApplicationInfo info, String customProcess) {
7665 String proc = customProcess != null ? customProcess : info.processName;
7666 BatteryStatsImpl.Uid.Proc ps = null;
7667 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7668 synchronized (stats) {
7669 ps = stats.getProcessStatsLocked(info.uid, proc);
7670 }
7671 return new ProcessRecord(ps, thread, info, proc);
7672 }
7673
7674 final ProcessRecord addAppLocked(ApplicationInfo info) {
7675 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7676
7677 if (app == null) {
7678 app = newProcessRecordLocked(null, info, null);
7679 mProcessNames.put(info.processName, info.uid, app);
7680 updateLRUListLocked(app, true);
7681 }
7682
7683 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7684 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7685 app.persistent = true;
7686 app.maxAdj = CORE_SERVER_ADJ;
7687 }
7688 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7689 mPersistentStartingProcesses.add(app);
7690 startProcessLocked(app, "added application", app.processName);
7691 }
7692
7693 return app;
7694 }
7695
7696 public void unhandledBack() {
7697 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7698 "unhandledBack()");
7699
7700 synchronized(this) {
7701 int count = mHistory.size();
7702 if (Config.LOGD) Log.d(
7703 TAG, "Performing unhandledBack(): stack size = " + count);
7704 if (count > 1) {
7705 final long origId = Binder.clearCallingIdentity();
7706 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7707 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7708 Binder.restoreCallingIdentity(origId);
7709 }
7710 }
7711 }
7712
7713 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7714 String name = uri.getAuthority();
7715 ContentProviderHolder cph = getContentProviderExternal(name);
7716 ParcelFileDescriptor pfd = null;
7717 if (cph != null) {
7718 // We record the binder invoker's uid in thread-local storage before
7719 // going to the content provider to open the file. Later, in the code
7720 // that handles all permissions checks, we look for this uid and use
7721 // that rather than the Activity Manager's own uid. The effect is that
7722 // we do the check against the caller's permissions even though it looks
7723 // to the content provider like the Activity Manager itself is making
7724 // the request.
7725 sCallerIdentity.set(new Identity(
7726 Binder.getCallingPid(), Binder.getCallingUid()));
7727 try {
7728 pfd = cph.provider.openFile(uri, "r");
7729 } catch (FileNotFoundException e) {
7730 // do nothing; pfd will be returned null
7731 } finally {
7732 // Ensure that whatever happens, we clean up the identity state
7733 sCallerIdentity.remove();
7734 }
7735
7736 // We've got the fd now, so we're done with the provider.
7737 removeContentProviderExternal(name);
7738 } else {
7739 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7740 }
7741 return pfd;
7742 }
7743
7744 public void goingToSleep() {
7745 synchronized(this) {
7746 mSleeping = true;
7747 mWindowManager.setEventDispatching(false);
7748
7749 if (mResumedActivity != null) {
7750 pauseIfSleepingLocked();
7751 } else {
7752 Log.w(TAG, "goingToSleep with no resumed activity!");
7753 }
7754 }
7755 }
7756
Dianne Hackborn55280a92009-05-07 15:53:46 -07007757 public boolean shutdown(int timeout) {
7758 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7759 != PackageManager.PERMISSION_GRANTED) {
7760 throw new SecurityException("Requires permission "
7761 + android.Manifest.permission.SHUTDOWN);
7762 }
7763
7764 boolean timedout = false;
7765
7766 synchronized(this) {
7767 mShuttingDown = true;
7768 mWindowManager.setEventDispatching(false);
7769
7770 if (mResumedActivity != null) {
7771 pauseIfSleepingLocked();
7772 final long endTime = System.currentTimeMillis() + timeout;
7773 while (mResumedActivity != null || mPausingActivity != null) {
7774 long delay = endTime - System.currentTimeMillis();
7775 if (delay <= 0) {
7776 Log.w(TAG, "Activity manager shutdown timed out");
7777 timedout = true;
7778 break;
7779 }
7780 try {
7781 this.wait();
7782 } catch (InterruptedException e) {
7783 }
7784 }
7785 }
7786 }
7787
7788 mUsageStatsService.shutdown();
7789 mBatteryStatsService.shutdown();
7790
7791 return timedout;
7792 }
7793
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007794 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007795 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007796 if (!mGoingToSleep.isHeld()) {
7797 mGoingToSleep.acquire();
7798 if (mLaunchingActivity.isHeld()) {
7799 mLaunchingActivity.release();
7800 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7801 }
7802 }
7803
7804 // If we are not currently pausing an activity, get the current
7805 // one to pause. If we are pausing one, we will just let that stuff
7806 // run and release the wake lock when all done.
7807 if (mPausingActivity == null) {
7808 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7809 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7810 startPausingLocked(false, true);
7811 }
7812 }
7813 }
7814
7815 public void wakingUp() {
7816 synchronized(this) {
7817 if (mGoingToSleep.isHeld()) {
7818 mGoingToSleep.release();
7819 }
7820 mWindowManager.setEventDispatching(true);
7821 mSleeping = false;
7822 resumeTopActivityLocked(null);
7823 }
7824 }
7825
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007826 public void stopAppSwitches() {
7827 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7828 != PackageManager.PERMISSION_GRANTED) {
7829 throw new SecurityException("Requires permission "
7830 + android.Manifest.permission.STOP_APP_SWITCHES);
7831 }
7832
7833 synchronized(this) {
7834 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7835 + APP_SWITCH_DELAY_TIME;
7836 mDidAppSwitch = false;
7837 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7838 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7839 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7840 }
7841 }
7842
7843 public void resumeAppSwitches() {
7844 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7845 != PackageManager.PERMISSION_GRANTED) {
7846 throw new SecurityException("Requires permission "
7847 + android.Manifest.permission.STOP_APP_SWITCHES);
7848 }
7849
7850 synchronized(this) {
7851 // Note that we don't execute any pending app switches... we will
7852 // let those wait until either the timeout, or the next start
7853 // activity request.
7854 mAppSwitchesAllowedTime = 0;
7855 }
7856 }
7857
7858 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7859 String name) {
7860 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7861 return true;
7862 }
7863
7864 final int perm = checkComponentPermission(
7865 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7866 callingUid, -1);
7867 if (perm == PackageManager.PERMISSION_GRANTED) {
7868 return true;
7869 }
7870
7871 Log.w(TAG, name + " request from " + callingUid + " stopped");
7872 return false;
7873 }
7874
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007875 public void setDebugApp(String packageName, boolean waitForDebugger,
7876 boolean persistent) {
7877 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7878 "setDebugApp()");
7879
7880 // Note that this is not really thread safe if there are multiple
7881 // callers into it at the same time, but that's not a situation we
7882 // care about.
7883 if (persistent) {
7884 final ContentResolver resolver = mContext.getContentResolver();
7885 Settings.System.putString(
7886 resolver, Settings.System.DEBUG_APP,
7887 packageName);
7888 Settings.System.putInt(
7889 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7890 waitForDebugger ? 1 : 0);
7891 }
7892
7893 synchronized (this) {
7894 if (!persistent) {
7895 mOrigDebugApp = mDebugApp;
7896 mOrigWaitForDebugger = mWaitForDebugger;
7897 }
7898 mDebugApp = packageName;
7899 mWaitForDebugger = waitForDebugger;
7900 mDebugTransient = !persistent;
7901 if (packageName != null) {
7902 final long origId = Binder.clearCallingIdentity();
7903 uninstallPackageLocked(packageName, -1, false);
7904 Binder.restoreCallingIdentity(origId);
7905 }
7906 }
7907 }
7908
7909 public void setAlwaysFinish(boolean enabled) {
7910 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7911 "setAlwaysFinish()");
7912
7913 Settings.System.putInt(
7914 mContext.getContentResolver(),
7915 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7916
7917 synchronized (this) {
7918 mAlwaysFinishActivities = enabled;
7919 }
7920 }
7921
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007922 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007923 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007924 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007925 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007926 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007927 }
7928 }
7929
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007930 public void registerActivityWatcher(IActivityWatcher watcher) {
7931 mWatchers.register(watcher);
7932 }
7933
7934 public void unregisterActivityWatcher(IActivityWatcher watcher) {
7935 mWatchers.unregister(watcher);
7936 }
7937
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007938 public final void enterSafeMode() {
7939 synchronized(this) {
7940 // It only makes sense to do this before the system is ready
7941 // and started launching other packages.
7942 if (!mSystemReady) {
7943 try {
7944 ActivityThread.getPackageManager().enterSafeMode();
7945 } catch (RemoteException e) {
7946 }
7947
7948 View v = LayoutInflater.from(mContext).inflate(
7949 com.android.internal.R.layout.safe_mode, null);
7950 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7951 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7952 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7953 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7954 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7955 lp.format = v.getBackground().getOpacity();
7956 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7957 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7958 ((WindowManager)mContext.getSystemService(
7959 Context.WINDOW_SERVICE)).addView(v, lp);
7960 }
7961 }
7962 }
7963
7964 public void noteWakeupAlarm(IIntentSender sender) {
7965 if (!(sender instanceof PendingIntentRecord)) {
7966 return;
7967 }
7968 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7969 synchronized (stats) {
7970 if (mBatteryStatsService.isOnBattery()) {
7971 mBatteryStatsService.enforceCallingPermission();
7972 PendingIntentRecord rec = (PendingIntentRecord)sender;
7973 int MY_UID = Binder.getCallingUid();
7974 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7975 BatteryStatsImpl.Uid.Pkg pkg =
7976 stats.getPackageStatsLocked(uid, rec.key.packageName);
7977 pkg.incWakeupsLocked();
7978 }
7979 }
7980 }
7981
7982 public boolean killPidsForMemory(int[] pids) {
7983 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7984 throw new SecurityException("killPidsForMemory only available to the system");
7985 }
7986
7987 // XXX Note: don't acquire main activity lock here, because the window
7988 // manager calls in with its locks held.
7989
7990 boolean killed = false;
7991 synchronized (mPidsSelfLocked) {
7992 int[] types = new int[pids.length];
7993 int worstType = 0;
7994 for (int i=0; i<pids.length; i++) {
7995 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7996 if (proc != null) {
7997 int type = proc.setAdj;
7998 types[i] = type;
7999 if (type > worstType) {
8000 worstType = type;
8001 }
8002 }
8003 }
8004
8005 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8006 // then constrain it so we will kill all hidden procs.
8007 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8008 worstType = HIDDEN_APP_MIN_ADJ;
8009 }
8010 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8011 for (int i=0; i<pids.length; i++) {
8012 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8013 if (proc == null) {
8014 continue;
8015 }
8016 int adj = proc.setAdj;
8017 if (adj >= worstType) {
8018 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8019 + adj + ")");
8020 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
8021 proc.processName, adj);
8022 killed = true;
8023 Process.killProcess(pids[i]);
8024 }
8025 }
8026 }
8027 return killed;
8028 }
8029
8030 public void reportPss(IApplicationThread caller, int pss) {
8031 Watchdog.PssRequestor req;
8032 String name;
8033 ProcessRecord callerApp;
8034 synchronized (this) {
8035 if (caller == null) {
8036 return;
8037 }
8038 callerApp = getRecordForAppLocked(caller);
8039 if (callerApp == null) {
8040 return;
8041 }
8042 callerApp.lastPss = pss;
8043 req = callerApp;
8044 name = callerApp.processName;
8045 }
8046 Watchdog.getInstance().reportPss(req, name, pss);
8047 if (!callerApp.persistent) {
8048 removeRequestedPss(callerApp);
8049 }
8050 }
8051
8052 public void requestPss(Runnable completeCallback) {
8053 ArrayList<ProcessRecord> procs;
8054 synchronized (this) {
8055 mRequestPssCallback = completeCallback;
8056 mRequestPssList.clear();
8057 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8058 ProcessRecord proc = mLRUProcesses.get(i);
8059 if (!proc.persistent) {
8060 mRequestPssList.add(proc);
8061 }
8062 }
8063 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8064 }
8065
8066 int oldPri = Process.getThreadPriority(Process.myTid());
8067 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8068 for (int i=procs.size()-1; i>=0; i--) {
8069 ProcessRecord proc = procs.get(i);
8070 proc.lastPss = 0;
8071 proc.requestPss();
8072 }
8073 Process.setThreadPriority(oldPri);
8074 }
8075
8076 void removeRequestedPss(ProcessRecord proc) {
8077 Runnable callback = null;
8078 synchronized (this) {
8079 if (mRequestPssList.remove(proc)) {
8080 if (mRequestPssList.size() == 0) {
8081 callback = mRequestPssCallback;
8082 mRequestPssCallback = null;
8083 }
8084 }
8085 }
8086
8087 if (callback != null) {
8088 callback.run();
8089 }
8090 }
8091
8092 public void collectPss(Watchdog.PssStats stats) {
8093 stats.mEmptyPss = 0;
8094 stats.mEmptyCount = 0;
8095 stats.mBackgroundPss = 0;
8096 stats.mBackgroundCount = 0;
8097 stats.mServicePss = 0;
8098 stats.mServiceCount = 0;
8099 stats.mVisiblePss = 0;
8100 stats.mVisibleCount = 0;
8101 stats.mForegroundPss = 0;
8102 stats.mForegroundCount = 0;
8103 stats.mNoPssCount = 0;
8104 synchronized (this) {
8105 int i;
8106 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8107 ? mProcDeaths.length : stats.mProcDeaths.length;
8108 int aggr = 0;
8109 for (i=0; i<NPD; i++) {
8110 aggr += mProcDeaths[i];
8111 stats.mProcDeaths[i] = aggr;
8112 }
8113 while (i<stats.mProcDeaths.length) {
8114 stats.mProcDeaths[i] = 0;
8115 i++;
8116 }
8117
8118 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8119 ProcessRecord proc = mLRUProcesses.get(i);
8120 if (proc.persistent) {
8121 continue;
8122 }
8123 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8124 if (proc.lastPss == 0) {
8125 stats.mNoPssCount++;
8126 continue;
8127 }
8128 if (proc.setAdj == EMPTY_APP_ADJ) {
8129 stats.mEmptyPss += proc.lastPss;
8130 stats.mEmptyCount++;
8131 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8132 stats.mEmptyPss += proc.lastPss;
8133 stats.mEmptyCount++;
8134 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8135 stats.mBackgroundPss += proc.lastPss;
8136 stats.mBackgroundCount++;
8137 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8138 stats.mVisiblePss += proc.lastPss;
8139 stats.mVisibleCount++;
8140 } else {
8141 stats.mForegroundPss += proc.lastPss;
8142 stats.mForegroundCount++;
8143 }
8144 }
8145 }
8146 }
8147
8148 public final void startRunning(String pkg, String cls, String action,
8149 String data) {
8150 synchronized(this) {
8151 if (mStartRunning) {
8152 return;
8153 }
8154 mStartRunning = true;
8155 mTopComponent = pkg != null && cls != null
8156 ? new ComponentName(pkg, cls) : null;
8157 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8158 mTopData = data;
8159 if (!mSystemReady) {
8160 return;
8161 }
8162 }
8163
8164 systemReady();
8165 }
8166
8167 private void retrieveSettings() {
8168 final ContentResolver resolver = mContext.getContentResolver();
8169 String debugApp = Settings.System.getString(
8170 resolver, Settings.System.DEBUG_APP);
8171 boolean waitForDebugger = Settings.System.getInt(
8172 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8173 boolean alwaysFinishActivities = Settings.System.getInt(
8174 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8175
8176 Configuration configuration = new Configuration();
8177 Settings.System.getConfiguration(resolver, configuration);
8178
8179 synchronized (this) {
8180 mDebugApp = mOrigDebugApp = debugApp;
8181 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8182 mAlwaysFinishActivities = alwaysFinishActivities;
8183 // This happens before any activities are started, so we can
8184 // change mConfiguration in-place.
8185 mConfiguration.updateFrom(configuration);
8186 }
8187 }
8188
8189 public boolean testIsSystemReady() {
8190 // no need to synchronize(this) just to read & return the value
8191 return mSystemReady;
8192 }
8193
8194 public void systemReady() {
8195 // In the simulator, startRunning will never have been called, which
8196 // normally sets a few crucial variables. Do it here instead.
8197 if (!Process.supportsProcesses()) {
8198 mStartRunning = true;
8199 mTopAction = Intent.ACTION_MAIN;
8200 }
8201
8202 synchronized(this) {
8203 if (mSystemReady) {
8204 return;
8205 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008206
8207 // Check to see if there are any update receivers to run.
8208 if (!mDidUpdate) {
8209 if (mWaitingUpdate) {
8210 return;
8211 }
8212 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8213 List<ResolveInfo> ris = null;
8214 try {
8215 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8216 intent, null, 0);
8217 } catch (RemoteException e) {
8218 }
8219 if (ris != null) {
8220 for (int i=ris.size()-1; i>=0; i--) {
8221 if ((ris.get(i).activityInfo.applicationInfo.flags
8222 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8223 ris.remove(i);
8224 }
8225 }
8226 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8227 for (int i=0; i<ris.size(); i++) {
8228 ActivityInfo ai = ris.get(i).activityInfo;
8229 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8230 IIntentReceiver finisher = null;
8231 if (i == 0) {
8232 finisher = new IIntentReceiver.Stub() {
8233 public void performReceive(Intent intent, int resultCode,
8234 String data, Bundle extras, boolean ordered)
8235 throws RemoteException {
8236 synchronized (ActivityManagerService.this) {
8237 mDidUpdate = true;
8238 }
8239 systemReady();
8240 }
8241 };
8242 }
8243 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8244 broadcastIntentLocked(null, null, intent, null, finisher,
8245 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8246 if (i == 0) {
8247 mWaitingUpdate = true;
8248 }
8249 }
8250 }
8251 if (mWaitingUpdate) {
8252 return;
8253 }
8254 mDidUpdate = true;
8255 }
8256
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008257 mSystemReady = true;
8258 if (!mStartRunning) {
8259 return;
8260 }
8261 }
8262
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008263 ArrayList<ProcessRecord> procsToKill = null;
8264 synchronized(mPidsSelfLocked) {
8265 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8266 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8267 if (!isAllowedWhileBooting(proc.info)){
8268 if (procsToKill == null) {
8269 procsToKill = new ArrayList<ProcessRecord>();
8270 }
8271 procsToKill.add(proc);
8272 }
8273 }
8274 }
8275
8276 if (procsToKill != null) {
8277 synchronized(this) {
8278 for (int i=procsToKill.size()-1; i>=0; i--) {
8279 ProcessRecord proc = procsToKill.get(i);
8280 Log.i(TAG, "Removing system update proc: " + proc);
8281 removeProcessLocked(proc, true);
8282 }
8283 }
8284 }
8285
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008286 if (Config.LOGD) Log.d(TAG, "Start running!");
8287 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8288 SystemClock.uptimeMillis());
8289
8290 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008291 // Make sure we have no pre-ready processes sitting around.
8292
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008293 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8294 ResolveInfo ri = mContext.getPackageManager()
8295 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008296 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008297 CharSequence errorMsg = null;
8298 if (ri != null) {
8299 ActivityInfo ai = ri.activityInfo;
8300 ApplicationInfo app = ai.applicationInfo;
8301 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8302 mTopAction = Intent.ACTION_FACTORY_TEST;
8303 mTopData = null;
8304 mTopComponent = new ComponentName(app.packageName,
8305 ai.name);
8306 } else {
8307 errorMsg = mContext.getResources().getText(
8308 com.android.internal.R.string.factorytest_not_system);
8309 }
8310 } else {
8311 errorMsg = mContext.getResources().getText(
8312 com.android.internal.R.string.factorytest_no_action);
8313 }
8314 if (errorMsg != null) {
8315 mTopAction = null;
8316 mTopData = null;
8317 mTopComponent = null;
8318 Message msg = Message.obtain();
8319 msg.what = SHOW_FACTORY_ERROR_MSG;
8320 msg.getData().putCharSequence("msg", errorMsg);
8321 mHandler.sendMessage(msg);
8322 }
8323 }
8324 }
8325
8326 retrieveSettings();
8327
8328 synchronized (this) {
8329 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8330 try {
8331 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008332 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008333 if (apps != null) {
8334 int N = apps.size();
8335 int i;
8336 for (i=0; i<N; i++) {
8337 ApplicationInfo info
8338 = (ApplicationInfo)apps.get(i);
8339 if (info != null &&
8340 !info.packageName.equals("android")) {
8341 addAppLocked(info);
8342 }
8343 }
8344 }
8345 } catch (RemoteException ex) {
8346 // pm is in same process, this will never happen.
8347 }
8348 }
8349
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008350 // Start up initial activity.
8351 mBooting = true;
8352
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008353 try {
8354 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8355 Message msg = Message.obtain();
8356 msg.what = SHOW_UID_ERROR_MSG;
8357 mHandler.sendMessage(msg);
8358 }
8359 } catch (RemoteException e) {
8360 }
8361
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008362 resumeTopActivityLocked(null);
8363 }
8364 }
8365
8366 boolean makeAppCrashingLocked(ProcessRecord app,
8367 String tag, String shortMsg, String longMsg, byte[] crashData) {
8368 app.crashing = true;
8369 app.crashingReport = generateProcessError(app,
8370 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8371 startAppProblemLocked(app);
8372 app.stopFreezingAllLocked();
8373 return handleAppCrashLocked(app);
8374 }
8375
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008376 private ComponentName getErrorReportReceiver(ProcessRecord app) {
8377 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008378
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008379 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008380 // look for receiver in the installer package
8381 String candidate = pm.getInstallerPackageName(app.info.packageName);
8382 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8383 if (result != null) {
8384 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008385 }
8386
Jacek Surazski82a73df2009-06-17 14:33:18 +02008387 // if the error app is on the system image, look for system apps
8388 // error receiver
8389 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8390 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8391 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8392 if (result != null) {
8393 return result;
8394 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008395 }
8396
Jacek Surazski82a73df2009-06-17 14:33:18 +02008397 // if there is a default receiver, try that
8398 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8399 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008400 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008401 // should not happen
8402 Log.e(TAG, "error talking to PackageManager", e);
8403 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008404 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008405 }
8406
8407 /**
8408 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8409 *
8410 * @param pm PackageManager isntance
8411 * @param errorPackage package which caused the error
8412 * @param receiverPackage candidate package to receive the error
8413 * @return activity component within receiverPackage which handles
8414 * ACTION_APP_ERROR, or null if not found
8415 */
8416 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8417 String receiverPackage) throws RemoteException {
8418 if (receiverPackage == null || receiverPackage.length() == 0) {
8419 return null;
8420 }
8421
8422 // break the loop if it's the error report receiver package that crashed
8423 if (receiverPackage.equals(errorPackage)) {
8424 return null;
8425 }
8426
8427 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8428 intent.setPackage(receiverPackage);
8429 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8430 if (info == null || info.activityInfo == null) {
8431 return null;
8432 }
8433 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008434 }
8435
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008436 void makeAppNotRespondingLocked(ProcessRecord app,
8437 String tag, String shortMsg, String longMsg, byte[] crashData) {
8438 app.notResponding = true;
8439 app.notRespondingReport = generateProcessError(app,
8440 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8441 crashData);
8442 startAppProblemLocked(app);
8443 app.stopFreezingAllLocked();
8444 }
8445
8446 /**
8447 * Generate a process error record, suitable for attachment to a ProcessRecord.
8448 *
8449 * @param app The ProcessRecord in which the error occurred.
8450 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8451 * ActivityManager.AppErrorStateInfo
8452 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8453 * @param shortMsg Short message describing the crash.
8454 * @param longMsg Long message describing the crash.
8455 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8456 *
8457 * @return Returns a fully-formed AppErrorStateInfo record.
8458 */
8459 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8460 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8461 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8462
8463 report.condition = condition;
8464 report.processName = app.processName;
8465 report.pid = app.pid;
8466 report.uid = app.info.uid;
8467 report.tag = tag;
8468 report.shortMsg = shortMsg;
8469 report.longMsg = longMsg;
8470 report.crashData = crashData;
8471
8472 return report;
8473 }
8474
8475 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8476 boolean crashed) {
8477 synchronized (this) {
8478 app.crashing = false;
8479 app.crashingReport = null;
8480 app.notResponding = false;
8481 app.notRespondingReport = null;
8482 if (app.anrDialog == fromDialog) {
8483 app.anrDialog = null;
8484 }
8485 if (app.waitDialog == fromDialog) {
8486 app.waitDialog = null;
8487 }
8488 if (app.pid > 0 && app.pid != MY_PID) {
8489 if (crashed) {
8490 handleAppCrashLocked(app);
8491 }
8492 Log.i(ActivityManagerService.TAG, "Killing process "
8493 + app.processName
8494 + " (pid=" + app.pid + ") at user's request");
8495 Process.killProcess(app.pid);
8496 }
8497
8498 }
8499 }
8500
8501 boolean handleAppCrashLocked(ProcessRecord app) {
8502 long now = SystemClock.uptimeMillis();
8503
8504 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8505 app.info.uid);
8506 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8507 // This process loses!
8508 Log.w(TAG, "Process " + app.info.processName
8509 + " has crashed too many times: killing!");
8510 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8511 app.info.processName, app.info.uid);
8512 killServicesLocked(app, false);
8513 for (int i=mHistory.size()-1; i>=0; i--) {
8514 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8515 if (r.app == app) {
8516 if (Config.LOGD) Log.d(
8517 TAG, " Force finishing activity "
8518 + r.intent.getComponent().flattenToShortString());
8519 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8520 }
8521 }
8522 if (!app.persistent) {
8523 // We don't want to start this process again until the user
8524 // explicitly does so... but for persistent process, we really
8525 // need to keep it running. If a persistent process is actually
8526 // repeatedly crashing, then badness for everyone.
8527 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8528 app.info.processName);
8529 mBadProcesses.put(app.info.processName, app.info.uid, now);
8530 app.bad = true;
8531 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8532 app.removed = true;
8533 removeProcessLocked(app, false);
8534 return false;
8535 }
8536 }
8537
8538 // Bump up the crash count of any services currently running in the proc.
8539 if (app.services.size() != 0) {
8540 // Any services running in the application need to be placed
8541 // back in the pending list.
8542 Iterator it = app.services.iterator();
8543 while (it.hasNext()) {
8544 ServiceRecord sr = (ServiceRecord)it.next();
8545 sr.crashCount++;
8546 }
8547 }
8548
8549 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8550 return true;
8551 }
8552
8553 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008554 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008555 skipCurrentReceiverLocked(app);
8556 }
8557
8558 void skipCurrentReceiverLocked(ProcessRecord app) {
8559 boolean reschedule = false;
8560 BroadcastRecord r = app.curReceiver;
8561 if (r != null) {
8562 // The current broadcast is waiting for this app's receiver
8563 // to be finished. Looks like that's not going to happen, so
8564 // let the broadcast continue.
8565 logBroadcastReceiverDiscard(r);
8566 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8567 r.resultExtras, r.resultAbort, true);
8568 reschedule = true;
8569 }
8570 r = mPendingBroadcast;
8571 if (r != null && r.curApp == app) {
8572 if (DEBUG_BROADCAST) Log.v(TAG,
8573 "skip & discard pending app " + r);
8574 logBroadcastReceiverDiscard(r);
8575 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8576 r.resultExtras, r.resultAbort, true);
8577 reschedule = true;
8578 }
8579 if (reschedule) {
8580 scheduleBroadcastsLocked();
8581 }
8582 }
8583
8584 public int handleApplicationError(IBinder app, int flags,
8585 String tag, String shortMsg, String longMsg, byte[] crashData) {
8586 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008587 ProcessRecord r = null;
8588 synchronized (this) {
8589 if (app != null) {
8590 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8591 final int NA = apps.size();
8592 for (int ia=0; ia<NA; ia++) {
8593 ProcessRecord p = apps.valueAt(ia);
8594 if (p.thread != null && p.thread.asBinder() == app) {
8595 r = p;
8596 break;
8597 }
8598 }
8599 }
8600 }
8601
8602 if (r != null) {
8603 // The application has crashed. Send the SIGQUIT to the process so
8604 // that it can dump its state.
8605 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8606 //Log.i(TAG, "Current system threads:");
8607 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8608 }
8609
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008610 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008611 try {
8612 String name = r != null ? r.processName : null;
8613 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008614 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008615 shortMsg, longMsg, crashData)) {
8616 Log.w(TAG, "Force-killing crashed app " + name
8617 + " at watcher's request");
8618 Process.killProcess(pid);
8619 return 0;
8620 }
8621 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008622 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008623 }
8624 }
8625
8626 final long origId = Binder.clearCallingIdentity();
8627
8628 // If this process is running instrumentation, finish it.
8629 if (r != null && r.instrumentationClass != null) {
8630 Log.w(TAG, "Error in app " + r.processName
8631 + " running instrumentation " + r.instrumentationClass + ":");
8632 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8633 if (longMsg != null) Log.w(TAG, " " + longMsg);
8634 Bundle info = new Bundle();
8635 info.putString("shortMsg", shortMsg);
8636 info.putString("longMsg", longMsg);
8637 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8638 Binder.restoreCallingIdentity(origId);
8639 return 0;
8640 }
8641
8642 if (r != null) {
8643 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8644 return 0;
8645 }
8646 } else {
8647 Log.w(TAG, "Some application object " + app + " tag " + tag
8648 + " has crashed, but I don't know who it is.");
8649 Log.w(TAG, "ShortMsg:" + shortMsg);
8650 Log.w(TAG, "LongMsg:" + longMsg);
8651 Binder.restoreCallingIdentity(origId);
8652 return 0;
8653 }
8654
8655 Message msg = Message.obtain();
8656 msg.what = SHOW_ERROR_MSG;
8657 HashMap data = new HashMap();
8658 data.put("result", result);
8659 data.put("app", r);
8660 data.put("flags", flags);
8661 data.put("shortMsg", shortMsg);
8662 data.put("longMsg", longMsg);
8663 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8664 // For system processes, submit crash data to the server.
8665 data.put("crashData", crashData);
8666 }
8667 msg.obj = data;
8668 mHandler.sendMessage(msg);
8669
8670 Binder.restoreCallingIdentity(origId);
8671 }
8672
8673 int res = result.get();
8674
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008675 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008676 synchronized (this) {
8677 if (r != null) {
8678 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8679 SystemClock.uptimeMillis());
8680 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008681 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8682 appErrorIntent = createAppErrorIntentLocked(r);
8683 res = AppErrorDialog.FORCE_QUIT;
8684 }
8685 }
8686
8687 if (appErrorIntent != null) {
8688 try {
8689 mContext.startActivity(appErrorIntent);
8690 } catch (ActivityNotFoundException e) {
8691 Log.w(TAG, "bug report receiver dissappeared", e);
8692 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008693 }
8694
8695 return res;
8696 }
8697
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008698 Intent createAppErrorIntentLocked(ProcessRecord r) {
8699 ApplicationErrorReport report = createAppErrorReportLocked(r);
8700 if (report == null) {
8701 return null;
8702 }
8703 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8704 result.setComponent(r.errorReportReceiver);
8705 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8706 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8707 return result;
8708 }
8709
8710 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8711 if (r.errorReportReceiver == null) {
8712 return null;
8713 }
8714
8715 if (!r.crashing && !r.notResponding) {
8716 return null;
8717 }
8718
8719 try {
8720 ApplicationErrorReport report = new ApplicationErrorReport();
8721 report.packageName = r.info.packageName;
8722 report.installerPackageName = r.errorReportReceiver.getPackageName();
8723 report.processName = r.processName;
8724
8725 if (r.crashing) {
8726 report.type = ApplicationErrorReport.TYPE_CRASH;
8727 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8728
8729 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8730 r.crashingReport.crashData);
8731 DataInputStream dataStream = new DataInputStream(byteStream);
8732 CrashData crashData = new CrashData(dataStream);
8733 ThrowableData throwData = crashData.getThrowableData();
8734
8735 report.time = crashData.getTime();
8736 report.crashInfo.stackTrace = throwData.toString();
8737
Jacek Surazskif829a782009-06-11 22:47:02 +02008738 // Extract the source of the exception, useful for report
8739 // clustering. Also extract the "deepest" non-null exception
8740 // message.
8741 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008742 while (throwData.getCause() != null) {
8743 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008744 String msg = throwData.getMessage();
8745 if (msg != null && msg.length() > 0) {
8746 exceptionMessage = msg;
8747 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008748 }
8749 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008750 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008751 report.crashInfo.exceptionClassName = throwData.getType();
8752 report.crashInfo.throwFileName = trace.getFileName();
8753 report.crashInfo.throwClassName = trace.getClassName();
8754 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008755 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008756 } else if (r.notResponding) {
8757 report.type = ApplicationErrorReport.TYPE_ANR;
8758 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8759
8760 report.anrInfo.activity = r.notRespondingReport.tag;
8761 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8762 report.anrInfo.info = r.notRespondingReport.longMsg;
8763 }
8764
8765 return report;
8766 } catch (IOException e) {
8767 // we don't send it
8768 }
8769
8770 return null;
8771 }
8772
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008773 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8774 // assume our apps are happy - lazy create the list
8775 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8776
8777 synchronized (this) {
8778
8779 // iterate across all processes
8780 final int N = mLRUProcesses.size();
8781 for (int i = 0; i < N; i++) {
8782 ProcessRecord app = mLRUProcesses.get(i);
8783 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8784 // This one's in trouble, so we'll generate a report for it
8785 // crashes are higher priority (in case there's a crash *and* an anr)
8786 ActivityManager.ProcessErrorStateInfo report = null;
8787 if (app.crashing) {
8788 report = app.crashingReport;
8789 } else if (app.notResponding) {
8790 report = app.notRespondingReport;
8791 }
8792
8793 if (report != null) {
8794 if (errList == null) {
8795 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8796 }
8797 errList.add(report);
8798 } else {
8799 Log.w(TAG, "Missing app error report, app = " + app.processName +
8800 " crashing = " + app.crashing +
8801 " notResponding = " + app.notResponding);
8802 }
8803 }
8804 }
8805 }
8806
8807 return errList;
8808 }
8809
8810 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8811 // Lazy instantiation of list
8812 List<ActivityManager.RunningAppProcessInfo> runList = null;
8813 synchronized (this) {
8814 // Iterate across all processes
8815 final int N = mLRUProcesses.size();
8816 for (int i = 0; i < N; i++) {
8817 ProcessRecord app = mLRUProcesses.get(i);
8818 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8819 // Generate process state info for running application
8820 ActivityManager.RunningAppProcessInfo currApp =
8821 new ActivityManager.RunningAppProcessInfo(app.processName,
8822 app.pid, app.getPackageList());
8823 int adj = app.curAdj;
8824 if (adj >= CONTENT_PROVIDER_ADJ) {
8825 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8826 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8827 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008828 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8829 } else if (adj >= HOME_APP_ADJ) {
8830 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8831 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008832 } else if (adj >= SECONDARY_SERVER_ADJ) {
8833 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8834 } else if (adj >= VISIBLE_APP_ADJ) {
8835 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8836 } else {
8837 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8838 }
8839 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8840 // + " lru=" + currApp.lru);
8841 if (runList == null) {
8842 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8843 }
8844 runList.add(currApp);
8845 }
8846 }
8847 }
8848 return runList;
8849 }
8850
8851 @Override
8852 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8853 synchronized (this) {
8854 if (checkCallingPermission(android.Manifest.permission.DUMP)
8855 != PackageManager.PERMISSION_GRANTED) {
8856 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8857 + Binder.getCallingPid()
8858 + ", uid=" + Binder.getCallingUid()
8859 + " without permission "
8860 + android.Manifest.permission.DUMP);
8861 return;
8862 }
8863 if (args.length != 0 && "service".equals(args[0])) {
8864 dumpService(fd, pw, args);
8865 return;
8866 }
8867 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008868 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008869 pw.println(" ");
8870 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008871 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008872 if (mWaitingVisibleActivities.size() > 0) {
8873 pw.println(" ");
8874 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008875 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008876 }
8877 if (mStoppingActivities.size() > 0) {
8878 pw.println(" ");
8879 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008880 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008881 }
8882 if (mFinishingActivities.size() > 0) {
8883 pw.println(" ");
8884 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008885 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008886 }
8887
8888 pw.println(" ");
8889 pw.println(" mPausingActivity: " + mPausingActivity);
8890 pw.println(" mResumedActivity: " + mResumedActivity);
8891 pw.println(" mFocusedActivity: " + mFocusedActivity);
8892 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8893
8894 if (mRecentTasks.size() > 0) {
8895 pw.println(" ");
8896 pw.println("Recent tasks in Current Activity Manager State:");
8897
8898 final int N = mRecentTasks.size();
8899 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008900 TaskRecord tr = mRecentTasks.get(i);
8901 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8902 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008903 mRecentTasks.get(i).dump(pw, " ");
8904 }
8905 }
8906
8907 pw.println(" ");
8908 pw.println(" mCurTask: " + mCurTask);
8909
8910 pw.println(" ");
8911 pw.println("Processes in Current Activity Manager State:");
8912
8913 boolean needSep = false;
8914 int numPers = 0;
8915
8916 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8917 final int NA = procs.size();
8918 for (int ia=0; ia<NA; ia++) {
8919 if (!needSep) {
8920 pw.println(" All known processes:");
8921 needSep = true;
8922 }
8923 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008924 pw.print(r.persistent ? " *PERS*" : " *APP*");
8925 pw.print(" UID "); pw.print(procs.keyAt(ia));
8926 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008927 r.dump(pw, " ");
8928 if (r.persistent) {
8929 numPers++;
8930 }
8931 }
8932 }
8933
8934 if (mLRUProcesses.size() > 0) {
8935 if (needSep) pw.println(" ");
8936 needSep = true;
8937 pw.println(" Running processes (most recent first):");
8938 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008939 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008940 needSep = true;
8941 }
8942
8943 synchronized (mPidsSelfLocked) {
8944 if (mPidsSelfLocked.size() > 0) {
8945 if (needSep) pw.println(" ");
8946 needSep = true;
8947 pw.println(" PID mappings:");
8948 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008949 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8950 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008951 }
8952 }
8953 }
8954
8955 if (mForegroundProcesses.size() > 0) {
8956 if (needSep) pw.println(" ");
8957 needSep = true;
8958 pw.println(" Foreground Processes:");
8959 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008960 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8961 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008962 }
8963 }
8964
8965 if (mPersistentStartingProcesses.size() > 0) {
8966 if (needSep) pw.println(" ");
8967 needSep = true;
8968 pw.println(" Persisent processes that are starting:");
8969 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008970 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008971 }
8972
8973 if (mStartingProcesses.size() > 0) {
8974 if (needSep) pw.println(" ");
8975 needSep = true;
8976 pw.println(" Processes that are starting:");
8977 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008978 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008979 }
8980
8981 if (mRemovedProcesses.size() > 0) {
8982 if (needSep) pw.println(" ");
8983 needSep = true;
8984 pw.println(" Processes that are being removed:");
8985 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008986 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008987 }
8988
8989 if (mProcessesOnHold.size() > 0) {
8990 if (needSep) pw.println(" ");
8991 needSep = true;
8992 pw.println(" Processes that are on old until the system is ready:");
8993 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008994 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008995 }
8996
Dianne Hackbornfd12af42009-08-27 00:44:33 -07008997 if (mProcessesToGc.size() > 0) {
8998 if (needSep) pw.println(" ");
8999 needSep = true;
9000 pw.println(" Processes that are waiting to GC:");
9001 long now = SystemClock.uptimeMillis();
9002 for (int i=0; i<mProcessesToGc.size(); i++) {
9003 ProcessRecord proc = mProcessesToGc.get(i);
9004 pw.print(" Process "); pw.println(proc);
9005 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9006 pw.print(", last gced=");
9007 pw.print(now-proc.lastRequestedGc);
9008 pw.print(" ms ago, last lowMwm=");
9009 pw.print(now-proc.lastLowMemory);
9010 pw.println(" ms ago");
9011
9012 }
9013 }
9014
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009015 if (mProcessCrashTimes.getMap().size() > 0) {
9016 if (needSep) pw.println(" ");
9017 needSep = true;
9018 pw.println(" Time since processes crashed:");
9019 long now = SystemClock.uptimeMillis();
9020 for (Map.Entry<String, SparseArray<Long>> procs
9021 : mProcessCrashTimes.getMap().entrySet()) {
9022 SparseArray<Long> uids = procs.getValue();
9023 final int N = uids.size();
9024 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009025 pw.print(" Process "); pw.print(procs.getKey());
9026 pw.print(" uid "); pw.print(uids.keyAt(i));
9027 pw.print(": last crashed ");
9028 pw.print((now-uids.valueAt(i)));
9029 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009030 }
9031 }
9032 }
9033
9034 if (mBadProcesses.getMap().size() > 0) {
9035 if (needSep) pw.println(" ");
9036 needSep = true;
9037 pw.println(" Bad processes:");
9038 for (Map.Entry<String, SparseArray<Long>> procs
9039 : mBadProcesses.getMap().entrySet()) {
9040 SparseArray<Long> uids = procs.getValue();
9041 final int N = uids.size();
9042 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009043 pw.print(" Bad process "); pw.print(procs.getKey());
9044 pw.print(" uid "); pw.print(uids.keyAt(i));
9045 pw.print(": crashed at time ");
9046 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009047 }
9048 }
9049 }
9050
9051 pw.println(" ");
9052 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009053 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009054 pw.println(" mConfiguration: " + mConfiguration);
9055 pw.println(" mStartRunning=" + mStartRunning
9056 + " mSystemReady=" + mSystemReady
9057 + " mBooting=" + mBooting
9058 + " mBooted=" + mBooted
9059 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009060 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009061 pw.println(" mGoingToSleep=" + mGoingToSleep);
9062 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9063 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9064 + " mDebugTransient=" + mDebugTransient
9065 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9066 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009067 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009068 }
9069 }
9070
9071 /**
9072 * There are three ways to call this:
9073 * - no service specified: dump all the services
9074 * - a flattened component name that matched an existing service was specified as the
9075 * first arg: dump that one service
9076 * - the first arg isn't the flattened component name of an existing service:
9077 * dump all services whose component contains the first arg as a substring
9078 */
9079 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9080 String[] newArgs;
9081 String componentNameString;
9082 ServiceRecord r;
9083 if (args.length == 1) {
9084 componentNameString = null;
9085 newArgs = EMPTY_STRING_ARRAY;
9086 r = null;
9087 } else {
9088 componentNameString = args[1];
9089 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9090 r = componentName != null ? mServices.get(componentName) : null;
9091 newArgs = new String[args.length - 2];
9092 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9093 }
9094
9095 if (r != null) {
9096 dumpService(fd, pw, r, newArgs);
9097 } else {
9098 for (ServiceRecord r1 : mServices.values()) {
9099 if (componentNameString == null
9100 || r1.name.flattenToString().contains(componentNameString)) {
9101 dumpService(fd, pw, r1, newArgs);
9102 }
9103 }
9104 }
9105 }
9106
9107 /**
9108 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9109 * there is a thread associated with the service.
9110 */
9111 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9112 pw.println(" Service " + r.name.flattenToString());
9113 if (r.app != null && r.app.thread != null) {
9114 try {
9115 // flush anything that is already in the PrintWriter since the thread is going
9116 // to write to the file descriptor directly
9117 pw.flush();
9118 r.app.thread.dumpService(fd, r, args);
9119 pw.print("\n");
9120 } catch (RemoteException e) {
9121 pw.println("got a RemoteException while dumping the service");
9122 }
9123 }
9124 }
9125
9126 void dumpBroadcasts(PrintWriter pw) {
9127 synchronized (this) {
9128 if (checkCallingPermission(android.Manifest.permission.DUMP)
9129 != PackageManager.PERMISSION_GRANTED) {
9130 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9131 + Binder.getCallingPid()
9132 + ", uid=" + Binder.getCallingUid()
9133 + " without permission "
9134 + android.Manifest.permission.DUMP);
9135 return;
9136 }
9137 pw.println("Broadcasts in Current Activity Manager State:");
9138
9139 if (mRegisteredReceivers.size() > 0) {
9140 pw.println(" ");
9141 pw.println(" Registered Receivers:");
9142 Iterator it = mRegisteredReceivers.values().iterator();
9143 while (it.hasNext()) {
9144 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009145 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009146 r.dump(pw, " ");
9147 }
9148 }
9149
9150 pw.println(" ");
9151 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009152 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009153
9154 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9155 || mPendingBroadcast != null) {
9156 if (mParallelBroadcasts.size() > 0) {
9157 pw.println(" ");
9158 pw.println(" Active broadcasts:");
9159 }
9160 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9161 pw.println(" Broadcast #" + i + ":");
9162 mParallelBroadcasts.get(i).dump(pw, " ");
9163 }
9164 if (mOrderedBroadcasts.size() > 0) {
9165 pw.println(" ");
9166 pw.println(" Active serialized broadcasts:");
9167 }
9168 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9169 pw.println(" Serialized Broadcast #" + i + ":");
9170 mOrderedBroadcasts.get(i).dump(pw, " ");
9171 }
9172 pw.println(" ");
9173 pw.println(" Pending broadcast:");
9174 if (mPendingBroadcast != null) {
9175 mPendingBroadcast.dump(pw, " ");
9176 } else {
9177 pw.println(" (null)");
9178 }
9179 }
9180
9181 pw.println(" ");
9182 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9183 if (mStickyBroadcasts != null) {
9184 pw.println(" ");
9185 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009186 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009187 for (Map.Entry<String, ArrayList<Intent>> ent
9188 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009189 pw.print(" * Sticky action "); pw.print(ent.getKey());
9190 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009191 ArrayList<Intent> intents = ent.getValue();
9192 final int N = intents.size();
9193 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009194 sb.setLength(0);
9195 sb.append(" Intent: ");
9196 intents.get(i).toShortString(sb, true, false);
9197 pw.println(sb.toString());
9198 Bundle bundle = intents.get(i).getExtras();
9199 if (bundle != null) {
9200 pw.print(" ");
9201 pw.println(bundle.toString());
9202 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009203 }
9204 }
9205 }
9206
9207 pw.println(" ");
9208 pw.println(" mHandler:");
9209 mHandler.dump(new PrintWriterPrinter(pw), " ");
9210 }
9211 }
9212
9213 void dumpServices(PrintWriter pw) {
9214 synchronized (this) {
9215 if (checkCallingPermission(android.Manifest.permission.DUMP)
9216 != PackageManager.PERMISSION_GRANTED) {
9217 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9218 + Binder.getCallingPid()
9219 + ", uid=" + Binder.getCallingUid()
9220 + " without permission "
9221 + android.Manifest.permission.DUMP);
9222 return;
9223 }
9224 pw.println("Services in Current Activity Manager State:");
9225
9226 boolean needSep = false;
9227
9228 if (mServices.size() > 0) {
9229 pw.println(" Active services:");
9230 Iterator<ServiceRecord> it = mServices.values().iterator();
9231 while (it.hasNext()) {
9232 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009233 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009234 r.dump(pw, " ");
9235 }
9236 needSep = true;
9237 }
9238
9239 if (mPendingServices.size() > 0) {
9240 if (needSep) pw.println(" ");
9241 pw.println(" Pending services:");
9242 for (int i=0; i<mPendingServices.size(); i++) {
9243 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009244 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009245 r.dump(pw, " ");
9246 }
9247 needSep = true;
9248 }
9249
9250 if (mRestartingServices.size() > 0) {
9251 if (needSep) pw.println(" ");
9252 pw.println(" Restarting services:");
9253 for (int i=0; i<mRestartingServices.size(); i++) {
9254 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009255 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009256 r.dump(pw, " ");
9257 }
9258 needSep = true;
9259 }
9260
9261 if (mStoppingServices.size() > 0) {
9262 if (needSep) pw.println(" ");
9263 pw.println(" Stopping services:");
9264 for (int i=0; i<mStoppingServices.size(); i++) {
9265 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009266 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009267 r.dump(pw, " ");
9268 }
9269 needSep = true;
9270 }
9271
9272 if (mServiceConnections.size() > 0) {
9273 if (needSep) pw.println(" ");
9274 pw.println(" Connection bindings to services:");
9275 Iterator<ConnectionRecord> it
9276 = mServiceConnections.values().iterator();
9277 while (it.hasNext()) {
9278 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009279 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009280 r.dump(pw, " ");
9281 }
9282 }
9283 }
9284 }
9285
9286 void dumpProviders(PrintWriter pw) {
9287 synchronized (this) {
9288 if (checkCallingPermission(android.Manifest.permission.DUMP)
9289 != PackageManager.PERMISSION_GRANTED) {
9290 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9291 + Binder.getCallingPid()
9292 + ", uid=" + Binder.getCallingUid()
9293 + " without permission "
9294 + android.Manifest.permission.DUMP);
9295 return;
9296 }
9297
9298 pw.println("Content Providers in Current Activity Manager State:");
9299
9300 boolean needSep = false;
9301
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009302 if (mProvidersByClass.size() > 0) {
9303 if (needSep) pw.println(" ");
9304 pw.println(" Published content providers (by class):");
9305 Iterator it = mProvidersByClass.entrySet().iterator();
9306 while (it.hasNext()) {
9307 Map.Entry e = (Map.Entry)it.next();
9308 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009309 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009310 r.dump(pw, " ");
9311 }
9312 needSep = true;
9313 }
9314
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009315 if (mProvidersByName.size() > 0) {
9316 pw.println(" ");
9317 pw.println(" Authority to provider mappings:");
9318 Iterator it = mProvidersByName.entrySet().iterator();
9319 while (it.hasNext()) {
9320 Map.Entry e = (Map.Entry)it.next();
9321 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9322 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9323 pw.println(r);
9324 }
9325 needSep = true;
9326 }
9327
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009328 if (mLaunchingProviders.size() > 0) {
9329 if (needSep) pw.println(" ");
9330 pw.println(" Launching content providers:");
9331 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009332 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9333 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009334 }
9335 needSep = true;
9336 }
9337
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009338 if (mGrantedUriPermissions.size() > 0) {
9339 pw.println();
9340 pw.println("Granted Uri Permissions:");
9341 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9342 int uid = mGrantedUriPermissions.keyAt(i);
9343 HashMap<Uri, UriPermission> perms
9344 = mGrantedUriPermissions.valueAt(i);
9345 pw.print(" * UID "); pw.print(uid);
9346 pw.println(" holds:");
9347 for (UriPermission perm : perms.values()) {
9348 pw.print(" "); pw.println(perm);
9349 perm.dump(pw, " ");
9350 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009351 }
9352 }
9353 }
9354 }
9355
9356 void dumpSenders(PrintWriter pw) {
9357 synchronized (this) {
9358 if (checkCallingPermission(android.Manifest.permission.DUMP)
9359 != PackageManager.PERMISSION_GRANTED) {
9360 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9361 + Binder.getCallingPid()
9362 + ", uid=" + Binder.getCallingUid()
9363 + " without permission "
9364 + android.Manifest.permission.DUMP);
9365 return;
9366 }
9367
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009368 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009369
9370 if (this.mIntentSenderRecords.size() > 0) {
9371 Iterator<WeakReference<PendingIntentRecord>> it
9372 = mIntentSenderRecords.values().iterator();
9373 while (it.hasNext()) {
9374 WeakReference<PendingIntentRecord> ref = it.next();
9375 PendingIntentRecord rec = ref != null ? ref.get(): null;
9376 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009377 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009378 rec.dump(pw, " ");
9379 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009380 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009381 }
9382 }
9383 }
9384 }
9385 }
9386
9387 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009388 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009389 TaskRecord lastTask = null;
9390 for (int i=list.size()-1; i>=0; i--) {
9391 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009392 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009393 if (lastTask != r.task) {
9394 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009395 pw.print(prefix);
9396 pw.print(full ? "* " : " ");
9397 pw.println(lastTask);
9398 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009399 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009400 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009401 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009402 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9403 pw.print(" #"); pw.print(i); pw.print(": ");
9404 pw.println(r);
9405 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009406 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009407 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009408 }
9409 }
9410
9411 private static final int dumpProcessList(PrintWriter pw, List list,
9412 String prefix, String normalLabel, String persistentLabel,
9413 boolean inclOomAdj) {
9414 int numPers = 0;
9415 for (int i=list.size()-1; i>=0; i--) {
9416 ProcessRecord r = (ProcessRecord)list.get(i);
9417 if (false) {
9418 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9419 + " #" + i + ":");
9420 r.dump(pw, prefix + " ");
9421 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009422 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009423 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009424 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9425 if (r.adjSource != null || r.adjTarget != null) {
9426 pw.println(prefix + " " + r.adjTarget
9427 + " used by " + r.adjSource);
9428 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009429 } else {
9430 pw.println(String.format("%s%s #%2d: %s",
9431 prefix, (r.persistent ? persistentLabel : normalLabel),
9432 i, r.toString()));
9433 }
9434 if (r.persistent) {
9435 numPers++;
9436 }
9437 }
9438 return numPers;
9439 }
9440
9441 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9442 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009443 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009444 long uptime = SystemClock.uptimeMillis();
9445 long realtime = SystemClock.elapsedRealtime();
9446
9447 if (isCheckinRequest) {
9448 // short checkin version
9449 pw.println(uptime + "," + realtime);
9450 pw.flush();
9451 } else {
9452 pw.println("Applications Memory Usage (kB):");
9453 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9454 }
9455 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9456 ProcessRecord r = (ProcessRecord)list.get(i);
9457 if (r.thread != null) {
9458 if (!isCheckinRequest) {
9459 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9460 pw.flush();
9461 }
9462 try {
9463 r.thread.asBinder().dump(fd, args);
9464 } catch (RemoteException e) {
9465 if (!isCheckinRequest) {
9466 pw.println("Got RemoteException!");
9467 pw.flush();
9468 }
9469 }
9470 }
9471 }
9472 }
9473
9474 /**
9475 * Searches array of arguments for the specified string
9476 * @param args array of argument strings
9477 * @param value value to search for
9478 * @return true if the value is contained in the array
9479 */
9480 private static boolean scanArgs(String[] args, String value) {
9481 if (args != null) {
9482 for (String arg : args) {
9483 if (value.equals(arg)) {
9484 return true;
9485 }
9486 }
9487 }
9488 return false;
9489 }
9490
Dianne Hackborn75b03852009-06-12 15:43:26 -07009491 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009492 int count = mHistory.size();
9493
9494 // convert the token to an entry in the history.
9495 HistoryRecord r = null;
9496 int index = -1;
9497 for (int i=count-1; i>=0; i--) {
9498 Object o = mHistory.get(i);
9499 if (o == token) {
9500 r = (HistoryRecord)o;
9501 index = i;
9502 break;
9503 }
9504 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009505
9506 return index;
9507 }
9508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009509 private final void killServicesLocked(ProcessRecord app,
9510 boolean allowRestart) {
9511 // Report disconnected services.
9512 if (false) {
9513 // XXX we are letting the client link to the service for
9514 // death notifications.
9515 if (app.services.size() > 0) {
9516 Iterator it = app.services.iterator();
9517 while (it.hasNext()) {
9518 ServiceRecord r = (ServiceRecord)it.next();
9519 if (r.connections.size() > 0) {
9520 Iterator<ConnectionRecord> jt
9521 = r.connections.values().iterator();
9522 while (jt.hasNext()) {
9523 ConnectionRecord c = jt.next();
9524 if (c.binding.client != app) {
9525 try {
9526 //c.conn.connected(r.className, null);
9527 } catch (Exception e) {
9528 // todo: this should be asynchronous!
9529 Log.w(TAG, "Exception thrown disconnected servce "
9530 + r.shortName
9531 + " from app " + app.processName, e);
9532 }
9533 }
9534 }
9535 }
9536 }
9537 }
9538 }
9539
9540 // Clean up any connections this application has to other services.
9541 if (app.connections.size() > 0) {
9542 Iterator<ConnectionRecord> it = app.connections.iterator();
9543 while (it.hasNext()) {
9544 ConnectionRecord r = it.next();
9545 removeConnectionLocked(r, app, null);
9546 }
9547 }
9548 app.connections.clear();
9549
9550 if (app.services.size() != 0) {
9551 // Any services running in the application need to be placed
9552 // back in the pending list.
9553 Iterator it = app.services.iterator();
9554 while (it.hasNext()) {
9555 ServiceRecord sr = (ServiceRecord)it.next();
9556 synchronized (sr.stats.getBatteryStats()) {
9557 sr.stats.stopLaunchedLocked();
9558 }
9559 sr.app = null;
9560 sr.executeNesting = 0;
9561 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009562
9563 boolean hasClients = sr.bindings.size() > 0;
9564 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009565 Iterator<IntentBindRecord> bindings
9566 = sr.bindings.values().iterator();
9567 while (bindings.hasNext()) {
9568 IntentBindRecord b = bindings.next();
9569 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9570 + ": shouldUnbind=" + b.hasBound);
9571 b.binder = null;
9572 b.requested = b.received = b.hasBound = false;
9573 }
9574 }
9575
9576 if (sr.crashCount >= 2) {
9577 Log.w(TAG, "Service crashed " + sr.crashCount
9578 + " times, stopping: " + sr);
9579 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9580 sr.crashCount, sr.shortName, app.pid);
9581 bringDownServiceLocked(sr, true);
9582 } else if (!allowRestart) {
9583 bringDownServiceLocked(sr, true);
9584 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009585 boolean canceled = scheduleServiceRestartLocked(sr, true);
9586
9587 // Should the service remain running? Note that in the
9588 // extreme case of so many attempts to deliver a command
9589 // that it failed, that we also will stop it here.
9590 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9591 if (sr.pendingStarts.size() == 0) {
9592 sr.startRequested = false;
9593 if (!hasClients) {
9594 // Whoops, no reason to restart!
9595 bringDownServiceLocked(sr, true);
9596 }
9597 }
9598 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009599 }
9600 }
9601
9602 if (!allowRestart) {
9603 app.services.clear();
9604 }
9605 }
9606
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009607 // Make sure we have no more records on the stopping list.
9608 int i = mStoppingServices.size();
9609 while (i > 0) {
9610 i--;
9611 ServiceRecord sr = mStoppingServices.get(i);
9612 if (sr.app == app) {
9613 mStoppingServices.remove(i);
9614 }
9615 }
9616
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009617 app.executingServices.clear();
9618 }
9619
9620 private final void removeDyingProviderLocked(ProcessRecord proc,
9621 ContentProviderRecord cpr) {
9622 synchronized (cpr) {
9623 cpr.launchingApp = null;
9624 cpr.notifyAll();
9625 }
9626
9627 mProvidersByClass.remove(cpr.info.name);
9628 String names[] = cpr.info.authority.split(";");
9629 for (int j = 0; j < names.length; j++) {
9630 mProvidersByName.remove(names[j]);
9631 }
9632
9633 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9634 while (cit.hasNext()) {
9635 ProcessRecord capp = cit.next();
9636 if (!capp.persistent && capp.thread != null
9637 && capp.pid != 0
9638 && capp.pid != MY_PID) {
9639 Log.i(TAG, "Killing app " + capp.processName
9640 + " (pid " + capp.pid
9641 + ") because provider " + cpr.info.name
9642 + " is in dying process " + proc.processName);
9643 Process.killProcess(capp.pid);
9644 }
9645 }
9646
9647 mLaunchingProviders.remove(cpr);
9648 }
9649
9650 /**
9651 * Main code for cleaning up a process when it has gone away. This is
9652 * called both as a result of the process dying, or directly when stopping
9653 * a process when running in single process mode.
9654 */
9655 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9656 boolean restarting, int index) {
9657 if (index >= 0) {
9658 mLRUProcesses.remove(index);
9659 }
9660
9661 // Dismiss any open dialogs.
9662 if (app.crashDialog != null) {
9663 app.crashDialog.dismiss();
9664 app.crashDialog = null;
9665 }
9666 if (app.anrDialog != null) {
9667 app.anrDialog.dismiss();
9668 app.anrDialog = null;
9669 }
9670 if (app.waitDialog != null) {
9671 app.waitDialog.dismiss();
9672 app.waitDialog = null;
9673 }
9674
9675 app.crashing = false;
9676 app.notResponding = false;
9677
9678 app.resetPackageList();
9679 app.thread = null;
9680 app.forcingToForeground = null;
9681 app.foregroundServices = false;
9682
9683 killServicesLocked(app, true);
9684
9685 boolean restart = false;
9686
9687 int NL = mLaunchingProviders.size();
9688
9689 // Remove published content providers.
9690 if (!app.pubProviders.isEmpty()) {
9691 Iterator it = app.pubProviders.values().iterator();
9692 while (it.hasNext()) {
9693 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9694 cpr.provider = null;
9695 cpr.app = null;
9696
9697 // See if someone is waiting for this provider... in which
9698 // case we don't remove it, but just let it restart.
9699 int i = 0;
9700 if (!app.bad) {
9701 for (; i<NL; i++) {
9702 if (mLaunchingProviders.get(i) == cpr) {
9703 restart = true;
9704 break;
9705 }
9706 }
9707 } else {
9708 i = NL;
9709 }
9710
9711 if (i >= NL) {
9712 removeDyingProviderLocked(app, cpr);
9713 NL = mLaunchingProviders.size();
9714 }
9715 }
9716 app.pubProviders.clear();
9717 }
9718
9719 // Look through the content providers we are waiting to have launched,
9720 // and if any run in this process then either schedule a restart of
9721 // the process or kill the client waiting for it if this process has
9722 // gone bad.
9723 for (int i=0; i<NL; i++) {
9724 ContentProviderRecord cpr = (ContentProviderRecord)
9725 mLaunchingProviders.get(i);
9726 if (cpr.launchingApp == app) {
9727 if (!app.bad) {
9728 restart = true;
9729 } else {
9730 removeDyingProviderLocked(app, cpr);
9731 NL = mLaunchingProviders.size();
9732 }
9733 }
9734 }
9735
9736 // Unregister from connected content providers.
9737 if (!app.conProviders.isEmpty()) {
9738 Iterator it = app.conProviders.iterator();
9739 while (it.hasNext()) {
9740 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9741 cpr.clients.remove(app);
9742 }
9743 app.conProviders.clear();
9744 }
9745
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009746 // At this point there may be remaining entries in mLaunchingProviders
9747 // where we were the only one waiting, so they are no longer of use.
9748 // Look for these and clean up if found.
9749 // XXX Commented out for now. Trying to figure out a way to reproduce
9750 // the actual situation to identify what is actually going on.
9751 if (false) {
9752 for (int i=0; i<NL; i++) {
9753 ContentProviderRecord cpr = (ContentProviderRecord)
9754 mLaunchingProviders.get(i);
9755 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9756 synchronized (cpr) {
9757 cpr.launchingApp = null;
9758 cpr.notifyAll();
9759 }
9760 }
9761 }
9762 }
9763
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009764 skipCurrentReceiverLocked(app);
9765
9766 // Unregister any receivers.
9767 if (app.receivers.size() > 0) {
9768 Iterator<ReceiverList> it = app.receivers.iterator();
9769 while (it.hasNext()) {
9770 removeReceiverLocked(it.next());
9771 }
9772 app.receivers.clear();
9773 }
9774
Christopher Tate181fafa2009-05-14 11:12:14 -07009775 // If the app is undergoing backup, tell the backup manager about it
9776 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9777 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9778 try {
9779 IBackupManager bm = IBackupManager.Stub.asInterface(
9780 ServiceManager.getService(Context.BACKUP_SERVICE));
9781 bm.agentDisconnected(app.info.packageName);
9782 } catch (RemoteException e) {
9783 // can't happen; backup manager is local
9784 }
9785 }
9786
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009787 // If the caller is restarting this app, then leave it in its
9788 // current lists and let the caller take care of it.
9789 if (restarting) {
9790 return;
9791 }
9792
9793 if (!app.persistent) {
9794 if (DEBUG_PROCESSES) Log.v(TAG,
9795 "Removing non-persistent process during cleanup: " + app);
9796 mProcessNames.remove(app.processName, app.info.uid);
9797 } else if (!app.removed) {
9798 // This app is persistent, so we need to keep its record around.
9799 // If it is not already on the pending app list, add it there
9800 // and start a new process for it.
9801 app.thread = null;
9802 app.forcingToForeground = null;
9803 app.foregroundServices = false;
9804 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9805 mPersistentStartingProcesses.add(app);
9806 restart = true;
9807 }
9808 }
9809 mProcessesOnHold.remove(app);
9810
The Android Open Source Project4df24232009-03-05 14:34:35 -08009811 if (app == mHomeProcess) {
9812 mHomeProcess = null;
9813 }
9814
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009815 if (restart) {
9816 // We have components that still need to be running in the
9817 // process, so re-launch it.
9818 mProcessNames.put(app.processName, app.info.uid, app);
9819 startProcessLocked(app, "restart", app.processName);
9820 } else if (app.pid > 0 && app.pid != MY_PID) {
9821 // Goodbye!
9822 synchronized (mPidsSelfLocked) {
9823 mPidsSelfLocked.remove(app.pid);
9824 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9825 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009826 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009827 }
9828 }
9829
9830 // =========================================================
9831 // SERVICES
9832 // =========================================================
9833
9834 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9835 ActivityManager.RunningServiceInfo info =
9836 new ActivityManager.RunningServiceInfo();
9837 info.service = r.name;
9838 if (r.app != null) {
9839 info.pid = r.app.pid;
9840 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -07009841 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009842 info.process = r.processName;
9843 info.foreground = r.isForeground;
9844 info.activeSince = r.createTime;
9845 info.started = r.startRequested;
9846 info.clientCount = r.connections.size();
9847 info.crashCount = r.crashCount;
9848 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07009849 if (r.isForeground) {
9850 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
9851 }
9852 if (r.startRequested) {
9853 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
9854 }
9855 if (r.app != null && r.app.pid == Process.myPid()) {
9856 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
9857 }
9858 if (r.app != null && r.app.persistent) {
9859 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
9860 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009861 return info;
9862 }
9863
9864 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9865 int flags) {
9866 synchronized (this) {
9867 ArrayList<ActivityManager.RunningServiceInfo> res
9868 = new ArrayList<ActivityManager.RunningServiceInfo>();
9869
9870 if (mServices.size() > 0) {
9871 Iterator<ServiceRecord> it = mServices.values().iterator();
9872 while (it.hasNext() && res.size() < maxNum) {
9873 res.add(makeRunningServiceInfoLocked(it.next()));
9874 }
9875 }
9876
9877 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9878 ServiceRecord r = mRestartingServices.get(i);
9879 ActivityManager.RunningServiceInfo info =
9880 makeRunningServiceInfoLocked(r);
9881 info.restarting = r.nextRestartTime;
9882 res.add(info);
9883 }
9884
9885 return res;
9886 }
9887 }
9888
9889 private final ServiceRecord findServiceLocked(ComponentName name,
9890 IBinder token) {
9891 ServiceRecord r = mServices.get(name);
9892 return r == token ? r : null;
9893 }
9894
9895 private final class ServiceLookupResult {
9896 final ServiceRecord record;
9897 final String permission;
9898
9899 ServiceLookupResult(ServiceRecord _record, String _permission) {
9900 record = _record;
9901 permission = _permission;
9902 }
9903 };
9904
9905 private ServiceLookupResult findServiceLocked(Intent service,
9906 String resolvedType) {
9907 ServiceRecord r = null;
9908 if (service.getComponent() != null) {
9909 r = mServices.get(service.getComponent());
9910 }
9911 if (r == null) {
9912 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9913 r = mServicesByIntent.get(filter);
9914 }
9915
9916 if (r == null) {
9917 try {
9918 ResolveInfo rInfo =
9919 ActivityThread.getPackageManager().resolveService(
9920 service, resolvedType, 0);
9921 ServiceInfo sInfo =
9922 rInfo != null ? rInfo.serviceInfo : null;
9923 if (sInfo == null) {
9924 return null;
9925 }
9926
9927 ComponentName name = new ComponentName(
9928 sInfo.applicationInfo.packageName, sInfo.name);
9929 r = mServices.get(name);
9930 } catch (RemoteException ex) {
9931 // pm is in same process, this will never happen.
9932 }
9933 }
9934 if (r != null) {
9935 int callingPid = Binder.getCallingPid();
9936 int callingUid = Binder.getCallingUid();
9937 if (checkComponentPermission(r.permission,
9938 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9939 != PackageManager.PERMISSION_GRANTED) {
9940 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9941 + " from pid=" + callingPid
9942 + ", uid=" + callingUid
9943 + " requires " + r.permission);
9944 return new ServiceLookupResult(null, r.permission);
9945 }
9946 return new ServiceLookupResult(r, null);
9947 }
9948 return null;
9949 }
9950
9951 private class ServiceRestarter implements Runnable {
9952 private ServiceRecord mService;
9953
9954 void setService(ServiceRecord service) {
9955 mService = service;
9956 }
9957
9958 public void run() {
9959 synchronized(ActivityManagerService.this) {
9960 performServiceRestartLocked(mService);
9961 }
9962 }
9963 }
9964
9965 private ServiceLookupResult retrieveServiceLocked(Intent service,
9966 String resolvedType, int callingPid, int callingUid) {
9967 ServiceRecord r = null;
9968 if (service.getComponent() != null) {
9969 r = mServices.get(service.getComponent());
9970 }
9971 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9972 r = mServicesByIntent.get(filter);
9973 if (r == null) {
9974 try {
9975 ResolveInfo rInfo =
9976 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009977 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009978 ServiceInfo sInfo =
9979 rInfo != null ? rInfo.serviceInfo : null;
9980 if (sInfo == null) {
9981 Log.w(TAG, "Unable to start service " + service +
9982 ": not found");
9983 return null;
9984 }
9985
9986 ComponentName name = new ComponentName(
9987 sInfo.applicationInfo.packageName, sInfo.name);
9988 r = mServices.get(name);
9989 if (r == null) {
9990 filter = new Intent.FilterComparison(service.cloneFilter());
9991 ServiceRestarter res = new ServiceRestarter();
9992 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9993 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9994 synchronized (stats) {
9995 ss = stats.getServiceStatsLocked(
9996 sInfo.applicationInfo.uid, sInfo.packageName,
9997 sInfo.name);
9998 }
9999 r = new ServiceRecord(ss, name, filter, sInfo, res);
10000 res.setService(r);
10001 mServices.put(name, r);
10002 mServicesByIntent.put(filter, r);
10003
10004 // Make sure this component isn't in the pending list.
10005 int N = mPendingServices.size();
10006 for (int i=0; i<N; i++) {
10007 ServiceRecord pr = mPendingServices.get(i);
10008 if (pr.name.equals(name)) {
10009 mPendingServices.remove(i);
10010 i--;
10011 N--;
10012 }
10013 }
10014 }
10015 } catch (RemoteException ex) {
10016 // pm is in same process, this will never happen.
10017 }
10018 }
10019 if (r != null) {
10020 if (checkComponentPermission(r.permission,
10021 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10022 != PackageManager.PERMISSION_GRANTED) {
10023 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10024 + " from pid=" + Binder.getCallingPid()
10025 + ", uid=" + Binder.getCallingUid()
10026 + " requires " + r.permission);
10027 return new ServiceLookupResult(null, r.permission);
10028 }
10029 return new ServiceLookupResult(r, null);
10030 }
10031 return null;
10032 }
10033
10034 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10035 long now = SystemClock.uptimeMillis();
10036 if (r.executeNesting == 0 && r.app != null) {
10037 if (r.app.executingServices.size() == 0) {
10038 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10039 msg.obj = r.app;
10040 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10041 }
10042 r.app.executingServices.add(r);
10043 }
10044 r.executeNesting++;
10045 r.executingStart = now;
10046 }
10047
10048 private final void sendServiceArgsLocked(ServiceRecord r,
10049 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010050 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010051 if (N == 0) {
10052 return;
10053 }
10054
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010055 int i = 0;
10056 while (i < N) {
10057 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010058 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010059 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010060 + r.name + " " + r.intent + " args=" + si.intent);
10061 if (si.intent == null && N > 0) {
10062 // If somehow we got a dummy start at the front, then
10063 // just drop it here.
10064 i++;
10065 continue;
10066 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010067 bumpServiceExecutingLocked(r);
10068 if (!oomAdjusted) {
10069 oomAdjusted = true;
10070 updateOomAdjLocked(r.app);
10071 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010072 int flags = 0;
10073 if (si.deliveryCount > 0) {
10074 flags |= Service.START_FLAG_RETRY;
10075 }
10076 if (si.doneExecutingCount > 0) {
10077 flags |= Service.START_FLAG_REDELIVERY;
10078 }
10079 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10080 si.deliveredTime = SystemClock.uptimeMillis();
10081 r.deliveredStarts.add(si);
10082 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010083 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010084 } catch (RemoteException e) {
10085 // Remote process gone... we'll let the normal cleanup take
10086 // care of this.
10087 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010088 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010089 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010090 break;
10091 }
10092 }
10093 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010094 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010095 } else {
10096 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010097 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010098 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010099 }
10100 }
10101 }
10102
10103 private final boolean requestServiceBindingLocked(ServiceRecord r,
10104 IntentBindRecord i, boolean rebind) {
10105 if (r.app == null || r.app.thread == null) {
10106 // If service is not currently running, can't yet bind.
10107 return false;
10108 }
10109 if ((!i.requested || rebind) && i.apps.size() > 0) {
10110 try {
10111 bumpServiceExecutingLocked(r);
10112 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10113 + ": shouldUnbind=" + i.hasBound);
10114 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10115 if (!rebind) {
10116 i.requested = true;
10117 }
10118 i.hasBound = true;
10119 i.doRebind = false;
10120 } catch (RemoteException e) {
10121 return false;
10122 }
10123 }
10124 return true;
10125 }
10126
10127 private final void requestServiceBindingsLocked(ServiceRecord r) {
10128 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10129 while (bindings.hasNext()) {
10130 IntentBindRecord i = bindings.next();
10131 if (!requestServiceBindingLocked(r, i, false)) {
10132 break;
10133 }
10134 }
10135 }
10136
10137 private final void realStartServiceLocked(ServiceRecord r,
10138 ProcessRecord app) throws RemoteException {
10139 if (app.thread == null) {
10140 throw new RemoteException();
10141 }
10142
10143 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010144 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010145
10146 app.services.add(r);
10147 bumpServiceExecutingLocked(r);
10148 updateLRUListLocked(app, true);
10149
10150 boolean created = false;
10151 try {
10152 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10153 + r.name + " " + r.intent);
10154 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
10155 System.identityHashCode(r), r.shortName,
10156 r.intent.getIntent().toString(), r.app.pid);
10157 synchronized (r.stats.getBatteryStats()) {
10158 r.stats.startLaunchedLocked();
10159 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010160 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010161 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010162 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010163 created = true;
10164 } finally {
10165 if (!created) {
10166 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010167 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010168 }
10169 }
10170
10171 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010172
10173 // If the service is in the started state, and there are no
10174 // pending arguments, then fake up one so its onStartCommand() will
10175 // be called.
10176 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10177 r.lastStartId++;
10178 if (r.lastStartId < 1) {
10179 r.lastStartId = 1;
10180 }
10181 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10182 }
10183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010184 sendServiceArgsLocked(r, true);
10185 }
10186
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010187 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10188 boolean allowCancel) {
10189 boolean canceled = false;
10190
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010191 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010192 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010193 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010194
10195 // Any delivered but not yet finished starts should be put back
10196 // on the pending list.
10197 final int N = r.deliveredStarts.size();
10198 if (N > 0) {
10199 for (int i=N-1; i>=0; i--) {
10200 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10201 if (si.intent == null) {
10202 // We'll generate this again if needed.
10203 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10204 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10205 r.pendingStarts.add(0, si);
10206 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10207 dur *= 2;
10208 if (minDuration < dur) minDuration = dur;
10209 if (resetTime < dur) resetTime = dur;
10210 } else {
10211 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10212 + r.name);
10213 canceled = true;
10214 }
10215 }
10216 r.deliveredStarts.clear();
10217 }
10218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010219 r.totalRestartCount++;
10220 if (r.restartDelay == 0) {
10221 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010222 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010223 } else {
10224 // If it has been a "reasonably long time" since the service
10225 // was started, then reset our restart duration back to
10226 // the beginning, so we don't infinitely increase the duration
10227 // on a service that just occasionally gets killed (which is
10228 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010229 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010230 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010231 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010232 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010233 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010234 if (r.restartDelay < minDuration) {
10235 r.restartDelay = minDuration;
10236 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010237 }
10238 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010239
10240 r.nextRestartTime = now + r.restartDelay;
10241
10242 // Make sure that we don't end up restarting a bunch of services
10243 // all at the same time.
10244 boolean repeat;
10245 do {
10246 repeat = false;
10247 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10248 ServiceRecord r2 = mRestartingServices.get(i);
10249 if (r2 != r && r.nextRestartTime
10250 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10251 && r.nextRestartTime
10252 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10253 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10254 r.restartDelay = r.nextRestartTime - now;
10255 repeat = true;
10256 break;
10257 }
10258 }
10259 } while (repeat);
10260
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010261 if (!mRestartingServices.contains(r)) {
10262 mRestartingServices.add(r);
10263 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010264
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010265 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010266
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010267 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010268 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010269 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10270 Log.w(TAG, "Scheduling restart of crashed service "
10271 + r.shortName + " in " + r.restartDelay + "ms");
10272 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10273 r.shortName, r.restartDelay);
10274
10275 Message msg = Message.obtain();
10276 msg.what = SERVICE_ERROR_MSG;
10277 msg.obj = r;
10278 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010279
10280 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010281 }
10282
10283 final void performServiceRestartLocked(ServiceRecord r) {
10284 if (!mRestartingServices.contains(r)) {
10285 return;
10286 }
10287 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10288 }
10289
10290 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10291 if (r.restartDelay == 0) {
10292 return false;
10293 }
10294 r.resetRestartCounter();
10295 mRestartingServices.remove(r);
10296 mHandler.removeCallbacks(r.restarter);
10297 return true;
10298 }
10299
10300 private final boolean bringUpServiceLocked(ServiceRecord r,
10301 int intentFlags, boolean whileRestarting) {
10302 //Log.i(TAG, "Bring up service:");
10303 //r.dump(" ");
10304
10305 if (r.app != null) {
10306 sendServiceArgsLocked(r, false);
10307 return true;
10308 }
10309
10310 if (!whileRestarting && r.restartDelay > 0) {
10311 // If waiting for a restart, then do nothing.
10312 return true;
10313 }
10314
10315 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10316 + " " + r.intent);
10317
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010318 // We are now bringing the service up, so no longer in the
10319 // restarting state.
10320 mRestartingServices.remove(r);
10321
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010322 final String appName = r.processName;
10323 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10324 if (app != null && app.thread != null) {
10325 try {
10326 realStartServiceLocked(r, app);
10327 return true;
10328 } catch (RemoteException e) {
10329 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10330 }
10331
10332 // If a dead object exception was thrown -- fall through to
10333 // restart the application.
10334 }
10335
10336 if (!mPendingServices.contains(r)) {
10337 // Not running -- get it started, and enqueue this service record
10338 // to be executed when the app comes up.
10339 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070010340 "service", r.name, false) == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010341 Log.w(TAG, "Unable to launch app "
10342 + r.appInfo.packageName + "/"
10343 + r.appInfo.uid + " for service "
10344 + r.intent.getIntent() + ": process is bad");
10345 bringDownServiceLocked(r, true);
10346 return false;
10347 }
10348 mPendingServices.add(r);
10349 }
10350 return true;
10351 }
10352
10353 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10354 //Log.i(TAG, "Bring down service:");
10355 //r.dump(" ");
10356
10357 // Does it still need to run?
10358 if (!force && r.startRequested) {
10359 return;
10360 }
10361 if (r.connections.size() > 0) {
10362 if (!force) {
10363 // XXX should probably keep a count of the number of auto-create
10364 // connections directly in the service.
10365 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10366 while (it.hasNext()) {
10367 ConnectionRecord cr = it.next();
10368 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10369 return;
10370 }
10371 }
10372 }
10373
10374 // Report to all of the connections that the service is no longer
10375 // available.
10376 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10377 while (it.hasNext()) {
10378 ConnectionRecord c = it.next();
10379 try {
10380 // todo: shouldn't be a synchronous call!
10381 c.conn.connected(r.name, null);
10382 } catch (Exception e) {
10383 Log.w(TAG, "Failure disconnecting service " + r.name +
10384 " to connection " + c.conn.asBinder() +
10385 " (in " + c.binding.client.processName + ")", e);
10386 }
10387 }
10388 }
10389
10390 // Tell the service that it has been unbound.
10391 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10392 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10393 while (it.hasNext()) {
10394 IntentBindRecord ibr = it.next();
10395 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10396 + ": hasBound=" + ibr.hasBound);
10397 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10398 try {
10399 bumpServiceExecutingLocked(r);
10400 updateOomAdjLocked(r.app);
10401 ibr.hasBound = false;
10402 r.app.thread.scheduleUnbindService(r,
10403 ibr.intent.getIntent());
10404 } catch (Exception e) {
10405 Log.w(TAG, "Exception when unbinding service "
10406 + r.shortName, e);
10407 serviceDoneExecutingLocked(r, true);
10408 }
10409 }
10410 }
10411 }
10412
10413 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10414 + " " + r.intent);
10415 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10416 System.identityHashCode(r), r.shortName,
10417 (r.app != null) ? r.app.pid : -1);
10418
10419 mServices.remove(r.name);
10420 mServicesByIntent.remove(r.intent);
10421 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10422 r.totalRestartCount = 0;
10423 unscheduleServiceRestartLocked(r);
10424
10425 // Also make sure it is not on the pending list.
10426 int N = mPendingServices.size();
10427 for (int i=0; i<N; i++) {
10428 if (mPendingServices.get(i) == r) {
10429 mPendingServices.remove(i);
10430 if (DEBUG_SERVICE) Log.v(
10431 TAG, "Removed pending service: " + r.shortName);
10432 i--;
10433 N--;
10434 }
10435 }
10436
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010437 r.cancelNotification();
10438 r.isForeground = false;
10439 r.foregroundId = 0;
10440 r.foregroundNoti = null;
10441
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010442 // Clear start entries.
10443 r.deliveredStarts.clear();
10444 r.pendingStarts.clear();
10445
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010446 if (r.app != null) {
10447 synchronized (r.stats.getBatteryStats()) {
10448 r.stats.stopLaunchedLocked();
10449 }
10450 r.app.services.remove(r);
10451 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010452 try {
10453 Log.i(TAG, "Stopping service: " + r.shortName);
10454 bumpServiceExecutingLocked(r);
10455 mStoppingServices.add(r);
10456 updateOomAdjLocked(r.app);
10457 r.app.thread.scheduleStopService(r);
10458 } catch (Exception e) {
10459 Log.w(TAG, "Exception when stopping service "
10460 + r.shortName, e);
10461 serviceDoneExecutingLocked(r, true);
10462 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010463 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010464 } else {
10465 if (DEBUG_SERVICE) Log.v(
10466 TAG, "Removed service that has no process: " + r.shortName);
10467 }
10468 } else {
10469 if (DEBUG_SERVICE) Log.v(
10470 TAG, "Removed service that is not running: " + r.shortName);
10471 }
10472 }
10473
10474 ComponentName startServiceLocked(IApplicationThread caller,
10475 Intent service, String resolvedType,
10476 int callingPid, int callingUid) {
10477 synchronized(this) {
10478 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10479 + " type=" + resolvedType + " args=" + service.getExtras());
10480
10481 if (caller != null) {
10482 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10483 if (callerApp == null) {
10484 throw new SecurityException(
10485 "Unable to find app for caller " + caller
10486 + " (pid=" + Binder.getCallingPid()
10487 + ") when starting service " + service);
10488 }
10489 }
10490
10491 ServiceLookupResult res =
10492 retrieveServiceLocked(service, resolvedType,
10493 callingPid, callingUid);
10494 if (res == null) {
10495 return null;
10496 }
10497 if (res.record == null) {
10498 return new ComponentName("!", res.permission != null
10499 ? res.permission : "private to package");
10500 }
10501 ServiceRecord r = res.record;
10502 if (unscheduleServiceRestartLocked(r)) {
10503 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10504 + r.shortName);
10505 }
10506 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010507 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010508 r.lastStartId++;
10509 if (r.lastStartId < 1) {
10510 r.lastStartId = 1;
10511 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010512 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010513 r.lastActivity = SystemClock.uptimeMillis();
10514 synchronized (r.stats.getBatteryStats()) {
10515 r.stats.startRunningLocked();
10516 }
10517 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10518 return new ComponentName("!", "Service process is bad");
10519 }
10520 return r.name;
10521 }
10522 }
10523
10524 public ComponentName startService(IApplicationThread caller, Intent service,
10525 String resolvedType) {
10526 // Refuse possible leaked file descriptors
10527 if (service != null && service.hasFileDescriptors() == true) {
10528 throw new IllegalArgumentException("File descriptors passed in Intent");
10529 }
10530
10531 synchronized(this) {
10532 final int callingPid = Binder.getCallingPid();
10533 final int callingUid = Binder.getCallingUid();
10534 final long origId = Binder.clearCallingIdentity();
10535 ComponentName res = startServiceLocked(caller, service,
10536 resolvedType, callingPid, callingUid);
10537 Binder.restoreCallingIdentity(origId);
10538 return res;
10539 }
10540 }
10541
10542 ComponentName startServiceInPackage(int uid,
10543 Intent service, String resolvedType) {
10544 synchronized(this) {
10545 final long origId = Binder.clearCallingIdentity();
10546 ComponentName res = startServiceLocked(null, service,
10547 resolvedType, -1, uid);
10548 Binder.restoreCallingIdentity(origId);
10549 return res;
10550 }
10551 }
10552
10553 public int stopService(IApplicationThread caller, Intent service,
10554 String resolvedType) {
10555 // Refuse possible leaked file descriptors
10556 if (service != null && service.hasFileDescriptors() == true) {
10557 throw new IllegalArgumentException("File descriptors passed in Intent");
10558 }
10559
10560 synchronized(this) {
10561 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10562 + " type=" + resolvedType);
10563
10564 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10565 if (caller != null && callerApp == null) {
10566 throw new SecurityException(
10567 "Unable to find app for caller " + caller
10568 + " (pid=" + Binder.getCallingPid()
10569 + ") when stopping service " + service);
10570 }
10571
10572 // If this service is active, make sure it is stopped.
10573 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10574 if (r != null) {
10575 if (r.record != null) {
10576 synchronized (r.record.stats.getBatteryStats()) {
10577 r.record.stats.stopRunningLocked();
10578 }
10579 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010580 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010581 final long origId = Binder.clearCallingIdentity();
10582 bringDownServiceLocked(r.record, false);
10583 Binder.restoreCallingIdentity(origId);
10584 return 1;
10585 }
10586 return -1;
10587 }
10588 }
10589
10590 return 0;
10591 }
10592
10593 public IBinder peekService(Intent service, String resolvedType) {
10594 // Refuse possible leaked file descriptors
10595 if (service != null && service.hasFileDescriptors() == true) {
10596 throw new IllegalArgumentException("File descriptors passed in Intent");
10597 }
10598
10599 IBinder ret = null;
10600
10601 synchronized(this) {
10602 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10603
10604 if (r != null) {
10605 // r.record is null if findServiceLocked() failed the caller permission check
10606 if (r.record == null) {
10607 throw new SecurityException(
10608 "Permission Denial: Accessing service " + r.record.name
10609 + " from pid=" + Binder.getCallingPid()
10610 + ", uid=" + Binder.getCallingUid()
10611 + " requires " + r.permission);
10612 }
10613 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10614 if (ib != null) {
10615 ret = ib.binder;
10616 }
10617 }
10618 }
10619
10620 return ret;
10621 }
10622
10623 public boolean stopServiceToken(ComponentName className, IBinder token,
10624 int startId) {
10625 synchronized(this) {
10626 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10627 + " " + token + " startId=" + startId);
10628 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010629 if (r != null) {
10630 if (startId >= 0) {
10631 // Asked to only stop if done with all work. Note that
10632 // to avoid leaks, we will take this as dropping all
10633 // start items up to and including this one.
10634 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10635 if (si != null) {
10636 while (r.deliveredStarts.size() > 0) {
10637 if (r.deliveredStarts.remove(0) == si) {
10638 break;
10639 }
10640 }
10641 }
10642
10643 if (r.lastStartId != startId) {
10644 return false;
10645 }
10646
10647 if (r.deliveredStarts.size() > 0) {
10648 Log.w(TAG, "stopServiceToken startId " + startId
10649 + " is last, but have " + r.deliveredStarts.size()
10650 + " remaining args");
10651 }
10652 }
10653
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010654 synchronized (r.stats.getBatteryStats()) {
10655 r.stats.stopRunningLocked();
10656 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010657 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010658 }
10659 final long origId = Binder.clearCallingIdentity();
10660 bringDownServiceLocked(r, false);
10661 Binder.restoreCallingIdentity(origId);
10662 return true;
10663 }
10664 }
10665 return false;
10666 }
10667
10668 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010669 int id, Notification notification, boolean removeNotification) {
10670 final long origId = Binder.clearCallingIdentity();
10671 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010672 synchronized(this) {
10673 ServiceRecord r = findServiceLocked(className, token);
10674 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010675 if (id != 0) {
10676 if (notification == null) {
10677 throw new IllegalArgumentException("null notification");
10678 }
10679 if (r.foregroundId != id) {
10680 r.cancelNotification();
10681 r.foregroundId = id;
10682 }
10683 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10684 r.foregroundNoti = notification;
10685 r.isForeground = true;
10686 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010687 if (r.app != null) {
10688 updateServiceForegroundLocked(r.app, true);
10689 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010690 } else {
10691 if (r.isForeground) {
10692 r.isForeground = false;
10693 if (r.app != null) {
10694 updateServiceForegroundLocked(r.app, true);
10695 }
10696 }
10697 if (removeNotification) {
10698 r.cancelNotification();
10699 r.foregroundId = 0;
10700 r.foregroundNoti = null;
10701 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010702 }
10703 }
10704 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010705 } finally {
10706 Binder.restoreCallingIdentity(origId);
10707 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010708 }
10709
10710 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10711 boolean anyForeground = false;
10712 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10713 if (sr.isForeground) {
10714 anyForeground = true;
10715 break;
10716 }
10717 }
10718 if (anyForeground != proc.foregroundServices) {
10719 proc.foregroundServices = anyForeground;
10720 if (oomAdj) {
10721 updateOomAdjLocked();
10722 }
10723 }
10724 }
10725
10726 public int bindService(IApplicationThread caller, IBinder token,
10727 Intent service, String resolvedType,
10728 IServiceConnection connection, int flags) {
10729 // Refuse possible leaked file descriptors
10730 if (service != null && service.hasFileDescriptors() == true) {
10731 throw new IllegalArgumentException("File descriptors passed in Intent");
10732 }
10733
10734 synchronized(this) {
10735 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10736 + " type=" + resolvedType + " conn=" + connection.asBinder()
10737 + " flags=0x" + Integer.toHexString(flags));
10738 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10739 if (callerApp == null) {
10740 throw new SecurityException(
10741 "Unable to find app for caller " + caller
10742 + " (pid=" + Binder.getCallingPid()
10743 + ") when binding service " + service);
10744 }
10745
10746 HistoryRecord activity = null;
10747 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010748 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010749 if (aindex < 0) {
10750 Log.w(TAG, "Binding with unknown activity: " + token);
10751 return 0;
10752 }
10753 activity = (HistoryRecord)mHistory.get(aindex);
10754 }
10755
10756 ServiceLookupResult res =
10757 retrieveServiceLocked(service, resolvedType,
10758 Binder.getCallingPid(), Binder.getCallingUid());
10759 if (res == null) {
10760 return 0;
10761 }
10762 if (res.record == null) {
10763 return -1;
10764 }
10765 ServiceRecord s = res.record;
10766
10767 final long origId = Binder.clearCallingIdentity();
10768
10769 if (unscheduleServiceRestartLocked(s)) {
10770 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10771 + s.shortName);
10772 }
10773
10774 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10775 ConnectionRecord c = new ConnectionRecord(b, activity,
10776 connection, flags);
10777
10778 IBinder binder = connection.asBinder();
10779 s.connections.put(binder, c);
10780 b.connections.add(c);
10781 if (activity != null) {
10782 if (activity.connections == null) {
10783 activity.connections = new HashSet<ConnectionRecord>();
10784 }
10785 activity.connections.add(c);
10786 }
10787 b.client.connections.add(c);
10788 mServiceConnections.put(binder, c);
10789
10790 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10791 s.lastActivity = SystemClock.uptimeMillis();
10792 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10793 return 0;
10794 }
10795 }
10796
10797 if (s.app != null) {
10798 // This could have made the service more important.
10799 updateOomAdjLocked(s.app);
10800 }
10801
10802 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10803 + ": received=" + b.intent.received
10804 + " apps=" + b.intent.apps.size()
10805 + " doRebind=" + b.intent.doRebind);
10806
10807 if (s.app != null && b.intent.received) {
10808 // Service is already running, so we can immediately
10809 // publish the connection.
10810 try {
10811 c.conn.connected(s.name, b.intent.binder);
10812 } catch (Exception e) {
10813 Log.w(TAG, "Failure sending service " + s.shortName
10814 + " to connection " + c.conn.asBinder()
10815 + " (in " + c.binding.client.processName + ")", e);
10816 }
10817
10818 // If this is the first app connected back to this binding,
10819 // and the service had previously asked to be told when
10820 // rebound, then do so.
10821 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10822 requestServiceBindingLocked(s, b.intent, true);
10823 }
10824 } else if (!b.intent.requested) {
10825 requestServiceBindingLocked(s, b.intent, false);
10826 }
10827
10828 Binder.restoreCallingIdentity(origId);
10829 }
10830
10831 return 1;
10832 }
10833
10834 private void removeConnectionLocked(
10835 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10836 IBinder binder = c.conn.asBinder();
10837 AppBindRecord b = c.binding;
10838 ServiceRecord s = b.service;
10839 s.connections.remove(binder);
10840 b.connections.remove(c);
10841 if (c.activity != null && c.activity != skipAct) {
10842 if (c.activity.connections != null) {
10843 c.activity.connections.remove(c);
10844 }
10845 }
10846 if (b.client != skipApp) {
10847 b.client.connections.remove(c);
10848 }
10849 mServiceConnections.remove(binder);
10850
10851 if (b.connections.size() == 0) {
10852 b.intent.apps.remove(b.client);
10853 }
10854
10855 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10856 + ": shouldUnbind=" + b.intent.hasBound);
10857 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10858 && b.intent.hasBound) {
10859 try {
10860 bumpServiceExecutingLocked(s);
10861 updateOomAdjLocked(s.app);
10862 b.intent.hasBound = false;
10863 // Assume the client doesn't want to know about a rebind;
10864 // we will deal with that later if it asks for one.
10865 b.intent.doRebind = false;
10866 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10867 } catch (Exception e) {
10868 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10869 serviceDoneExecutingLocked(s, true);
10870 }
10871 }
10872
10873 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10874 bringDownServiceLocked(s, false);
10875 }
10876 }
10877
10878 public boolean unbindService(IServiceConnection connection) {
10879 synchronized (this) {
10880 IBinder binder = connection.asBinder();
10881 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10882 ConnectionRecord r = mServiceConnections.get(binder);
10883 if (r == null) {
10884 Log.w(TAG, "Unbind failed: could not find connection for "
10885 + connection.asBinder());
10886 return false;
10887 }
10888
10889 final long origId = Binder.clearCallingIdentity();
10890
10891 removeConnectionLocked(r, null, null);
10892
10893 if (r.binding.service.app != null) {
10894 // This could have made the service less important.
10895 updateOomAdjLocked(r.binding.service.app);
10896 }
10897
10898 Binder.restoreCallingIdentity(origId);
10899 }
10900
10901 return true;
10902 }
10903
10904 public void publishService(IBinder token, Intent intent, IBinder service) {
10905 // Refuse possible leaked file descriptors
10906 if (intent != null && intent.hasFileDescriptors() == true) {
10907 throw new IllegalArgumentException("File descriptors passed in Intent");
10908 }
10909
10910 synchronized(this) {
10911 if (!(token instanceof ServiceRecord)) {
10912 throw new IllegalArgumentException("Invalid service token");
10913 }
10914 ServiceRecord r = (ServiceRecord)token;
10915
10916 final long origId = Binder.clearCallingIdentity();
10917
10918 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10919 + " " + intent + ": " + service);
10920 if (r != null) {
10921 Intent.FilterComparison filter
10922 = new Intent.FilterComparison(intent);
10923 IntentBindRecord b = r.bindings.get(filter);
10924 if (b != null && !b.received) {
10925 b.binder = service;
10926 b.requested = true;
10927 b.received = true;
10928 if (r.connections.size() > 0) {
10929 Iterator<ConnectionRecord> it
10930 = r.connections.values().iterator();
10931 while (it.hasNext()) {
10932 ConnectionRecord c = it.next();
10933 if (!filter.equals(c.binding.intent.intent)) {
10934 if (DEBUG_SERVICE) Log.v(
10935 TAG, "Not publishing to: " + c);
10936 if (DEBUG_SERVICE) Log.v(
10937 TAG, "Bound intent: " + c.binding.intent.intent);
10938 if (DEBUG_SERVICE) Log.v(
10939 TAG, "Published intent: " + intent);
10940 continue;
10941 }
10942 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10943 try {
10944 c.conn.connected(r.name, service);
10945 } catch (Exception e) {
10946 Log.w(TAG, "Failure sending service " + r.name +
10947 " to connection " + c.conn.asBinder() +
10948 " (in " + c.binding.client.processName + ")", e);
10949 }
10950 }
10951 }
10952 }
10953
10954 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10955
10956 Binder.restoreCallingIdentity(origId);
10957 }
10958 }
10959 }
10960
10961 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10962 // Refuse possible leaked file descriptors
10963 if (intent != null && intent.hasFileDescriptors() == true) {
10964 throw new IllegalArgumentException("File descriptors passed in Intent");
10965 }
10966
10967 synchronized(this) {
10968 if (!(token instanceof ServiceRecord)) {
10969 throw new IllegalArgumentException("Invalid service token");
10970 }
10971 ServiceRecord r = (ServiceRecord)token;
10972
10973 final long origId = Binder.clearCallingIdentity();
10974
10975 if (r != null) {
10976 Intent.FilterComparison filter
10977 = new Intent.FilterComparison(intent);
10978 IntentBindRecord b = r.bindings.get(filter);
10979 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10980 + " at " + b + ": apps="
10981 + (b != null ? b.apps.size() : 0));
10982 if (b != null) {
10983 if (b.apps.size() > 0) {
10984 // Applications have already bound since the last
10985 // unbind, so just rebind right here.
10986 requestServiceBindingLocked(r, b, true);
10987 } else {
10988 // Note to tell the service the next time there is
10989 // a new client.
10990 b.doRebind = true;
10991 }
10992 }
10993
10994 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10995
10996 Binder.restoreCallingIdentity(origId);
10997 }
10998 }
10999 }
11000
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011001 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011002 synchronized(this) {
11003 if (!(token instanceof ServiceRecord)) {
11004 throw new IllegalArgumentException("Invalid service token");
11005 }
11006 ServiceRecord r = (ServiceRecord)token;
11007 boolean inStopping = mStoppingServices.contains(token);
11008 if (r != null) {
11009 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11010 + ": nesting=" + r.executeNesting
11011 + ", inStopping=" + inStopping);
11012 if (r != token) {
11013 Log.w(TAG, "Done executing service " + r.name
11014 + " with incorrect token: given " + token
11015 + ", expected " + r);
11016 return;
11017 }
11018
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011019 if (type == 1) {
11020 // This is a call from a service start... take care of
11021 // book-keeping.
11022 r.callStart = true;
11023 switch (res) {
11024 case Service.START_STICKY_COMPATIBILITY:
11025 case Service.START_STICKY: {
11026 // We are done with the associated start arguments.
11027 r.findDeliveredStart(startId, true);
11028 // Don't stop if killed.
11029 r.stopIfKilled = false;
11030 break;
11031 }
11032 case Service.START_NOT_STICKY: {
11033 // We are done with the associated start arguments.
11034 r.findDeliveredStart(startId, true);
11035 if (r.lastStartId == startId) {
11036 // There is no more work, and this service
11037 // doesn't want to hang around if killed.
11038 r.stopIfKilled = true;
11039 }
11040 break;
11041 }
11042 case Service.START_REDELIVER_INTENT: {
11043 // We'll keep this item until they explicitly
11044 // call stop for it, but keep track of the fact
11045 // that it was delivered.
11046 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11047 if (si != null) {
11048 si.deliveryCount = 0;
11049 si.doneExecutingCount++;
11050 // Don't stop if killed.
11051 r.stopIfKilled = true;
11052 }
11053 break;
11054 }
11055 default:
11056 throw new IllegalArgumentException(
11057 "Unknown service start result: " + res);
11058 }
11059 if (res == Service.START_STICKY_COMPATIBILITY) {
11060 r.callStart = false;
11061 }
11062 }
11063
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011064 final long origId = Binder.clearCallingIdentity();
11065 serviceDoneExecutingLocked(r, inStopping);
11066 Binder.restoreCallingIdentity(origId);
11067 } else {
11068 Log.w(TAG, "Done executing unknown service " + r.name
11069 + " with token " + token);
11070 }
11071 }
11072 }
11073
11074 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11075 r.executeNesting--;
11076 if (r.executeNesting <= 0 && r.app != null) {
11077 r.app.executingServices.remove(r);
11078 if (r.app.executingServices.size() == 0) {
11079 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11080 }
11081 if (inStopping) {
11082 mStoppingServices.remove(r);
11083 }
11084 updateOomAdjLocked(r.app);
11085 }
11086 }
11087
11088 void serviceTimeout(ProcessRecord proc) {
11089 synchronized(this) {
11090 if (proc.executingServices.size() == 0 || proc.thread == null) {
11091 return;
11092 }
11093 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11094 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11095 ServiceRecord timeout = null;
11096 long nextTime = 0;
11097 while (it.hasNext()) {
11098 ServiceRecord sr = it.next();
11099 if (sr.executingStart < maxTime) {
11100 timeout = sr;
11101 break;
11102 }
11103 if (sr.executingStart > nextTime) {
11104 nextTime = sr.executingStart;
11105 }
11106 }
11107 if (timeout != null && mLRUProcesses.contains(proc)) {
11108 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011109 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011110 + timeout.name);
11111 } else {
11112 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11113 msg.obj = proc;
11114 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11115 }
11116 }
11117 }
11118
11119 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011120 // BACKUP AND RESTORE
11121 // =========================================================
11122
11123 // Cause the target app to be launched if necessary and its backup agent
11124 // instantiated. The backup agent will invoke backupAgentCreated() on the
11125 // activity manager to announce its creation.
11126 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11127 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11128 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11129
11130 synchronized(this) {
11131 // !!! TODO: currently no check here that we're already bound
11132 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11133 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11134 synchronized (stats) {
11135 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11136 }
11137
11138 BackupRecord r = new BackupRecord(ss, app, backupMode);
11139 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11140 // startProcessLocked() returns existing proc's record if it's already running
11141 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011142 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011143 if (proc == null) {
11144 Log.e(TAG, "Unable to start backup agent process " + r);
11145 return false;
11146 }
11147
11148 r.app = proc;
11149 mBackupTarget = r;
11150 mBackupAppName = app.packageName;
11151
Christopher Tate6fa95972009-06-05 18:43:55 -070011152 // Try not to kill the process during backup
11153 updateOomAdjLocked(proc);
11154
Christopher Tate181fafa2009-05-14 11:12:14 -070011155 // If the process is already attached, schedule the creation of the backup agent now.
11156 // If it is not yet live, this will be done when it attaches to the framework.
11157 if (proc.thread != null) {
11158 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11159 try {
11160 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11161 } catch (RemoteException e) {
11162 // !!! TODO: notify the backup manager that we crashed, or rely on
11163 // death notices, or...?
11164 }
11165 } else {
11166 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11167 }
11168 // Invariants: at this point, the target app process exists and the application
11169 // is either already running or in the process of coming up. mBackupTarget and
11170 // mBackupAppName describe the app, so that when it binds back to the AM we
11171 // know that it's scheduled for a backup-agent operation.
11172 }
11173
11174 return true;
11175 }
11176
11177 // A backup agent has just come up
11178 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11179 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11180 + " = " + agent);
11181
11182 synchronized(this) {
11183 if (!agentPackageName.equals(mBackupAppName)) {
11184 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11185 return;
11186 }
11187
Christopher Tate043dadc2009-06-02 16:11:00 -070011188 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011189 try {
11190 IBackupManager bm = IBackupManager.Stub.asInterface(
11191 ServiceManager.getService(Context.BACKUP_SERVICE));
11192 bm.agentConnected(agentPackageName, agent);
11193 } catch (RemoteException e) {
11194 // can't happen; the backup manager service is local
11195 } catch (Exception e) {
11196 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11197 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011198 } finally {
11199 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011200 }
11201 }
11202 }
11203
11204 // done with this agent
11205 public void unbindBackupAgent(ApplicationInfo appInfo) {
11206 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011207 if (appInfo == null) {
11208 Log.w(TAG, "unbind backup agent for null app");
11209 return;
11210 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011211
11212 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011213 if (mBackupAppName == null) {
11214 Log.w(TAG, "Unbinding backup agent with no active backup");
11215 return;
11216 }
11217
Christopher Tate181fafa2009-05-14 11:12:14 -070011218 if (!mBackupAppName.equals(appInfo.packageName)) {
11219 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11220 return;
11221 }
11222
Christopher Tate6fa95972009-06-05 18:43:55 -070011223 ProcessRecord proc = mBackupTarget.app;
11224 mBackupTarget = null;
11225 mBackupAppName = null;
11226
11227 // Not backing this app up any more; reset its OOM adjustment
11228 updateOomAdjLocked(proc);
11229
Christopher Tatec7b31e32009-06-10 15:49:30 -070011230 // If the app crashed during backup, 'thread' will be null here
11231 if (proc.thread != null) {
11232 try {
11233 proc.thread.scheduleDestroyBackupAgent(appInfo);
11234 } catch (Exception e) {
11235 Log.e(TAG, "Exception when unbinding backup agent:");
11236 e.printStackTrace();
11237 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011238 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011239 }
11240 }
11241 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011242 // BROADCASTS
11243 // =========================================================
11244
11245 private final List getStickies(String action, IntentFilter filter,
11246 List cur) {
11247 final ContentResolver resolver = mContext.getContentResolver();
11248 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11249 if (list == null) {
11250 return cur;
11251 }
11252 int N = list.size();
11253 for (int i=0; i<N; i++) {
11254 Intent intent = list.get(i);
11255 if (filter.match(resolver, intent, true, TAG) >= 0) {
11256 if (cur == null) {
11257 cur = new ArrayList<Intent>();
11258 }
11259 cur.add(intent);
11260 }
11261 }
11262 return cur;
11263 }
11264
11265 private final void scheduleBroadcastsLocked() {
11266 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11267 + mBroadcastsScheduled);
11268
11269 if (mBroadcastsScheduled) {
11270 return;
11271 }
11272 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11273 mBroadcastsScheduled = true;
11274 }
11275
11276 public Intent registerReceiver(IApplicationThread caller,
11277 IIntentReceiver receiver, IntentFilter filter, String permission) {
11278 synchronized(this) {
11279 ProcessRecord callerApp = null;
11280 if (caller != null) {
11281 callerApp = getRecordForAppLocked(caller);
11282 if (callerApp == null) {
11283 throw new SecurityException(
11284 "Unable to find app for caller " + caller
11285 + " (pid=" + Binder.getCallingPid()
11286 + ") when registering receiver " + receiver);
11287 }
11288 }
11289
11290 List allSticky = null;
11291
11292 // Look for any matching sticky broadcasts...
11293 Iterator actions = filter.actionsIterator();
11294 if (actions != null) {
11295 while (actions.hasNext()) {
11296 String action = (String)actions.next();
11297 allSticky = getStickies(action, filter, allSticky);
11298 }
11299 } else {
11300 allSticky = getStickies(null, filter, allSticky);
11301 }
11302
11303 // The first sticky in the list is returned directly back to
11304 // the client.
11305 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11306
11307 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11308 + ": " + sticky);
11309
11310 if (receiver == null) {
11311 return sticky;
11312 }
11313
11314 ReceiverList rl
11315 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11316 if (rl == null) {
11317 rl = new ReceiverList(this, callerApp,
11318 Binder.getCallingPid(),
11319 Binder.getCallingUid(), receiver);
11320 if (rl.app != null) {
11321 rl.app.receivers.add(rl);
11322 } else {
11323 try {
11324 receiver.asBinder().linkToDeath(rl, 0);
11325 } catch (RemoteException e) {
11326 return sticky;
11327 }
11328 rl.linkedToDeath = true;
11329 }
11330 mRegisteredReceivers.put(receiver.asBinder(), rl);
11331 }
11332 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11333 rl.add(bf);
11334 if (!bf.debugCheck()) {
11335 Log.w(TAG, "==> For Dynamic broadast");
11336 }
11337 mReceiverResolver.addFilter(bf);
11338
11339 // Enqueue broadcasts for all existing stickies that match
11340 // this filter.
11341 if (allSticky != null) {
11342 ArrayList receivers = new ArrayList();
11343 receivers.add(bf);
11344
11345 int N = allSticky.size();
11346 for (int i=0; i<N; i++) {
11347 Intent intent = (Intent)allSticky.get(i);
11348 BroadcastRecord r = new BroadcastRecord(intent, null,
11349 null, -1, -1, null, receivers, null, 0, null, null,
11350 false);
11351 if (mParallelBroadcasts.size() == 0) {
11352 scheduleBroadcastsLocked();
11353 }
11354 mParallelBroadcasts.add(r);
11355 }
11356 }
11357
11358 return sticky;
11359 }
11360 }
11361
11362 public void unregisterReceiver(IIntentReceiver receiver) {
11363 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11364
11365 boolean doNext = false;
11366
11367 synchronized(this) {
11368 ReceiverList rl
11369 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11370 if (rl != null) {
11371 if (rl.curBroadcast != null) {
11372 BroadcastRecord r = rl.curBroadcast;
11373 doNext = finishReceiverLocked(
11374 receiver.asBinder(), r.resultCode, r.resultData,
11375 r.resultExtras, r.resultAbort, true);
11376 }
11377
11378 if (rl.app != null) {
11379 rl.app.receivers.remove(rl);
11380 }
11381 removeReceiverLocked(rl);
11382 if (rl.linkedToDeath) {
11383 rl.linkedToDeath = false;
11384 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11385 }
11386 }
11387 }
11388
11389 if (!doNext) {
11390 return;
11391 }
11392
11393 final long origId = Binder.clearCallingIdentity();
11394 processNextBroadcast(false);
11395 trimApplications();
11396 Binder.restoreCallingIdentity(origId);
11397 }
11398
11399 void removeReceiverLocked(ReceiverList rl) {
11400 mRegisteredReceivers.remove(rl.receiver.asBinder());
11401 int N = rl.size();
11402 for (int i=0; i<N; i++) {
11403 mReceiverResolver.removeFilter(rl.get(i));
11404 }
11405 }
11406
11407 private final int broadcastIntentLocked(ProcessRecord callerApp,
11408 String callerPackage, Intent intent, String resolvedType,
11409 IIntentReceiver resultTo, int resultCode, String resultData,
11410 Bundle map, String requiredPermission,
11411 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11412 intent = new Intent(intent);
11413
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011414 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011415 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11416 + " ordered=" + ordered);
11417 if ((resultTo != null) && !ordered) {
11418 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11419 }
11420
11421 // Handle special intents: if this broadcast is from the package
11422 // manager about a package being removed, we need to remove all of
11423 // its activities from the history stack.
11424 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11425 intent.getAction());
11426 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11427 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11428 || uidRemoved) {
11429 if (checkComponentPermission(
11430 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11431 callingPid, callingUid, -1)
11432 == PackageManager.PERMISSION_GRANTED) {
11433 if (uidRemoved) {
11434 final Bundle intentExtras = intent.getExtras();
11435 final int uid = intentExtras != null
11436 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11437 if (uid >= 0) {
11438 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11439 synchronized (bs) {
11440 bs.removeUidStatsLocked(uid);
11441 }
11442 }
11443 } else {
11444 Uri data = intent.getData();
11445 String ssp;
11446 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11447 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11448 uninstallPackageLocked(ssp,
11449 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011450 AttributeCache ac = AttributeCache.instance();
11451 if (ac != null) {
11452 ac.removePackage(ssp);
11453 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011454 }
11455 }
11456 }
11457 } else {
11458 String msg = "Permission Denial: " + intent.getAction()
11459 + " broadcast from " + callerPackage + " (pid=" + callingPid
11460 + ", uid=" + callingUid + ")"
11461 + " requires "
11462 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11463 Log.w(TAG, msg);
11464 throw new SecurityException(msg);
11465 }
11466 }
11467
11468 /*
11469 * If this is the time zone changed action, queue up a message that will reset the timezone
11470 * of all currently running processes. This message will get queued up before the broadcast
11471 * happens.
11472 */
11473 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11474 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11475 }
11476
Dianne Hackborn854060af2009-07-09 18:14:31 -070011477 /*
11478 * Prevent non-system code (defined here to be non-persistent
11479 * processes) from sending protected broadcasts.
11480 */
11481 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11482 || callingUid == Process.SHELL_UID || callingUid == 0) {
11483 // Always okay.
11484 } else if (callerApp == null || !callerApp.persistent) {
11485 try {
11486 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11487 intent.getAction())) {
11488 String msg = "Permission Denial: not allowed to send broadcast "
11489 + intent.getAction() + " from pid="
11490 + callingPid + ", uid=" + callingUid;
11491 Log.w(TAG, msg);
11492 throw new SecurityException(msg);
11493 }
11494 } catch (RemoteException e) {
11495 Log.w(TAG, "Remote exception", e);
11496 return BROADCAST_SUCCESS;
11497 }
11498 }
11499
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011500 // Add to the sticky list if requested.
11501 if (sticky) {
11502 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11503 callingPid, callingUid)
11504 != PackageManager.PERMISSION_GRANTED) {
11505 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11506 + callingPid + ", uid=" + callingUid
11507 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11508 Log.w(TAG, msg);
11509 throw new SecurityException(msg);
11510 }
11511 if (requiredPermission != null) {
11512 Log.w(TAG, "Can't broadcast sticky intent " + intent
11513 + " and enforce permission " + requiredPermission);
11514 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11515 }
11516 if (intent.getComponent() != null) {
11517 throw new SecurityException(
11518 "Sticky broadcasts can't target a specific component");
11519 }
11520 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11521 if (list == null) {
11522 list = new ArrayList<Intent>();
11523 mStickyBroadcasts.put(intent.getAction(), list);
11524 }
11525 int N = list.size();
11526 int i;
11527 for (i=0; i<N; i++) {
11528 if (intent.filterEquals(list.get(i))) {
11529 // This sticky already exists, replace it.
11530 list.set(i, new Intent(intent));
11531 break;
11532 }
11533 }
11534 if (i >= N) {
11535 list.add(new Intent(intent));
11536 }
11537 }
11538
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011539 // Figure out who all will receive this broadcast.
11540 List receivers = null;
11541 List<BroadcastFilter> registeredReceivers = null;
11542 try {
11543 if (intent.getComponent() != null) {
11544 // Broadcast is going to one specific receiver class...
11545 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011546 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011547 if (ai != null) {
11548 receivers = new ArrayList();
11549 ResolveInfo ri = new ResolveInfo();
11550 ri.activityInfo = ai;
11551 receivers.add(ri);
11552 }
11553 } else {
11554 // Need to resolve the intent to interested receivers...
11555 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11556 == 0) {
11557 receivers =
11558 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011559 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011560 }
Mihai Preda074edef2009-05-18 17:13:31 +020011561 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011562 }
11563 } catch (RemoteException ex) {
11564 // pm is in same process, this will never happen.
11565 }
11566
11567 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11568 if (!ordered && NR > 0) {
11569 // If we are not serializing this broadcast, then send the
11570 // registered receivers separately so they don't wait for the
11571 // components to be launched.
11572 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11573 callerPackage, callingPid, callingUid, requiredPermission,
11574 registeredReceivers, resultTo, resultCode, resultData, map,
11575 ordered);
11576 if (DEBUG_BROADCAST) Log.v(
11577 TAG, "Enqueueing parallel broadcast " + r
11578 + ": prev had " + mParallelBroadcasts.size());
11579 mParallelBroadcasts.add(r);
11580 scheduleBroadcastsLocked();
11581 registeredReceivers = null;
11582 NR = 0;
11583 }
11584
11585 // Merge into one list.
11586 int ir = 0;
11587 if (receivers != null) {
11588 // A special case for PACKAGE_ADDED: do not allow the package
11589 // being added to see this broadcast. This prevents them from
11590 // using this as a back door to get run as soon as they are
11591 // installed. Maybe in the future we want to have a special install
11592 // broadcast or such for apps, but we'd like to deliberately make
11593 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011594 boolean skip = false;
11595 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011596 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011597 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11598 skip = true;
11599 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11600 skip = true;
11601 }
11602 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011603 ? intent.getData().getSchemeSpecificPart()
11604 : null;
11605 if (skipPackage != null && receivers != null) {
11606 int NT = receivers.size();
11607 for (int it=0; it<NT; it++) {
11608 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11609 if (curt.activityInfo.packageName.equals(skipPackage)) {
11610 receivers.remove(it);
11611 it--;
11612 NT--;
11613 }
11614 }
11615 }
11616
11617 int NT = receivers != null ? receivers.size() : 0;
11618 int it = 0;
11619 ResolveInfo curt = null;
11620 BroadcastFilter curr = null;
11621 while (it < NT && ir < NR) {
11622 if (curt == null) {
11623 curt = (ResolveInfo)receivers.get(it);
11624 }
11625 if (curr == null) {
11626 curr = registeredReceivers.get(ir);
11627 }
11628 if (curr.getPriority() >= curt.priority) {
11629 // Insert this broadcast record into the final list.
11630 receivers.add(it, curr);
11631 ir++;
11632 curr = null;
11633 it++;
11634 NT++;
11635 } else {
11636 // Skip to the next ResolveInfo in the final list.
11637 it++;
11638 curt = null;
11639 }
11640 }
11641 }
11642 while (ir < NR) {
11643 if (receivers == null) {
11644 receivers = new ArrayList();
11645 }
11646 receivers.add(registeredReceivers.get(ir));
11647 ir++;
11648 }
11649
11650 if ((receivers != null && receivers.size() > 0)
11651 || resultTo != null) {
11652 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11653 callerPackage, callingPid, callingUid, requiredPermission,
11654 receivers, resultTo, resultCode, resultData, map, ordered);
11655 if (DEBUG_BROADCAST) Log.v(
11656 TAG, "Enqueueing ordered broadcast " + r
11657 + ": prev had " + mOrderedBroadcasts.size());
11658 if (DEBUG_BROADCAST) {
11659 int seq = r.intent.getIntExtra("seq", -1);
11660 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11661 }
11662 mOrderedBroadcasts.add(r);
11663 scheduleBroadcastsLocked();
11664 }
11665
11666 return BROADCAST_SUCCESS;
11667 }
11668
11669 public final int broadcastIntent(IApplicationThread caller,
11670 Intent intent, String resolvedType, IIntentReceiver resultTo,
11671 int resultCode, String resultData, Bundle map,
11672 String requiredPermission, boolean serialized, boolean sticky) {
11673 // Refuse possible leaked file descriptors
11674 if (intent != null && intent.hasFileDescriptors() == true) {
11675 throw new IllegalArgumentException("File descriptors passed in Intent");
11676 }
11677
11678 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011679 int flags = intent.getFlags();
11680
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011681 if (!mSystemReady) {
11682 // if the caller really truly claims to know what they're doing, go
11683 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011684 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11685 intent = new Intent(intent);
11686 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11687 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11688 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11689 + " before boot completion");
11690 throw new IllegalStateException("Cannot broadcast before boot completed");
11691 }
11692 }
11693
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011694 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
11695 throw new IllegalArgumentException(
11696 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
11697 }
11698
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011699 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11700 final int callingPid = Binder.getCallingPid();
11701 final int callingUid = Binder.getCallingUid();
11702 final long origId = Binder.clearCallingIdentity();
11703 int res = broadcastIntentLocked(callerApp,
11704 callerApp != null ? callerApp.info.packageName : null,
11705 intent, resolvedType, resultTo,
11706 resultCode, resultData, map, requiredPermission, serialized,
11707 sticky, callingPid, callingUid);
11708 Binder.restoreCallingIdentity(origId);
11709 return res;
11710 }
11711 }
11712
11713 int broadcastIntentInPackage(String packageName, int uid,
11714 Intent intent, String resolvedType, IIntentReceiver resultTo,
11715 int resultCode, String resultData, Bundle map,
11716 String requiredPermission, boolean serialized, boolean sticky) {
11717 synchronized(this) {
11718 final long origId = Binder.clearCallingIdentity();
11719 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11720 resultTo, resultCode, resultData, map, requiredPermission,
11721 serialized, sticky, -1, uid);
11722 Binder.restoreCallingIdentity(origId);
11723 return res;
11724 }
11725 }
11726
11727 public final void unbroadcastIntent(IApplicationThread caller,
11728 Intent intent) {
11729 // Refuse possible leaked file descriptors
11730 if (intent != null && intent.hasFileDescriptors() == true) {
11731 throw new IllegalArgumentException("File descriptors passed in Intent");
11732 }
11733
11734 synchronized(this) {
11735 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11736 != PackageManager.PERMISSION_GRANTED) {
11737 String msg = "Permission Denial: unbroadcastIntent() from pid="
11738 + Binder.getCallingPid()
11739 + ", uid=" + Binder.getCallingUid()
11740 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11741 Log.w(TAG, msg);
11742 throw new SecurityException(msg);
11743 }
11744 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11745 if (list != null) {
11746 int N = list.size();
11747 int i;
11748 for (i=0; i<N; i++) {
11749 if (intent.filterEquals(list.get(i))) {
11750 list.remove(i);
11751 break;
11752 }
11753 }
11754 }
11755 }
11756 }
11757
11758 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11759 String resultData, Bundle resultExtras, boolean resultAbort,
11760 boolean explicit) {
11761 if (mOrderedBroadcasts.size() == 0) {
11762 if (explicit) {
11763 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11764 }
11765 return false;
11766 }
11767 BroadcastRecord r = mOrderedBroadcasts.get(0);
11768 if (r.receiver == null) {
11769 if (explicit) {
11770 Log.w(TAG, "finishReceiver called but none active");
11771 }
11772 return false;
11773 }
11774 if (r.receiver != receiver) {
11775 Log.w(TAG, "finishReceiver called but active receiver is different");
11776 return false;
11777 }
11778 int state = r.state;
11779 r.state = r.IDLE;
11780 if (state == r.IDLE) {
11781 if (explicit) {
11782 Log.w(TAG, "finishReceiver called but state is IDLE");
11783 }
11784 }
11785 r.receiver = null;
11786 r.intent.setComponent(null);
11787 if (r.curApp != null) {
11788 r.curApp.curReceiver = null;
11789 }
11790 if (r.curFilter != null) {
11791 r.curFilter.receiverList.curBroadcast = null;
11792 }
11793 r.curFilter = null;
11794 r.curApp = null;
11795 r.curComponent = null;
11796 r.curReceiver = null;
11797 mPendingBroadcast = null;
11798
11799 r.resultCode = resultCode;
11800 r.resultData = resultData;
11801 r.resultExtras = resultExtras;
11802 r.resultAbort = resultAbort;
11803
11804 // We will process the next receiver right now if this is finishing
11805 // an app receiver (which is always asynchronous) or after we have
11806 // come back from calling a receiver.
11807 return state == BroadcastRecord.APP_RECEIVE
11808 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11809 }
11810
11811 public void finishReceiver(IBinder who, int resultCode, String resultData,
11812 Bundle resultExtras, boolean resultAbort) {
11813 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11814
11815 // Refuse possible leaked file descriptors
11816 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11817 throw new IllegalArgumentException("File descriptors passed in Bundle");
11818 }
11819
11820 boolean doNext;
11821
11822 final long origId = Binder.clearCallingIdentity();
11823
11824 synchronized(this) {
11825 doNext = finishReceiverLocked(
11826 who, resultCode, resultData, resultExtras, resultAbort, true);
11827 }
11828
11829 if (doNext) {
11830 processNextBroadcast(false);
11831 }
11832 trimApplications();
11833
11834 Binder.restoreCallingIdentity(origId);
11835 }
11836
11837 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11838 if (r.nextReceiver > 0) {
11839 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11840 if (curReceiver instanceof BroadcastFilter) {
11841 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11842 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11843 System.identityHashCode(r),
11844 r.intent.getAction(),
11845 r.nextReceiver - 1,
11846 System.identityHashCode(bf));
11847 } else {
11848 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11849 System.identityHashCode(r),
11850 r.intent.getAction(),
11851 r.nextReceiver - 1,
11852 ((ResolveInfo)curReceiver).toString());
11853 }
11854 } else {
11855 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11856 + r);
11857 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11858 System.identityHashCode(r),
11859 r.intent.getAction(),
11860 r.nextReceiver,
11861 "NONE");
11862 }
11863 }
11864
11865 private final void broadcastTimeout() {
11866 synchronized (this) {
11867 if (mOrderedBroadcasts.size() == 0) {
11868 return;
11869 }
11870 long now = SystemClock.uptimeMillis();
11871 BroadcastRecord r = mOrderedBroadcasts.get(0);
11872 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11873 if (DEBUG_BROADCAST) Log.v(TAG,
11874 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11875 + (r.startTime + BROADCAST_TIMEOUT));
11876 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11877 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11878 return;
11879 }
11880
11881 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11882 r.startTime = now;
11883 r.anrCount++;
11884
11885 // Current receiver has passed its expiration date.
11886 if (r.nextReceiver <= 0) {
11887 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11888 return;
11889 }
11890
11891 ProcessRecord app = null;
11892
11893 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11894 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11895 logBroadcastReceiverDiscard(r);
11896 if (curReceiver instanceof BroadcastFilter) {
11897 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11898 if (bf.receiverList.pid != 0
11899 && bf.receiverList.pid != MY_PID) {
11900 synchronized (this.mPidsSelfLocked) {
11901 app = this.mPidsSelfLocked.get(
11902 bf.receiverList.pid);
11903 }
11904 }
11905 } else {
11906 app = r.curApp;
11907 }
11908
11909 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011910 appNotRespondingLocked(app, null, null,
11911 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011912 }
11913
11914 if (mPendingBroadcast == r) {
11915 mPendingBroadcast = null;
11916 }
11917
11918 // Move on to the next receiver.
11919 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11920 r.resultExtras, r.resultAbort, true);
11921 scheduleBroadcastsLocked();
11922 }
11923 }
11924
11925 private final void processCurBroadcastLocked(BroadcastRecord r,
11926 ProcessRecord app) throws RemoteException {
11927 if (app.thread == null) {
11928 throw new RemoteException();
11929 }
11930 r.receiver = app.thread.asBinder();
11931 r.curApp = app;
11932 app.curReceiver = r;
11933 updateLRUListLocked(app, true);
11934
11935 // Tell the application to launch this receiver.
11936 r.intent.setComponent(r.curComponent);
11937
11938 boolean started = false;
11939 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011940 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011941 "Delivering to component " + r.curComponent
11942 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070011943 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011944 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11945 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11946 started = true;
11947 } finally {
11948 if (!started) {
11949 r.receiver = null;
11950 r.curApp = null;
11951 app.curReceiver = null;
11952 }
11953 }
11954
11955 }
11956
11957 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11958 Intent intent, int resultCode, String data,
11959 Bundle extras, boolean ordered) throws RemoteException {
11960 if (app != null && app.thread != null) {
11961 // If we have an app thread, do the call through that so it is
11962 // correctly ordered with other one-way calls.
11963 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11964 data, extras, ordered);
11965 } else {
11966 receiver.performReceive(intent, resultCode, data, extras, ordered);
11967 }
11968 }
11969
11970 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11971 BroadcastFilter filter, boolean ordered) {
11972 boolean skip = false;
11973 if (filter.requiredPermission != null) {
11974 int perm = checkComponentPermission(filter.requiredPermission,
11975 r.callingPid, r.callingUid, -1);
11976 if (perm != PackageManager.PERMISSION_GRANTED) {
11977 Log.w(TAG, "Permission Denial: broadcasting "
11978 + r.intent.toString()
11979 + " from " + r.callerPackage + " (pid="
11980 + r.callingPid + ", uid=" + r.callingUid + ")"
11981 + " requires " + filter.requiredPermission
11982 + " due to registered receiver " + filter);
11983 skip = true;
11984 }
11985 }
11986 if (r.requiredPermission != null) {
11987 int perm = checkComponentPermission(r.requiredPermission,
11988 filter.receiverList.pid, filter.receiverList.uid, -1);
11989 if (perm != PackageManager.PERMISSION_GRANTED) {
11990 Log.w(TAG, "Permission Denial: receiving "
11991 + r.intent.toString()
11992 + " to " + filter.receiverList.app
11993 + " (pid=" + filter.receiverList.pid
11994 + ", uid=" + filter.receiverList.uid + ")"
11995 + " requires " + r.requiredPermission
11996 + " due to sender " + r.callerPackage
11997 + " (uid " + r.callingUid + ")");
11998 skip = true;
11999 }
12000 }
12001
12002 if (!skip) {
12003 // If this is not being sent as an ordered broadcast, then we
12004 // don't want to touch the fields that keep track of the current
12005 // state of ordered broadcasts.
12006 if (ordered) {
12007 r.receiver = filter.receiverList.receiver.asBinder();
12008 r.curFilter = filter;
12009 filter.receiverList.curBroadcast = r;
12010 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012011 if (filter.receiverList.app != null) {
12012 // Bump hosting application to no longer be in background
12013 // scheduling class. Note that we can't do that if there
12014 // isn't an app... but we can only be in that case for
12015 // things that directly call the IActivityManager API, which
12016 // are already core system stuff so don't matter for this.
12017 r.curApp = filter.receiverList.app;
12018 filter.receiverList.app.curReceiver = r;
12019 updateOomAdjLocked();
12020 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012021 }
12022 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012023 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012024 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012025 Log.i(TAG, "Delivering to " + filter.receiverList.app
12026 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012027 }
12028 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12029 new Intent(r.intent), r.resultCode,
12030 r.resultData, r.resultExtras, r.ordered);
12031 if (ordered) {
12032 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12033 }
12034 } catch (RemoteException e) {
12035 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12036 if (ordered) {
12037 r.receiver = null;
12038 r.curFilter = null;
12039 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012040 if (filter.receiverList.app != null) {
12041 filter.receiverList.app.curReceiver = null;
12042 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012043 }
12044 }
12045 }
12046 }
12047
12048 private final void processNextBroadcast(boolean fromMsg) {
12049 synchronized(this) {
12050 BroadcastRecord r;
12051
12052 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12053 + mParallelBroadcasts.size() + " broadcasts, "
12054 + mOrderedBroadcasts.size() + " serialized broadcasts");
12055
12056 updateCpuStats();
12057
12058 if (fromMsg) {
12059 mBroadcastsScheduled = false;
12060 }
12061
12062 // First, deliver any non-serialized broadcasts right away.
12063 while (mParallelBroadcasts.size() > 0) {
12064 r = mParallelBroadcasts.remove(0);
12065 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012066 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12067 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012068 for (int i=0; i<N; i++) {
12069 Object target = r.receivers.get(i);
12070 if (DEBUG_BROADCAST) Log.v(TAG,
12071 "Delivering non-serialized to registered "
12072 + target + ": " + r);
12073 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12074 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012075 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12076 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012077 }
12078
12079 // Now take care of the next serialized one...
12080
12081 // If we are waiting for a process to come up to handle the next
12082 // broadcast, then do nothing at this point. Just in case, we
12083 // check that the process we're waiting for still exists.
12084 if (mPendingBroadcast != null) {
12085 Log.i(TAG, "processNextBroadcast: waiting for "
12086 + mPendingBroadcast.curApp);
12087
12088 boolean isDead;
12089 synchronized (mPidsSelfLocked) {
12090 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12091 }
12092 if (!isDead) {
12093 // It's still alive, so keep waiting
12094 return;
12095 } else {
12096 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12097 + " died before responding to broadcast");
12098 mPendingBroadcast = null;
12099 }
12100 }
12101
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012102 boolean looped = false;
12103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012104 do {
12105 if (mOrderedBroadcasts.size() == 0) {
12106 // No more broadcasts pending, so all done!
12107 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012108 if (looped) {
12109 // If we had finished the last ordered broadcast, then
12110 // make sure all processes have correct oom and sched
12111 // adjustments.
12112 updateOomAdjLocked();
12113 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012114 return;
12115 }
12116 r = mOrderedBroadcasts.get(0);
12117 boolean forceReceive = false;
12118
12119 // Ensure that even if something goes awry with the timeout
12120 // detection, we catch "hung" broadcasts here, discard them,
12121 // and continue to make progress.
12122 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12123 long now = SystemClock.uptimeMillis();
12124 if (r.dispatchTime > 0) {
12125 if ((numReceivers > 0) &&
12126 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12127 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12128 + " now=" + now
12129 + " dispatchTime=" + r.dispatchTime
12130 + " startTime=" + r.startTime
12131 + " intent=" + r.intent
12132 + " numReceivers=" + numReceivers
12133 + " nextReceiver=" + r.nextReceiver
12134 + " state=" + r.state);
12135 broadcastTimeout(); // forcibly finish this broadcast
12136 forceReceive = true;
12137 r.state = BroadcastRecord.IDLE;
12138 }
12139 }
12140
12141 if (r.state != BroadcastRecord.IDLE) {
12142 if (DEBUG_BROADCAST) Log.d(TAG,
12143 "processNextBroadcast() called when not idle (state="
12144 + r.state + ")");
12145 return;
12146 }
12147
12148 if (r.receivers == null || r.nextReceiver >= numReceivers
12149 || r.resultAbort || forceReceive) {
12150 // No more receivers for this broadcast! Send the final
12151 // result if requested...
12152 if (r.resultTo != null) {
12153 try {
12154 if (DEBUG_BROADCAST) {
12155 int seq = r.intent.getIntExtra("seq", -1);
12156 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12157 + " seq=" + seq + " app=" + r.callerApp);
12158 }
12159 performReceive(r.callerApp, r.resultTo,
12160 new Intent(r.intent), r.resultCode,
12161 r.resultData, r.resultExtras, false);
12162 } catch (RemoteException e) {
12163 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12164 }
12165 }
12166
12167 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12168 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12169
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012170 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12171 + r);
12172
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012173 // ... and on to the next...
12174 mOrderedBroadcasts.remove(0);
12175 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012176 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012177 continue;
12178 }
12179 } while (r == null);
12180
12181 // Get the next receiver...
12182 int recIdx = r.nextReceiver++;
12183
12184 // Keep track of when this receiver started, and make sure there
12185 // is a timeout message pending to kill it if need be.
12186 r.startTime = SystemClock.uptimeMillis();
12187 if (recIdx == 0) {
12188 r.dispatchTime = r.startTime;
12189
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012190 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12191 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012192 if (DEBUG_BROADCAST) Log.v(TAG,
12193 "Submitting BROADCAST_TIMEOUT_MSG for "
12194 + (r.startTime + BROADCAST_TIMEOUT));
12195 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12196 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12197 }
12198
12199 Object nextReceiver = r.receivers.get(recIdx);
12200 if (nextReceiver instanceof BroadcastFilter) {
12201 // Simple case: this is a registered receiver who gets
12202 // a direct call.
12203 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12204 if (DEBUG_BROADCAST) Log.v(TAG,
12205 "Delivering serialized to registered "
12206 + filter + ": " + r);
12207 deliverToRegisteredReceiver(r, filter, r.ordered);
12208 if (r.receiver == null || !r.ordered) {
12209 // The receiver has already finished, so schedule to
12210 // process the next one.
12211 r.state = BroadcastRecord.IDLE;
12212 scheduleBroadcastsLocked();
12213 }
12214 return;
12215 }
12216
12217 // Hard case: need to instantiate the receiver, possibly
12218 // starting its application process to host it.
12219
12220 ResolveInfo info =
12221 (ResolveInfo)nextReceiver;
12222
12223 boolean skip = false;
12224 int perm = checkComponentPermission(info.activityInfo.permission,
12225 r.callingPid, r.callingUid,
12226 info.activityInfo.exported
12227 ? -1 : info.activityInfo.applicationInfo.uid);
12228 if (perm != PackageManager.PERMISSION_GRANTED) {
12229 Log.w(TAG, "Permission Denial: broadcasting "
12230 + r.intent.toString()
12231 + " from " + r.callerPackage + " (pid=" + r.callingPid
12232 + ", uid=" + r.callingUid + ")"
12233 + " requires " + info.activityInfo.permission
12234 + " due to receiver " + info.activityInfo.packageName
12235 + "/" + info.activityInfo.name);
12236 skip = true;
12237 }
12238 if (r.callingUid != Process.SYSTEM_UID &&
12239 r.requiredPermission != null) {
12240 try {
12241 perm = ActivityThread.getPackageManager().
12242 checkPermission(r.requiredPermission,
12243 info.activityInfo.applicationInfo.packageName);
12244 } catch (RemoteException e) {
12245 perm = PackageManager.PERMISSION_DENIED;
12246 }
12247 if (perm != PackageManager.PERMISSION_GRANTED) {
12248 Log.w(TAG, "Permission Denial: receiving "
12249 + r.intent + " to "
12250 + info.activityInfo.applicationInfo.packageName
12251 + " requires " + r.requiredPermission
12252 + " due to sender " + r.callerPackage
12253 + " (uid " + r.callingUid + ")");
12254 skip = true;
12255 }
12256 }
12257 if (r.curApp != null && r.curApp.crashing) {
12258 // If the target process is crashing, just skip it.
12259 skip = true;
12260 }
12261
12262 if (skip) {
12263 r.receiver = null;
12264 r.curFilter = null;
12265 r.state = BroadcastRecord.IDLE;
12266 scheduleBroadcastsLocked();
12267 return;
12268 }
12269
12270 r.state = BroadcastRecord.APP_RECEIVE;
12271 String targetProcess = info.activityInfo.processName;
12272 r.curComponent = new ComponentName(
12273 info.activityInfo.applicationInfo.packageName,
12274 info.activityInfo.name);
12275 r.curReceiver = info.activityInfo;
12276
12277 // Is this receiver's application already running?
12278 ProcessRecord app = getProcessRecordLocked(targetProcess,
12279 info.activityInfo.applicationInfo.uid);
12280 if (app != null && app.thread != null) {
12281 try {
12282 processCurBroadcastLocked(r, app);
12283 return;
12284 } catch (RemoteException e) {
12285 Log.w(TAG, "Exception when sending broadcast to "
12286 + r.curComponent, e);
12287 }
12288
12289 // If a dead object exception was thrown -- fall through to
12290 // restart the application.
12291 }
12292
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012293 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012294 if ((r.curApp=startProcessLocked(targetProcess,
12295 info.activityInfo.applicationInfo, true,
12296 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012297 "broadcast", r.curComponent,
12298 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12299 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012300 // Ah, this recipient is unavailable. Finish it if necessary,
12301 // and mark the broadcast record as ready for the next.
12302 Log.w(TAG, "Unable to launch app "
12303 + info.activityInfo.applicationInfo.packageName + "/"
12304 + info.activityInfo.applicationInfo.uid + " for broadcast "
12305 + r.intent + ": process is bad");
12306 logBroadcastReceiverDiscard(r);
12307 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12308 r.resultExtras, r.resultAbort, true);
12309 scheduleBroadcastsLocked();
12310 r.state = BroadcastRecord.IDLE;
12311 return;
12312 }
12313
12314 mPendingBroadcast = r;
12315 }
12316 }
12317
12318 // =========================================================
12319 // INSTRUMENTATION
12320 // =========================================================
12321
12322 public boolean startInstrumentation(ComponentName className,
12323 String profileFile, int flags, Bundle arguments,
12324 IInstrumentationWatcher watcher) {
12325 // Refuse possible leaked file descriptors
12326 if (arguments != null && arguments.hasFileDescriptors()) {
12327 throw new IllegalArgumentException("File descriptors passed in Bundle");
12328 }
12329
12330 synchronized(this) {
12331 InstrumentationInfo ii = null;
12332 ApplicationInfo ai = null;
12333 try {
12334 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012335 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012336 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012337 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012338 } catch (PackageManager.NameNotFoundException e) {
12339 }
12340 if (ii == null) {
12341 reportStartInstrumentationFailure(watcher, className,
12342 "Unable to find instrumentation info for: " + className);
12343 return false;
12344 }
12345 if (ai == null) {
12346 reportStartInstrumentationFailure(watcher, className,
12347 "Unable to find instrumentation target package: " + ii.targetPackage);
12348 return false;
12349 }
12350
12351 int match = mContext.getPackageManager().checkSignatures(
12352 ii.targetPackage, ii.packageName);
12353 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12354 String msg = "Permission Denial: starting instrumentation "
12355 + className + " from pid="
12356 + Binder.getCallingPid()
12357 + ", uid=" + Binder.getCallingPid()
12358 + " not allowed because package " + ii.packageName
12359 + " does not have a signature matching the target "
12360 + ii.targetPackage;
12361 reportStartInstrumentationFailure(watcher, className, msg);
12362 throw new SecurityException(msg);
12363 }
12364
12365 final long origId = Binder.clearCallingIdentity();
12366 uninstallPackageLocked(ii.targetPackage, -1, true);
12367 ProcessRecord app = addAppLocked(ai);
12368 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012369 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012370 app.instrumentationProfileFile = profileFile;
12371 app.instrumentationArguments = arguments;
12372 app.instrumentationWatcher = watcher;
12373 app.instrumentationResultClass = className;
12374 Binder.restoreCallingIdentity(origId);
12375 }
12376
12377 return true;
12378 }
12379
12380 /**
12381 * Report errors that occur while attempting to start Instrumentation. Always writes the
12382 * error to the logs, but if somebody is watching, send the report there too. This enables
12383 * the "am" command to report errors with more information.
12384 *
12385 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12386 * @param cn The component name of the instrumentation.
12387 * @param report The error report.
12388 */
12389 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12390 ComponentName cn, String report) {
12391 Log.w(TAG, report);
12392 try {
12393 if (watcher != null) {
12394 Bundle results = new Bundle();
12395 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12396 results.putString("Error", report);
12397 watcher.instrumentationStatus(cn, -1, results);
12398 }
12399 } catch (RemoteException e) {
12400 Log.w(TAG, e);
12401 }
12402 }
12403
12404 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12405 if (app.instrumentationWatcher != null) {
12406 try {
12407 // NOTE: IInstrumentationWatcher *must* be oneway here
12408 app.instrumentationWatcher.instrumentationFinished(
12409 app.instrumentationClass,
12410 resultCode,
12411 results);
12412 } catch (RemoteException e) {
12413 }
12414 }
12415 app.instrumentationWatcher = null;
12416 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012417 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012418 app.instrumentationProfileFile = null;
12419 app.instrumentationArguments = null;
12420
12421 uninstallPackageLocked(app.processName, -1, false);
12422 }
12423
12424 public void finishInstrumentation(IApplicationThread target,
12425 int resultCode, Bundle results) {
12426 // Refuse possible leaked file descriptors
12427 if (results != null && results.hasFileDescriptors()) {
12428 throw new IllegalArgumentException("File descriptors passed in Intent");
12429 }
12430
12431 synchronized(this) {
12432 ProcessRecord app = getRecordForAppLocked(target);
12433 if (app == null) {
12434 Log.w(TAG, "finishInstrumentation: no app for " + target);
12435 return;
12436 }
12437 final long origId = Binder.clearCallingIdentity();
12438 finishInstrumentationLocked(app, resultCode, results);
12439 Binder.restoreCallingIdentity(origId);
12440 }
12441 }
12442
12443 // =========================================================
12444 // CONFIGURATION
12445 // =========================================================
12446
12447 public ConfigurationInfo getDeviceConfigurationInfo() {
12448 ConfigurationInfo config = new ConfigurationInfo();
12449 synchronized (this) {
12450 config.reqTouchScreen = mConfiguration.touchscreen;
12451 config.reqKeyboardType = mConfiguration.keyboard;
12452 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012453 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12454 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012455 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12456 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012457 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12458 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012459 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12460 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012461 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012462 }
12463 return config;
12464 }
12465
12466 public Configuration getConfiguration() {
12467 Configuration ci;
12468 synchronized(this) {
12469 ci = new Configuration(mConfiguration);
12470 }
12471 return ci;
12472 }
12473
12474 public void updateConfiguration(Configuration values) {
12475 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12476 "updateConfiguration()");
12477
12478 synchronized(this) {
12479 if (values == null && mWindowManager != null) {
12480 // sentinel: fetch the current configuration from the window manager
12481 values = mWindowManager.computeNewConfiguration();
12482 }
12483
12484 final long origId = Binder.clearCallingIdentity();
12485 updateConfigurationLocked(values, null);
12486 Binder.restoreCallingIdentity(origId);
12487 }
12488 }
12489
12490 /**
12491 * Do either or both things: (1) change the current configuration, and (2)
12492 * make sure the given activity is running with the (now) current
12493 * configuration. Returns true if the activity has been left running, or
12494 * false if <var>starting</var> is being destroyed to match the new
12495 * configuration.
12496 */
12497 public boolean updateConfigurationLocked(Configuration values,
12498 HistoryRecord starting) {
12499 int changes = 0;
12500
12501 boolean kept = true;
12502
12503 if (values != null) {
12504 Configuration newConfig = new Configuration(mConfiguration);
12505 changes = newConfig.updateFrom(values);
12506 if (changes != 0) {
12507 if (DEBUG_SWITCH) {
12508 Log.i(TAG, "Updating configuration to: " + values);
12509 }
12510
12511 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12512
12513 if (values.locale != null) {
12514 saveLocaleLocked(values.locale,
12515 !values.locale.equals(mConfiguration.locale),
12516 values.userSetLocale);
12517 }
12518
12519 mConfiguration = newConfig;
12520
12521 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12522 msg.obj = new Configuration(mConfiguration);
12523 mHandler.sendMessage(msg);
12524
12525 final int N = mLRUProcesses.size();
12526 for (int i=0; i<N; i++) {
12527 ProcessRecord app = mLRUProcesses.get(i);
12528 try {
12529 if (app.thread != null) {
12530 app.thread.scheduleConfigurationChanged(mConfiguration);
12531 }
12532 } catch (Exception e) {
12533 }
12534 }
12535 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12536 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12537 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012538
12539 AttributeCache ac = AttributeCache.instance();
12540 if (ac != null) {
12541 ac.updateConfiguration(mConfiguration);
12542 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012543 }
12544 }
12545
12546 if (changes != 0 && starting == null) {
12547 // If the configuration changed, and the caller is not already
12548 // in the process of starting an activity, then find the top
12549 // activity to check if its configuration needs to change.
12550 starting = topRunningActivityLocked(null);
12551 }
12552
12553 if (starting != null) {
12554 kept = ensureActivityConfigurationLocked(starting, changes);
12555 if (kept) {
12556 // If this didn't result in the starting activity being
12557 // destroyed, then we need to make sure at this point that all
12558 // other activities are made visible.
12559 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12560 + ", ensuring others are correct.");
12561 ensureActivitiesVisibleLocked(starting, changes);
12562 }
12563 }
12564
12565 return kept;
12566 }
12567
12568 private final boolean relaunchActivityLocked(HistoryRecord r,
12569 int changes, boolean andResume) {
12570 List<ResultInfo> results = null;
12571 List<Intent> newIntents = null;
12572 if (andResume) {
12573 results = r.results;
12574 newIntents = r.newIntents;
12575 }
12576 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12577 + " with results=" + results + " newIntents=" + newIntents
12578 + " andResume=" + andResume);
12579 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12580 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12581 r.task.taskId, r.shortComponentName);
12582
12583 r.startFreezingScreenLocked(r.app, 0);
12584
12585 try {
12586 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12587 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12588 changes, !andResume);
12589 // Note: don't need to call pauseIfSleepingLocked() here, because
12590 // the caller will only pass in 'andResume' if this activity is
12591 // currently resumed, which implies we aren't sleeping.
12592 } catch (RemoteException e) {
12593 return false;
12594 }
12595
12596 if (andResume) {
12597 r.results = null;
12598 r.newIntents = null;
12599 }
12600
12601 return true;
12602 }
12603
12604 /**
12605 * Make sure the given activity matches the current configuration. Returns
12606 * false if the activity had to be destroyed. Returns true if the
12607 * configuration is the same, or the activity will remain running as-is
12608 * for whatever reason. Ensures the HistoryRecord is updated with the
12609 * correct configuration and all other bookkeeping is handled.
12610 */
12611 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12612 int globalChanges) {
12613 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12614
12615 // Short circuit: if the two configurations are the exact same
12616 // object (the common case), then there is nothing to do.
12617 Configuration newConfig = mConfiguration;
12618 if (r.configuration == newConfig) {
12619 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12620 return true;
12621 }
12622
12623 // We don't worry about activities that are finishing.
12624 if (r.finishing) {
12625 if (DEBUG_SWITCH) Log.i(TAG,
12626 "Configuration doesn't matter in finishing " + r);
12627 r.stopFreezingScreenLocked(false);
12628 return true;
12629 }
12630
12631 // Okay we now are going to make this activity have the new config.
12632 // But then we need to figure out how it needs to deal with that.
12633 Configuration oldConfig = r.configuration;
12634 r.configuration = newConfig;
12635
12636 // If the activity isn't currently running, just leave the new
12637 // configuration and it will pick that up next time it starts.
12638 if (r.app == null || r.app.thread == null) {
12639 if (DEBUG_SWITCH) Log.i(TAG,
12640 "Configuration doesn't matter not running " + r);
12641 r.stopFreezingScreenLocked(false);
12642 return true;
12643 }
12644
12645 // If the activity isn't persistent, there is a chance we will
12646 // need to restart it.
12647 if (!r.persistent) {
12648
12649 // Figure out what has changed between the two configurations.
12650 int changes = oldConfig.diff(newConfig);
12651 if (DEBUG_SWITCH) {
12652 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12653 + Integer.toHexString(changes) + ", handles=0x"
12654 + Integer.toHexString(r.info.configChanges));
12655 }
12656 if ((changes&(~r.info.configChanges)) != 0) {
12657 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12658 r.configChangeFlags |= changes;
12659 r.startFreezingScreenLocked(r.app, globalChanges);
12660 if (r.app == null || r.app.thread == null) {
12661 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12662 destroyActivityLocked(r, true);
12663 } else if (r.state == ActivityState.PAUSING) {
12664 // A little annoying: we are waiting for this activity to
12665 // finish pausing. Let's not do anything now, but just
12666 // flag that it needs to be restarted when done pausing.
12667 r.configDestroy = true;
12668 return true;
12669 } else if (r.state == ActivityState.RESUMED) {
12670 // Try to optimize this case: the configuration is changing
12671 // and we need to restart the top, resumed activity.
12672 // Instead of doing the normal handshaking, just say
12673 // "restart!".
12674 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12675 relaunchActivityLocked(r, r.configChangeFlags, true);
12676 r.configChangeFlags = 0;
12677 } else {
12678 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12679 relaunchActivityLocked(r, r.configChangeFlags, false);
12680 r.configChangeFlags = 0;
12681 }
12682
12683 // All done... tell the caller we weren't able to keep this
12684 // activity around.
12685 return false;
12686 }
12687 }
12688
12689 // Default case: the activity can handle this new configuration, so
12690 // hand it over. Note that we don't need to give it the new
12691 // configuration, since we always send configuration changes to all
12692 // process when they happen so it can just use whatever configuration
12693 // it last got.
12694 if (r.app != null && r.app.thread != null) {
12695 try {
12696 r.app.thread.scheduleActivityConfigurationChanged(r);
12697 } catch (RemoteException e) {
12698 // If process died, whatever.
12699 }
12700 }
12701 r.stopFreezingScreenLocked(false);
12702
12703 return true;
12704 }
12705
12706 /**
12707 * Save the locale. You must be inside a synchronized (this) block.
12708 */
12709 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12710 if(isDiff) {
12711 SystemProperties.set("user.language", l.getLanguage());
12712 SystemProperties.set("user.region", l.getCountry());
12713 }
12714
12715 if(isPersist) {
12716 SystemProperties.set("persist.sys.language", l.getLanguage());
12717 SystemProperties.set("persist.sys.country", l.getCountry());
12718 SystemProperties.set("persist.sys.localevar", l.getVariant());
12719 }
12720 }
12721
12722 // =========================================================
12723 // LIFETIME MANAGEMENT
12724 // =========================================================
12725
12726 private final int computeOomAdjLocked(
12727 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12728 if (mAdjSeq == app.adjSeq) {
12729 // This adjustment has already been computed.
12730 return app.curAdj;
12731 }
12732
12733 if (app.thread == null) {
12734 app.adjSeq = mAdjSeq;
12735 return (app.curAdj=EMPTY_APP_ADJ);
12736 }
12737
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012738 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
12739 // The max adjustment doesn't allow this app to be anything
12740 // below foreground, so it is not worth doing work for it.
12741 app.adjType = "fixed";
12742 app.adjSeq = mAdjSeq;
12743 app.curRawAdj = app.maxAdj;
12744 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
12745 return (app.curAdj=app.maxAdj);
12746 }
12747
12748 app.adjSource = null;
12749 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012750
The Android Open Source Project4df24232009-03-05 14:34:35 -080012751 // Determine the importance of the process, starting with most
12752 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012753 int adj;
12754 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012755 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012756 // The last app on the list is the foreground app.
12757 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012758 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012759 } else if (app.instrumentationClass != null) {
12760 // Don't want to kill running instrumentation.
12761 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012762 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012763 } else if (app.persistentActivities > 0) {
12764 // Special persistent activities... shouldn't be used these days.
12765 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012766 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012767 } else if (app.curReceiver != null ||
12768 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12769 // An app that is currently receiving a broadcast also
12770 // counts as being in the foreground.
12771 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012772 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012773 } else if (app.executingServices.size() > 0) {
12774 // An app that is currently executing a service callback also
12775 // counts as being in the foreground.
12776 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012777 app.adjType = "exec-service";
12778 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012779 // The user is aware of this app, so make it visible.
12780 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012781 app.adjType = "foreground-service";
12782 } else if (app.forcingToForeground != null) {
12783 // The user is aware of this app, so make it visible.
12784 adj = VISIBLE_APP_ADJ;
12785 app.adjType = "force-foreground";
12786 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012787 } else if (app == mHomeProcess) {
12788 // This process is hosting what we currently consider to be the
12789 // home app, so we don't want to let it go into the background.
12790 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012791 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012792 } else if ((N=app.activities.size()) != 0) {
12793 // This app is in the background with paused activities.
12794 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012795 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012796 for (int j=0; j<N; j++) {
12797 if (((HistoryRecord)app.activities.get(j)).visible) {
12798 // This app has a visible activity!
12799 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012800 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012801 break;
12802 }
12803 }
12804 } else {
12805 // A very not-needed process.
12806 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012807 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012808 }
12809
The Android Open Source Project4df24232009-03-05 14:34:35 -080012810 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012811 // there are applications dependent on our services or providers, but
12812 // this gives us a baseline and makes sure we don't get into an
12813 // infinite recursion.
12814 app.adjSeq = mAdjSeq;
12815 app.curRawAdj = adj;
12816 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12817
Christopher Tate6fa95972009-06-05 18:43:55 -070012818 if (mBackupTarget != null && app == mBackupTarget.app) {
12819 // If possible we want to avoid killing apps while they're being backed up
12820 if (adj > BACKUP_APP_ADJ) {
12821 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12822 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012823 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070012824 }
12825 }
12826
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012827 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12828 // If this process has active services running in it, we would
12829 // like to avoid killing it unless it would prevent the current
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012830 // application from running. By default we put the process in
12831 // with the rest of the background processes; as we scan through
12832 // its services we may bump it up from there.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012833 if (adj > hiddenAdj) {
12834 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012835 app.adjType = "bg-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012836 }
12837 final long now = SystemClock.uptimeMillis();
12838 // This process is more important if the top activity is
12839 // bound to the service.
12840 Iterator jt = app.services.iterator();
12841 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12842 ServiceRecord s = (ServiceRecord)jt.next();
12843 if (s.startRequested) {
12844 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12845 // This service has seen some activity within
12846 // recent memory, so we will keep its process ahead
12847 // of the background processes.
12848 if (adj > SECONDARY_SERVER_ADJ) {
12849 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012850 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012851 }
12852 }
12853 }
12854 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12855 Iterator<ConnectionRecord> kt
12856 = s.connections.values().iterator();
12857 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12858 // XXX should compute this based on the max of
12859 // all connected clients.
12860 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012861 if (cr.binding.client == app) {
12862 // Binding to ourself is not interesting.
12863 continue;
12864 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012865 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12866 ProcessRecord client = cr.binding.client;
12867 int myHiddenAdj = hiddenAdj;
12868 if (myHiddenAdj > client.hiddenAdj) {
12869 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12870 myHiddenAdj = client.hiddenAdj;
12871 } else {
12872 myHiddenAdj = VISIBLE_APP_ADJ;
12873 }
12874 }
12875 int clientAdj = computeOomAdjLocked(
12876 client, myHiddenAdj, TOP_APP);
12877 if (adj > clientAdj) {
12878 adj = clientAdj > VISIBLE_APP_ADJ
12879 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012880 app.adjType = "service";
12881 app.adjSource = cr.binding.client;
12882 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012883 }
12884 }
12885 HistoryRecord a = cr.activity;
12886 //if (a != null) {
12887 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12888 //}
12889 if (a != null && adj > FOREGROUND_APP_ADJ &&
12890 (a.state == ActivityState.RESUMED
12891 || a.state == ActivityState.PAUSING)) {
12892 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012893 app.adjType = "service";
12894 app.adjSource = a;
12895 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012896 }
12897 }
12898 }
12899 }
12900 }
12901
12902 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12903 // If this process has published any content providers, then
12904 // its adjustment makes it at least as important as any of the
12905 // processes using those providers, and no less important than
12906 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12907 if (adj > CONTENT_PROVIDER_ADJ) {
12908 adj = CONTENT_PROVIDER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012909 app.adjType = "pub-providers";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012910 }
12911 Iterator jt = app.pubProviders.values().iterator();
12912 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12913 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12914 if (cpr.clients.size() != 0) {
12915 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12916 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12917 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012918 if (client == app) {
12919 // Being our own client is not interesting.
12920 continue;
12921 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012922 int myHiddenAdj = hiddenAdj;
12923 if (myHiddenAdj > client.hiddenAdj) {
12924 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12925 myHiddenAdj = client.hiddenAdj;
12926 } else {
12927 myHiddenAdj = FOREGROUND_APP_ADJ;
12928 }
12929 }
12930 int clientAdj = computeOomAdjLocked(
12931 client, myHiddenAdj, TOP_APP);
12932 if (adj > clientAdj) {
12933 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012934 ? clientAdj : FOREGROUND_APP_ADJ;
12935 app.adjType = "provider";
12936 app.adjSource = client;
12937 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012938 }
12939 }
12940 }
12941 // If the provider has external (non-framework) process
12942 // dependencies, ensure that its adjustment is at least
12943 // FOREGROUND_APP_ADJ.
12944 if (cpr.externals != 0) {
12945 if (adj > FOREGROUND_APP_ADJ) {
12946 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012947 app.adjType = "provider";
12948 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012949 }
12950 }
12951 }
12952 }
12953
12954 app.curRawAdj = adj;
12955
12956 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12957 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12958 if (adj > app.maxAdj) {
12959 adj = app.maxAdj;
12960 }
12961
12962 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012963 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012964 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12965 : Process.THREAD_GROUP_DEFAULT;
12966
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012967 return adj;
12968 }
12969
12970 /**
12971 * Ask a given process to GC right now.
12972 */
12973 final void performAppGcLocked(ProcessRecord app) {
12974 try {
12975 app.lastRequestedGc = SystemClock.uptimeMillis();
12976 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012977 if (app.reportLowMemory) {
12978 app.reportLowMemory = false;
12979 app.thread.scheduleLowMemory();
12980 } else {
12981 app.thread.processInBackground();
12982 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012983 }
12984 } catch (Exception e) {
12985 // whatever.
12986 }
12987 }
12988
12989 /**
12990 * Returns true if things are idle enough to perform GCs.
12991 */
12992 private final boolean canGcNow() {
12993 return mParallelBroadcasts.size() == 0
12994 && mOrderedBroadcasts.size() == 0
12995 && (mSleeping || (mResumedActivity != null &&
12996 mResumedActivity.idle));
12997 }
12998
12999 /**
13000 * Perform GCs on all processes that are waiting for it, but only
13001 * if things are idle.
13002 */
13003 final void performAppGcsLocked() {
13004 final int N = mProcessesToGc.size();
13005 if (N <= 0) {
13006 return;
13007 }
13008 if (canGcNow()) {
13009 while (mProcessesToGc.size() > 0) {
13010 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013011 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13012 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13013 <= SystemClock.uptimeMillis()) {
13014 // To avoid spamming the system, we will GC processes one
13015 // at a time, waiting a few seconds between each.
13016 performAppGcLocked(proc);
13017 scheduleAppGcsLocked();
13018 return;
13019 } else {
13020 // It hasn't been long enough since we last GCed this
13021 // process... put it in the list to wait for its time.
13022 addProcessToGcListLocked(proc);
13023 break;
13024 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013025 }
13026 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013027
13028 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013029 }
13030 }
13031
13032 /**
13033 * If all looks good, perform GCs on all processes waiting for them.
13034 */
13035 final void performAppGcsIfAppropriateLocked() {
13036 if (canGcNow()) {
13037 performAppGcsLocked();
13038 return;
13039 }
13040 // Still not idle, wait some more.
13041 scheduleAppGcsLocked();
13042 }
13043
13044 /**
13045 * Schedule the execution of all pending app GCs.
13046 */
13047 final void scheduleAppGcsLocked() {
13048 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013049
13050 if (mProcessesToGc.size() > 0) {
13051 // Schedule a GC for the time to the next process.
13052 ProcessRecord proc = mProcessesToGc.get(0);
13053 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13054
13055 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13056 long now = SystemClock.uptimeMillis();
13057 if (when < (now+GC_TIMEOUT)) {
13058 when = now + GC_TIMEOUT;
13059 }
13060 mHandler.sendMessageAtTime(msg, when);
13061 }
13062 }
13063
13064 /**
13065 * Add a process to the array of processes waiting to be GCed. Keeps the
13066 * list in sorted order by the last GC time. The process can't already be
13067 * on the list.
13068 */
13069 final void addProcessToGcListLocked(ProcessRecord proc) {
13070 boolean added = false;
13071 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13072 if (mProcessesToGc.get(i).lastRequestedGc <
13073 proc.lastRequestedGc) {
13074 added = true;
13075 mProcessesToGc.add(i+1, proc);
13076 break;
13077 }
13078 }
13079 if (!added) {
13080 mProcessesToGc.add(0, proc);
13081 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013082 }
13083
13084 /**
13085 * Set up to ask a process to GC itself. This will either do it
13086 * immediately, or put it on the list of processes to gc the next
13087 * time things are idle.
13088 */
13089 final void scheduleAppGcLocked(ProcessRecord app) {
13090 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013091 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013092 return;
13093 }
13094 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013095 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013096 scheduleAppGcsLocked();
13097 }
13098 }
13099
13100 private final boolean updateOomAdjLocked(
13101 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13102 app.hiddenAdj = hiddenAdj;
13103
13104 if (app.thread == null) {
13105 return true;
13106 }
13107
13108 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
13109
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013110 if (app.pid != 0 && app.pid != MY_PID) {
13111 if (app.curRawAdj != app.setRawAdj) {
13112 if (app.curRawAdj > FOREGROUND_APP_ADJ
13113 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13114 // If this app is transitioning from foreground to
13115 // non-foreground, have it do a gc.
13116 scheduleAppGcLocked(app);
13117 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13118 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13119 // Likewise do a gc when an app is moving in to the
13120 // background (such as a service stopping).
13121 scheduleAppGcLocked(app);
13122 }
13123 app.setRawAdj = app.curRawAdj;
13124 }
13125 if (adj != app.setAdj) {
13126 if (Process.setOomAdj(app.pid, adj)) {
13127 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13128 TAG, "Set app " + app.processName +
13129 " oom adj to " + adj);
13130 app.setAdj = adj;
13131 } else {
13132 return false;
13133 }
13134 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013135 if (app.setSchedGroup != app.curSchedGroup) {
13136 app.setSchedGroup = app.curSchedGroup;
13137 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13138 "Setting process group of " + app.processName
13139 + " to " + app.curSchedGroup);
13140 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013141 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013142 try {
13143 Process.setProcessGroup(app.pid, app.curSchedGroup);
13144 } catch (Exception e) {
13145 Log.w(TAG, "Failed setting process group of " + app.pid
13146 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013147 e.printStackTrace();
13148 } finally {
13149 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013150 }
13151 }
13152 if (false) {
13153 if (app.thread != null) {
13154 try {
13155 app.thread.setSchedulingGroup(app.curSchedGroup);
13156 } catch (RemoteException e) {
13157 }
13158 }
13159 }
13160 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013161 }
13162
13163 return true;
13164 }
13165
13166 private final HistoryRecord resumedAppLocked() {
13167 HistoryRecord resumedActivity = mResumedActivity;
13168 if (resumedActivity == null || resumedActivity.app == null) {
13169 resumedActivity = mPausingActivity;
13170 if (resumedActivity == null || resumedActivity.app == null) {
13171 resumedActivity = topRunningActivityLocked(null);
13172 }
13173 }
13174 return resumedActivity;
13175 }
13176
13177 private final boolean updateOomAdjLocked(ProcessRecord app) {
13178 final HistoryRecord TOP_ACT = resumedAppLocked();
13179 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13180 int curAdj = app.curAdj;
13181 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13182 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13183
13184 mAdjSeq++;
13185
13186 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13187 if (res) {
13188 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13189 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13190 if (nowHidden != wasHidden) {
13191 // Changed to/from hidden state, so apps after it in the LRU
13192 // list may also be changed.
13193 updateOomAdjLocked();
13194 }
13195 }
13196 return res;
13197 }
13198
13199 private final boolean updateOomAdjLocked() {
13200 boolean didOomAdj = true;
13201 final HistoryRecord TOP_ACT = resumedAppLocked();
13202 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13203
13204 if (false) {
13205 RuntimeException e = new RuntimeException();
13206 e.fillInStackTrace();
13207 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13208 }
13209
13210 mAdjSeq++;
13211
13212 // First try updating the OOM adjustment for each of the
13213 // application processes based on their current state.
13214 int i = mLRUProcesses.size();
13215 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13216 while (i > 0) {
13217 i--;
13218 ProcessRecord app = mLRUProcesses.get(i);
13219 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13220 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13221 && app.curAdj == curHiddenAdj) {
13222 curHiddenAdj++;
13223 }
13224 } else {
13225 didOomAdj = false;
13226 }
13227 }
13228
13229 // todo: for now pretend like OOM ADJ didn't work, because things
13230 // aren't behaving as expected on Linux -- it's not killing processes.
13231 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13232 }
13233
13234 private final void trimApplications() {
13235 synchronized (this) {
13236 int i;
13237
13238 // First remove any unused application processes whose package
13239 // has been removed.
13240 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13241 final ProcessRecord app = mRemovedProcesses.get(i);
13242 if (app.activities.size() == 0
13243 && app.curReceiver == null && app.services.size() == 0) {
13244 Log.i(
13245 TAG, "Exiting empty application process "
13246 + app.processName + " ("
13247 + (app.thread != null ? app.thread.asBinder() : null)
13248 + ")\n");
13249 if (app.pid > 0 && app.pid != MY_PID) {
13250 Process.killProcess(app.pid);
13251 } else {
13252 try {
13253 app.thread.scheduleExit();
13254 } catch (Exception e) {
13255 // Ignore exceptions.
13256 }
13257 }
13258 cleanUpApplicationRecordLocked(app, false, -1);
13259 mRemovedProcesses.remove(i);
13260
13261 if (app.persistent) {
13262 if (app.persistent) {
13263 addAppLocked(app.info);
13264 }
13265 }
13266 }
13267 }
13268
13269 // Now try updating the OOM adjustment for each of the
13270 // application processes based on their current state.
13271 // If the setOomAdj() API is not supported, then go with our
13272 // back-up plan...
13273 if (!updateOomAdjLocked()) {
13274
13275 // Count how many processes are running services.
13276 int numServiceProcs = 0;
13277 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13278 final ProcessRecord app = mLRUProcesses.get(i);
13279
13280 if (app.persistent || app.services.size() != 0
13281 || app.curReceiver != null
13282 || app.persistentActivities > 0) {
13283 // Don't count processes holding services against our
13284 // maximum process count.
13285 if (localLOGV) Log.v(
13286 TAG, "Not trimming app " + app + " with services: "
13287 + app.services);
13288 numServiceProcs++;
13289 }
13290 }
13291
13292 int curMaxProcs = mProcessLimit;
13293 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13294 if (mAlwaysFinishActivities) {
13295 curMaxProcs = 1;
13296 }
13297 curMaxProcs += numServiceProcs;
13298
13299 // Quit as many processes as we can to get down to the desired
13300 // process count. First remove any processes that no longer
13301 // have activites running in them.
13302 for ( i=0;
13303 i<mLRUProcesses.size()
13304 && mLRUProcesses.size() > curMaxProcs;
13305 i++) {
13306 final ProcessRecord app = mLRUProcesses.get(i);
13307 // Quit an application only if it is not currently
13308 // running any activities.
13309 if (!app.persistent && app.activities.size() == 0
13310 && app.curReceiver == null && app.services.size() == 0) {
13311 Log.i(
13312 TAG, "Exiting empty application process "
13313 + app.processName + " ("
13314 + (app.thread != null ? app.thread.asBinder() : null)
13315 + ")\n");
13316 if (app.pid > 0 && app.pid != MY_PID) {
13317 Process.killProcess(app.pid);
13318 } else {
13319 try {
13320 app.thread.scheduleExit();
13321 } catch (Exception e) {
13322 // Ignore exceptions.
13323 }
13324 }
13325 // todo: For now we assume the application is not buggy
13326 // or evil, and will quit as a result of our request.
13327 // Eventually we need to drive this off of the death
13328 // notification, and kill the process if it takes too long.
13329 cleanUpApplicationRecordLocked(app, false, i);
13330 i--;
13331 }
13332 }
13333
13334 // If we still have too many processes, now from the least
13335 // recently used process we start finishing activities.
13336 if (Config.LOGV) Log.v(
13337 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13338 " of " + curMaxProcs + " processes");
13339 for ( i=0;
13340 i<mLRUProcesses.size()
13341 && mLRUProcesses.size() > curMaxProcs;
13342 i++) {
13343 final ProcessRecord app = mLRUProcesses.get(i);
13344 // Quit the application only if we have a state saved for
13345 // all of its activities.
13346 boolean canQuit = !app.persistent && app.curReceiver == null
13347 && app.services.size() == 0
13348 && app.persistentActivities == 0;
13349 int NUMA = app.activities.size();
13350 int j;
13351 if (Config.LOGV) Log.v(
13352 TAG, "Looking to quit " + app.processName);
13353 for (j=0; j<NUMA && canQuit; j++) {
13354 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13355 if (Config.LOGV) Log.v(
13356 TAG, " " + r.intent.getComponent().flattenToShortString()
13357 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13358 canQuit = (r.haveState || !r.stateNotNeeded)
13359 && !r.visible && r.stopped;
13360 }
13361 if (canQuit) {
13362 // Finish all of the activities, and then the app itself.
13363 for (j=0; j<NUMA; j++) {
13364 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13365 if (!r.finishing) {
13366 destroyActivityLocked(r, false);
13367 }
13368 r.resultTo = null;
13369 }
13370 Log.i(TAG, "Exiting application process "
13371 + app.processName + " ("
13372 + (app.thread != null ? app.thread.asBinder() : null)
13373 + ")\n");
13374 if (app.pid > 0 && app.pid != MY_PID) {
13375 Process.killProcess(app.pid);
13376 } else {
13377 try {
13378 app.thread.scheduleExit();
13379 } catch (Exception e) {
13380 // Ignore exceptions.
13381 }
13382 }
13383 // todo: For now we assume the application is not buggy
13384 // or evil, and will quit as a result of our request.
13385 // Eventually we need to drive this off of the death
13386 // notification, and kill the process if it takes too long.
13387 cleanUpApplicationRecordLocked(app, false, i);
13388 i--;
13389 //dump();
13390 }
13391 }
13392
13393 }
13394
13395 int curMaxActivities = MAX_ACTIVITIES;
13396 if (mAlwaysFinishActivities) {
13397 curMaxActivities = 1;
13398 }
13399
13400 // Finally, if there are too many activities now running, try to
13401 // finish as many as we can to get back down to the limit.
13402 for ( i=0;
13403 i<mLRUActivities.size()
13404 && mLRUActivities.size() > curMaxActivities;
13405 i++) {
13406 final HistoryRecord r
13407 = (HistoryRecord)mLRUActivities.get(i);
13408
13409 // We can finish this one if we have its icicle saved and
13410 // it is not persistent.
13411 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13412 && r.stopped && !r.persistent && !r.finishing) {
13413 final int origSize = mLRUActivities.size();
13414 destroyActivityLocked(r, true);
13415
13416 // This will remove it from the LRU list, so keep
13417 // our index at the same value. Note that this check to
13418 // see if the size changes is just paranoia -- if
13419 // something unexpected happens, we don't want to end up
13420 // in an infinite loop.
13421 if (origSize > mLRUActivities.size()) {
13422 i--;
13423 }
13424 }
13425 }
13426 }
13427 }
13428
13429 /** This method sends the specified signal to each of the persistent apps */
13430 public void signalPersistentProcesses(int sig) throws RemoteException {
13431 if (sig != Process.SIGNAL_USR1) {
13432 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13433 }
13434
13435 synchronized (this) {
13436 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13437 != PackageManager.PERMISSION_GRANTED) {
13438 throw new SecurityException("Requires permission "
13439 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13440 }
13441
13442 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13443 ProcessRecord r = mLRUProcesses.get(i);
13444 if (r.thread != null && r.persistent) {
13445 Process.sendSignal(r.pid, sig);
13446 }
13447 }
13448 }
13449 }
13450
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013451 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013452 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013453
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013454 try {
13455 synchronized (this) {
13456 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13457 // its own permission.
13458 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13459 != PackageManager.PERMISSION_GRANTED) {
13460 throw new SecurityException("Requires permission "
13461 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013462 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013463
13464 if (start && fd == null) {
13465 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013466 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013467
13468 ProcessRecord proc = null;
13469 try {
13470 int pid = Integer.parseInt(process);
13471 synchronized (mPidsSelfLocked) {
13472 proc = mPidsSelfLocked.get(pid);
13473 }
13474 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013475 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013476
13477 if (proc == null) {
13478 HashMap<String, SparseArray<ProcessRecord>> all
13479 = mProcessNames.getMap();
13480 SparseArray<ProcessRecord> procs = all.get(process);
13481 if (procs != null && procs.size() > 0) {
13482 proc = procs.valueAt(0);
13483 }
13484 }
13485
13486 if (proc == null || proc.thread == null) {
13487 throw new IllegalArgumentException("Unknown process: " + process);
13488 }
13489
13490 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13491 if (isSecure) {
13492 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13493 throw new SecurityException("Process not debuggable: " + proc);
13494 }
13495 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013496
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013497 proc.thread.profilerControl(start, path, fd);
13498 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013499 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013500 }
13501 } catch (RemoteException e) {
13502 throw new IllegalStateException("Process disappeared");
13503 } finally {
13504 if (fd != null) {
13505 try {
13506 fd.close();
13507 } catch (IOException e) {
13508 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013509 }
13510 }
13511 }
13512
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013513 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13514 public void monitor() {
13515 synchronized (this) { }
13516 }
13517}