blob: e1e8beae7dd2699059c264acf0267a774ef5da32 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
19import com.android.internal.os.BatteryStatsImpl;
Dianne Hackbornde7faf62009-06-30 13:27:30 -070020import com.android.server.AttributeCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import com.android.server.IntentResolver;
22import com.android.server.ProcessMap;
23import com.android.server.ProcessStats;
24import com.android.server.SystemServer;
25import com.android.server.Watchdog;
26import com.android.server.WindowManagerService;
27
28import android.app.Activity;
29import android.app.ActivityManager;
30import android.app.ActivityManagerNative;
31import android.app.ActivityThread;
32import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020033import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.app.Dialog;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070035import android.app.IActivityController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.app.IActivityWatcher;
37import android.app.IApplicationThread;
38import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.app.IServiceConnection;
40import android.app.IThumbnailReceiver;
41import android.app.Instrumentation;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070042import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.app.PendingIntent;
44import android.app.ResultInfo;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070045import android.app.Service;
Christopher Tate181fafa2009-05-14 11:12:14 -070046import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020047import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.ComponentName;
49import android.content.ContentResolver;
50import android.content.Context;
51import android.content.Intent;
52import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070053import android.content.IIntentReceiver;
54import android.content.IIntentSender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -070055import android.content.IntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.content.pm.ActivityInfo;
57import android.content.pm.ApplicationInfo;
58import android.content.pm.ConfigurationInfo;
59import android.content.pm.IPackageDataObserver;
60import android.content.pm.IPackageManager;
61import android.content.pm.InstrumentationInfo;
62import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070063import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import android.content.pm.ProviderInfo;
65import android.content.pm.ResolveInfo;
66import android.content.pm.ServiceInfo;
67import android.content.res.Configuration;
68import android.graphics.Bitmap;
69import android.net.Uri;
70import android.os.Binder;
71import android.os.Bundle;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070072import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.os.Environment;
74import android.os.FileUtils;
75import android.os.Handler;
76import android.os.IBinder;
77import android.os.IPermissionController;
78import android.os.Looper;
79import android.os.Message;
80import android.os.Parcel;
81import android.os.ParcelFileDescriptor;
82import android.os.PowerManager;
83import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070084import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.os.RemoteException;
86import android.os.ServiceManager;
87import android.os.SystemClock;
88import android.os.SystemProperties;
89import android.provider.Checkin;
90import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020091import android.server.data.CrashData;
92import android.server.data.StackTraceElementData;
93import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094import android.text.TextUtils;
95import android.util.Config;
96import android.util.EventLog;
97import android.util.Log;
98import android.util.PrintWriterPrinter;
99import android.util.SparseArray;
100import android.view.Gravity;
101import android.view.LayoutInflater;
102import android.view.View;
103import android.view.WindowManager;
104import android.view.WindowManagerPolicy;
105
106import dalvik.system.Zygote;
107
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200108import java.io.ByteArrayInputStream;
109import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110import java.io.File;
111import java.io.FileDescriptor;
112import java.io.FileInputStream;
113import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200114import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115import java.io.PrintWriter;
116import java.lang.IllegalStateException;
117import java.lang.ref.WeakReference;
118import java.util.ArrayList;
119import java.util.HashMap;
120import java.util.HashSet;
121import java.util.Iterator;
122import java.util.List;
123import java.util.Locale;
124import java.util.Map;
125
126public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
127 static final String TAG = "ActivityManager";
128 static final boolean DEBUG = false;
129 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
130 static final boolean DEBUG_SWITCH = localLOGV || false;
131 static final boolean DEBUG_TASKS = localLOGV || false;
132 static final boolean DEBUG_PAUSE = localLOGV || false;
133 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
134 static final boolean DEBUG_TRANSITION = localLOGV || false;
135 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700136 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 static final boolean DEBUG_SERVICE = localLOGV || false;
138 static final boolean DEBUG_VISBILITY = localLOGV || false;
139 static final boolean DEBUG_PROCESSES = localLOGV || false;
Dianne Hackborna1e989b2009-09-01 19:54:29 -0700140 static final boolean DEBUG_PROVIDER = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700142 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate436344a2009-09-30 16:17:37 -0700143 static final boolean DEBUG_BACKUP = localLOGV || false;
Dianne Hackborndc6b6352009-09-30 14:20:09 -0700144 static final boolean DEBUG_CONFIGURATION = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 static final boolean VALIDATE_TOKENS = false;
146 static final boolean SHOW_ACTIVITY_START_TIME = true;
147
148 // Control over CPU and battery monitoring.
149 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
150 static final boolean MONITOR_CPU_USAGE = true;
151 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
152 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
153 static final boolean MONITOR_THREAD_CPU_USAGE = false;
154
155 // Event log tags
156 static final int LOG_CONFIGURATION_CHANGED = 2719;
157 static final int LOG_CPU = 2721;
158 static final int LOG_AM_FINISH_ACTIVITY = 30001;
159 static final int LOG_TASK_TO_FRONT = 30002;
160 static final int LOG_AM_NEW_INTENT = 30003;
161 static final int LOG_AM_CREATE_TASK = 30004;
162 static final int LOG_AM_CREATE_ACTIVITY = 30005;
163 static final int LOG_AM_RESTART_ACTIVITY = 30006;
164 static final int LOG_AM_RESUME_ACTIVITY = 30007;
165 static final int LOG_ANR = 30008;
166 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
167 static final int LOG_AM_PROCESS_BOUND = 30010;
168 static final int LOG_AM_PROCESS_DIED = 30011;
169 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
170 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
171 static final int LOG_AM_PROCESS_START = 30014;
172 static final int LOG_AM_PROCESS_BAD = 30015;
173 static final int LOG_AM_PROCESS_GOOD = 30016;
174 static final int LOG_AM_LOW_MEMORY = 30017;
175 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
176 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
177 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
178 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
179 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
180 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
181 static final int LOG_AM_CREATE_SERVICE = 30030;
182 static final int LOG_AM_DESTROY_SERVICE = 30031;
183 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
184 static final int LOG_AM_DROP_PROCESS = 30033;
185 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
186 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
187 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
188
189 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
190 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
191
Dianne Hackborn1655be42009-05-08 14:29:01 -0700192 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700193 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 private static final String SYSTEM_SECURE = "ro.secure";
196
197 // This is the maximum number of application processes we would like
198 // to have running. Due to the asynchronous nature of things, we can
199 // temporarily go beyond this limit.
200 static final int MAX_PROCESSES = 2;
201
202 // Set to false to leave processes running indefinitely, relying on
203 // the kernel killing them as resources are required.
204 static final boolean ENFORCE_PROCESS_LIMIT = false;
205
206 // This is the maximum number of activities that we would like to have
207 // running at a given time.
208 static final int MAX_ACTIVITIES = 20;
209
210 // Maximum number of recent tasks that we can remember.
211 static final int MAX_RECENT_TASKS = 20;
212
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700213 // Amount of time after a call to stopAppSwitches() during which we will
214 // prevent further untrusted switches from happening.
215 static final long APP_SWITCH_DELAY_TIME = 5*1000;
216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 // How long until we reset a task when the user returns to it. Currently
218 // 30 minutes.
219 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
220
221 // Set to true to disable the icon that is shown while a new activity
222 // is being started.
223 static final boolean SHOW_APP_STARTING_ICON = true;
224
225 // How long we wait until giving up on the last activity to pause. This
226 // is short because it directly impacts the responsiveness of starting the
227 // next activity.
228 static final int PAUSE_TIMEOUT = 500;
229
230 /**
231 * How long we can hold the launch wake lock before giving up.
232 */
233 static final int LAUNCH_TIMEOUT = 10*1000;
234
235 // How long we wait for a launched process to attach to the activity manager
236 // before we decide it's never going to come up for real.
237 static final int PROC_START_TIMEOUT = 10*1000;
238
239 // How long we wait until giving up on the last activity telling us it
240 // is idle.
241 static final int IDLE_TIMEOUT = 10*1000;
242
243 // How long to wait after going idle before forcing apps to GC.
244 static final int GC_TIMEOUT = 5*1000;
245
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700246 // The minimum amount of time between successive GC requests for a process.
247 static final int GC_MIN_INTERVAL = 60*1000;
248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 // How long we wait until giving up on an activity telling us it has
250 // finished destroying itself.
251 static final int DESTROY_TIMEOUT = 10*1000;
252
253 // How long we allow a receiver to run before giving up on it.
254 static final int BROADCAST_TIMEOUT = 10*1000;
255
256 // How long we wait for a service to finish executing.
257 static final int SERVICE_TIMEOUT = 20*1000;
258
259 // How long a service needs to be running until restarting its process
260 // is no longer considered to be a relaunch of the service.
261 static final int SERVICE_RESTART_DURATION = 5*1000;
262
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700263 // How long a service needs to be running until it will start back at
264 // SERVICE_RESTART_DURATION after being killed.
265 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
266
267 // Multiplying factor to increase restart duration time by, for each time
268 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
269 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
270
271 // The minimum amount of time between restarting services that we allow.
272 // That is, when multiple services are restarting, we won't allow each
273 // to restart less than this amount of time from the last one.
274 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 // Maximum amount of time for there to be no activity on a service before
277 // we consider it non-essential and allow its process to go on the
278 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700279 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280
281 // How long we wait until we timeout on key dispatching.
282 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
283
284 // The minimum time we allow between crashes, for us to consider this
285 // application to be bad and stop and its services and reject broadcasts.
286 static final int MIN_CRASH_INTERVAL = 60*1000;
287
288 // How long we wait until we timeout on key dispatching during instrumentation.
289 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
290
291 // OOM adjustments for processes in various states:
292
293 // This is a process without anything currently running in it. Definitely
294 // the first to go! Value set in system/rootdir/init.rc on startup.
295 // This value is initalized in the constructor, careful when refering to
296 // this static variable externally.
297 static int EMPTY_APP_ADJ;
298
299 // This is a process with a content provider that does not have any clients
300 // attached to it. If it did have any clients, its adjustment would be the
301 // one for the highest-priority of those processes.
302 static int CONTENT_PROVIDER_ADJ;
303
304 // This is a process only hosting activities that are not visible,
305 // so it can be killed without any disruption. Value set in
306 // system/rootdir/init.rc on startup.
307 final int HIDDEN_APP_MAX_ADJ;
308 static int HIDDEN_APP_MIN_ADJ;
309
The Android Open Source Project4df24232009-03-05 14:34:35 -0800310 // This is a process holding the home application -- we want to try
311 // avoiding killing it, even if it would normally be in the background,
312 // because the user interacts with it so much.
313 final int HOME_APP_ADJ;
314
Christopher Tate6fa95972009-06-05 18:43:55 -0700315 // This is a process currently hosting a backup operation. Killing it
316 // is not entirely fatal but is generally a bad idea.
317 final int BACKUP_APP_ADJ;
318
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 // This is a process holding a secondary server -- killing it will not
320 // have much of an impact as far as the user is concerned. Value set in
321 // system/rootdir/init.rc on startup.
322 final int SECONDARY_SERVER_ADJ;
323
324 // This is a process only hosting activities that are visible to the
325 // user, so we'd prefer they don't disappear. Value set in
326 // system/rootdir/init.rc on startup.
327 final int VISIBLE_APP_ADJ;
328
329 // This is the process running the current foreground app. We'd really
330 // rather not kill it! Value set in system/rootdir/init.rc on startup.
331 final int FOREGROUND_APP_ADJ;
332
333 // This is a process running a core server, such as telephony. Definitely
334 // don't want to kill it, but doing so is not completely fatal.
335 static final int CORE_SERVER_ADJ = -12;
336
337 // The system process runs at the default adjustment.
338 static final int SYSTEM_ADJ = -16;
339
340 // Memory pages are 4K.
341 static final int PAGE_SIZE = 4*1024;
342
Jacek Surazski82a73df2009-06-17 14:33:18 +0200343 // System property defining error report receiver for system apps
344 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
345
346 // System property defining default error report receiver
347 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 // Corresponding memory levels for above adjustments.
350 final int EMPTY_APP_MEM;
351 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800352 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700353 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 final int SECONDARY_SERVER_MEM;
355 final int VISIBLE_APP_MEM;
356 final int FOREGROUND_APP_MEM;
357
358 final int MY_PID;
359
360 static final String[] EMPTY_STRING_ARRAY = new String[0];
361
362 enum ActivityState {
363 INITIALIZING,
364 RESUMED,
365 PAUSING,
366 PAUSED,
367 STOPPING,
368 STOPPED,
369 FINISHING,
370 DESTROYING,
371 DESTROYED
372 }
373
374 /**
375 * The back history of all previous (and possibly still
376 * running) activities. It contains HistoryRecord objects.
377 */
378 final ArrayList mHistory = new ArrayList();
379
380 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700381 * Description of a request to start a new activity, which has been held
382 * due to app switches being disabled.
383 */
384 class PendingActivityLaunch {
385 HistoryRecord r;
386 HistoryRecord sourceRecord;
387 Uri[] grantedUriPermissions;
388 int grantedMode;
389 boolean onlyIfNeeded;
390 }
391
392 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
393 = new ArrayList<PendingActivityLaunch>();
394
395 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 * List of all active broadcasts that are to be executed immediately
397 * (without waiting for another broadcast to finish). Currently this only
398 * contains broadcasts to registered receivers, to avoid spinning up
399 * a bunch of processes to execute IntentReceiver components.
400 */
401 final ArrayList<BroadcastRecord> mParallelBroadcasts
402 = new ArrayList<BroadcastRecord>();
403
404 /**
405 * List of all active broadcasts that are to be executed one at a time.
406 * The object at the top of the list is the currently activity broadcasts;
407 * those after it are waiting for the top to finish..
408 */
409 final ArrayList<BroadcastRecord> mOrderedBroadcasts
410 = new ArrayList<BroadcastRecord>();
411
412 /**
413 * Set when we current have a BROADCAST_INTENT_MSG in flight.
414 */
415 boolean mBroadcastsScheduled = false;
416
417 /**
418 * Set to indicate whether to issue an onUserLeaving callback when a
419 * newly launched activity is being brought in front of us.
420 */
421 boolean mUserLeaving = false;
422
423 /**
424 * When we are in the process of pausing an activity, before starting the
425 * next one, this variable holds the activity that is currently being paused.
426 */
427 HistoryRecord mPausingActivity = null;
428
429 /**
430 * Current activity that is resumed, or null if there is none.
431 */
432 HistoryRecord mResumedActivity = null;
433
434 /**
435 * Activity we have told the window manager to have key focus.
436 */
437 HistoryRecord mFocusedActivity = null;
438
439 /**
440 * This is the last activity that we put into the paused state. This is
441 * used to determine if we need to do an activity transition while sleeping,
442 * when we normally hold the top activity paused.
443 */
444 HistoryRecord mLastPausedActivity = null;
445
446 /**
447 * List of activities that are waiting for a new activity
448 * to become visible before completing whatever operation they are
449 * supposed to do.
450 */
451 final ArrayList mWaitingVisibleActivities = new ArrayList();
452
453 /**
454 * List of activities that are ready to be stopped, but waiting
455 * for the next activity to settle down before doing so. It contains
456 * HistoryRecord objects.
457 */
458 final ArrayList<HistoryRecord> mStoppingActivities
459 = new ArrayList<HistoryRecord>();
460
461 /**
Dianne Hackbornbfe319e2009-09-21 00:34:05 -0700462 * Animations that for the current transition have requested not to
463 * be considered for the transition animation.
464 */
465 final ArrayList<HistoryRecord> mNoAnimActivities
466 = new ArrayList<HistoryRecord>();
467
468 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 * List of intents that were used to start the most recent tasks.
470 */
471 final ArrayList<TaskRecord> mRecentTasks
472 = new ArrayList<TaskRecord>();
473
474 /**
475 * List of activities that are ready to be finished, but waiting
476 * for the previous activity to settle down before doing so. It contains
477 * HistoryRecord objects.
478 */
479 final ArrayList mFinishingActivities = new ArrayList();
480
481 /**
482 * All of the applications we currently have running organized by name.
483 * The keys are strings of the application package name (as
484 * returned by the package manager), and the keys are ApplicationRecord
485 * objects.
486 */
487 final ProcessMap<ProcessRecord> mProcessNames
488 = new ProcessMap<ProcessRecord>();
489
490 /**
491 * The last time that various processes have crashed.
492 */
493 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
494
495 /**
496 * Set of applications that we consider to be bad, and will reject
497 * incoming broadcasts from (which the user has no control over).
498 * Processes are added to this set when they have crashed twice within
499 * a minimum amount of time; they are removed from it when they are
500 * later restarted (hopefully due to some user action). The value is the
501 * time it was added to the list.
502 */
503 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
504
505 /**
506 * All of the processes we currently have running organized by pid.
507 * The keys are the pid running the application.
508 *
509 * <p>NOTE: This object is protected by its own lock, NOT the global
510 * activity manager lock!
511 */
512 final SparseArray<ProcessRecord> mPidsSelfLocked
513 = new SparseArray<ProcessRecord>();
514
515 /**
516 * All of the processes that have been forced to be foreground. The key
517 * is the pid of the caller who requested it (we hold a death
518 * link on it).
519 */
520 abstract class ForegroundToken implements IBinder.DeathRecipient {
521 int pid;
522 IBinder token;
523 }
524 final SparseArray<ForegroundToken> mForegroundProcesses
525 = new SparseArray<ForegroundToken>();
526
527 /**
528 * List of records for processes that someone had tried to start before the
529 * system was ready. We don't start them at that point, but ensure they
530 * are started by the time booting is complete.
531 */
532 final ArrayList<ProcessRecord> mProcessesOnHold
533 = new ArrayList<ProcessRecord>();
534
535 /**
536 * List of records for processes that we have started and are waiting
537 * for them to call back. This is really only needed when running in
538 * single processes mode, in which case we do not have a unique pid for
539 * each process.
540 */
541 final ArrayList<ProcessRecord> mStartingProcesses
542 = new ArrayList<ProcessRecord>();
543
544 /**
545 * List of persistent applications that are in the process
546 * of being started.
547 */
548 final ArrayList<ProcessRecord> mPersistentStartingProcesses
549 = new ArrayList<ProcessRecord>();
550
551 /**
552 * Processes that are being forcibly torn down.
553 */
554 final ArrayList<ProcessRecord> mRemovedProcesses
555 = new ArrayList<ProcessRecord>();
556
557 /**
558 * List of running applications, sorted by recent usage.
559 * The first entry in the list is the least recently used.
560 * It contains ApplicationRecord objects. This list does NOT include
561 * any persistent application records (since we never want to exit them).
562 */
563 final ArrayList<ProcessRecord> mLRUProcesses
564 = new ArrayList<ProcessRecord>();
565
566 /**
567 * List of processes that should gc as soon as things are idle.
568 */
569 final ArrayList<ProcessRecord> mProcessesToGc
570 = new ArrayList<ProcessRecord>();
571
572 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800573 * This is the process holding what we currently consider to be
574 * the "home" activity.
575 */
576 private ProcessRecord mHomeProcess;
577
578 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 * List of running activities, sorted by recent usage.
580 * The first entry in the list is the least recently used.
581 * It contains HistoryRecord objects.
582 */
583 private final ArrayList mLRUActivities = new ArrayList();
584
585 /**
586 * Set of PendingResultRecord objects that are currently active.
587 */
588 final HashSet mPendingResultRecords = new HashSet();
589
590 /**
591 * Set of IntentSenderRecord objects that are currently active.
592 */
593 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
594 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
595
596 /**
597 * Intent broadcast that we have tried to start, but are
598 * waiting for its application's process to be created. We only
599 * need one (instead of a list) because we always process broadcasts
600 * one at a time, so no others can be started while waiting for this
601 * one.
602 */
603 BroadcastRecord mPendingBroadcast = null;
604
605 /**
606 * Keeps track of all IIntentReceivers that have been registered for
607 * broadcasts. Hash keys are the receiver IBinder, hash value is
608 * a ReceiverList.
609 */
610 final HashMap mRegisteredReceivers = new HashMap();
611
612 /**
613 * Resolver for broadcast intents to registered receivers.
614 * Holds BroadcastFilter (subclass of IntentFilter).
615 */
616 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
617 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
618 @Override
619 protected boolean allowFilterResult(
620 BroadcastFilter filter, List<BroadcastFilter> dest) {
621 IBinder target = filter.receiverList.receiver.asBinder();
622 for (int i=dest.size()-1; i>=0; i--) {
623 if (dest.get(i).receiverList.receiver.asBinder() == target) {
624 return false;
625 }
626 }
627 return true;
628 }
629 };
630
631 /**
632 * State of all active sticky broadcasts. Keys are the action of the
633 * sticky Intent, values are an ArrayList of all broadcasted intents with
634 * that action (which should usually be one).
635 */
636 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
637 new HashMap<String, ArrayList<Intent>>();
638
639 /**
640 * All currently running services.
641 */
642 final HashMap<ComponentName, ServiceRecord> mServices =
643 new HashMap<ComponentName, ServiceRecord>();
644
645 /**
646 * All currently running services indexed by the Intent used to start them.
647 */
648 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
649 new HashMap<Intent.FilterComparison, ServiceRecord>();
650
651 /**
652 * All currently bound service connections. Keys are the IBinder of
653 * the client's IServiceConnection.
654 */
655 final HashMap<IBinder, ConnectionRecord> mServiceConnections
656 = new HashMap<IBinder, ConnectionRecord>();
657
658 /**
659 * List of services that we have been asked to start,
660 * but haven't yet been able to. It is used to hold start requests
661 * while waiting for their corresponding application thread to get
662 * going.
663 */
664 final ArrayList<ServiceRecord> mPendingServices
665 = new ArrayList<ServiceRecord>();
666
667 /**
668 * List of services that are scheduled to restart following a crash.
669 */
670 final ArrayList<ServiceRecord> mRestartingServices
671 = new ArrayList<ServiceRecord>();
672
673 /**
674 * List of services that are in the process of being stopped.
675 */
676 final ArrayList<ServiceRecord> mStoppingServices
677 = new ArrayList<ServiceRecord>();
678
679 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700680 * Backup/restore process management
681 */
682 String mBackupAppName = null;
683 BackupRecord mBackupTarget = null;
684
685 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 * List of PendingThumbnailsRecord objects of clients who are still
687 * waiting to receive all of the thumbnails for a task.
688 */
689 final ArrayList mPendingThumbnails = new ArrayList();
690
691 /**
692 * List of HistoryRecord objects that have been finished and must
693 * still report back to a pending thumbnail receiver.
694 */
695 final ArrayList mCancelledThumbnails = new ArrayList();
696
697 /**
698 * All of the currently running global content providers. Keys are a
699 * string containing the provider name and values are a
700 * ContentProviderRecord object containing the data about it. Note
701 * that a single provider may be published under multiple names, so
702 * there may be multiple entries here for a single one in mProvidersByClass.
703 */
704 final HashMap mProvidersByName = new HashMap();
705
706 /**
707 * All of the currently running global content providers. Keys are a
708 * string containing the provider's implementation class and values are a
709 * ContentProviderRecord object containing the data about it.
710 */
711 final HashMap mProvidersByClass = new HashMap();
712
713 /**
714 * List of content providers who have clients waiting for them. The
715 * application is currently being launched and the provider will be
716 * removed from this list once it is published.
717 */
718 final ArrayList mLaunchingProviders = new ArrayList();
719
720 /**
721 * Global set of specific Uri permissions that have been granted.
722 */
723 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
724 = new SparseArray<HashMap<Uri, UriPermission>>();
725
726 /**
727 * Thread-local storage used to carry caller permissions over through
728 * indirect content-provider access.
729 * @see #ActivityManagerService.openContentUri()
730 */
731 private class Identity {
732 public int pid;
733 public int uid;
734
735 Identity(int _pid, int _uid) {
736 pid = _pid;
737 uid = _uid;
738 }
739 }
740 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
741
742 /**
743 * All information we have collected about the runtime performance of
744 * any user id that can impact battery performance.
745 */
746 final BatteryStatsService mBatteryStatsService;
747
748 /**
749 * information about component usage
750 */
751 final UsageStatsService mUsageStatsService;
752
753 /**
754 * Current configuration information. HistoryRecord objects are given
755 * a reference to this object to indicate which configuration they are
756 * currently running in, so this object must be kept immutable.
757 */
758 Configuration mConfiguration = new Configuration();
759
760 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700761 * Hardware-reported OpenGLES version.
762 */
763 final int GL_ES_VERSION;
764
765 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 * List of initialization arguments to pass to all processes when binding applications to them.
767 * For example, references to the commonly used services.
768 */
769 HashMap<String, IBinder> mAppBindArgs;
770
771 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700772 * Temporary to avoid allocations. Protected by main lock.
773 */
774 final StringBuilder mStringBuilder = new StringBuilder(256);
775
776 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 * Used to control how we initialize the service.
778 */
779 boolean mStartRunning = false;
780 ComponentName mTopComponent;
781 String mTopAction;
782 String mTopData;
783 boolean mSystemReady = false;
784 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700785 boolean mWaitingUpdate = false;
786 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787
788 Context mContext;
789
790 int mFactoryTest;
791
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700792 boolean mCheckedForSetup;
793
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700795 * The time at which we will allow normal application switches again,
796 * after a call to {@link #stopAppSwitches()}.
797 */
798 long mAppSwitchesAllowedTime;
799
800 /**
801 * This is set to true after the first switch after mAppSwitchesAllowedTime
802 * is set; any switches after that will clear the time.
803 */
804 boolean mDidAppSwitch;
805
806 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 * Set while we are wanting to sleep, to prevent any
808 * activities from being started/resumed.
809 */
810 boolean mSleeping = false;
811
812 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700813 * Set if we are shutting down the system, similar to sleeping.
814 */
815 boolean mShuttingDown = false;
816
817 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 * Set when the system is going to sleep, until we have
819 * successfully paused the current activity and released our wake lock.
820 * At that point the system is allowed to actually sleep.
821 */
822 PowerManager.WakeLock mGoingToSleep;
823
824 /**
825 * We don't want to allow the device to go to sleep while in the process
826 * of launching an activity. This is primarily to allow alarm intent
827 * receivers to launch an activity and get that to run before the device
828 * goes back to sleep.
829 */
830 PowerManager.WakeLock mLaunchingActivity;
831
832 /**
833 * Task identifier that activities are currently being started
834 * in. Incremented each time a new task is created.
835 * todo: Replace this with a TokenSpace class that generates non-repeating
836 * integers that won't wrap.
837 */
838 int mCurTask = 1;
839
840 /**
841 * Current sequence id for oom_adj computation traversal.
842 */
843 int mAdjSeq = 0;
844
845 /**
846 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
847 * is set, indicating the user wants processes started in such a way
848 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
849 * running in each process (thus no pre-initialized process, etc).
850 */
851 boolean mSimpleProcessManagement = false;
852
853 /**
854 * System monitoring: number of processes that died since the last
855 * N procs were started.
856 */
857 int[] mProcDeaths = new int[20];
858
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700859 /**
860 * This is set if we had to do a delayed dexopt of an app before launching
861 * it, to increasing the ANR timeouts in that case.
862 */
863 boolean mDidDexOpt;
864
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800865 String mDebugApp = null;
866 boolean mWaitForDebugger = false;
867 boolean mDebugTransient = false;
868 String mOrigDebugApp = null;
869 boolean mOrigWaitForDebugger = false;
870 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700871 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800872
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700873 final RemoteCallbackList<IActivityWatcher> mWatchers
874 = new RemoteCallbackList<IActivityWatcher>();
875
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 /**
877 * Callback of last caller to {@link #requestPss}.
878 */
879 Runnable mRequestPssCallback;
880
881 /**
882 * Remaining processes for which we are waiting results from the last
883 * call to {@link #requestPss}.
884 */
885 final ArrayList<ProcessRecord> mRequestPssList
886 = new ArrayList<ProcessRecord>();
887
888 /**
889 * Runtime statistics collection thread. This object's lock is used to
890 * protect all related state.
891 */
892 final Thread mProcessStatsThread;
893
894 /**
895 * Used to collect process stats when showing not responding dialog.
896 * Protected by mProcessStatsThread.
897 */
898 final ProcessStats mProcessStats = new ProcessStats(
899 MONITOR_THREAD_CPU_USAGE);
900 long mLastCpuTime = 0;
901 long mLastWriteTime = 0;
902
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700903 long mInitialStartTime = 0;
904
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 /**
906 * Set to true after the system has finished booting.
907 */
908 boolean mBooted = false;
909
910 int mProcessLimit = 0;
911
912 WindowManagerService mWindowManager;
913
914 static ActivityManagerService mSelf;
915 static ActivityThread mSystemThread;
916
917 private final class AppDeathRecipient implements IBinder.DeathRecipient {
918 final ProcessRecord mApp;
919 final int mPid;
920 final IApplicationThread mAppThread;
921
922 AppDeathRecipient(ProcessRecord app, int pid,
923 IApplicationThread thread) {
924 if (localLOGV) Log.v(
925 TAG, "New death recipient " + this
926 + " for thread " + thread.asBinder());
927 mApp = app;
928 mPid = pid;
929 mAppThread = thread;
930 }
931
932 public void binderDied() {
933 if (localLOGV) Log.v(
934 TAG, "Death received in " + this
935 + " for thread " + mAppThread.asBinder());
936 removeRequestedPss(mApp);
937 synchronized(ActivityManagerService.this) {
938 appDiedLocked(mApp, mPid, mAppThread);
939 }
940 }
941 }
942
943 static final int SHOW_ERROR_MSG = 1;
944 static final int SHOW_NOT_RESPONDING_MSG = 2;
945 static final int SHOW_FACTORY_ERROR_MSG = 3;
946 static final int UPDATE_CONFIGURATION_MSG = 4;
947 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
948 static final int WAIT_FOR_DEBUGGER_MSG = 6;
949 static final int BROADCAST_INTENT_MSG = 7;
950 static final int BROADCAST_TIMEOUT_MSG = 8;
951 static final int PAUSE_TIMEOUT_MSG = 9;
952 static final int IDLE_TIMEOUT_MSG = 10;
953 static final int IDLE_NOW_MSG = 11;
954 static final int SERVICE_TIMEOUT_MSG = 12;
955 static final int UPDATE_TIME_ZONE = 13;
956 static final int SHOW_UID_ERROR_MSG = 14;
957 static final int IM_FEELING_LUCKY_MSG = 15;
958 static final int LAUNCH_TIMEOUT_MSG = 16;
959 static final int DESTROY_TIMEOUT_MSG = 17;
960 static final int SERVICE_ERROR_MSG = 18;
961 static final int RESUME_TOP_ACTIVITY_MSG = 19;
962 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700963 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700964 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965
966 AlertDialog mUidAlert;
967
968 final Handler mHandler = new Handler() {
969 //public Handler() {
970 // if (localLOGV) Log.v(TAG, "Handler started!");
971 //}
972
973 public void handleMessage(Message msg) {
974 switch (msg.what) {
975 case SHOW_ERROR_MSG: {
976 HashMap data = (HashMap) msg.obj;
977 byte[] crashData = (byte[])data.get("crashData");
978 if (crashData != null) {
979 // This needs to be *un*synchronized to avoid deadlock.
980 ContentResolver resolver = mContext.getContentResolver();
981 Checkin.reportCrash(resolver, crashData);
982 }
983 synchronized (ActivityManagerService.this) {
984 ProcessRecord proc = (ProcessRecord)data.get("app");
985 if (proc != null && proc.crashDialog != null) {
986 Log.e(TAG, "App already has crash dialog: " + proc);
987 return;
988 }
989 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700990 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991 Dialog d = new AppErrorDialog(
992 mContext, res, proc,
993 (Integer)data.get("flags"),
994 (String)data.get("shortMsg"),
995 (String)data.get("longMsg"));
996 d.show();
997 proc.crashDialog = d;
998 } else {
999 // The device is asleep, so just pretend that the user
1000 // saw a crash dialog and hit "force quit".
1001 res.set(0);
1002 }
1003 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001004
1005 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001006 } break;
1007 case SHOW_NOT_RESPONDING_MSG: {
1008 synchronized (ActivityManagerService.this) {
1009 HashMap data = (HashMap) msg.obj;
1010 ProcessRecord proc = (ProcessRecord)data.get("app");
1011 if (proc != null && proc.anrDialog != null) {
1012 Log.e(TAG, "App already has anr dialog: " + proc);
1013 return;
1014 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001015
1016 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1017 null, null, 0, null, null, null,
1018 false, false, MY_PID, Process.SYSTEM_UID);
1019
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1021 mContext, proc, (HistoryRecord)data.get("activity"));
1022 d.show();
1023 proc.anrDialog = d;
1024 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001025
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001026 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001027 } break;
1028 case SHOW_FACTORY_ERROR_MSG: {
1029 Dialog d = new FactoryErrorDialog(
1030 mContext, msg.getData().getCharSequence("msg"));
1031 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001032 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033 } break;
1034 case UPDATE_CONFIGURATION_MSG: {
1035 final ContentResolver resolver = mContext.getContentResolver();
1036 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1037 } break;
1038 case GC_BACKGROUND_PROCESSES_MSG: {
1039 synchronized (ActivityManagerService.this) {
1040 performAppGcsIfAppropriateLocked();
1041 }
1042 } break;
1043 case WAIT_FOR_DEBUGGER_MSG: {
1044 synchronized (ActivityManagerService.this) {
1045 ProcessRecord app = (ProcessRecord)msg.obj;
1046 if (msg.arg1 != 0) {
1047 if (!app.waitedForDebugger) {
1048 Dialog d = new AppWaitingForDebuggerDialog(
1049 ActivityManagerService.this,
1050 mContext, app);
1051 app.waitDialog = d;
1052 app.waitedForDebugger = true;
1053 d.show();
1054 }
1055 } else {
1056 if (app.waitDialog != null) {
1057 app.waitDialog.dismiss();
1058 app.waitDialog = null;
1059 }
1060 }
1061 }
1062 } break;
1063 case BROADCAST_INTENT_MSG: {
1064 if (DEBUG_BROADCAST) Log.v(
1065 TAG, "Received BROADCAST_INTENT_MSG");
1066 processNextBroadcast(true);
1067 } break;
1068 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001069 if (mDidDexOpt) {
1070 mDidDexOpt = false;
1071 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1072 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1073 return;
1074 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001075 broadcastTimeout();
1076 } break;
1077 case PAUSE_TIMEOUT_MSG: {
1078 IBinder token = (IBinder)msg.obj;
1079 // We don't at this point know if the activity is fullscreen,
1080 // so we need to be conservative and assume it isn't.
1081 Log.w(TAG, "Activity pause timeout for " + token);
1082 activityPaused(token, null, true);
1083 } break;
1084 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001085 if (mDidDexOpt) {
1086 mDidDexOpt = false;
1087 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1088 nmsg.obj = msg.obj;
1089 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1090 return;
1091 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001092 // We don't at this point know if the activity is fullscreen,
1093 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001094 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001095 Log.w(TAG, "Activity idle timeout for " + token);
Dianne Hackborne88846e2009-09-30 21:34:25 -07001096 activityIdleInternal(token, true, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097 } break;
1098 case DESTROY_TIMEOUT_MSG: {
1099 IBinder token = (IBinder)msg.obj;
1100 // We don't at this point know if the activity is fullscreen,
1101 // so we need to be conservative and assume it isn't.
1102 Log.w(TAG, "Activity destroy timeout for " + token);
1103 activityDestroyed(token);
1104 } break;
1105 case IDLE_NOW_MSG: {
1106 IBinder token = (IBinder)msg.obj;
Dianne Hackborne88846e2009-09-30 21:34:25 -07001107 activityIdle(token, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001108 } break;
1109 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001110 if (mDidDexOpt) {
1111 mDidDexOpt = false;
1112 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1113 nmsg.obj = msg.obj;
1114 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1115 return;
1116 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117 serviceTimeout((ProcessRecord)msg.obj);
1118 } break;
1119 case UPDATE_TIME_ZONE: {
1120 synchronized (ActivityManagerService.this) {
1121 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1122 ProcessRecord r = mLRUProcesses.get(i);
1123 if (r.thread != null) {
1124 try {
1125 r.thread.updateTimeZone();
1126 } catch (RemoteException ex) {
1127 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1128 }
1129 }
1130 }
1131 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001132 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001133 case SHOW_UID_ERROR_MSG: {
1134 // XXX This is a temporary dialog, no need to localize.
1135 AlertDialog d = new BaseErrorDialog(mContext);
1136 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1137 d.setCancelable(false);
1138 d.setTitle("System UIDs Inconsistent");
1139 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1140 d.setButton("I'm Feeling Lucky",
1141 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1142 mUidAlert = d;
1143 d.show();
1144 } break;
1145 case IM_FEELING_LUCKY_MSG: {
1146 if (mUidAlert != null) {
1147 mUidAlert.dismiss();
1148 mUidAlert = null;
1149 }
1150 } break;
1151 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001152 if (mDidDexOpt) {
1153 mDidDexOpt = false;
1154 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1155 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1156 return;
1157 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001158 synchronized (ActivityManagerService.this) {
1159 if (mLaunchingActivity.isHeld()) {
1160 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1161 mLaunchingActivity.release();
1162 }
1163 }
1164 } break;
1165 case SERVICE_ERROR_MSG: {
1166 ServiceRecord srv = (ServiceRecord)msg.obj;
1167 // This needs to be *un*synchronized to avoid deadlock.
1168 Checkin.logEvent(mContext.getContentResolver(),
1169 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1170 srv.name.toShortString());
1171 } break;
1172 case RESUME_TOP_ACTIVITY_MSG: {
1173 synchronized (ActivityManagerService.this) {
1174 resumeTopActivityLocked(null);
1175 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001176 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001178 if (mDidDexOpt) {
1179 mDidDexOpt = false;
1180 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1181 nmsg.obj = msg.obj;
1182 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1183 return;
1184 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001185 ProcessRecord app = (ProcessRecord)msg.obj;
1186 synchronized (ActivityManagerService.this) {
1187 processStartTimedOutLocked(app);
1188 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001189 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001190 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1191 synchronized (ActivityManagerService.this) {
1192 doPendingActivityLaunchesLocked(true);
1193 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001194 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001195 case KILL_APPLICATION_MSG: {
1196 synchronized (ActivityManagerService.this) {
1197 int uid = msg.arg1;
1198 boolean restart = (msg.arg2 == 1);
1199 String pkg = (String) msg.obj;
1200 uninstallPackageLocked(pkg, uid, restart);
1201 }
1202 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001203 }
1204 }
1205 };
1206
1207 public static void setSystemProcess() {
1208 try {
1209 ActivityManagerService m = mSelf;
1210
1211 ServiceManager.addService("activity", m);
1212 ServiceManager.addService("meminfo", new MemBinder(m));
1213 if (MONITOR_CPU_USAGE) {
1214 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1215 }
1216 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1217 ServiceManager.addService("activity.services", new ServicesBinder(m));
1218 ServiceManager.addService("activity.senders", new SendersBinder(m));
1219 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1220 ServiceManager.addService("permission", new PermissionController(m));
1221
1222 ApplicationInfo info =
1223 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001224 "android", STOCK_PM_FLAGS);
Mike Cleron432b7132009-09-24 15:28:29 -07001225 mSystemThread.installSystemApplicationInfo(info);
1226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001227 synchronized (mSelf) {
1228 ProcessRecord app = mSelf.newProcessRecordLocked(
1229 mSystemThread.getApplicationThread(), info,
1230 info.processName);
1231 app.persistent = true;
1232 app.pid = Process.myPid();
1233 app.maxAdj = SYSTEM_ADJ;
1234 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1235 synchronized (mSelf.mPidsSelfLocked) {
1236 mSelf.mPidsSelfLocked.put(app.pid, app);
1237 }
1238 mSelf.updateLRUListLocked(app, true);
1239 }
1240 } catch (PackageManager.NameNotFoundException e) {
1241 throw new RuntimeException(
1242 "Unable to find android system package", e);
1243 }
1244 }
1245
1246 public void setWindowManager(WindowManagerService wm) {
1247 mWindowManager = wm;
1248 }
1249
1250 public static final Context main(int factoryTest) {
1251 AThread thr = new AThread();
1252 thr.start();
1253
1254 synchronized (thr) {
1255 while (thr.mService == null) {
1256 try {
1257 thr.wait();
1258 } catch (InterruptedException e) {
1259 }
1260 }
1261 }
1262
1263 ActivityManagerService m = thr.mService;
1264 mSelf = m;
1265 ActivityThread at = ActivityThread.systemMain();
1266 mSystemThread = at;
1267 Context context = at.getSystemContext();
1268 m.mContext = context;
1269 m.mFactoryTest = factoryTest;
1270 PowerManager pm =
1271 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1272 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1273 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1274 m.mLaunchingActivity.setReferenceCounted(false);
1275
1276 m.mBatteryStatsService.publish(context);
1277 m.mUsageStatsService.publish(context);
1278
1279 synchronized (thr) {
1280 thr.mReady = true;
1281 thr.notifyAll();
1282 }
1283
1284 m.startRunning(null, null, null, null);
1285
1286 return context;
1287 }
1288
1289 public static ActivityManagerService self() {
1290 return mSelf;
1291 }
1292
1293 static class AThread extends Thread {
1294 ActivityManagerService mService;
1295 boolean mReady = false;
1296
1297 public AThread() {
1298 super("ActivityManager");
1299 }
1300
1301 public void run() {
1302 Looper.prepare();
1303
1304 android.os.Process.setThreadPriority(
1305 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1306
1307 ActivityManagerService m = new ActivityManagerService();
1308
1309 synchronized (this) {
1310 mService = m;
1311 notifyAll();
1312 }
1313
1314 synchronized (this) {
1315 while (!mReady) {
1316 try {
1317 wait();
1318 } catch (InterruptedException e) {
1319 }
1320 }
1321 }
1322
1323 Looper.loop();
1324 }
1325 }
1326
1327 static class BroadcastsBinder extends Binder {
1328 ActivityManagerService mActivityManagerService;
1329 BroadcastsBinder(ActivityManagerService activityManagerService) {
1330 mActivityManagerService = activityManagerService;
1331 }
1332
1333 @Override
1334 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1335 mActivityManagerService.dumpBroadcasts(pw);
1336 }
1337 }
1338
1339 static class ServicesBinder extends Binder {
1340 ActivityManagerService mActivityManagerService;
1341 ServicesBinder(ActivityManagerService activityManagerService) {
1342 mActivityManagerService = activityManagerService;
1343 }
1344
1345 @Override
1346 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1347 mActivityManagerService.dumpServices(pw);
1348 }
1349 }
1350
1351 static class SendersBinder extends Binder {
1352 ActivityManagerService mActivityManagerService;
1353 SendersBinder(ActivityManagerService activityManagerService) {
1354 mActivityManagerService = activityManagerService;
1355 }
1356
1357 @Override
1358 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1359 mActivityManagerService.dumpSenders(pw);
1360 }
1361 }
1362
1363 static class ProvidersBinder extends Binder {
1364 ActivityManagerService mActivityManagerService;
1365 ProvidersBinder(ActivityManagerService activityManagerService) {
1366 mActivityManagerService = activityManagerService;
1367 }
1368
1369 @Override
1370 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1371 mActivityManagerService.dumpProviders(pw);
1372 }
1373 }
1374
1375 static class MemBinder extends Binder {
1376 ActivityManagerService mActivityManagerService;
1377 MemBinder(ActivityManagerService activityManagerService) {
1378 mActivityManagerService = activityManagerService;
1379 }
1380
1381 @Override
1382 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1383 ActivityManagerService service = mActivityManagerService;
1384 ArrayList<ProcessRecord> procs;
1385 synchronized (mActivityManagerService) {
1386 if (args != null && args.length > 0
1387 && args[0].charAt(0) != '-') {
1388 procs = new ArrayList<ProcessRecord>();
1389 int pid = -1;
1390 try {
1391 pid = Integer.parseInt(args[0]);
1392 } catch (NumberFormatException e) {
1393
1394 }
1395 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1396 ProcessRecord proc = service.mLRUProcesses.get(i);
1397 if (proc.pid == pid) {
1398 procs.add(proc);
1399 } else if (proc.processName.equals(args[0])) {
1400 procs.add(proc);
1401 }
1402 }
1403 if (procs.size() <= 0) {
1404 pw.println("No process found for: " + args[0]);
1405 return;
1406 }
1407 } else {
1408 procs = service.mLRUProcesses;
1409 }
1410 }
1411 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1412 }
1413 }
1414
1415 static class CpuBinder extends Binder {
1416 ActivityManagerService mActivityManagerService;
1417 CpuBinder(ActivityManagerService activityManagerService) {
1418 mActivityManagerService = activityManagerService;
1419 }
1420
1421 @Override
1422 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1423 synchronized (mActivityManagerService.mProcessStatsThread) {
1424 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1425 }
1426 }
1427 }
1428
1429 private ActivityManagerService() {
1430 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1431 if (v != null && Integer.getInteger(v) != 0) {
1432 mSimpleProcessManagement = true;
1433 }
1434 v = System.getenv("ANDROID_DEBUG_APP");
1435 if (v != null) {
1436 mSimpleProcessManagement = true;
1437 }
1438
Dianne Hackborn2c6c5e62009-10-08 17:55:49 -07001439 Log.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
1440
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001441 MY_PID = Process.myPid();
1442
1443 File dataDir = Environment.getDataDirectory();
1444 File systemDir = new File(dataDir, "system");
1445 systemDir.mkdirs();
1446 mBatteryStatsService = new BatteryStatsService(new File(
1447 systemDir, "batterystats.bin").toString());
1448 mBatteryStatsService.getActiveStatistics().readLocked();
1449 mBatteryStatsService.getActiveStatistics().writeLocked();
1450
1451 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001452 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001453
Jack Palevichb90d28c2009-07-22 15:35:24 -07001454 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1455 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1456
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001457 mConfiguration.makeDefault();
1458 mProcessStats.init();
1459
1460 // Add ourself to the Watchdog monitors.
1461 Watchdog.getInstance().addMonitor(this);
1462
1463 // These values are set in system/rootdir/init.rc on startup.
1464 FOREGROUND_APP_ADJ =
1465 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1466 VISIBLE_APP_ADJ =
1467 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1468 SECONDARY_SERVER_ADJ =
1469 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001470 BACKUP_APP_ADJ =
1471 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001472 HOME_APP_ADJ =
1473 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001474 HIDDEN_APP_MIN_ADJ =
1475 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1476 CONTENT_PROVIDER_ADJ =
1477 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1478 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1479 EMPTY_APP_ADJ =
1480 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1481 FOREGROUND_APP_MEM =
1482 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1483 VISIBLE_APP_MEM =
1484 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1485 SECONDARY_SERVER_MEM =
1486 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001487 BACKUP_APP_MEM =
1488 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001489 HOME_APP_MEM =
1490 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001491 HIDDEN_APP_MEM =
1492 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1493 EMPTY_APP_MEM =
1494 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1495
1496 mProcessStatsThread = new Thread("ProcessStats") {
1497 public void run() {
1498 while (true) {
1499 try {
1500 try {
1501 synchronized(this) {
1502 final long now = SystemClock.uptimeMillis();
1503 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1504 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1505 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1506 // + ", write delay=" + nextWriteDelay);
1507 if (nextWriteDelay < nextCpuDelay) {
1508 nextCpuDelay = nextWriteDelay;
1509 }
1510 if (nextCpuDelay > 0) {
1511 this.wait(nextCpuDelay);
1512 }
1513 }
1514 } catch (InterruptedException e) {
1515 }
1516
1517 updateCpuStatsNow();
1518 } catch (Exception e) {
1519 Log.e(TAG, "Unexpected exception collecting process stats", e);
1520 }
1521 }
1522 }
1523 };
1524 mProcessStatsThread.start();
1525 }
1526
1527 @Override
1528 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1529 throws RemoteException {
1530 try {
1531 return super.onTransact(code, data, reply, flags);
1532 } catch (RuntimeException e) {
1533 // The activity manager only throws security exceptions, so let's
1534 // log all others.
1535 if (!(e instanceof SecurityException)) {
1536 Log.e(TAG, "Activity Manager Crash", e);
1537 }
1538 throw e;
1539 }
1540 }
1541
1542 void updateCpuStats() {
1543 synchronized (mProcessStatsThread) {
1544 final long now = SystemClock.uptimeMillis();
1545 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1546 mProcessStatsThread.notify();
1547 }
1548 }
1549 }
1550
1551 void updateCpuStatsNow() {
1552 synchronized (mProcessStatsThread) {
1553 final long now = SystemClock.uptimeMillis();
1554 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001555
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001556 if (MONITOR_CPU_USAGE &&
1557 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1558 mLastCpuTime = now;
1559 haveNewCpuStats = true;
1560 mProcessStats.update();
1561 //Log.i(TAG, mProcessStats.printCurrentState());
1562 //Log.i(TAG, "Total CPU usage: "
1563 // + mProcessStats.getTotalCpuPercent() + "%");
1564
1565 // Log the cpu usage if the property is set.
1566 if ("true".equals(SystemProperties.get("events.cpu"))) {
1567 int user = mProcessStats.getLastUserTime();
1568 int system = mProcessStats.getLastSystemTime();
1569 int iowait = mProcessStats.getLastIoWaitTime();
1570 int irq = mProcessStats.getLastIrqTime();
1571 int softIrq = mProcessStats.getLastSoftIrqTime();
1572 int idle = mProcessStats.getLastIdleTime();
1573
1574 int total = user + system + iowait + irq + softIrq + idle;
1575 if (total == 0) total = 1;
1576
1577 EventLog.writeEvent(LOG_CPU,
1578 ((user+system+iowait+irq+softIrq) * 100) / total,
1579 (user * 100) / total,
1580 (system * 100) / total,
1581 (iowait * 100) / total,
1582 (irq * 100) / total,
1583 (softIrq * 100) / total);
1584 }
1585 }
1586
Amith Yamasanie43530a2009-08-21 13:11:37 -07001587 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001588 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001589 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001590 synchronized(mPidsSelfLocked) {
1591 if (haveNewCpuStats) {
1592 if (mBatteryStatsService.isOnBattery()) {
1593 final int N = mProcessStats.countWorkingStats();
1594 for (int i=0; i<N; i++) {
1595 ProcessStats.Stats st
1596 = mProcessStats.getWorkingStats(i);
1597 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1598 if (pr != null) {
1599 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1600 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001601 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001602 } else {
1603 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001604 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001605 if (ps != null) {
1606 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001607 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001608 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001609 }
1610 }
1611 }
1612 }
1613 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001614
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001615 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1616 mLastWriteTime = now;
1617 mBatteryStatsService.getActiveStatistics().writeLocked();
1618 }
1619 }
1620 }
1621 }
1622
1623 /**
1624 * Initialize the application bind args. These are passed to each
1625 * process when the bindApplication() IPC is sent to the process. They're
1626 * lazily setup to make sure the services are running when they're asked for.
1627 */
1628 private HashMap<String, IBinder> getCommonServicesLocked() {
1629 if (mAppBindArgs == null) {
1630 mAppBindArgs = new HashMap<String, IBinder>();
1631
1632 // Setup the application init args
1633 mAppBindArgs.put("package", ServiceManager.getService("package"));
1634 mAppBindArgs.put("window", ServiceManager.getService("window"));
1635 mAppBindArgs.put(Context.ALARM_SERVICE,
1636 ServiceManager.getService(Context.ALARM_SERVICE));
1637 }
1638 return mAppBindArgs;
1639 }
1640
1641 private final void setFocusedActivityLocked(HistoryRecord r) {
1642 if (mFocusedActivity != r) {
1643 mFocusedActivity = r;
1644 mWindowManager.setFocusedApp(r, true);
1645 }
1646 }
1647
1648 private final void updateLRUListLocked(ProcessRecord app,
1649 boolean oomAdj) {
1650 // put it on the LRU to keep track of when it should be exited.
1651 int lrui = mLRUProcesses.indexOf(app);
1652 if (lrui >= 0) mLRUProcesses.remove(lrui);
1653 mLRUProcesses.add(app);
1654 //Log.i(TAG, "Putting proc to front: " + app.processName);
1655 if (oomAdj) {
1656 updateOomAdjLocked();
1657 }
1658 }
1659
1660 private final boolean updateLRUListLocked(HistoryRecord r) {
1661 final boolean hadit = mLRUActivities.remove(r);
1662 mLRUActivities.add(r);
1663 return hadit;
1664 }
1665
1666 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1667 int i = mHistory.size()-1;
1668 while (i >= 0) {
1669 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1670 if (!r.finishing && r != notTop) {
1671 return r;
1672 }
1673 i--;
1674 }
1675 return null;
1676 }
1677
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001678 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1679 int i = mHistory.size()-1;
1680 while (i >= 0) {
1681 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1682 if (!r.finishing && !r.delayedResume && r != notTop) {
1683 return r;
1684 }
1685 i--;
1686 }
1687 return null;
1688 }
1689
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 /**
1691 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001692 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001693 *
1694 * @param token If non-null, any history records matching this token will be skipped.
1695 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1696 *
1697 * @return Returns the HistoryRecord of the next activity on the stack.
1698 */
1699 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1700 int i = mHistory.size()-1;
1701 while (i >= 0) {
1702 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1703 // Note: the taskId check depends on real taskId fields being non-zero
1704 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1705 return r;
1706 }
1707 i--;
1708 }
1709 return null;
1710 }
1711
1712 private final ProcessRecord getProcessRecordLocked(
1713 String processName, int uid) {
1714 if (uid == Process.SYSTEM_UID) {
1715 // The system gets to run in any process. If there are multiple
1716 // processes with the same uid, just pick the first (this
1717 // should never happen).
1718 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1719 processName);
1720 return procs != null ? procs.valueAt(0) : null;
1721 }
1722 ProcessRecord proc = mProcessNames.get(processName, uid);
1723 return proc;
1724 }
1725
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001726 private void ensurePackageDexOpt(String packageName) {
1727 IPackageManager pm = ActivityThread.getPackageManager();
1728 try {
1729 if (pm.performDexOpt(packageName)) {
1730 mDidDexOpt = true;
1731 }
1732 } catch (RemoteException e) {
1733 }
1734 }
1735
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001736 private boolean isNextTransitionForward() {
1737 int transit = mWindowManager.getPendingAppTransition();
1738 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1739 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1740 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1741 }
1742
1743 private final boolean realStartActivityLocked(HistoryRecord r,
1744 ProcessRecord app, boolean andResume, boolean checkConfig)
1745 throws RemoteException {
1746
1747 r.startFreezingScreenLocked(app, 0);
1748 mWindowManager.setAppVisibility(r, true);
1749
1750 // Have the window manager re-evaluate the orientation of
1751 // the screen based on the new activity order. Note that
1752 // as a result of this, it can call back into the activity
1753 // manager with a new orientation. We don't care about that,
1754 // because the activity is not currently running so we are
1755 // just restarting it anyway.
1756 if (checkConfig) {
1757 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001758 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001759 r.mayFreezeScreenLocked(app) ? r : null);
1760 updateConfigurationLocked(config, r);
1761 }
1762
1763 r.app = app;
1764
1765 if (localLOGV) Log.v(TAG, "Launching: " + r);
1766
1767 int idx = app.activities.indexOf(r);
1768 if (idx < 0) {
1769 app.activities.add(r);
1770 }
1771 updateLRUListLocked(app, true);
1772
1773 try {
1774 if (app.thread == null) {
1775 throw new RemoteException();
1776 }
1777 List<ResultInfo> results = null;
1778 List<Intent> newIntents = null;
1779 if (andResume) {
1780 results = r.results;
1781 newIntents = r.newIntents;
1782 }
1783 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1784 + " icicle=" + r.icicle
1785 + " with results=" + results + " newIntents=" + newIntents
1786 + " andResume=" + andResume);
1787 if (andResume) {
1788 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1789 System.identityHashCode(r),
1790 r.task.taskId, r.shortComponentName);
1791 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001792 if (r.isHomeActivity) {
1793 mHomeProcess = app;
1794 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001795 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001796 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001797 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001798 r.info, r.icicle, results, newIntents, !andResume,
1799 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001800 } catch (RemoteException e) {
1801 if (r.launchFailed) {
1802 // This is the second time we failed -- finish activity
1803 // and give up.
1804 Log.e(TAG, "Second failure launching "
1805 + r.intent.getComponent().flattenToShortString()
1806 + ", giving up", e);
1807 appDiedLocked(app, app.pid, app.thread);
1808 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1809 "2nd-crash");
1810 return false;
1811 }
1812
1813 // This is the first time we failed -- restart process and
1814 // retry.
1815 app.activities.remove(r);
1816 throw e;
1817 }
1818
1819 r.launchFailed = false;
1820 if (updateLRUListLocked(r)) {
1821 Log.w(TAG, "Activity " + r
1822 + " being launched, but already in LRU list");
1823 }
1824
1825 if (andResume) {
1826 // As part of the process of launching, ActivityThread also performs
1827 // a resume.
1828 r.state = ActivityState.RESUMED;
1829 r.icicle = null;
1830 r.haveState = false;
1831 r.stopped = false;
1832 mResumedActivity = r;
1833 r.task.touchActiveTime();
1834 completeResumeLocked(r);
1835 pauseIfSleepingLocked();
1836 } else {
1837 // This activity is not starting in the resumed state... which
1838 // should look like we asked it to pause+stop (but remain visible),
1839 // and it has done so and reported back the current icicle and
1840 // other state.
1841 r.state = ActivityState.STOPPED;
1842 r.stopped = true;
1843 }
1844
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001845 // Launch the new version setup screen if needed. We do this -after-
1846 // launching the initial activity (that is, home), so that it can have
1847 // a chance to initialize itself while in the background, making the
1848 // switch back to it faster and look better.
1849 startSetupActivityLocked();
1850
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001851 return true;
1852 }
1853
1854 private final void startSpecificActivityLocked(HistoryRecord r,
1855 boolean andResume, boolean checkConfig) {
1856 // Is this activity's application already running?
1857 ProcessRecord app = getProcessRecordLocked(r.processName,
1858 r.info.applicationInfo.uid);
1859
1860 if (r.startTime == 0) {
1861 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001862 if (mInitialStartTime == 0) {
1863 mInitialStartTime = r.startTime;
1864 }
1865 } else if (mInitialStartTime == 0) {
1866 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001867 }
1868
1869 if (app != null && app.thread != null) {
1870 try {
1871 realStartActivityLocked(r, app, andResume, checkConfig);
1872 return;
1873 } catch (RemoteException e) {
1874 Log.w(TAG, "Exception when starting activity "
1875 + r.intent.getComponent().flattenToShortString(), e);
1876 }
1877
1878 // If a dead object exception was thrown -- fall through to
1879 // restart the application.
1880 }
1881
1882 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001883 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001884 }
1885
1886 private final ProcessRecord startProcessLocked(String processName,
1887 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001888 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001889 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1890 // We don't have to do anything more if:
1891 // (1) There is an existing application record; and
1892 // (2) The caller doesn't think it is dead, OR there is no thread
1893 // object attached to it so we know it couldn't have crashed; and
1894 // (3) There is a pid assigned to it, so it is either starting or
1895 // already running.
1896 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1897 + " app=" + app + " knownToBeDead=" + knownToBeDead
1898 + " thread=" + (app != null ? app.thread : null)
1899 + " pid=" + (app != null ? app.pid : -1));
1900 if (app != null &&
1901 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1902 return app;
1903 }
1904
1905 String hostingNameStr = hostingName != null
1906 ? hostingName.flattenToShortString() : null;
1907
1908 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1909 // If we are in the background, then check to see if this process
1910 // is bad. If so, we will just silently fail.
1911 if (mBadProcesses.get(info.processName, info.uid) != null) {
1912 return null;
1913 }
1914 } else {
1915 // When the user is explicitly starting a process, then clear its
1916 // crash count so that we won't make it bad until they see at
1917 // least one crash dialog again, and make the process good again
1918 // if it had been bad.
1919 mProcessCrashTimes.remove(info.processName, info.uid);
1920 if (mBadProcesses.get(info.processName, info.uid) != null) {
1921 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1922 info.processName);
1923 mBadProcesses.remove(info.processName, info.uid);
1924 if (app != null) {
1925 app.bad = false;
1926 }
1927 }
1928 }
1929
1930 if (app == null) {
1931 app = newProcessRecordLocked(null, info, processName);
1932 mProcessNames.put(processName, info.uid, app);
1933 } else {
1934 // If this is a new package in the process, add the package to the list
1935 app.addPackage(info.packageName);
1936 }
1937
1938 // If the system is not ready yet, then hold off on starting this
1939 // process until it is.
1940 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001941 && !isAllowedWhileBooting(info)
1942 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001943 if (!mProcessesOnHold.contains(app)) {
1944 mProcessesOnHold.add(app);
1945 }
1946 return app;
1947 }
1948
1949 startProcessLocked(app, hostingType, hostingNameStr);
1950 return (app.pid != 0) ? app : null;
1951 }
1952
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001953 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1954 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1955 }
1956
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001957 private final void startProcessLocked(ProcessRecord app,
1958 String hostingType, String hostingNameStr) {
1959 if (app.pid > 0 && app.pid != MY_PID) {
1960 synchronized (mPidsSelfLocked) {
1961 mPidsSelfLocked.remove(app.pid);
1962 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1963 }
1964 app.pid = 0;
1965 }
1966
1967 mProcessesOnHold.remove(app);
1968
1969 updateCpuStats();
1970
1971 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1972 mProcDeaths[0] = 0;
1973
1974 try {
1975 int uid = app.info.uid;
1976 int[] gids = null;
1977 try {
1978 gids = mContext.getPackageManager().getPackageGids(
1979 app.info.packageName);
1980 } catch (PackageManager.NameNotFoundException e) {
1981 Log.w(TAG, "Unable to retrieve gids", e);
1982 }
1983 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1984 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1985 && mTopComponent != null
1986 && app.processName.equals(mTopComponent.getPackageName())) {
1987 uid = 0;
1988 }
1989 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1990 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1991 uid = 0;
1992 }
1993 }
1994 int debugFlags = 0;
1995 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1996 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1997 }
1998 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1999 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
2000 }
2001 if ("1".equals(SystemProperties.get("debug.assert"))) {
2002 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
2003 }
2004 int pid = Process.start("android.app.ActivityThread",
2005 mSimpleProcessManagement ? app.processName : null, uid, uid,
2006 gids, debugFlags, null);
2007 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
2008 synchronized (bs) {
2009 if (bs.isOnBattery()) {
2010 app.batteryStats.incStartsLocked();
2011 }
2012 }
2013
2014 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
2015 app.processName, hostingType,
2016 hostingNameStr != null ? hostingNameStr : "");
2017
2018 if (app.persistent) {
2019 Watchdog.getInstance().processStarted(app, app.processName, pid);
2020 }
2021
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07002022 StringBuilder buf = mStringBuilder;
2023 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002024 buf.append("Start proc ");
2025 buf.append(app.processName);
2026 buf.append(" for ");
2027 buf.append(hostingType);
2028 if (hostingNameStr != null) {
2029 buf.append(" ");
2030 buf.append(hostingNameStr);
2031 }
2032 buf.append(": pid=");
2033 buf.append(pid);
2034 buf.append(" uid=");
2035 buf.append(uid);
2036 buf.append(" gids={");
2037 if (gids != null) {
2038 for (int gi=0; gi<gids.length; gi++) {
2039 if (gi != 0) buf.append(", ");
2040 buf.append(gids[gi]);
2041
2042 }
2043 }
2044 buf.append("}");
2045 Log.i(TAG, buf.toString());
2046 if (pid == 0 || pid == MY_PID) {
2047 // Processes are being emulated with threads.
2048 app.pid = MY_PID;
2049 app.removed = false;
2050 mStartingProcesses.add(app);
2051 } else if (pid > 0) {
2052 app.pid = pid;
2053 app.removed = false;
2054 synchronized (mPidsSelfLocked) {
2055 this.mPidsSelfLocked.put(pid, app);
2056 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2057 msg.obj = app;
2058 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2059 }
2060 } else {
2061 app.pid = 0;
2062 RuntimeException e = new RuntimeException(
2063 "Failure starting process " + app.processName
2064 + ": returned pid=" + pid);
2065 Log.e(TAG, e.getMessage(), e);
2066 }
2067 } catch (RuntimeException e) {
2068 // XXX do better error recovery.
2069 app.pid = 0;
2070 Log.e(TAG, "Failure starting process " + app.processName, e);
2071 }
2072 }
2073
2074 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2075 if (mPausingActivity != null) {
2076 RuntimeException e = new RuntimeException();
2077 Log.e(TAG, "Trying to pause when pause is already pending for "
2078 + mPausingActivity, e);
2079 }
2080 HistoryRecord prev = mResumedActivity;
2081 if (prev == null) {
2082 RuntimeException e = new RuntimeException();
2083 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2084 resumeTopActivityLocked(null);
2085 return;
2086 }
2087 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2088 mResumedActivity = null;
2089 mPausingActivity = prev;
2090 mLastPausedActivity = prev;
2091 prev.state = ActivityState.PAUSING;
2092 prev.task.touchActiveTime();
2093
2094 updateCpuStats();
2095
2096 if (prev.app != null && prev.app.thread != null) {
2097 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2098 try {
2099 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2100 System.identityHashCode(prev),
2101 prev.shortComponentName);
2102 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2103 prev.configChangeFlags);
2104 updateUsageStats(prev, false);
2105 } catch (Exception e) {
2106 // Ignore exception, if process died other code will cleanup.
2107 Log.w(TAG, "Exception thrown during pause", e);
2108 mPausingActivity = null;
2109 mLastPausedActivity = null;
2110 }
2111 } else {
2112 mPausingActivity = null;
2113 mLastPausedActivity = null;
2114 }
2115
2116 // If we are not going to sleep, we want to ensure the device is
2117 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002118 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002119 mLaunchingActivity.acquire();
2120 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2121 // To be safe, don't allow the wake lock to be held for too long.
2122 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2123 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2124 }
2125 }
2126
2127
2128 if (mPausingActivity != null) {
2129 // Have the window manager pause its key dispatching until the new
2130 // activity has started. If we're pausing the activity just because
2131 // the screen is being turned off and the UI is sleeping, don't interrupt
2132 // key dispatch; the same activity will pick it up again on wakeup.
2133 if (!uiSleeping) {
2134 prev.pauseKeyDispatchingLocked();
2135 } else {
2136 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2137 }
2138
2139 // Schedule a pause timeout in case the app doesn't respond.
2140 // We don't give it much time because this directly impacts the
2141 // responsiveness seen by the user.
2142 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2143 msg.obj = prev;
2144 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2145 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2146 } else {
2147 // This activity failed to schedule the
2148 // pause, so just treat it as being paused now.
2149 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2150 resumeTopActivityLocked(null);
2151 }
2152 }
2153
2154 private final void completePauseLocked() {
2155 HistoryRecord prev = mPausingActivity;
2156 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2157
2158 if (prev != null) {
2159 if (prev.finishing) {
2160 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2161 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2162 } else if (prev.app != null) {
2163 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2164 if (prev.waitingVisible) {
2165 prev.waitingVisible = false;
2166 mWaitingVisibleActivities.remove(prev);
2167 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2168 TAG, "Complete pause, no longer waiting: " + prev);
2169 }
2170 if (prev.configDestroy) {
2171 // The previous is being paused because the configuration
2172 // is changing, which means it is actually stopping...
2173 // To juggle the fact that we are also starting a new
2174 // instance right now, we need to first completely stop
2175 // the current instance before starting the new one.
2176 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2177 destroyActivityLocked(prev, true);
2178 } else {
2179 mStoppingActivities.add(prev);
2180 if (mStoppingActivities.size() > 3) {
2181 // If we already have a few activities waiting to stop,
2182 // then give up on things going idle and start clearing
2183 // them out.
2184 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2185 Message msg = Message.obtain();
2186 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2187 mHandler.sendMessage(msg);
2188 }
2189 }
2190 } else {
2191 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2192 prev = null;
2193 }
2194 mPausingActivity = null;
2195 }
2196
Dianne Hackborn55280a92009-05-07 15:53:46 -07002197 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002198 resumeTopActivityLocked(prev);
2199 } else {
2200 if (mGoingToSleep.isHeld()) {
2201 mGoingToSleep.release();
2202 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002203 if (mShuttingDown) {
2204 notifyAll();
2205 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002206 }
2207
2208 if (prev != null) {
2209 prev.resumeKeyDispatchingLocked();
2210 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002211
2212 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2213 long diff = 0;
2214 synchronized (mProcessStatsThread) {
2215 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2216 }
2217 if (diff > 0) {
2218 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2219 synchronized (bsi) {
2220 BatteryStatsImpl.Uid.Proc ps =
2221 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2222 prev.info.packageName);
2223 if (ps != null) {
2224 ps.addForegroundTimeLocked(diff);
2225 }
2226 }
2227 }
2228 }
2229 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002230 }
2231
2232 /**
2233 * Once we know that we have asked an application to put an activity in
2234 * the resumed state (either by launching it or explicitly telling it),
2235 * this function updates the rest of our state to match that fact.
2236 */
2237 private final void completeResumeLocked(HistoryRecord next) {
2238 next.idle = false;
2239 next.results = null;
2240 next.newIntents = null;
2241
2242 // schedule an idle timeout in case the app doesn't do it for us.
2243 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2244 msg.obj = next;
2245 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2246
2247 if (false) {
2248 // The activity was never told to pause, so just keep
2249 // things going as-is. To maintain our own state,
2250 // we need to emulate it coming back and saying it is
2251 // idle.
2252 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2253 msg.obj = next;
2254 mHandler.sendMessage(msg);
2255 }
2256
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002257 reportResumedActivityLocked(next);
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002258
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002259 next.thumbnail = null;
2260 setFocusedActivityLocked(next);
2261 next.resumeKeyDispatchingLocked();
2262 ensureActivitiesVisibleLocked(null, 0);
2263 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002264 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002265
2266 // Mark the point when the activity is resuming
2267 // TODO: To be more accurate, the mark should be before the onCreate,
2268 // not after the onResume. But for subsequent starts, onResume is fine.
2269 if (next.app != null) {
2270 synchronized (mProcessStatsThread) {
2271 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2272 }
2273 } else {
2274 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2275 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002276 }
2277
2278 /**
2279 * Make sure that all activities that need to be visible (that is, they
2280 * currently can be seen by the user) actually are.
2281 */
2282 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2283 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2284 if (DEBUG_VISBILITY) Log.v(
2285 TAG, "ensureActivitiesVisible behind " + top
2286 + " configChanges=0x" + Integer.toHexString(configChanges));
2287
2288 // If the top activity is not fullscreen, then we need to
2289 // make sure any activities under it are now visible.
2290 final int count = mHistory.size();
2291 int i = count-1;
2292 while (mHistory.get(i) != top) {
2293 i--;
2294 }
2295 HistoryRecord r;
2296 boolean behindFullscreen = false;
2297 for (; i>=0; i--) {
2298 r = (HistoryRecord)mHistory.get(i);
2299 if (DEBUG_VISBILITY) Log.v(
2300 TAG, "Make visible? " + r + " finishing=" + r.finishing
2301 + " state=" + r.state);
2302 if (r.finishing) {
2303 continue;
2304 }
2305
2306 final boolean doThisProcess = onlyThisProcess == null
2307 || onlyThisProcess.equals(r.processName);
2308
2309 // First: if this is not the current activity being started, make
2310 // sure it matches the current configuration.
2311 if (r != starting && doThisProcess) {
2312 ensureActivityConfigurationLocked(r, 0);
2313 }
2314
2315 if (r.app == null || r.app.thread == null) {
2316 if (onlyThisProcess == null
2317 || onlyThisProcess.equals(r.processName)) {
2318 // This activity needs to be visible, but isn't even
2319 // running... get it started, but don't resume it
2320 // at this point.
2321 if (DEBUG_VISBILITY) Log.v(
2322 TAG, "Start and freeze screen for " + r);
2323 if (r != starting) {
2324 r.startFreezingScreenLocked(r.app, configChanges);
2325 }
2326 if (!r.visible) {
2327 if (DEBUG_VISBILITY) Log.v(
2328 TAG, "Starting and making visible: " + r);
2329 mWindowManager.setAppVisibility(r, true);
2330 }
2331 if (r != starting) {
2332 startSpecificActivityLocked(r, false, false);
2333 }
2334 }
2335
2336 } else if (r.visible) {
2337 // If this activity is already visible, then there is nothing
2338 // else to do here.
2339 if (DEBUG_VISBILITY) Log.v(
2340 TAG, "Skipping: already visible at " + r);
2341 r.stopFreezingScreenLocked(false);
2342
2343 } else if (onlyThisProcess == null) {
2344 // This activity is not currently visible, but is running.
2345 // Tell it to become visible.
2346 r.visible = true;
2347 if (r.state != ActivityState.RESUMED && r != starting) {
2348 // If this activity is paused, tell it
2349 // to now show its window.
2350 if (DEBUG_VISBILITY) Log.v(
2351 TAG, "Making visible and scheduling visibility: " + r);
2352 try {
2353 mWindowManager.setAppVisibility(r, true);
2354 r.app.thread.scheduleWindowVisibility(r, true);
2355 r.stopFreezingScreenLocked(false);
2356 } catch (Exception e) {
2357 // Just skip on any failure; we'll make it
2358 // visible when it next restarts.
2359 Log.w(TAG, "Exception thrown making visibile: "
2360 + r.intent.getComponent(), e);
2361 }
2362 }
2363 }
2364
2365 // Aggregate current change flags.
2366 configChanges |= r.configChangeFlags;
2367
2368 if (r.fullscreen) {
2369 // At this point, nothing else needs to be shown
2370 if (DEBUG_VISBILITY) Log.v(
2371 TAG, "Stopping: fullscreen at " + r);
2372 behindFullscreen = true;
2373 i--;
2374 break;
2375 }
2376 }
2377
2378 // Now for any activities that aren't visible to the user, make
2379 // sure they no longer are keeping the screen frozen.
2380 while (i >= 0) {
2381 r = (HistoryRecord)mHistory.get(i);
2382 if (DEBUG_VISBILITY) Log.v(
2383 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2384 + " state=" + r.state
2385 + " behindFullscreen=" + behindFullscreen);
2386 if (!r.finishing) {
2387 if (behindFullscreen) {
2388 if (r.visible) {
2389 if (DEBUG_VISBILITY) Log.v(
2390 TAG, "Making invisible: " + r);
2391 r.visible = false;
2392 try {
2393 mWindowManager.setAppVisibility(r, false);
2394 if ((r.state == ActivityState.STOPPING
2395 || r.state == ActivityState.STOPPED)
2396 && r.app != null && r.app.thread != null) {
2397 if (DEBUG_VISBILITY) Log.v(
2398 TAG, "Scheduling invisibility: " + r);
2399 r.app.thread.scheduleWindowVisibility(r, false);
2400 }
2401 } catch (Exception e) {
2402 // Just skip on any failure; we'll make it
2403 // visible when it next restarts.
2404 Log.w(TAG, "Exception thrown making hidden: "
2405 + r.intent.getComponent(), e);
2406 }
2407 } else {
2408 if (DEBUG_VISBILITY) Log.v(
2409 TAG, "Already invisible: " + r);
2410 }
2411 } else if (r.fullscreen) {
2412 if (DEBUG_VISBILITY) Log.v(
2413 TAG, "Now behindFullscreen: " + r);
2414 behindFullscreen = true;
2415 }
2416 }
2417 i--;
2418 }
2419 }
2420
2421 /**
2422 * Version of ensureActivitiesVisible that can easily be called anywhere.
2423 */
2424 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2425 int configChanges) {
2426 HistoryRecord r = topRunningActivityLocked(null);
2427 if (r != null) {
2428 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2429 }
2430 }
2431
2432 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2433 if (resumed) {
2434 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2435 } else {
2436 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2437 }
2438 }
2439
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002440 private boolean startHomeActivityLocked() {
2441 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2442 && mTopAction == null) {
2443 // We are running in factory test mode, but unable to find
2444 // the factory test app, so just sit around displaying the
2445 // error message and don't try to start anything.
2446 return false;
2447 }
2448 Intent intent = new Intent(
2449 mTopAction,
2450 mTopData != null ? Uri.parse(mTopData) : null);
2451 intent.setComponent(mTopComponent);
2452 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2453 intent.addCategory(Intent.CATEGORY_HOME);
2454 }
2455 ActivityInfo aInfo =
2456 intent.resolveActivityInfo(mContext.getPackageManager(),
2457 STOCK_PM_FLAGS);
2458 if (aInfo != null) {
2459 intent.setComponent(new ComponentName(
2460 aInfo.applicationInfo.packageName, aInfo.name));
2461 // Don't do this if the home app is currently being
2462 // instrumented.
2463 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2464 aInfo.applicationInfo.uid);
2465 if (app == null || app.instrumentationClass == null) {
2466 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2467 startActivityLocked(null, intent, null, null, 0, aInfo,
2468 null, null, 0, 0, 0, false, false);
2469 }
2470 }
2471
2472
2473 return true;
2474 }
2475
2476 /**
2477 * Starts the "new version setup screen" if appropriate.
2478 */
2479 private void startSetupActivityLocked() {
2480 // Only do this once per boot.
2481 if (mCheckedForSetup) {
2482 return;
2483 }
2484
2485 // We will show this screen if the current one is a different
2486 // version than the last one shown, and we are not running in
2487 // low-level factory test mode.
2488 final ContentResolver resolver = mContext.getContentResolver();
2489 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2490 Settings.Secure.getInt(resolver,
2491 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2492 mCheckedForSetup = true;
2493
2494 // See if we should be showing the platform update setup UI.
2495 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2496 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2497 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2498
2499 // We don't allow third party apps to replace this.
2500 ResolveInfo ri = null;
2501 for (int i=0; ris != null && i<ris.size(); i++) {
2502 if ((ris.get(i).activityInfo.applicationInfo.flags
2503 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2504 ri = ris.get(i);
2505 break;
2506 }
2507 }
2508
2509 if (ri != null) {
2510 String vers = ri.activityInfo.metaData != null
2511 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2512 : null;
2513 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2514 vers = ri.activityInfo.applicationInfo.metaData.getString(
2515 Intent.METADATA_SETUP_VERSION);
2516 }
2517 String lastVers = Settings.Secure.getString(
2518 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2519 if (vers != null && !vers.equals(lastVers)) {
2520 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2521 intent.setComponent(new ComponentName(
2522 ri.activityInfo.packageName, ri.activityInfo.name));
2523 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2524 null, null, 0, 0, 0, false, false);
2525 }
2526 }
2527 }
2528 }
2529
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002530 private void reportResumedActivityLocked(HistoryRecord r) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002531 //Log.i(TAG, "**** REPORT RESUME: " + r);
2532
2533 final int identHash = System.identityHashCode(r);
2534 updateUsageStats(r, true);
2535
2536 int i = mWatchers.beginBroadcast();
2537 while (i > 0) {
2538 i--;
2539 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2540 if (w != null) {
2541 try {
2542 w.activityResuming(identHash);
2543 } catch (RemoteException e) {
2544 }
2545 }
2546 }
2547 mWatchers.finishBroadcast();
2548 }
2549
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002550 /**
2551 * Ensure that the top activity in the stack is resumed.
2552 *
2553 * @param prev The previously resumed activity, for when in the process
2554 * of pausing; can be null to call from elsewhere.
2555 *
2556 * @return Returns true if something is being resumed, or false if
2557 * nothing happened.
2558 */
2559 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2560 // Find the first activity that is not finishing.
2561 HistoryRecord next = topRunningActivityLocked(null);
2562
2563 // Remember how we'll process this pause/resume situation, and ensure
2564 // that the state is reset however we wind up proceeding.
2565 final boolean userLeaving = mUserLeaving;
2566 mUserLeaving = false;
2567
2568 if (next == null) {
2569 // There are no more activities! Let's just start up the
2570 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002571 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002572 }
2573
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002574 next.delayedResume = false;
2575
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002576 // If the top activity is the resumed one, nothing to do.
2577 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2578 // Make sure we have executed any pending transitions, since there
2579 // should be nothing left to do at this point.
2580 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002581 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002582 return false;
2583 }
2584
2585 // If we are sleeping, and there is no resumed activity, and the top
2586 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002587 if ((mSleeping || mShuttingDown)
2588 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002589 // Make sure we have executed any pending transitions, since there
2590 // should be nothing left to do at this point.
2591 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002592 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002593 return false;
2594 }
2595
2596 // The activity may be waiting for stop, but that is no longer
2597 // appropriate for it.
2598 mStoppingActivities.remove(next);
2599 mWaitingVisibleActivities.remove(next);
2600
2601 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2602
2603 // If we are currently pausing an activity, then don't do anything
2604 // until that is done.
2605 if (mPausingActivity != null) {
2606 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2607 return false;
2608 }
2609
2610 // We need to start pausing the current activity so the top one
2611 // can be resumed...
2612 if (mResumedActivity != null) {
2613 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2614 startPausingLocked(userLeaving, false);
2615 return true;
2616 }
2617
2618 if (prev != null && prev != next) {
2619 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2620 prev.waitingVisible = true;
2621 mWaitingVisibleActivities.add(prev);
2622 if (DEBUG_SWITCH) Log.v(
2623 TAG, "Resuming top, waiting visible to hide: " + prev);
2624 } else {
2625 // The next activity is already visible, so hide the previous
2626 // activity's windows right now so we can show the new one ASAP.
2627 // We only do this if the previous is finishing, which should mean
2628 // it is on top of the one being resumed so hiding it quickly
2629 // is good. Otherwise, we want to do the normal route of allowing
2630 // the resumed activity to be shown so we can decide if the
2631 // previous should actually be hidden depending on whether the
2632 // new one is found to be full-screen or not.
2633 if (prev.finishing) {
2634 mWindowManager.setAppVisibility(prev, false);
2635 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2636 + prev + ", waitingVisible="
2637 + (prev != null ? prev.waitingVisible : null)
2638 + ", nowVisible=" + next.nowVisible);
2639 } else {
2640 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2641 + prev + ", waitingVisible="
2642 + (prev != null ? prev.waitingVisible : null)
2643 + ", nowVisible=" + next.nowVisible);
2644 }
2645 }
2646 }
2647
2648 // We are starting up the next activity, so tell the window manager
2649 // that the previous one will be hidden soon. This way it can know
2650 // to ignore it when computing the desired screen orientation.
2651 if (prev != null) {
2652 if (prev.finishing) {
2653 if (DEBUG_TRANSITION) Log.v(TAG,
2654 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002655 if (mNoAnimActivities.contains(prev)) {
2656 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2657 } else {
2658 mWindowManager.prepareAppTransition(prev.task == next.task
2659 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2660 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2661 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002662 mWindowManager.setAppWillBeHidden(prev);
2663 mWindowManager.setAppVisibility(prev, false);
2664 } else {
2665 if (DEBUG_TRANSITION) Log.v(TAG,
2666 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002667 if (mNoAnimActivities.contains(next)) {
2668 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2669 } else {
2670 mWindowManager.prepareAppTransition(prev.task == next.task
2671 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2672 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2673 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002674 }
2675 if (false) {
2676 mWindowManager.setAppWillBeHidden(prev);
2677 mWindowManager.setAppVisibility(prev, false);
2678 }
2679 } else if (mHistory.size() > 1) {
2680 if (DEBUG_TRANSITION) Log.v(TAG,
2681 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002682 if (mNoAnimActivities.contains(next)) {
2683 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2684 } else {
2685 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2686 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002687 }
2688
2689 if (next.app != null && next.app.thread != null) {
2690 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2691
2692 // This activity is now becoming visible.
2693 mWindowManager.setAppVisibility(next, true);
2694
2695 HistoryRecord lastResumedActivity = mResumedActivity;
2696 ActivityState lastState = next.state;
2697
2698 updateCpuStats();
2699
2700 next.state = ActivityState.RESUMED;
2701 mResumedActivity = next;
2702 next.task.touchActiveTime();
2703 updateLRUListLocked(next.app, true);
2704 updateLRUListLocked(next);
2705
2706 // Have the window manager re-evaluate the orientation of
2707 // the screen based on the new activity order.
2708 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002709 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002710 next.mayFreezeScreenLocked(next.app) ? next : null);
2711 if (config != null) {
2712 next.frozenBeforeDestroy = true;
2713 }
2714 if (!updateConfigurationLocked(config, next)) {
2715 // The configuration update wasn't able to keep the existing
2716 // instance of the activity, and instead started a new one.
2717 // We should be all done, but let's just make sure our activity
2718 // is still at the top and schedule another run if something
2719 // weird happened.
2720 HistoryRecord nextNext = topRunningActivityLocked(null);
2721 if (DEBUG_SWITCH) Log.i(TAG,
2722 "Activity config changed during resume: " + next
2723 + ", new next: " + nextNext);
2724 if (nextNext != next) {
2725 // Do over!
2726 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2727 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002728 setFocusedActivityLocked(next);
2729 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002730 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002731 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002732 return true;
2733 }
2734
2735 try {
2736 // Deliver all pending results.
2737 ArrayList a = next.results;
2738 if (a != null) {
2739 final int N = a.size();
2740 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002741 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002742 TAG, "Delivering results to " + next
2743 + ": " + a);
2744 next.app.thread.scheduleSendResult(next, a);
2745 }
2746 }
2747
2748 if (next.newIntents != null) {
2749 next.app.thread.scheduleNewIntent(next.newIntents, next);
2750 }
2751
2752 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2753 System.identityHashCode(next),
2754 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002755
2756 next.app.thread.scheduleResumeActivity(next,
2757 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002758
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002759 pauseIfSleepingLocked();
2760
2761 } catch (Exception e) {
2762 // Whoops, need to restart this activity!
2763 next.state = lastState;
2764 mResumedActivity = lastResumedActivity;
2765 if (Config.LOGD) Log.d(TAG,
2766 "Restarting because process died: " + next);
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 }
2777 startSpecificActivityLocked(next, true, false);
2778 return true;
2779 }
2780
2781 // From this point on, if something goes wrong there is no way
2782 // to recover the activity.
2783 try {
2784 next.visible = true;
2785 completeResumeLocked(next);
2786 } catch (Exception e) {
2787 // If any exception gets thrown, toss away this
2788 // activity and try the next one.
2789 Log.w(TAG, "Exception thrown during resume of " + next, e);
2790 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2791 "resume-exception");
2792 return true;
2793 }
2794
2795 // Didn't need to use the icicle, and it is now out of date.
2796 next.icicle = null;
2797 next.haveState = false;
2798 next.stopped = false;
2799
2800 } else {
2801 // Whoops, need to restart this activity!
2802 if (!next.hasBeenLaunched) {
2803 next.hasBeenLaunched = true;
2804 } else {
2805 if (SHOW_APP_STARTING_ICON) {
2806 mWindowManager.setAppStartingWindow(
2807 next, next.packageName, next.theme,
2808 next.nonLocalizedLabel,
2809 next.labelRes, next.icon, null, true);
2810 }
2811 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2812 }
2813 startSpecificActivityLocked(next, true, true);
2814 }
2815
2816 return true;
2817 }
2818
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002819 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2820 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002821 final int NH = mHistory.size();
2822
2823 int addPos = -1;
2824
2825 if (!newTask) {
2826 // If starting in an existing task, find where that is...
2827 HistoryRecord next = null;
2828 boolean startIt = true;
2829 for (int i = NH-1; i >= 0; i--) {
2830 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2831 if (p.finishing) {
2832 continue;
2833 }
2834 if (p.task == r.task) {
2835 // Here it is! Now, if this is not yet visible to the
2836 // user, then just add it without starting; it will
2837 // get started when the user navigates back to it.
2838 addPos = i+1;
2839 if (!startIt) {
2840 mHistory.add(addPos, r);
2841 r.inHistory = true;
2842 r.task.numActivities++;
2843 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2844 r.info.screenOrientation, r.fullscreen);
2845 if (VALIDATE_TOKENS) {
2846 mWindowManager.validateAppTokens(mHistory);
2847 }
2848 return;
2849 }
2850 break;
2851 }
2852 if (p.fullscreen) {
2853 startIt = false;
2854 }
2855 next = p;
2856 }
2857 }
2858
2859 // Place a new activity at top of stack, so it is next to interact
2860 // with the user.
2861 if (addPos < 0) {
2862 addPos = mHistory.size();
2863 }
2864
2865 // If we are not placing the new activity frontmost, we do not want
2866 // to deliver the onUserLeaving callback to the actual frontmost
2867 // activity
2868 if (addPos < NH) {
2869 mUserLeaving = false;
2870 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2871 }
2872
2873 // Slot the activity into the history stack and proceed
2874 mHistory.add(addPos, r);
2875 r.inHistory = true;
2876 r.frontOfTask = newTask;
2877 r.task.numActivities++;
2878 if (NH > 0) {
2879 // We want to show the starting preview window if we are
2880 // switching to a new task, or the next activity's process is
2881 // not currently running.
2882 boolean showStartingIcon = newTask;
2883 ProcessRecord proc = r.app;
2884 if (proc == null) {
2885 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2886 }
2887 if (proc == null || proc.thread == null) {
2888 showStartingIcon = true;
2889 }
2890 if (DEBUG_TRANSITION) Log.v(TAG,
2891 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002892 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2893 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2894 mNoAnimActivities.add(r);
2895 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2896 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2897 mNoAnimActivities.remove(r);
2898 } else {
2899 mWindowManager.prepareAppTransition(newTask
2900 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2901 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2902 mNoAnimActivities.remove(r);
2903 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002904 mWindowManager.addAppToken(
2905 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2906 boolean doShow = true;
2907 if (newTask) {
2908 // Even though this activity is starting fresh, we still need
2909 // to reset it to make sure we apply affinities to move any
2910 // existing activities from other tasks in to it.
2911 // If the caller has requested that the target task be
2912 // reset, then do so.
2913 if ((r.intent.getFlags()
2914 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2915 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002916 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002917 }
2918 }
2919 if (SHOW_APP_STARTING_ICON && doShow) {
2920 // Figure out if we are transitioning from another activity that is
2921 // "has the same starting icon" as the next one. This allows the
2922 // window manager to keep the previous window it had previously
2923 // created, if it still had one.
2924 HistoryRecord prev = mResumedActivity;
2925 if (prev != null) {
2926 // We don't want to reuse the previous starting preview if:
2927 // (1) The current activity is in a different task.
2928 if (prev.task != r.task) prev = null;
2929 // (2) The current activity is already displayed.
2930 else if (prev.nowVisible) prev = null;
2931 }
2932 mWindowManager.setAppStartingWindow(
2933 r, r.packageName, r.theme, r.nonLocalizedLabel,
2934 r.labelRes, r.icon, prev, showStartingIcon);
2935 }
2936 } else {
2937 // If this is the first activity, don't do any fancy animations,
2938 // because there is nothing for it to animate on top of.
2939 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2940 r.info.screenOrientation, r.fullscreen);
2941 }
2942 if (VALIDATE_TOKENS) {
2943 mWindowManager.validateAppTokens(mHistory);
2944 }
2945
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002946 if (doResume) {
2947 resumeTopActivityLocked(null);
2948 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002949 }
2950
2951 /**
2952 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002953 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2954 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002955 * an instance of that activity in the stack and, if found, finish all
2956 * activities on top of it and return the instance.
2957 *
2958 * @param newR Description of the new activity being started.
2959 * @return Returns the old activity that should be continue to be used,
2960 * or null if none was found.
2961 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002962 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002963 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002964 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002965
2966 // First find the requested task.
2967 while (i > 0) {
2968 i--;
2969 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2970 if (r.task.taskId == taskId) {
2971 i++;
2972 break;
2973 }
2974 }
2975
2976 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002977 while (i > 0) {
2978 i--;
2979 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2980 if (r.finishing) {
2981 continue;
2982 }
2983 if (r.task.taskId != taskId) {
2984 return null;
2985 }
2986 if (r.realActivity.equals(newR.realActivity)) {
2987 // Here it is! Now finish everything in front...
2988 HistoryRecord ret = r;
2989 if (doClear) {
2990 while (i < (mHistory.size()-1)) {
2991 i++;
2992 r = (HistoryRecord)mHistory.get(i);
2993 if (r.finishing) {
2994 continue;
2995 }
2996 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2997 null, "clear")) {
2998 i--;
2999 }
3000 }
3001 }
3002
3003 // Finally, if this is a normal launch mode (that is, not
3004 // expecting onNewIntent()), then we will finish the current
3005 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003006 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
3007 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003008 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003009 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003010 if (index >= 0) {
3011 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
3012 null, "clear");
3013 }
3014 return null;
3015 }
3016 }
3017
3018 return ret;
3019 }
3020 }
3021
3022 return null;
3023 }
3024
3025 /**
3026 * Find the activity in the history stack within the given task. Returns
3027 * the index within the history at which it's found, or < 0 if not found.
3028 */
3029 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3030 int i = mHistory.size();
3031 while (i > 0) {
3032 i--;
3033 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3034 if (candidate.task.taskId != task) {
3035 break;
3036 }
3037 if (candidate.realActivity.equals(r.realActivity)) {
3038 return i;
3039 }
3040 }
3041
3042 return -1;
3043 }
3044
3045 /**
3046 * Reorder the history stack so that the activity at the given index is
3047 * brought to the front.
3048 */
3049 private final HistoryRecord moveActivityToFrontLocked(int where) {
3050 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3051 int top = mHistory.size();
3052 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3053 mHistory.add(top, newTop);
3054 oldTop.frontOfTask = false;
3055 newTop.frontOfTask = true;
3056 return newTop;
3057 }
3058
3059 /**
3060 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3061 * method will be called at the proper time.
3062 */
3063 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3064 boolean sent = false;
3065 if (r.state == ActivityState.RESUMED
3066 && r.app != null && r.app.thread != null) {
3067 try {
3068 ArrayList<Intent> ar = new ArrayList<Intent>();
3069 ar.add(new Intent(intent));
3070 r.app.thread.scheduleNewIntent(ar, r);
3071 sent = true;
3072 } catch (Exception e) {
3073 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3074 }
3075 }
3076 if (!sent) {
3077 r.addNewIntentLocked(new Intent(intent));
3078 }
3079 }
3080
3081 private final void logStartActivity(int tag, HistoryRecord r,
3082 TaskRecord task) {
3083 EventLog.writeEvent(tag,
3084 System.identityHashCode(r), task.taskId,
3085 r.shortComponentName, r.intent.getAction(),
3086 r.intent.getType(), r.intent.getDataString(),
3087 r.intent.getFlags());
3088 }
3089
3090 private final int startActivityLocked(IApplicationThread caller,
3091 Intent intent, String resolvedType,
3092 Uri[] grantedUriPermissions,
3093 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3094 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003095 int callingPid, int callingUid, boolean onlyIfNeeded,
3096 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003097 Log.i(TAG, "Starting activity: " + intent);
3098
3099 HistoryRecord sourceRecord = null;
3100 HistoryRecord resultRecord = null;
3101 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003102 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003103 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003104 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3105 if (index >= 0) {
3106 sourceRecord = (HistoryRecord)mHistory.get(index);
3107 if (requestCode >= 0 && !sourceRecord.finishing) {
3108 resultRecord = sourceRecord;
3109 }
3110 }
3111 }
3112
3113 int launchFlags = intent.getFlags();
3114
3115 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3116 && sourceRecord != null) {
3117 // Transfer the result target from the source activity to the new
3118 // one being started, including any failures.
3119 if (requestCode >= 0) {
3120 return START_FORWARD_AND_REQUEST_CONFLICT;
3121 }
3122 resultRecord = sourceRecord.resultTo;
3123 resultWho = sourceRecord.resultWho;
3124 requestCode = sourceRecord.requestCode;
3125 sourceRecord.resultTo = null;
3126 if (resultRecord != null) {
3127 resultRecord.removeResultsLocked(
3128 sourceRecord, resultWho, requestCode);
3129 }
3130 }
3131
3132 int err = START_SUCCESS;
3133
3134 if (intent.getComponent() == null) {
3135 // We couldn't find a class that can handle the given Intent.
3136 // That's the end of that!
3137 err = START_INTENT_NOT_RESOLVED;
3138 }
3139
3140 if (err == START_SUCCESS && aInfo == null) {
3141 // We couldn't find the specific class specified in the Intent.
3142 // Also the end of the line.
3143 err = START_CLASS_NOT_FOUND;
3144 }
3145
3146 ProcessRecord callerApp = null;
3147 if (err == START_SUCCESS && caller != null) {
3148 callerApp = getRecordForAppLocked(caller);
3149 if (callerApp != null) {
3150 callingPid = callerApp.pid;
3151 callingUid = callerApp.info.uid;
3152 } else {
3153 Log.w(TAG, "Unable to find app for caller " + caller
3154 + " (pid=" + callingPid + ") when starting: "
3155 + intent.toString());
3156 err = START_PERMISSION_DENIED;
3157 }
3158 }
3159
3160 if (err != START_SUCCESS) {
3161 if (resultRecord != null) {
3162 sendActivityResultLocked(-1,
3163 resultRecord, resultWho, requestCode,
3164 Activity.RESULT_CANCELED, null);
3165 }
3166 return err;
3167 }
3168
3169 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3170 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3171 if (perm != PackageManager.PERMISSION_GRANTED) {
3172 if (resultRecord != null) {
3173 sendActivityResultLocked(-1,
3174 resultRecord, resultWho, requestCode,
3175 Activity.RESULT_CANCELED, null);
3176 }
3177 String msg = "Permission Denial: starting " + intent.toString()
3178 + " from " + callerApp + " (pid=" + callingPid
3179 + ", uid=" + callingUid + ")"
3180 + " requires " + aInfo.permission;
3181 Log.w(TAG, msg);
3182 throw new SecurityException(msg);
3183 }
3184
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003185 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003186 boolean abort = false;
3187 try {
3188 // The Intent we give to the watcher has the extra data
3189 // stripped off, since it can contain private information.
3190 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003191 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003192 aInfo.applicationInfo.packageName);
3193 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003194 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003195 }
3196
3197 if (abort) {
3198 if (resultRecord != null) {
3199 sendActivityResultLocked(-1,
3200 resultRecord, resultWho, requestCode,
3201 Activity.RESULT_CANCELED, null);
3202 }
3203 // We pretend to the caller that it was really started, but
3204 // they will just get a cancel result.
3205 return START_SUCCESS;
3206 }
3207 }
3208
3209 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3210 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003211 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003212
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003213 if (mResumedActivity == null
3214 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3215 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3216 PendingActivityLaunch pal = new PendingActivityLaunch();
3217 pal.r = r;
3218 pal.sourceRecord = sourceRecord;
3219 pal.grantedUriPermissions = grantedUriPermissions;
3220 pal.grantedMode = grantedMode;
3221 pal.onlyIfNeeded = onlyIfNeeded;
3222 mPendingActivityLaunches.add(pal);
3223 return START_SWITCHES_CANCELED;
3224 }
3225 }
3226
3227 if (mDidAppSwitch) {
3228 // This is the second allowed switch since we stopped switches,
3229 // so now just generally allow switches. Use case: user presses
3230 // home (switches disabled, switch to home, mDidAppSwitch now true);
3231 // user taps a home icon (coming from home so allowed, we hit here
3232 // and now allow anyone to switch again).
3233 mAppSwitchesAllowedTime = 0;
3234 } else {
3235 mDidAppSwitch = true;
3236 }
3237
3238 doPendingActivityLaunchesLocked(false);
3239
3240 return startActivityUncheckedLocked(r, sourceRecord,
3241 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3242 }
3243
3244 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3245 final int N = mPendingActivityLaunches.size();
3246 if (N <= 0) {
3247 return;
3248 }
3249 for (int i=0; i<N; i++) {
3250 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3251 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3252 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3253 doResume && i == (N-1));
3254 }
3255 mPendingActivityLaunches.clear();
3256 }
3257
3258 private final int startActivityUncheckedLocked(HistoryRecord r,
3259 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3260 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3261 final Intent intent = r.intent;
3262 final int callingUid = r.launchedFromUid;
3263
3264 int launchFlags = intent.getFlags();
3265
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003266 // We'll invoke onUserLeaving before onPause only if the launching
3267 // activity did not explicitly state that this is an automated launch.
3268 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3269 if (DEBUG_USER_LEAVING) Log.v(TAG,
3270 "startActivity() => mUserLeaving=" + mUserLeaving);
3271
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003272 // If the caller has asked not to resume at this point, we make note
3273 // of this in the record so that we can skip it when trying to find
3274 // the top running activity.
3275 if (!doResume) {
3276 r.delayedResume = true;
3277 }
3278
3279 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3280 != 0 ? r : null;
3281
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003282 // If the onlyIfNeeded flag is set, then we can do this if the activity
3283 // being launched is the same as the one making the call... or, as
3284 // a special case, if we do not know the caller then we count the
3285 // current top activity as the caller.
3286 if (onlyIfNeeded) {
3287 HistoryRecord checkedCaller = sourceRecord;
3288 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003289 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003290 }
3291 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3292 // Caller is not the same as launcher, so always needed.
3293 onlyIfNeeded = false;
3294 }
3295 }
3296
3297 if (grantedUriPermissions != null && callingUid > 0) {
3298 for (int i=0; i<grantedUriPermissions.length; i++) {
3299 grantUriPermissionLocked(callingUid, r.packageName,
3300 grantedUriPermissions[i], grantedMode, r);
3301 }
3302 }
3303
3304 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3305 intent, r);
3306
3307 if (sourceRecord == null) {
3308 // This activity is not being started from another... in this
3309 // case we -always- start a new task.
3310 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3311 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3312 + intent);
3313 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3314 }
3315 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3316 // The original activity who is starting us is running as a single
3317 // instance... this new activity it is starting must go on its
3318 // own task.
3319 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3320 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3321 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3322 // The activity being started is a single instance... it always
3323 // gets launched into its own task.
3324 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3325 }
3326
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003327 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003328 // For whatever reason this activity is being launched into a new
3329 // task... yet the caller has requested a result back. Well, that
3330 // is pretty messed up, so instead immediately send back a cancel
3331 // and let the new task continue launched as normal without a
3332 // dependency on its originator.
3333 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3334 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003335 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003336 Activity.RESULT_CANCELED, null);
3337 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003338 }
3339
3340 boolean addingToTask = false;
3341 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3342 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3343 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3344 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3345 // If bring to front is requested, and no result is requested, and
3346 // we can find a task that was started with this same
3347 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003348 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003349 // See if there is a task to bring to the front. If this is
3350 // a SINGLE_INSTANCE activity, there can be one and only one
3351 // instance of it in the history, and it is always in its own
3352 // unique task, so we do a special search.
3353 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3354 ? findTaskLocked(intent, r.info)
3355 : findActivityLocked(intent, r.info);
3356 if (taskTop != null) {
3357 if (taskTop.task.intent == null) {
3358 // This task was started because of movement of
3359 // the activity based on affinity... now that we
3360 // are actually launching it, we can assign the
3361 // base intent.
3362 taskTop.task.setIntent(intent, r.info);
3363 }
3364 // If the target task is not in the front, then we need
3365 // to bring it to the front... except... well, with
3366 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3367 // to have the same behavior as if a new instance was
3368 // being started, which means not bringing it to the front
3369 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003370 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003371 if (curTop.task != taskTop.task) {
3372 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3373 boolean callerAtFront = sourceRecord == null
3374 || curTop.task == sourceRecord.task;
3375 if (callerAtFront) {
3376 // We really do want to push this one into the
3377 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003378 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003379 }
3380 }
3381 // If the caller has requested that the target task be
3382 // reset, then do so.
3383 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3384 taskTop = resetTaskIfNeededLocked(taskTop, r);
3385 }
3386 if (onlyIfNeeded) {
3387 // We don't need to start a new activity, and
3388 // the client said not to do anything if that
3389 // is the case, so this is it! And for paranoia, make
3390 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003391 if (doResume) {
3392 resumeTopActivityLocked(null);
3393 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003394 return START_RETURN_INTENT_TO_CALLER;
3395 }
3396 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3397 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3398 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3399 // In this situation we want to remove all activities
3400 // from the task up to the one being started. In most
3401 // cases this means we are resetting the task to its
3402 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003403 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003404 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003405 if (top != null) {
3406 if (top.frontOfTask) {
3407 // Activity aliases may mean we use different
3408 // intents for the top activity, so make sure
3409 // the task now has the identity of the new
3410 // intent.
3411 top.task.setIntent(r.intent, r.info);
3412 }
3413 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3414 deliverNewIntentLocked(top, r.intent);
3415 } else {
3416 // A special case: we need to
3417 // start the activity because it is not currently
3418 // running, and the caller has asked to clear the
3419 // current task to have this activity at the top.
3420 addingToTask = true;
3421 // Now pretend like this activity is being started
3422 // by the top of its task, so it is put in the
3423 // right place.
3424 sourceRecord = taskTop;
3425 }
3426 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3427 // In this case the top activity on the task is the
3428 // same as the one being launched, so we take that
3429 // as a request to bring the task to the foreground.
3430 // If the top activity in the task is the root
3431 // activity, deliver this new intent to it if it
3432 // desires.
3433 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3434 && taskTop.realActivity.equals(r.realActivity)) {
3435 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3436 if (taskTop.frontOfTask) {
3437 taskTop.task.setIntent(r.intent, r.info);
3438 }
3439 deliverNewIntentLocked(taskTop, r.intent);
3440 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3441 // In this case we are launching the root activity
3442 // of the task, but with a different intent. We
3443 // should start a new instance on top.
3444 addingToTask = true;
3445 sourceRecord = taskTop;
3446 }
3447 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3448 // In this case an activity is being launched in to an
3449 // existing task, without resetting that task. This
3450 // is typically the situation of launching an activity
3451 // from a notification or shortcut. We want to place
3452 // the new activity on top of the current task.
3453 addingToTask = true;
3454 sourceRecord = taskTop;
3455 } else if (!taskTop.task.rootWasReset) {
3456 // In this case we are launching in to an existing task
3457 // that has not yet been started from its front door.
3458 // The current task has been brought to the front.
3459 // Ideally, we'd probably like to place this new task
3460 // at the bottom of its stack, but that's a little hard
3461 // to do with the current organization of the code so
3462 // for now we'll just drop it.
3463 taskTop.task.setIntent(r.intent, r.info);
3464 }
3465 if (!addingToTask) {
3466 // We didn't do anything... but it was needed (a.k.a., client
3467 // don't use that intent!) And for paranoia, make
3468 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003469 if (doResume) {
3470 resumeTopActivityLocked(null);
3471 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003472 return START_TASK_TO_FRONT;
3473 }
3474 }
3475 }
3476 }
3477
3478 //String uri = r.intent.toURI();
3479 //Intent intent2 = new Intent(uri);
3480 //Log.i(TAG, "Given intent: " + r.intent);
3481 //Log.i(TAG, "URI is: " + uri);
3482 //Log.i(TAG, "To intent: " + intent2);
3483
3484 if (r.packageName != null) {
3485 // If the activity being launched is the same as the one currently
3486 // at the top, then we need to check if it should only be launched
3487 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003488 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3489 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003490 if (top.realActivity.equals(r.realActivity)) {
3491 if (top.app != null && top.app.thread != null) {
3492 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3493 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3494 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3495 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3496 // For paranoia, make sure we have correctly
3497 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003498 if (doResume) {
3499 resumeTopActivityLocked(null);
3500 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003501 if (onlyIfNeeded) {
3502 // We don't need to start a new activity, and
3503 // the client said not to do anything if that
3504 // is the case, so this is it!
3505 return START_RETURN_INTENT_TO_CALLER;
3506 }
3507 deliverNewIntentLocked(top, r.intent);
3508 return START_DELIVERED_TO_TOP;
3509 }
3510 }
3511 }
3512 }
3513
3514 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003515 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003516 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003517 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003518 Activity.RESULT_CANCELED, null);
3519 }
3520 return START_CLASS_NOT_FOUND;
3521 }
3522
3523 boolean newTask = false;
3524
3525 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003526 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003527 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3528 // todo: should do better management of integers.
3529 mCurTask++;
3530 if (mCurTask <= 0) {
3531 mCurTask = 1;
3532 }
3533 r.task = new TaskRecord(mCurTask, r.info, intent,
3534 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3535 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3536 + " in new task " + r.task);
3537 newTask = true;
3538 addRecentTask(r.task);
3539
3540 } else if (sourceRecord != null) {
3541 if (!addingToTask &&
3542 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3543 // In this case, we are adding the activity to an existing
3544 // task, but the caller has asked to clear that task if the
3545 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003546 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003547 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003548 if (top != null) {
3549 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3550 deliverNewIntentLocked(top, r.intent);
3551 // For paranoia, make sure we have correctly
3552 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003553 if (doResume) {
3554 resumeTopActivityLocked(null);
3555 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003556 return START_DELIVERED_TO_TOP;
3557 }
3558 } else if (!addingToTask &&
3559 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3560 // In this case, we are launching an activity in our own task
3561 // that may already be running somewhere in the history, and
3562 // we want to shuffle it to the front of the stack if so.
3563 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3564 if (where >= 0) {
3565 HistoryRecord top = moveActivityToFrontLocked(where);
3566 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3567 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003568 if (doResume) {
3569 resumeTopActivityLocked(null);
3570 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003571 return START_DELIVERED_TO_TOP;
3572 }
3573 }
3574 // An existing activity is starting this new activity, so we want
3575 // to keep the new one in the same task as the one that is starting
3576 // it.
3577 r.task = sourceRecord.task;
3578 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3579 + " in existing task " + r.task);
3580
3581 } else {
3582 // This not being started from an existing activity, and not part
3583 // of a new task... just put it in the top task, though these days
3584 // this case should never happen.
3585 final int N = mHistory.size();
3586 HistoryRecord prev =
3587 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3588 r.task = prev != null
3589 ? prev.task
3590 : new TaskRecord(mCurTask, r.info, intent,
3591 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3592 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3593 + " in new guessed " + r.task);
3594 }
3595 if (newTask) {
3596 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3597 }
3598 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003599 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003600 return START_SUCCESS;
3601 }
3602
3603 public final int startActivity(IApplicationThread caller,
3604 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3605 int grantedMode, IBinder resultTo,
3606 String resultWho, int requestCode, boolean onlyIfNeeded,
3607 boolean debug) {
3608 // Refuse possible leaked file descriptors
3609 if (intent != null && intent.hasFileDescriptors()) {
3610 throw new IllegalArgumentException("File descriptors passed in Intent");
3611 }
3612
The Android Open Source Project4df24232009-03-05 14:34:35 -08003613 final boolean componentSpecified = intent.getComponent() != null;
3614
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003615 // Don't modify the client's object!
3616 intent = new Intent(intent);
3617
3618 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003619 ActivityInfo aInfo;
3620 try {
3621 ResolveInfo rInfo =
3622 ActivityThread.getPackageManager().resolveIntent(
3623 intent, resolvedType,
3624 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003625 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003626 aInfo = rInfo != null ? rInfo.activityInfo : null;
3627 } catch (RemoteException e) {
3628 aInfo = null;
3629 }
3630
3631 if (aInfo != null) {
3632 // Store the found target back into the intent, because now that
3633 // we have it we never want to do this again. For example, if the
3634 // user navigates back to this point in the history, we should
3635 // always restart the exact same activity.
3636 intent.setComponent(new ComponentName(
3637 aInfo.applicationInfo.packageName, aInfo.name));
3638
3639 // Don't debug things in the system process
3640 if (debug) {
3641 if (!aInfo.processName.equals("system")) {
3642 setDebugApp(aInfo.processName, true, false);
3643 }
3644 }
3645 }
3646
3647 synchronized(this) {
3648 final long origId = Binder.clearCallingIdentity();
3649 int res = startActivityLocked(caller, intent, resolvedType,
3650 grantedUriPermissions, grantedMode, aInfo,
3651 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003652 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003653 Binder.restoreCallingIdentity(origId);
3654 return res;
3655 }
3656 }
3657
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003658 public int startActivityIntentSender(IApplicationThread caller,
3659 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003660 IBinder resultTo, String resultWho, int requestCode,
3661 int flagsMask, int flagsValues) {
3662 // Refuse possible leaked file descriptors
3663 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3664 throw new IllegalArgumentException("File descriptors passed in Intent");
3665 }
3666
3667 IIntentSender sender = intent.getTarget();
3668 if (!(sender instanceof PendingIntentRecord)) {
3669 throw new IllegalArgumentException("Bad PendingIntent object");
3670 }
3671
3672 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003673
3674 synchronized (this) {
3675 // If this is coming from the currently resumed activity, it is
3676 // effectively saying that app switches are allowed at this point.
3677 if (mResumedActivity != null
3678 && mResumedActivity.info.applicationInfo.uid ==
3679 Binder.getCallingUid()) {
3680 mAppSwitchesAllowedTime = 0;
3681 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003682 }
3683
3684 return pir.sendInner(0, fillInIntent, resolvedType,
3685 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3686 }
3687
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003688 public boolean startNextMatchingActivity(IBinder callingActivity,
3689 Intent intent) {
3690 // Refuse possible leaked file descriptors
3691 if (intent != null && intent.hasFileDescriptors() == true) {
3692 throw new IllegalArgumentException("File descriptors passed in Intent");
3693 }
3694
3695 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003696 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003697 if (index < 0) {
3698 return false;
3699 }
3700 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3701 if (r.app == null || r.app.thread == null) {
3702 // The caller is not running... d'oh!
3703 return false;
3704 }
3705 intent = new Intent(intent);
3706 // The caller is not allowed to change the data.
3707 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3708 // And we are resetting to find the next component...
3709 intent.setComponent(null);
3710
3711 ActivityInfo aInfo = null;
3712 try {
3713 List<ResolveInfo> resolves =
3714 ActivityThread.getPackageManager().queryIntentActivities(
3715 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003716 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003717
3718 // Look for the original activity in the list...
3719 final int N = resolves != null ? resolves.size() : 0;
3720 for (int i=0; i<N; i++) {
3721 ResolveInfo rInfo = resolves.get(i);
3722 if (rInfo.activityInfo.packageName.equals(r.packageName)
3723 && rInfo.activityInfo.name.equals(r.info.name)) {
3724 // We found the current one... the next matching is
3725 // after it.
3726 i++;
3727 if (i<N) {
3728 aInfo = resolves.get(i).activityInfo;
3729 }
3730 break;
3731 }
3732 }
3733 } catch (RemoteException e) {
3734 }
3735
3736 if (aInfo == null) {
3737 // Nobody who is next!
3738 return false;
3739 }
3740
3741 intent.setComponent(new ComponentName(
3742 aInfo.applicationInfo.packageName, aInfo.name));
3743 intent.setFlags(intent.getFlags()&~(
3744 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3745 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3746 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3747 Intent.FLAG_ACTIVITY_NEW_TASK));
3748
3749 // Okay now we need to start the new activity, replacing the
3750 // currently running activity. This is a little tricky because
3751 // we want to start the new one as if the current one is finished,
3752 // but not finish the current one first so that there is no flicker.
3753 // And thus...
3754 final boolean wasFinishing = r.finishing;
3755 r.finishing = true;
3756
3757 // Propagate reply information over to the new activity.
3758 final HistoryRecord resultTo = r.resultTo;
3759 final String resultWho = r.resultWho;
3760 final int requestCode = r.requestCode;
3761 r.resultTo = null;
3762 if (resultTo != null) {
3763 resultTo.removeResultsLocked(r, resultWho, requestCode);
3764 }
3765
3766 final long origId = Binder.clearCallingIdentity();
3767 // XXX we are not dealing with propagating grantedUriPermissions...
3768 // those are not yet exposed to user code, so there is no need.
3769 int res = startActivityLocked(r.app.thread, intent,
3770 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003771 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003772 Binder.restoreCallingIdentity(origId);
3773
3774 r.finishing = wasFinishing;
3775 if (res != START_SUCCESS) {
3776 return false;
3777 }
3778 return true;
3779 }
3780 }
3781
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003782 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003783 Intent intent, String resolvedType, IBinder resultTo,
3784 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003785
3786 // This is so super not safe, that only the system (or okay root)
3787 // can do it.
3788 final int callingUid = Binder.getCallingUid();
3789 if (callingUid != 0 && callingUid != Process.myUid()) {
3790 throw new SecurityException(
3791 "startActivityInPackage only available to the system");
3792 }
3793
The Android Open Source Project4df24232009-03-05 14:34:35 -08003794 final boolean componentSpecified = intent.getComponent() != null;
3795
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003796 // Don't modify the client's object!
3797 intent = new Intent(intent);
3798
3799 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003800 ActivityInfo aInfo;
3801 try {
3802 ResolveInfo rInfo =
3803 ActivityThread.getPackageManager().resolveIntent(
3804 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003805 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003806 aInfo = rInfo != null ? rInfo.activityInfo : null;
3807 } catch (RemoteException e) {
3808 aInfo = null;
3809 }
3810
3811 if (aInfo != null) {
3812 // Store the found target back into the intent, because now that
3813 // we have it we never want to do this again. For example, if the
3814 // user navigates back to this point in the history, we should
3815 // always restart the exact same activity.
3816 intent.setComponent(new ComponentName(
3817 aInfo.applicationInfo.packageName, aInfo.name));
3818 }
3819
3820 synchronized(this) {
3821 return startActivityLocked(null, intent, resolvedType,
3822 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003823 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003824 }
3825 }
3826
3827 private final void addRecentTask(TaskRecord task) {
3828 // Remove any existing entries that are the same kind of task.
3829 int N = mRecentTasks.size();
3830 for (int i=0; i<N; i++) {
3831 TaskRecord tr = mRecentTasks.get(i);
3832 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3833 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3834 mRecentTasks.remove(i);
3835 i--;
3836 N--;
3837 if (task.intent == null) {
3838 // If the new recent task we are adding is not fully
3839 // specified, then replace it with the existing recent task.
3840 task = tr;
3841 }
3842 }
3843 }
3844 if (N >= MAX_RECENT_TASKS) {
3845 mRecentTasks.remove(N-1);
3846 }
3847 mRecentTasks.add(0, task);
3848 }
3849
3850 public void setRequestedOrientation(IBinder token,
3851 int requestedOrientation) {
3852 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003853 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003854 if (index < 0) {
3855 return;
3856 }
3857 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3858 final long origId = Binder.clearCallingIdentity();
3859 mWindowManager.setAppOrientation(r, requestedOrientation);
3860 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003861 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003862 r.mayFreezeScreenLocked(r.app) ? r : null);
3863 if (config != null) {
3864 r.frozenBeforeDestroy = true;
3865 if (!updateConfigurationLocked(config, r)) {
3866 resumeTopActivityLocked(null);
3867 }
3868 }
3869 Binder.restoreCallingIdentity(origId);
3870 }
3871 }
3872
3873 public int getRequestedOrientation(IBinder token) {
3874 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003875 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003876 if (index < 0) {
3877 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3878 }
3879 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3880 return mWindowManager.getAppOrientation(r);
3881 }
3882 }
3883
3884 private final void stopActivityLocked(HistoryRecord r) {
3885 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3886 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3887 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3888 if (!r.finishing) {
3889 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3890 "no-history");
3891 }
3892 } else if (r.app != null && r.app.thread != null) {
3893 if (mFocusedActivity == r) {
3894 setFocusedActivityLocked(topRunningActivityLocked(null));
3895 }
3896 r.resumeKeyDispatchingLocked();
3897 try {
3898 r.stopped = false;
3899 r.state = ActivityState.STOPPING;
3900 if (DEBUG_VISBILITY) Log.v(
3901 TAG, "Stopping visible=" + r.visible + " for " + r);
3902 if (!r.visible) {
3903 mWindowManager.setAppVisibility(r, false);
3904 }
3905 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3906 } catch (Exception e) {
3907 // Maybe just ignore exceptions here... if the process
3908 // has crashed, our death notification will clean things
3909 // up.
3910 Log.w(TAG, "Exception thrown during pause", e);
3911 // Just in case, assume it to be stopped.
3912 r.stopped = true;
3913 r.state = ActivityState.STOPPED;
3914 if (r.configDestroy) {
3915 destroyActivityLocked(r, true);
3916 }
3917 }
3918 }
3919 }
3920
3921 /**
3922 * @return Returns true if the activity is being finished, false if for
3923 * some reason it is being left as-is.
3924 */
3925 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3926 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003927 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003928 TAG, "Finishing activity: token=" + token
3929 + ", result=" + resultCode + ", data=" + resultData);
3930
Dianne Hackborn75b03852009-06-12 15:43:26 -07003931 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003932 if (index < 0) {
3933 return false;
3934 }
3935 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3936
3937 // Is this the last activity left?
3938 boolean lastActivity = true;
3939 for (int i=mHistory.size()-1; i>=0; i--) {
3940 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3941 if (!p.finishing && p != r) {
3942 lastActivity = false;
3943 break;
3944 }
3945 }
3946
3947 // If this is the last activity, but it is the home activity, then
3948 // just don't finish it.
3949 if (lastActivity) {
3950 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3951 return false;
3952 }
3953 }
3954
3955 finishActivityLocked(r, index, resultCode, resultData, reason);
3956 return true;
3957 }
3958
3959 /**
3960 * @return Returns true if this activity has been removed from the history
3961 * list, or false if it is still in the list and will be removed later.
3962 */
3963 private final boolean finishActivityLocked(HistoryRecord r, int index,
3964 int resultCode, Intent resultData, String reason) {
3965 if (r.finishing) {
3966 Log.w(TAG, "Duplicate finish request for " + r);
3967 return false;
3968 }
3969
3970 r.finishing = true;
3971 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3972 System.identityHashCode(r),
3973 r.task.taskId, r.shortComponentName, reason);
3974 r.task.numActivities--;
3975 if (r.frontOfTask && index < (mHistory.size()-1)) {
3976 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3977 if (next.task == r.task) {
3978 next.frontOfTask = true;
3979 }
3980 }
3981
3982 r.pauseKeyDispatchingLocked();
3983 if (mFocusedActivity == r) {
3984 setFocusedActivityLocked(topRunningActivityLocked(null));
3985 }
3986
3987 // send the result
3988 HistoryRecord resultTo = r.resultTo;
3989 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003990 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3991 + " who=" + r.resultWho + " req=" + r.requestCode
3992 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003993 if (r.info.applicationInfo.uid > 0) {
3994 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3995 r.packageName, resultData, r);
3996 }
3997 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3998 resultData);
3999 r.resultTo = null;
4000 }
Chris Tate8a7dc172009-03-24 20:11:42 -07004001 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004002
4003 // Make sure this HistoryRecord is not holding on to other resources,
4004 // because clients have remote IPC references to this object so we
4005 // can't assume that will go away and want to avoid circular IPC refs.
4006 r.results = null;
4007 r.pendingResults = null;
4008 r.newIntents = null;
4009 r.icicle = null;
4010
4011 if (mPendingThumbnails.size() > 0) {
4012 // There are clients waiting to receive thumbnails so, in case
4013 // this is an activity that someone is waiting for, add it
4014 // to the pending list so we can correctly update the clients.
4015 mCancelledThumbnails.add(r);
4016 }
4017
4018 if (mResumedActivity == r) {
4019 boolean endTask = index <= 0
4020 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
4021 if (DEBUG_TRANSITION) Log.v(TAG,
4022 "Prepare close transition: finishing " + r);
4023 mWindowManager.prepareAppTransition(endTask
4024 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
4025 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
4026
4027 // Tell window manager to prepare for this one to be removed.
4028 mWindowManager.setAppVisibility(r, false);
4029
4030 if (mPausingActivity == null) {
4031 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4032 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4033 startPausingLocked(false, false);
4034 }
4035
4036 } else if (r.state != ActivityState.PAUSING) {
4037 // If the activity is PAUSING, we will complete the finish once
4038 // it is done pausing; else we can just directly finish it here.
4039 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4040 return finishCurrentActivityLocked(r, index,
4041 FINISH_AFTER_PAUSE) == null;
4042 } else {
4043 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4044 }
4045
4046 return false;
4047 }
4048
4049 private static final int FINISH_IMMEDIATELY = 0;
4050 private static final int FINISH_AFTER_PAUSE = 1;
4051 private static final int FINISH_AFTER_VISIBLE = 2;
4052
4053 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4054 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004055 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004056 if (index < 0) {
4057 return null;
4058 }
4059
4060 return finishCurrentActivityLocked(r, index, mode);
4061 }
4062
4063 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4064 int index, int mode) {
4065 // First things first: if this activity is currently visible,
4066 // and the resumed activity is not yet visible, then hold off on
4067 // finishing until the resumed one becomes visible.
4068 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4069 if (!mStoppingActivities.contains(r)) {
4070 mStoppingActivities.add(r);
4071 if (mStoppingActivities.size() > 3) {
4072 // If we already have a few activities waiting to stop,
4073 // then give up on things going idle and start clearing
4074 // them out.
4075 Message msg = Message.obtain();
4076 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4077 mHandler.sendMessage(msg);
4078 }
4079 }
4080 r.state = ActivityState.STOPPING;
4081 updateOomAdjLocked();
4082 return r;
4083 }
4084
4085 // make sure the record is cleaned out of other places.
4086 mStoppingActivities.remove(r);
4087 mWaitingVisibleActivities.remove(r);
4088 if (mResumedActivity == r) {
4089 mResumedActivity = null;
4090 }
4091 final ActivityState prevState = r.state;
4092 r.state = ActivityState.FINISHING;
4093
4094 if (mode == FINISH_IMMEDIATELY
4095 || prevState == ActivityState.STOPPED
4096 || prevState == ActivityState.INITIALIZING) {
4097 // If this activity is already stopped, we can just finish
4098 // it right now.
4099 return destroyActivityLocked(r, true) ? null : r;
4100 } else {
4101 // Need to go through the full pause cycle to get this
4102 // activity into the stopped state and then finish it.
4103 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4104 mFinishingActivities.add(r);
4105 resumeTopActivityLocked(null);
4106 }
4107 return r;
4108 }
4109
4110 /**
4111 * This is the internal entry point for handling Activity.finish().
4112 *
4113 * @param token The Binder token referencing the Activity we want to finish.
4114 * @param resultCode Result code, if any, from this Activity.
4115 * @param resultData Result data (Intent), if any, from this Activity.
4116 *
4117 * @result Returns true if the activity successfully finished, or false if it is still running.
4118 */
4119 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4120 // Refuse possible leaked file descriptors
4121 if (resultData != null && resultData.hasFileDescriptors() == true) {
4122 throw new IllegalArgumentException("File descriptors passed in Intent");
4123 }
4124
4125 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004126 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004127 // Find the first activity that is not finishing.
4128 HistoryRecord next = topRunningActivityLocked(token, 0);
4129 if (next != null) {
4130 // ask watcher if this is allowed
4131 boolean resumeOK = true;
4132 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004133 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004134 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004135 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004136 }
4137
4138 if (!resumeOK) {
4139 return false;
4140 }
4141 }
4142 }
4143 final long origId = Binder.clearCallingIdentity();
4144 boolean res = requestFinishActivityLocked(token, resultCode,
4145 resultData, "app-request");
4146 Binder.restoreCallingIdentity(origId);
4147 return res;
4148 }
4149 }
4150
4151 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4152 String resultWho, int requestCode, int resultCode, Intent data) {
4153
4154 if (callingUid > 0) {
4155 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4156 data, r);
4157 }
4158
The Android Open Source Project10592532009-03-18 17:39:46 -07004159 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4160 + " : who=" + resultWho + " req=" + requestCode
4161 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004162 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4163 try {
4164 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4165 list.add(new ResultInfo(resultWho, requestCode,
4166 resultCode, data));
4167 r.app.thread.scheduleSendResult(r, list);
4168 return;
4169 } catch (Exception e) {
4170 Log.w(TAG, "Exception thrown sending result to " + r, e);
4171 }
4172 }
4173
4174 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4175 }
4176
4177 public final void finishSubActivity(IBinder token, String resultWho,
4178 int requestCode) {
4179 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004180 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004181 if (index < 0) {
4182 return;
4183 }
4184 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4185
4186 final long origId = Binder.clearCallingIdentity();
4187
4188 int i;
4189 for (i=mHistory.size()-1; i>=0; i--) {
4190 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4191 if (r.resultTo == self && r.requestCode == requestCode) {
4192 if ((r.resultWho == null && resultWho == null) ||
4193 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4194 finishActivityLocked(r, i,
4195 Activity.RESULT_CANCELED, null, "request-sub");
4196 }
4197 }
4198 }
4199
4200 Binder.restoreCallingIdentity(origId);
4201 }
4202 }
4203
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004204 public void overridePendingTransition(IBinder token, String packageName,
4205 int enterAnim, int exitAnim) {
4206 synchronized(this) {
4207 int index = indexOfTokenLocked(token);
4208 if (index < 0) {
4209 return;
4210 }
4211 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4212
4213 final long origId = Binder.clearCallingIdentity();
4214
4215 if (self.state == ActivityState.RESUMED
4216 || self.state == ActivityState.PAUSING) {
4217 mWindowManager.overridePendingAppTransition(packageName,
4218 enterAnim, exitAnim);
4219 }
4220
4221 Binder.restoreCallingIdentity(origId);
4222 }
4223 }
4224
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004225 /**
4226 * Perform clean-up of service connections in an activity record.
4227 */
4228 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4229 // Throw away any services that have been bound by this activity.
4230 if (r.connections != null) {
4231 Iterator<ConnectionRecord> it = r.connections.iterator();
4232 while (it.hasNext()) {
4233 ConnectionRecord c = it.next();
4234 removeConnectionLocked(c, null, r);
4235 }
4236 r.connections = null;
4237 }
4238 }
4239
4240 /**
4241 * Perform the common clean-up of an activity record. This is called both
4242 * as part of destroyActivityLocked() (when destroying the client-side
4243 * representation) and cleaning things up as a result of its hosting
4244 * processing going away, in which case there is no remaining client-side
4245 * state to destroy so only the cleanup here is needed.
4246 */
4247 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4248 if (mResumedActivity == r) {
4249 mResumedActivity = null;
4250 }
4251 if (mFocusedActivity == r) {
4252 mFocusedActivity = null;
4253 }
4254
4255 r.configDestroy = false;
4256 r.frozenBeforeDestroy = false;
4257
4258 // Make sure this record is no longer in the pending finishes list.
4259 // This could happen, for example, if we are trimming activities
4260 // down to the max limit while they are still waiting to finish.
4261 mFinishingActivities.remove(r);
4262 mWaitingVisibleActivities.remove(r);
4263
4264 // Remove any pending results.
4265 if (r.finishing && r.pendingResults != null) {
4266 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4267 PendingIntentRecord rec = apr.get();
4268 if (rec != null) {
4269 cancelIntentSenderLocked(rec, false);
4270 }
4271 }
4272 r.pendingResults = null;
4273 }
4274
4275 if (cleanServices) {
4276 cleanUpActivityServicesLocked(r);
4277 }
4278
4279 if (mPendingThumbnails.size() > 0) {
4280 // There are clients waiting to receive thumbnails so, in case
4281 // this is an activity that someone is waiting for, add it
4282 // to the pending list so we can correctly update the clients.
4283 mCancelledThumbnails.add(r);
4284 }
4285
4286 // Get rid of any pending idle timeouts.
4287 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4288 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4289 }
4290
4291 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4292 if (r.state != ActivityState.DESTROYED) {
4293 mHistory.remove(r);
4294 r.inHistory = false;
4295 r.state = ActivityState.DESTROYED;
4296 mWindowManager.removeAppToken(r);
4297 if (VALIDATE_TOKENS) {
4298 mWindowManager.validateAppTokens(mHistory);
4299 }
4300 cleanUpActivityServicesLocked(r);
4301 removeActivityUriPermissionsLocked(r);
4302 }
4303 }
4304
4305 /**
4306 * Destroy the current CLIENT SIDE instance of an activity. This may be
4307 * called both when actually finishing an activity, or when performing
4308 * a configuration switch where we destroy the current client-side object
4309 * but then create a new client-side object for this same HistoryRecord.
4310 */
4311 private final boolean destroyActivityLocked(HistoryRecord r,
4312 boolean removeFromApp) {
4313 if (DEBUG_SWITCH) Log.v(
4314 TAG, "Removing activity: token=" + r
4315 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4316 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4317 System.identityHashCode(r),
4318 r.task.taskId, r.shortComponentName);
4319
4320 boolean removedFromHistory = false;
4321
4322 cleanUpActivityLocked(r, false);
4323
4324 if (r.app != null) {
4325 if (removeFromApp) {
4326 int idx = r.app.activities.indexOf(r);
4327 if (idx >= 0) {
4328 r.app.activities.remove(idx);
4329 }
4330 if (r.persistent) {
4331 decPersistentCountLocked(r.app);
4332 }
4333 }
4334
4335 boolean skipDestroy = false;
4336
4337 try {
4338 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4339 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4340 r.configChangeFlags);
4341 } catch (Exception e) {
4342 // We can just ignore exceptions here... if the process
4343 // has crashed, our death notification will clean things
4344 // up.
4345 //Log.w(TAG, "Exception thrown during finish", e);
4346 if (r.finishing) {
4347 removeActivityFromHistoryLocked(r);
4348 removedFromHistory = true;
4349 skipDestroy = true;
4350 }
4351 }
4352
4353 r.app = null;
4354 r.nowVisible = false;
4355
4356 if (r.finishing && !skipDestroy) {
4357 r.state = ActivityState.DESTROYING;
4358 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4359 msg.obj = r;
4360 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4361 } else {
4362 r.state = ActivityState.DESTROYED;
4363 }
4364 } else {
4365 // remove this record from the history.
4366 if (r.finishing) {
4367 removeActivityFromHistoryLocked(r);
4368 removedFromHistory = true;
4369 } else {
4370 r.state = ActivityState.DESTROYED;
4371 }
4372 }
4373
4374 r.configChangeFlags = 0;
4375
4376 if (!mLRUActivities.remove(r)) {
4377 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4378 }
4379
4380 return removedFromHistory;
4381 }
4382
4383 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4384 ProcessRecord app)
4385 {
4386 int i = list.size();
4387 if (localLOGV) Log.v(
4388 TAG, "Removing app " + app + " from list " + list
4389 + " with " + i + " entries");
4390 while (i > 0) {
4391 i--;
4392 HistoryRecord r = (HistoryRecord)list.get(i);
4393 if (localLOGV) Log.v(
4394 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4395 if (r.app == app) {
4396 if (localLOGV) Log.v(TAG, "Removing this entry!");
4397 list.remove(i);
4398 }
4399 }
4400 }
4401
4402 /**
4403 * Main function for removing an existing process from the activity manager
4404 * as a result of that process going away. Clears out all connections
4405 * to the process.
4406 */
4407 private final void handleAppDiedLocked(ProcessRecord app,
4408 boolean restarting) {
4409 cleanUpApplicationRecordLocked(app, restarting, -1);
4410 if (!restarting) {
4411 mLRUProcesses.remove(app);
4412 }
4413
4414 // Just in case...
4415 if (mPausingActivity != null && mPausingActivity.app == app) {
4416 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4417 mPausingActivity = null;
4418 }
4419 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4420 mLastPausedActivity = null;
4421 }
4422
4423 // Remove this application's activities from active lists.
4424 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4425 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4426 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4427 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4428
4429 boolean atTop = true;
4430 boolean hasVisibleActivities = false;
4431
4432 // Clean out the history list.
4433 int i = mHistory.size();
4434 if (localLOGV) Log.v(
4435 TAG, "Removing app " + app + " from history with " + i + " entries");
4436 while (i > 0) {
4437 i--;
4438 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4439 if (localLOGV) Log.v(
4440 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4441 if (r.app == app) {
4442 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4443 if (localLOGV) Log.v(
4444 TAG, "Removing this entry! frozen=" + r.haveState
4445 + " finishing=" + r.finishing);
4446 mHistory.remove(i);
4447
4448 r.inHistory = false;
4449 mWindowManager.removeAppToken(r);
4450 if (VALIDATE_TOKENS) {
4451 mWindowManager.validateAppTokens(mHistory);
4452 }
4453 removeActivityUriPermissionsLocked(r);
4454
4455 } else {
4456 // We have the current state for this activity, so
4457 // it can be restarted later when needed.
4458 if (localLOGV) Log.v(
4459 TAG, "Keeping entry, setting app to null");
4460 if (r.visible) {
4461 hasVisibleActivities = true;
4462 }
4463 r.app = null;
4464 r.nowVisible = false;
4465 if (!r.haveState) {
4466 r.icicle = null;
4467 }
4468 }
4469
4470 cleanUpActivityLocked(r, true);
4471 r.state = ActivityState.STOPPED;
4472 }
4473 atTop = false;
4474 }
4475
4476 app.activities.clear();
4477
4478 if (app.instrumentationClass != null) {
4479 Log.w(TAG, "Crash of app " + app.processName
4480 + " running instrumentation " + app.instrumentationClass);
4481 Bundle info = new Bundle();
4482 info.putString("shortMsg", "Process crashed.");
4483 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4484 }
4485
4486 if (!restarting) {
4487 if (!resumeTopActivityLocked(null)) {
4488 // If there was nothing to resume, and we are not already
4489 // restarting this process, but there is a visible activity that
4490 // is hosted by the process... then make sure all visible
4491 // activities are running, taking care of restarting this
4492 // process.
4493 if (hasVisibleActivities) {
4494 ensureActivitiesVisibleLocked(null, 0);
4495 }
4496 }
4497 }
4498 }
4499
4500 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4501 IBinder threadBinder = thread.asBinder();
4502
4503 // Find the application record.
4504 int count = mLRUProcesses.size();
4505 int i;
4506 for (i=0; i<count; i++) {
4507 ProcessRecord rec = mLRUProcesses.get(i);
4508 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4509 return i;
4510 }
4511 }
4512 return -1;
4513 }
4514
4515 private final ProcessRecord getRecordForAppLocked(
4516 IApplicationThread thread) {
4517 if (thread == null) {
4518 return null;
4519 }
4520
4521 int appIndex = getLRURecordIndexForAppLocked(thread);
4522 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4523 }
4524
4525 private final void appDiedLocked(ProcessRecord app, int pid,
4526 IApplicationThread thread) {
4527
4528 mProcDeaths[0]++;
4529
4530 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4531 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4532 + ") has died.");
4533 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4534 if (localLOGV) Log.v(
4535 TAG, "Dying app: " + app + ", pid: " + pid
4536 + ", thread: " + thread.asBinder());
4537 boolean doLowMem = app.instrumentationClass == null;
4538 handleAppDiedLocked(app, false);
4539
4540 if (doLowMem) {
4541 // If there are no longer any background processes running,
4542 // and the app that died was not running instrumentation,
4543 // then tell everyone we are now low on memory.
4544 boolean haveBg = false;
4545 int count = mLRUProcesses.size();
4546 int i;
4547 for (i=0; i<count; i++) {
4548 ProcessRecord rec = mLRUProcesses.get(i);
4549 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4550 haveBg = true;
4551 break;
4552 }
4553 }
4554
4555 if (!haveBg) {
4556 Log.i(TAG, "Low Memory: No more background processes.");
4557 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004558 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004559 for (i=0; i<count; i++) {
4560 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackborn36124872009-10-08 16:22:03 -07004561 if (rec != app && rec.thread != null &&
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004562 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4563 // The low memory report is overriding any current
4564 // state for a GC request. Make sure to do
4565 // visible/foreground processes first.
4566 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4567 rec.lastRequestedGc = 0;
4568 } else {
4569 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004570 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004571 rec.reportLowMemory = true;
4572 rec.lastLowMemory = now;
4573 mProcessesToGc.remove(rec);
4574 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004575 }
4576 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004577 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004578 }
4579 }
4580 } else if (Config.LOGD) {
4581 Log.d(TAG, "Received spurious death notification for thread "
4582 + thread.asBinder());
4583 }
4584 }
4585
4586 final String readFile(String filename) {
4587 try {
4588 FileInputStream fs = new FileInputStream(filename);
4589 byte[] inp = new byte[8192];
4590 int size = fs.read(inp);
4591 fs.close();
4592 return new String(inp, 0, 0, size);
4593 } catch (java.io.IOException e) {
4594 }
4595 return "";
4596 }
4597
4598 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004599 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004600 if (app.notResponding || app.crashing) {
4601 return;
4602 }
4603
4604 // Log the ANR to the event log.
4605 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4606
4607 // If we are on a secure build and the application is not interesting to the user (it is
4608 // not visible or in the background), just kill it instead of displaying a dialog.
4609 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4610 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4611 Process.killProcess(app.pid);
4612 return;
4613 }
4614
4615 // DeviceMonitor.start();
4616
4617 String processInfo = null;
4618 if (MONITOR_CPU_USAGE) {
4619 updateCpuStatsNow();
4620 synchronized (mProcessStatsThread) {
4621 processInfo = mProcessStats.printCurrentState();
4622 }
4623 }
4624
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004625 StringBuilder info = mStringBuilder;
4626 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004627 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004628 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004629 if (reportedActivity != null && reportedActivity.app != null) {
4630 info.append(" (last in ");
4631 info.append(reportedActivity.app.processName);
4632 info.append(")");
4633 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004634 if (annotation != null) {
4635 info.append("\nAnnotation: ");
4636 info.append(annotation);
4637 }
4638 if (MONITOR_CPU_USAGE) {
4639 info.append("\nCPU usage:\n");
4640 info.append(processInfo);
4641 }
4642 Log.i(TAG, info.toString());
4643
4644 // The application is not responding. Dump as many thread traces as we can.
4645 boolean fileDump = prepareTraceFile(true);
4646 if (!fileDump) {
4647 // Dumping traces to the log, just dump the process that isn't responding so
4648 // we don't overflow the log
4649 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4650 } else {
4651 // Dumping traces to a file so dump all active processes we know about
4652 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004653 // First, these are the most important processes.
4654 final int[] imppids = new int[3];
4655 int i=0;
4656 imppids[0] = app.pid;
4657 i++;
4658 if (reportedActivity != null && reportedActivity.app != null
4659 && reportedActivity.app.thread != null
4660 && reportedActivity.app.pid != app.pid) {
4661 imppids[i] = reportedActivity.app.pid;
4662 i++;
4663 }
4664 imppids[i] = Process.myPid();
4665 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4666 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4667 synchronized (this) {
4668 try {
4669 wait(200);
4670 } catch (InterruptedException e) {
4671 }
4672 }
4673 }
4674 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004675 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004676 boolean done = false;
4677 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4678 if (imppids[j] == r.pid) {
4679 done = true;
4680 break;
4681 }
4682 }
4683 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004684 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004685 synchronized (this) {
4686 try {
4687 wait(200);
4688 } catch (InterruptedException e) {
4689 }
4690 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004691 }
4692 }
4693 }
4694 }
4695
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004696 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004697 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004698 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004699 app.pid, info.toString());
4700 if (res != 0) {
4701 if (res < 0) {
4702 // wait until the SIGQUIT has had a chance to process before killing the
4703 // process.
4704 try {
4705 wait(2000);
4706 } catch (InterruptedException e) {
4707 }
4708
4709 Process.killProcess(app.pid);
4710 return;
4711 }
4712 }
4713 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004714 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004715 }
4716 }
4717
4718 makeAppNotRespondingLocked(app,
4719 activity != null ? activity.shortComponentName : null,
4720 annotation != null ? "ANR " + annotation : "ANR",
4721 info.toString(), null);
4722 Message msg = Message.obtain();
4723 HashMap map = new HashMap();
4724 msg.what = SHOW_NOT_RESPONDING_MSG;
4725 msg.obj = map;
4726 map.put("app", app);
4727 if (activity != null) {
4728 map.put("activity", activity);
4729 }
4730
4731 mHandler.sendMessage(msg);
4732 return;
4733 }
4734
4735 /**
4736 * If a stack trace file has been configured, prepare the filesystem
4737 * by creating the directory if it doesn't exist and optionally
4738 * removing the old trace file.
4739 *
4740 * @param removeExisting If set, the existing trace file will be removed.
4741 * @return Returns true if the trace file preparations succeeded
4742 */
4743 public static boolean prepareTraceFile(boolean removeExisting) {
4744 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4745 boolean fileReady = false;
4746 if (!TextUtils.isEmpty(tracesPath)) {
4747 File f = new File(tracesPath);
4748 if (!f.exists()) {
4749 // Ensure the enclosing directory exists
4750 File dir = f.getParentFile();
4751 if (!dir.exists()) {
4752 fileReady = dir.mkdirs();
4753 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004754 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004755 } else if (dir.isDirectory()) {
4756 fileReady = true;
4757 }
4758 } else if (removeExisting) {
4759 // Remove the previous traces file, so we don't fill the disk.
4760 // The VM will recreate it
4761 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4762 fileReady = f.delete();
4763 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004764
4765 if (removeExisting) {
4766 try {
4767 f.createNewFile();
4768 FileUtils.setPermissions(f.getAbsolutePath(),
4769 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4770 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4771 fileReady = true;
4772 } catch (IOException e) {
4773 Log.w(TAG, "Unable to make ANR traces file", e);
4774 }
4775 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004776 }
4777
4778 return fileReady;
4779 }
4780
4781
4782 private final void decPersistentCountLocked(ProcessRecord app)
4783 {
4784 app.persistentActivities--;
4785 if (app.persistentActivities > 0) {
4786 // Still more of 'em...
4787 return;
4788 }
4789 if (app.persistent) {
4790 // Ah, but the application itself is persistent. Whatever!
4791 return;
4792 }
4793
4794 // App is no longer persistent... make sure it and the ones
4795 // following it in the LRU list have the correc oom_adj.
4796 updateOomAdjLocked();
4797 }
4798
4799 public void setPersistent(IBinder token, boolean isPersistent) {
4800 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4801 != PackageManager.PERMISSION_GRANTED) {
4802 String msg = "Permission Denial: setPersistent() from pid="
4803 + Binder.getCallingPid()
4804 + ", uid=" + Binder.getCallingUid()
4805 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4806 Log.w(TAG, msg);
4807 throw new SecurityException(msg);
4808 }
4809
4810 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004811 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004812 if (index < 0) {
4813 return;
4814 }
4815 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4816 ProcessRecord app = r.app;
4817
4818 if (localLOGV) Log.v(
4819 TAG, "Setting persistence " + isPersistent + ": " + r);
4820
4821 if (isPersistent) {
4822 if (r.persistent) {
4823 // Okay okay, I heard you already!
4824 if (localLOGV) Log.v(TAG, "Already persistent!");
4825 return;
4826 }
4827 r.persistent = true;
4828 app.persistentActivities++;
4829 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4830 if (app.persistentActivities > 1) {
4831 // We aren't the first...
4832 if (localLOGV) Log.v(TAG, "Not the first!");
4833 return;
4834 }
4835 if (app.persistent) {
4836 // This would be redundant.
4837 if (localLOGV) Log.v(TAG, "App is persistent!");
4838 return;
4839 }
4840
4841 // App is now persistent... make sure it and the ones
4842 // following it now have the correct oom_adj.
4843 final long origId = Binder.clearCallingIdentity();
4844 updateOomAdjLocked();
4845 Binder.restoreCallingIdentity(origId);
4846
4847 } else {
4848 if (!r.persistent) {
4849 // Okay okay, I heard you already!
4850 return;
4851 }
4852 r.persistent = false;
4853 final long origId = Binder.clearCallingIdentity();
4854 decPersistentCountLocked(app);
4855 Binder.restoreCallingIdentity(origId);
4856
4857 }
4858 }
4859 }
4860
4861 public boolean clearApplicationUserData(final String packageName,
4862 final IPackageDataObserver observer) {
4863 int uid = Binder.getCallingUid();
4864 int pid = Binder.getCallingPid();
4865 long callingId = Binder.clearCallingIdentity();
4866 try {
4867 IPackageManager pm = ActivityThread.getPackageManager();
4868 int pkgUid = -1;
4869 synchronized(this) {
4870 try {
4871 pkgUid = pm.getPackageUid(packageName);
4872 } catch (RemoteException e) {
4873 }
4874 if (pkgUid == -1) {
4875 Log.w(TAG, "Invalid packageName:" + packageName);
4876 return false;
4877 }
4878 if (uid == pkgUid || checkComponentPermission(
4879 android.Manifest.permission.CLEAR_APP_USER_DATA,
4880 pid, uid, -1)
4881 == PackageManager.PERMISSION_GRANTED) {
4882 restartPackageLocked(packageName, pkgUid);
4883 } else {
4884 throw new SecurityException(pid+" does not have permission:"+
4885 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4886 "for process:"+packageName);
4887 }
4888 }
4889
4890 try {
4891 //clear application user data
4892 pm.clearApplicationUserData(packageName, observer);
4893 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4894 Uri.fromParts("package", packageName, null));
4895 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4896 broadcastIntentLocked(null, null, intent,
4897 null, null, 0, null, null, null,
4898 false, false, MY_PID, Process.SYSTEM_UID);
4899 } catch (RemoteException e) {
4900 }
4901 } finally {
4902 Binder.restoreCallingIdentity(callingId);
4903 }
4904 return true;
4905 }
4906
4907 public void restartPackage(final String packageName) {
4908 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4909 != PackageManager.PERMISSION_GRANTED) {
4910 String msg = "Permission Denial: restartPackage() from pid="
4911 + Binder.getCallingPid()
4912 + ", uid=" + Binder.getCallingUid()
4913 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4914 Log.w(TAG, msg);
4915 throw new SecurityException(msg);
4916 }
4917
4918 long callingId = Binder.clearCallingIdentity();
4919 try {
4920 IPackageManager pm = ActivityThread.getPackageManager();
4921 int pkgUid = -1;
4922 synchronized(this) {
4923 try {
4924 pkgUid = pm.getPackageUid(packageName);
4925 } catch (RemoteException e) {
4926 }
4927 if (pkgUid == -1) {
4928 Log.w(TAG, "Invalid packageName: " + packageName);
4929 return;
4930 }
4931 restartPackageLocked(packageName, pkgUid);
4932 }
4933 } finally {
4934 Binder.restoreCallingIdentity(callingId);
4935 }
4936 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004937
4938 /*
4939 * The pkg name and uid have to be specified.
4940 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4941 */
4942 public void killApplicationWithUid(String pkg, int uid) {
4943 if (pkg == null) {
4944 return;
4945 }
4946 // Make sure the uid is valid.
4947 if (uid < 0) {
4948 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4949 return;
4950 }
4951 int callerUid = Binder.getCallingUid();
4952 // Only the system server can kill an application
4953 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004954 // Post an aysnc message to kill the application
4955 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4956 msg.arg1 = uid;
4957 msg.arg2 = 0;
4958 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004959 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004960 } else {
4961 throw new SecurityException(callerUid + " cannot kill pkg: " +
4962 pkg);
4963 }
4964 }
4965
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004966 public void closeSystemDialogs(String reason) {
4967 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4968 if (reason != null) {
4969 intent.putExtra("reason", reason);
4970 }
4971
4972 final int uid = Binder.getCallingUid();
4973 final long origId = Binder.clearCallingIdentity();
4974 synchronized (this) {
4975 int i = mWatchers.beginBroadcast();
4976 while (i > 0) {
4977 i--;
4978 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4979 if (w != null) {
4980 try {
4981 w.closingSystemDialogs(reason);
4982 } catch (RemoteException e) {
4983 }
4984 }
4985 }
4986 mWatchers.finishBroadcast();
4987
Dianne Hackbornffa42482009-09-23 22:20:11 -07004988 mWindowManager.closeSystemDialogs(reason);
4989
4990 for (i=mHistory.size()-1; i>=0; i--) {
4991 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4992 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
4993 finishActivityLocked(r, i,
4994 Activity.RESULT_CANCELED, null, "close-sys");
4995 }
4996 }
4997
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004998 broadcastIntentLocked(null, null, intent, null,
4999 null, 0, null, null, null, false, false, -1, uid);
5000 }
5001 Binder.restoreCallingIdentity(origId);
5002 }
5003
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005004 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005005 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005006 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
5007 for (int i=pids.length-1; i>=0; i--) {
5008 infos[i] = new Debug.MemoryInfo();
5009 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005010 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005011 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005012 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07005013
5014 public void killApplicationProcess(String processName, int uid) {
5015 if (processName == null) {
5016 return;
5017 }
5018
5019 int callerUid = Binder.getCallingUid();
5020 // Only the system server can kill an application
5021 if (callerUid == Process.SYSTEM_UID) {
5022 synchronized (this) {
5023 ProcessRecord app = getProcessRecordLocked(processName, uid);
5024 if (app != null) {
5025 try {
5026 app.thread.scheduleSuicide();
5027 } catch (RemoteException e) {
5028 // If the other end already died, then our work here is done.
5029 }
5030 } else {
5031 Log.w(TAG, "Process/uid not found attempting kill of "
5032 + processName + " / " + uid);
5033 }
5034 }
5035 } else {
5036 throw new SecurityException(callerUid + " cannot kill app process: " +
5037 processName);
5038 }
5039 }
5040
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005041 private void restartPackageLocked(final String packageName, int uid) {
5042 uninstallPackageLocked(packageName, uid, false);
5043 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5044 Uri.fromParts("package", packageName, null));
5045 intent.putExtra(Intent.EXTRA_UID, uid);
5046 broadcastIntentLocked(null, null, intent,
5047 null, null, 0, null, null, null,
5048 false, false, MY_PID, Process.SYSTEM_UID);
5049 }
5050
5051 private final void uninstallPackageLocked(String name, int uid,
5052 boolean callerWillRestart) {
5053 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
5054
5055 int i, N;
5056
5057 final String procNamePrefix = name + ":";
5058 if (uid < 0) {
5059 try {
5060 uid = ActivityThread.getPackageManager().getPackageUid(name);
5061 } catch (RemoteException e) {
5062 }
5063 }
5064
5065 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5066 while (badApps.hasNext()) {
5067 SparseArray<Long> ba = badApps.next();
5068 if (ba.get(uid) != null) {
5069 badApps.remove();
5070 }
5071 }
5072
5073 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
5074
5075 // Remove all processes this package may have touched: all with the
5076 // same UID (except for the system or root user), and all whose name
5077 // matches the package name.
5078 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5079 final int NA = apps.size();
5080 for (int ia=0; ia<NA; ia++) {
5081 ProcessRecord app = apps.valueAt(ia);
5082 if (app.removed) {
5083 procs.add(app);
5084 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5085 || app.processName.equals(name)
5086 || app.processName.startsWith(procNamePrefix)) {
5087 app.removed = true;
5088 procs.add(app);
5089 }
5090 }
5091 }
5092
5093 N = procs.size();
5094 for (i=0; i<N; i++) {
5095 removeProcessLocked(procs.get(i), callerWillRestart);
5096 }
5097
5098 for (i=mHistory.size()-1; i>=0; i--) {
5099 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5100 if (r.packageName.equals(name)) {
5101 if (Config.LOGD) Log.d(
5102 TAG, " Force finishing activity "
5103 + r.intent.getComponent().flattenToShortString());
5104 if (r.app != null) {
5105 r.app.removed = true;
5106 }
5107 r.app = null;
5108 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5109 }
5110 }
5111
5112 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5113 for (ServiceRecord service : mServices.values()) {
5114 if (service.packageName.equals(name)) {
5115 if (service.app != null) {
5116 service.app.removed = true;
5117 }
5118 service.app = null;
5119 services.add(service);
5120 }
5121 }
5122
5123 N = services.size();
5124 for (i=0; i<N; i++) {
5125 bringDownServiceLocked(services.get(i), true);
5126 }
5127
5128 resumeTopActivityLocked(null);
5129 }
5130
5131 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5132 final String name = app.processName;
5133 final int uid = app.info.uid;
5134 if (Config.LOGD) Log.d(
5135 TAG, "Force removing process " + app + " (" + name
5136 + "/" + uid + ")");
5137
5138 mProcessNames.remove(name, uid);
5139 boolean needRestart = false;
5140 if (app.pid > 0 && app.pid != MY_PID) {
5141 int pid = app.pid;
5142 synchronized (mPidsSelfLocked) {
5143 mPidsSelfLocked.remove(pid);
5144 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5145 }
5146 handleAppDiedLocked(app, true);
5147 mLRUProcesses.remove(app);
5148 Process.killProcess(pid);
5149
5150 if (app.persistent) {
5151 if (!callerWillRestart) {
5152 addAppLocked(app.info);
5153 } else {
5154 needRestart = true;
5155 }
5156 }
5157 } else {
5158 mRemovedProcesses.add(app);
5159 }
5160
5161 return needRestart;
5162 }
5163
5164 private final void processStartTimedOutLocked(ProcessRecord app) {
5165 final int pid = app.pid;
5166 boolean gone = false;
5167 synchronized (mPidsSelfLocked) {
5168 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5169 if (knownApp != null && knownApp.thread == null) {
5170 mPidsSelfLocked.remove(pid);
5171 gone = true;
5172 }
5173 }
5174
5175 if (gone) {
5176 Log.w(TAG, "Process " + app + " failed to attach");
5177 mProcessNames.remove(app.processName, app.info.uid);
5178 Process.killProcess(pid);
5179 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5180 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5181 mPendingBroadcast = null;
5182 scheduleBroadcastsLocked();
5183 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005184 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5185 Log.w(TAG, "Unattached app died before backup, skipping");
5186 try {
5187 IBackupManager bm = IBackupManager.Stub.asInterface(
5188 ServiceManager.getService(Context.BACKUP_SERVICE));
5189 bm.agentDisconnected(app.info.packageName);
5190 } catch (RemoteException e) {
5191 // Can't happen; the backup manager is local
5192 }
5193 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005194 } else {
5195 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5196 }
5197 }
5198
5199 private final boolean attachApplicationLocked(IApplicationThread thread,
5200 int pid) {
5201
5202 // Find the application record that is being attached... either via
5203 // the pid if we are running in multiple processes, or just pull the
5204 // next app record if we are emulating process with anonymous threads.
5205 ProcessRecord app;
5206 if (pid != MY_PID && pid >= 0) {
5207 synchronized (mPidsSelfLocked) {
5208 app = mPidsSelfLocked.get(pid);
5209 }
5210 } else if (mStartingProcesses.size() > 0) {
5211 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005212 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005213 } else {
5214 app = null;
5215 }
5216
5217 if (app == null) {
5218 Log.w(TAG, "No pending application record for pid " + pid
5219 + " (IApplicationThread " + thread + "); dropping process");
5220 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5221 if (pid > 0 && pid != MY_PID) {
5222 Process.killProcess(pid);
5223 } else {
5224 try {
5225 thread.scheduleExit();
5226 } catch (Exception e) {
5227 // Ignore exceptions.
5228 }
5229 }
5230 return false;
5231 }
5232
5233 // If this application record is still attached to a previous
5234 // process, clean it up now.
5235 if (app.thread != null) {
5236 handleAppDiedLocked(app, true);
5237 }
5238
5239 // Tell the process all about itself.
5240
5241 if (localLOGV) Log.v(
5242 TAG, "Binding process pid " + pid + " to record " + app);
5243
5244 String processName = app.processName;
5245 try {
5246 thread.asBinder().linkToDeath(new AppDeathRecipient(
5247 app, pid, thread), 0);
5248 } catch (RemoteException e) {
5249 app.resetPackageList();
5250 startProcessLocked(app, "link fail", processName);
5251 return false;
5252 }
5253
5254 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5255
5256 app.thread = thread;
5257 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005258 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005259 app.forcingToForeground = null;
5260 app.foregroundServices = false;
5261 app.debugging = false;
5262
5263 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5264
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005265 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5266 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005267
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005268 if (!normalMode) {
5269 Log.i(TAG, "Launching preboot mode app: " + app);
5270 }
5271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005272 if (localLOGV) Log.v(
5273 TAG, "New app record " + app
5274 + " thread=" + thread.asBinder() + " pid=" + pid);
5275 try {
5276 int testMode = IApplicationThread.DEBUG_OFF;
5277 if (mDebugApp != null && mDebugApp.equals(processName)) {
5278 testMode = mWaitForDebugger
5279 ? IApplicationThread.DEBUG_WAIT
5280 : IApplicationThread.DEBUG_ON;
5281 app.debugging = true;
5282 if (mDebugTransient) {
5283 mDebugApp = mOrigDebugApp;
5284 mWaitForDebugger = mOrigWaitForDebugger;
5285 }
5286 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005287
Christopher Tate181fafa2009-05-14 11:12:14 -07005288 // If the app is being launched for restore or full backup, set it up specially
5289 boolean isRestrictedBackupMode = false;
5290 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5291 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5292 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5293 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005294
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005295 ensurePackageDexOpt(app.instrumentationInfo != null
5296 ? app.instrumentationInfo.packageName
5297 : app.info.packageName);
5298 if (app.instrumentationClass != null) {
5299 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005300 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005301 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5302 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005303 thread.bindApplication(processName, app.instrumentationInfo != null
5304 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005305 app.instrumentationClass, app.instrumentationProfileFile,
5306 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005307 isRestrictedBackupMode || !normalMode,
5308 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005309 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005310 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005311 } catch (Exception e) {
5312 // todo: Yikes! What should we do? For now we will try to
5313 // start another process, but that could easily get us in
5314 // an infinite loop of restarting processes...
5315 Log.w(TAG, "Exception thrown during bind!", e);
5316
5317 app.resetPackageList();
5318 startProcessLocked(app, "bind fail", processName);
5319 return false;
5320 }
5321
5322 // Remove this record from the list of starting applications.
5323 mPersistentStartingProcesses.remove(app);
5324 mProcessesOnHold.remove(app);
5325
5326 boolean badApp = false;
5327 boolean didSomething = false;
5328
5329 // See if the top visible activity is waiting to run in this process...
5330 HistoryRecord hr = topRunningActivityLocked(null);
5331 if (hr != null) {
5332 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5333 && processName.equals(hr.processName)) {
5334 try {
5335 if (realStartActivityLocked(hr, app, true, true)) {
5336 didSomething = true;
5337 }
5338 } catch (Exception e) {
5339 Log.w(TAG, "Exception in new application when starting activity "
5340 + hr.intent.getComponent().flattenToShortString(), e);
5341 badApp = true;
5342 }
5343 } else {
5344 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5345 }
5346 }
5347
5348 // Find any services that should be running in this process...
5349 if (!badApp && mPendingServices.size() > 0) {
5350 ServiceRecord sr = null;
5351 try {
5352 for (int i=0; i<mPendingServices.size(); i++) {
5353 sr = mPendingServices.get(i);
5354 if (app.info.uid != sr.appInfo.uid
5355 || !processName.equals(sr.processName)) {
5356 continue;
5357 }
5358
5359 mPendingServices.remove(i);
5360 i--;
5361 realStartServiceLocked(sr, app);
5362 didSomething = true;
5363 }
5364 } catch (Exception e) {
5365 Log.w(TAG, "Exception in new application when starting service "
5366 + sr.shortName, e);
5367 badApp = true;
5368 }
5369 }
5370
5371 // Check if the next broadcast receiver is in this process...
5372 BroadcastRecord br = mPendingBroadcast;
5373 if (!badApp && br != null && br.curApp == app) {
5374 try {
5375 mPendingBroadcast = null;
5376 processCurBroadcastLocked(br, app);
5377 didSomething = true;
5378 } catch (Exception e) {
5379 Log.w(TAG, "Exception in new application when starting receiver "
5380 + br.curComponent.flattenToShortString(), e);
5381 badApp = true;
5382 logBroadcastReceiverDiscard(br);
5383 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5384 br.resultExtras, br.resultAbort, true);
5385 scheduleBroadcastsLocked();
5386 }
5387 }
5388
Christopher Tate181fafa2009-05-14 11:12:14 -07005389 // Check whether the next backup agent is in this process...
5390 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5391 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005392 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005393 try {
5394 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5395 } catch (Exception e) {
5396 Log.w(TAG, "Exception scheduling backup agent creation: ");
5397 e.printStackTrace();
5398 }
5399 }
5400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005401 if (badApp) {
5402 // todo: Also need to kill application to deal with all
5403 // kinds of exceptions.
5404 handleAppDiedLocked(app, false);
5405 return false;
5406 }
5407
5408 if (!didSomething) {
5409 updateOomAdjLocked();
5410 }
5411
5412 return true;
5413 }
5414
5415 public final void attachApplication(IApplicationThread thread) {
5416 synchronized (this) {
5417 int callingPid = Binder.getCallingPid();
5418 final long origId = Binder.clearCallingIdentity();
5419 attachApplicationLocked(thread, callingPid);
5420 Binder.restoreCallingIdentity(origId);
5421 }
5422 }
5423
Dianne Hackborne88846e2009-09-30 21:34:25 -07005424 public final void activityIdle(IBinder token, Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005425 final long origId = Binder.clearCallingIdentity();
Dianne Hackborne88846e2009-09-30 21:34:25 -07005426 activityIdleInternal(token, false, config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005427 Binder.restoreCallingIdentity(origId);
5428 }
5429
5430 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5431 boolean remove) {
5432 int N = mStoppingActivities.size();
5433 if (N <= 0) return null;
5434
5435 ArrayList<HistoryRecord> stops = null;
5436
5437 final boolean nowVisible = mResumedActivity != null
5438 && mResumedActivity.nowVisible
5439 && !mResumedActivity.waitingVisible;
5440 for (int i=0; i<N; i++) {
5441 HistoryRecord s = mStoppingActivities.get(i);
5442 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5443 + nowVisible + " waitingVisible=" + s.waitingVisible
5444 + " finishing=" + s.finishing);
5445 if (s.waitingVisible && nowVisible) {
5446 mWaitingVisibleActivities.remove(s);
5447 s.waitingVisible = false;
5448 if (s.finishing) {
5449 // If this activity is finishing, it is sitting on top of
5450 // everyone else but we now know it is no longer needed...
5451 // so get rid of it. Otherwise, we need to go through the
5452 // normal flow and hide it once we determine that it is
5453 // hidden by the activities in front of it.
5454 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5455 mWindowManager.setAppVisibility(s, false);
5456 }
5457 }
5458 if (!s.waitingVisible && remove) {
5459 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5460 if (stops == null) {
5461 stops = new ArrayList<HistoryRecord>();
5462 }
5463 stops.add(s);
5464 mStoppingActivities.remove(i);
5465 N--;
5466 i--;
5467 }
5468 }
5469
5470 return stops;
5471 }
5472
5473 void enableScreenAfterBoot() {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005474 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5475 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005476 mWindowManager.enableScreenAfterBoot();
5477 }
5478
Dianne Hackborne88846e2009-09-30 21:34:25 -07005479 final void activityIdleInternal(IBinder token, boolean fromTimeout,
5480 Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005481 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5482
5483 ArrayList<HistoryRecord> stops = null;
5484 ArrayList<HistoryRecord> finishes = null;
5485 ArrayList<HistoryRecord> thumbnails = null;
5486 int NS = 0;
5487 int NF = 0;
5488 int NT = 0;
5489 IApplicationThread sendThumbnail = null;
5490 boolean booting = false;
5491 boolean enableScreen = false;
5492
5493 synchronized (this) {
5494 if (token != null) {
5495 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5496 }
5497
5498 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005499 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005500 if (index >= 0) {
5501 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5502
Dianne Hackborne88846e2009-09-30 21:34:25 -07005503 // This is a hack to semi-deal with a race condition
5504 // in the client where it can be constructed with a
5505 // newer configuration from when we asked it to launch.
5506 // We'll update with whatever configuration it now says
5507 // it used to launch.
5508 if (config != null) {
5509 r.configuration = config;
5510 }
5511
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005512 // No longer need to keep the device awake.
5513 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5514 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5515 mLaunchingActivity.release();
5516 }
5517
5518 // We are now idle. If someone is waiting for a thumbnail from
5519 // us, we can now deliver.
5520 r.idle = true;
5521 scheduleAppGcsLocked();
5522 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5523 sendThumbnail = r.app.thread;
5524 r.thumbnailNeeded = false;
5525 }
5526
5527 // If this activity is fullscreen, set up to hide those under it.
5528
5529 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5530 ensureActivitiesVisibleLocked(null, 0);
5531
5532 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5533 if (!mBooted && !fromTimeout) {
5534 mBooted = true;
5535 enableScreen = true;
5536 }
5537 }
5538
5539 // Atomically retrieve all of the other things to do.
5540 stops = processStoppingActivitiesLocked(true);
5541 NS = stops != null ? stops.size() : 0;
5542 if ((NF=mFinishingActivities.size()) > 0) {
5543 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5544 mFinishingActivities.clear();
5545 }
5546 if ((NT=mCancelledThumbnails.size()) > 0) {
5547 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5548 mCancelledThumbnails.clear();
5549 }
5550
5551 booting = mBooting;
5552 mBooting = false;
5553 }
5554
5555 int i;
5556
5557 // Send thumbnail if requested.
5558 if (sendThumbnail != null) {
5559 try {
5560 sendThumbnail.requestThumbnail(token);
5561 } catch (Exception e) {
5562 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5563 sendPendingThumbnail(null, token, null, null, true);
5564 }
5565 }
5566
5567 // Stop any activities that are scheduled to do so but have been
5568 // waiting for the next one to start.
5569 for (i=0; i<NS; i++) {
5570 HistoryRecord r = (HistoryRecord)stops.get(i);
5571 synchronized (this) {
5572 if (r.finishing) {
5573 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5574 } else {
5575 stopActivityLocked(r);
5576 }
5577 }
5578 }
5579
5580 // Finish any activities that are scheduled to do so but have been
5581 // waiting for the next one to start.
5582 for (i=0; i<NF; i++) {
5583 HistoryRecord r = (HistoryRecord)finishes.get(i);
5584 synchronized (this) {
5585 destroyActivityLocked(r, true);
5586 }
5587 }
5588
5589 // Report back to any thumbnail receivers.
5590 for (i=0; i<NT; i++) {
5591 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5592 sendPendingThumbnail(r, null, null, null, true);
5593 }
5594
5595 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005596 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005597 }
5598
5599 trimApplications();
5600 //dump();
5601 //mWindowManager.dump();
5602
5603 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005604 enableScreenAfterBoot();
5605 }
5606 }
5607
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005608 final void finishBooting() {
5609 // Ensure that any processes we had put on hold are now started
5610 // up.
5611 final int NP = mProcessesOnHold.size();
5612 if (NP > 0) {
5613 ArrayList<ProcessRecord> procs =
5614 new ArrayList<ProcessRecord>(mProcessesOnHold);
5615 for (int ip=0; ip<NP; ip++) {
5616 this.startProcessLocked(procs.get(ip), "on-hold", null);
5617 }
5618 }
5619 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5620 // Tell anyone interested that we are done booting!
5621 synchronized (this) {
5622 broadcastIntentLocked(null, null,
5623 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5624 null, null, 0, null, null,
5625 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5626 false, false, MY_PID, Process.SYSTEM_UID);
5627 }
5628 }
5629 }
5630
5631 final void ensureBootCompleted() {
5632 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005633 boolean enableScreen;
5634 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005635 booting = mBooting;
5636 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005637 enableScreen = !mBooted;
5638 mBooted = true;
5639 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005640
5641 if (booting) {
5642 finishBooting();
5643 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005644
5645 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005646 enableScreenAfterBoot();
5647 }
5648 }
5649
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005650 public final void activityPaused(IBinder token, Bundle icicle) {
5651 // Refuse possible leaked file descriptors
5652 if (icicle != null && icicle.hasFileDescriptors()) {
5653 throw new IllegalArgumentException("File descriptors passed in Bundle");
5654 }
5655
5656 final long origId = Binder.clearCallingIdentity();
5657 activityPaused(token, icicle, false);
5658 Binder.restoreCallingIdentity(origId);
5659 }
5660
5661 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5662 if (DEBUG_PAUSE) Log.v(
5663 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5664 + ", timeout=" + timeout);
5665
5666 HistoryRecord r = null;
5667
5668 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005669 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005670 if (index >= 0) {
5671 r = (HistoryRecord)mHistory.get(index);
5672 if (!timeout) {
5673 r.icicle = icicle;
5674 r.haveState = true;
5675 }
5676 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5677 if (mPausingActivity == r) {
5678 r.state = ActivityState.PAUSED;
5679 completePauseLocked();
5680 } else {
5681 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5682 System.identityHashCode(r), r.shortComponentName,
5683 mPausingActivity != null
5684 ? mPausingActivity.shortComponentName : "(none)");
5685 }
5686 }
5687 }
5688 }
5689
5690 public final void activityStopped(IBinder token, Bitmap thumbnail,
5691 CharSequence description) {
5692 if (localLOGV) Log.v(
5693 TAG, "Activity stopped: token=" + token);
5694
5695 HistoryRecord r = null;
5696
5697 final long origId = Binder.clearCallingIdentity();
5698
5699 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005700 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005701 if (index >= 0) {
5702 r = (HistoryRecord)mHistory.get(index);
5703 r.thumbnail = thumbnail;
5704 r.description = description;
5705 r.stopped = true;
5706 r.state = ActivityState.STOPPED;
5707 if (!r.finishing) {
5708 if (r.configDestroy) {
5709 destroyActivityLocked(r, true);
5710 resumeTopActivityLocked(null);
5711 }
5712 }
5713 }
5714 }
5715
5716 if (r != null) {
5717 sendPendingThumbnail(r, null, null, null, false);
5718 }
5719
5720 trimApplications();
5721
5722 Binder.restoreCallingIdentity(origId);
5723 }
5724
5725 public final void activityDestroyed(IBinder token) {
5726 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5727 synchronized (this) {
5728 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5729
Dianne Hackborn75b03852009-06-12 15:43:26 -07005730 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005731 if (index >= 0) {
5732 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5733 if (r.state == ActivityState.DESTROYING) {
5734 final long origId = Binder.clearCallingIdentity();
5735 removeActivityFromHistoryLocked(r);
5736 Binder.restoreCallingIdentity(origId);
5737 }
5738 }
5739 }
5740 }
5741
5742 public String getCallingPackage(IBinder token) {
5743 synchronized (this) {
5744 HistoryRecord r = getCallingRecordLocked(token);
5745 return r != null && r.app != null ? r.app.processName : null;
5746 }
5747 }
5748
5749 public ComponentName getCallingActivity(IBinder token) {
5750 synchronized (this) {
5751 HistoryRecord r = getCallingRecordLocked(token);
5752 return r != null ? r.intent.getComponent() : null;
5753 }
5754 }
5755
5756 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005757 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005758 if (index >= 0) {
5759 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5760 if (r != null) {
5761 return r.resultTo;
5762 }
5763 }
5764 return null;
5765 }
5766
5767 public ComponentName getActivityClassForToken(IBinder token) {
5768 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005769 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005770 if (index >= 0) {
5771 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5772 return r.intent.getComponent();
5773 }
5774 return null;
5775 }
5776 }
5777
5778 public String getPackageForToken(IBinder token) {
5779 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005780 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005781 if (index >= 0) {
5782 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5783 return r.packageName;
5784 }
5785 return null;
5786 }
5787 }
5788
5789 public IIntentSender getIntentSender(int type,
5790 String packageName, IBinder token, String resultWho,
5791 int requestCode, Intent intent, String resolvedType, int flags) {
5792 // Refuse possible leaked file descriptors
5793 if (intent != null && intent.hasFileDescriptors() == true) {
5794 throw new IllegalArgumentException("File descriptors passed in Intent");
5795 }
5796
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005797 if (type == INTENT_SENDER_BROADCAST) {
5798 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5799 throw new IllegalArgumentException(
5800 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5801 }
5802 }
5803
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005804 synchronized(this) {
5805 int callingUid = Binder.getCallingUid();
5806 try {
5807 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5808 Process.supportsProcesses()) {
5809 int uid = ActivityThread.getPackageManager()
5810 .getPackageUid(packageName);
5811 if (uid != Binder.getCallingUid()) {
5812 String msg = "Permission Denial: getIntentSender() from pid="
5813 + Binder.getCallingPid()
5814 + ", uid=" + Binder.getCallingUid()
5815 + ", (need uid=" + uid + ")"
5816 + " is not allowed to send as package " + packageName;
5817 Log.w(TAG, msg);
5818 throw new SecurityException(msg);
5819 }
5820 }
5821 } catch (RemoteException e) {
5822 throw new SecurityException(e);
5823 }
5824 HistoryRecord activity = null;
5825 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005826 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005827 if (index < 0) {
5828 return null;
5829 }
5830 activity = (HistoryRecord)mHistory.get(index);
5831 if (activity.finishing) {
5832 return null;
5833 }
5834 }
5835
5836 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5837 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5838 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5839 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5840 |PendingIntent.FLAG_UPDATE_CURRENT);
5841
5842 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5843 type, packageName, activity, resultWho,
5844 requestCode, intent, resolvedType, flags);
5845 WeakReference<PendingIntentRecord> ref;
5846 ref = mIntentSenderRecords.get(key);
5847 PendingIntentRecord rec = ref != null ? ref.get() : null;
5848 if (rec != null) {
5849 if (!cancelCurrent) {
5850 if (updateCurrent) {
5851 rec.key.requestIntent.replaceExtras(intent);
5852 }
5853 return rec;
5854 }
5855 rec.canceled = true;
5856 mIntentSenderRecords.remove(key);
5857 }
5858 if (noCreate) {
5859 return rec;
5860 }
5861 rec = new PendingIntentRecord(this, key, callingUid);
5862 mIntentSenderRecords.put(key, rec.ref);
5863 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5864 if (activity.pendingResults == null) {
5865 activity.pendingResults
5866 = new HashSet<WeakReference<PendingIntentRecord>>();
5867 }
5868 activity.pendingResults.add(rec.ref);
5869 }
5870 return rec;
5871 }
5872 }
5873
5874 public void cancelIntentSender(IIntentSender sender) {
5875 if (!(sender instanceof PendingIntentRecord)) {
5876 return;
5877 }
5878 synchronized(this) {
5879 PendingIntentRecord rec = (PendingIntentRecord)sender;
5880 try {
5881 int uid = ActivityThread.getPackageManager()
5882 .getPackageUid(rec.key.packageName);
5883 if (uid != Binder.getCallingUid()) {
5884 String msg = "Permission Denial: cancelIntentSender() from pid="
5885 + Binder.getCallingPid()
5886 + ", uid=" + Binder.getCallingUid()
5887 + " is not allowed to cancel packges "
5888 + rec.key.packageName;
5889 Log.w(TAG, msg);
5890 throw new SecurityException(msg);
5891 }
5892 } catch (RemoteException e) {
5893 throw new SecurityException(e);
5894 }
5895 cancelIntentSenderLocked(rec, true);
5896 }
5897 }
5898
5899 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5900 rec.canceled = true;
5901 mIntentSenderRecords.remove(rec.key);
5902 if (cleanActivity && rec.key.activity != null) {
5903 rec.key.activity.pendingResults.remove(rec.ref);
5904 }
5905 }
5906
5907 public String getPackageForIntentSender(IIntentSender pendingResult) {
5908 if (!(pendingResult instanceof PendingIntentRecord)) {
5909 return null;
5910 }
5911 synchronized(this) {
5912 try {
5913 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5914 return res.key.packageName;
5915 } catch (ClassCastException e) {
5916 }
5917 }
5918 return null;
5919 }
5920
5921 public void setProcessLimit(int max) {
5922 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5923 "setProcessLimit()");
5924 mProcessLimit = max;
5925 }
5926
5927 public int getProcessLimit() {
5928 return mProcessLimit;
5929 }
5930
5931 void foregroundTokenDied(ForegroundToken token) {
5932 synchronized (ActivityManagerService.this) {
5933 synchronized (mPidsSelfLocked) {
5934 ForegroundToken cur
5935 = mForegroundProcesses.get(token.pid);
5936 if (cur != token) {
5937 return;
5938 }
5939 mForegroundProcesses.remove(token.pid);
5940 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5941 if (pr == null) {
5942 return;
5943 }
5944 pr.forcingToForeground = null;
5945 pr.foregroundServices = false;
5946 }
5947 updateOomAdjLocked();
5948 }
5949 }
5950
5951 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5952 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5953 "setProcessForeground()");
5954 synchronized(this) {
5955 boolean changed = false;
5956
5957 synchronized (mPidsSelfLocked) {
5958 ProcessRecord pr = mPidsSelfLocked.get(pid);
5959 if (pr == null) {
5960 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5961 return;
5962 }
5963 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5964 if (oldToken != null) {
5965 oldToken.token.unlinkToDeath(oldToken, 0);
5966 mForegroundProcesses.remove(pid);
5967 pr.forcingToForeground = null;
5968 changed = true;
5969 }
5970 if (isForeground && token != null) {
5971 ForegroundToken newToken = new ForegroundToken() {
5972 public void binderDied() {
5973 foregroundTokenDied(this);
5974 }
5975 };
5976 newToken.pid = pid;
5977 newToken.token = token;
5978 try {
5979 token.linkToDeath(newToken, 0);
5980 mForegroundProcesses.put(pid, newToken);
5981 pr.forcingToForeground = token;
5982 changed = true;
5983 } catch (RemoteException e) {
5984 // If the process died while doing this, we will later
5985 // do the cleanup with the process death link.
5986 }
5987 }
5988 }
5989
5990 if (changed) {
5991 updateOomAdjLocked();
5992 }
5993 }
5994 }
5995
5996 // =========================================================
5997 // PERMISSIONS
5998 // =========================================================
5999
6000 static class PermissionController extends IPermissionController.Stub {
6001 ActivityManagerService mActivityManagerService;
6002 PermissionController(ActivityManagerService activityManagerService) {
6003 mActivityManagerService = activityManagerService;
6004 }
6005
6006 public boolean checkPermission(String permission, int pid, int uid) {
6007 return mActivityManagerService.checkPermission(permission, pid,
6008 uid) == PackageManager.PERMISSION_GRANTED;
6009 }
6010 }
6011
6012 /**
6013 * This can be called with or without the global lock held.
6014 */
6015 int checkComponentPermission(String permission, int pid, int uid,
6016 int reqUid) {
6017 // We might be performing an operation on behalf of an indirect binder
6018 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
6019 // client identity accordingly before proceeding.
6020 Identity tlsIdentity = sCallerIdentity.get();
6021 if (tlsIdentity != null) {
6022 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6023 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6024 uid = tlsIdentity.uid;
6025 pid = tlsIdentity.pid;
6026 }
6027
6028 // Root, system server and our own process get to do everything.
6029 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6030 !Process.supportsProcesses()) {
6031 return PackageManager.PERMISSION_GRANTED;
6032 }
6033 // If the target requires a specific UID, always fail for others.
6034 if (reqUid >= 0 && uid != reqUid) {
6035 return PackageManager.PERMISSION_DENIED;
6036 }
6037 if (permission == null) {
6038 return PackageManager.PERMISSION_GRANTED;
6039 }
6040 try {
6041 return ActivityThread.getPackageManager()
6042 .checkUidPermission(permission, uid);
6043 } catch (RemoteException e) {
6044 // Should never happen, but if it does... deny!
6045 Log.e(TAG, "PackageManager is dead?!?", e);
6046 }
6047 return PackageManager.PERMISSION_DENIED;
6048 }
6049
6050 /**
6051 * As the only public entry point for permissions checking, this method
6052 * can enforce the semantic that requesting a check on a null global
6053 * permission is automatically denied. (Internally a null permission
6054 * string is used when calling {@link #checkComponentPermission} in cases
6055 * when only uid-based security is needed.)
6056 *
6057 * This can be called with or without the global lock held.
6058 */
6059 public int checkPermission(String permission, int pid, int uid) {
6060 if (permission == null) {
6061 return PackageManager.PERMISSION_DENIED;
6062 }
6063 return checkComponentPermission(permission, pid, uid, -1);
6064 }
6065
6066 /**
6067 * Binder IPC calls go through the public entry point.
6068 * This can be called with or without the global lock held.
6069 */
6070 int checkCallingPermission(String permission) {
6071 return checkPermission(permission,
6072 Binder.getCallingPid(),
6073 Binder.getCallingUid());
6074 }
6075
6076 /**
6077 * This can be called with or without the global lock held.
6078 */
6079 void enforceCallingPermission(String permission, String func) {
6080 if (checkCallingPermission(permission)
6081 == PackageManager.PERMISSION_GRANTED) {
6082 return;
6083 }
6084
6085 String msg = "Permission Denial: " + func + " from pid="
6086 + Binder.getCallingPid()
6087 + ", uid=" + Binder.getCallingUid()
6088 + " requires " + permission;
6089 Log.w(TAG, msg);
6090 throw new SecurityException(msg);
6091 }
6092
6093 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6094 ProviderInfo pi, int uid, int modeFlags) {
6095 try {
6096 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6097 if ((pi.readPermission != null) &&
6098 (pm.checkUidPermission(pi.readPermission, uid)
6099 != PackageManager.PERMISSION_GRANTED)) {
6100 return false;
6101 }
6102 }
6103 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6104 if ((pi.writePermission != null) &&
6105 (pm.checkUidPermission(pi.writePermission, uid)
6106 != PackageManager.PERMISSION_GRANTED)) {
6107 return false;
6108 }
6109 }
6110 return true;
6111 } catch (RemoteException e) {
6112 return false;
6113 }
6114 }
6115
6116 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6117 int modeFlags) {
6118 // Root gets to do everything.
6119 if (uid == 0 || !Process.supportsProcesses()) {
6120 return true;
6121 }
6122 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6123 if (perms == null) return false;
6124 UriPermission perm = perms.get(uri);
6125 if (perm == null) return false;
6126 return (modeFlags&perm.modeFlags) == modeFlags;
6127 }
6128
6129 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6130 // Another redirected-binder-call permissions check as in
6131 // {@link checkComponentPermission}.
6132 Identity tlsIdentity = sCallerIdentity.get();
6133 if (tlsIdentity != null) {
6134 uid = tlsIdentity.uid;
6135 pid = tlsIdentity.pid;
6136 }
6137
6138 // Our own process gets to do everything.
6139 if (pid == MY_PID) {
6140 return PackageManager.PERMISSION_GRANTED;
6141 }
6142 synchronized(this) {
6143 return checkUriPermissionLocked(uri, uid, modeFlags)
6144 ? PackageManager.PERMISSION_GRANTED
6145 : PackageManager.PERMISSION_DENIED;
6146 }
6147 }
6148
6149 private void grantUriPermissionLocked(int callingUid,
6150 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6151 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6152 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6153 if (modeFlags == 0) {
6154 return;
6155 }
6156
6157 final IPackageManager pm = ActivityThread.getPackageManager();
6158
6159 // If this is not a content: uri, we can't do anything with it.
6160 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6161 return;
6162 }
6163
6164 String name = uri.getAuthority();
6165 ProviderInfo pi = null;
6166 ContentProviderRecord cpr
6167 = (ContentProviderRecord)mProvidersByName.get(name);
6168 if (cpr != null) {
6169 pi = cpr.info;
6170 } else {
6171 try {
6172 pi = pm.resolveContentProvider(name,
6173 PackageManager.GET_URI_PERMISSION_PATTERNS);
6174 } catch (RemoteException ex) {
6175 }
6176 }
6177 if (pi == null) {
6178 Log.w(TAG, "No content provider found for: " + name);
6179 return;
6180 }
6181
6182 int targetUid;
6183 try {
6184 targetUid = pm.getPackageUid(targetPkg);
6185 if (targetUid < 0) {
6186 return;
6187 }
6188 } catch (RemoteException ex) {
6189 return;
6190 }
6191
6192 // First... does the target actually need this permission?
6193 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6194 // No need to grant the target this permission.
6195 return;
6196 }
6197
6198 // Second... maybe someone else has already granted the
6199 // permission?
6200 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6201 // No need to grant the target this permission.
6202 return;
6203 }
6204
6205 // Third... is the provider allowing granting of URI permissions?
6206 if (!pi.grantUriPermissions) {
6207 throw new SecurityException("Provider " + pi.packageName
6208 + "/" + pi.name
6209 + " does not allow granting of Uri permissions (uri "
6210 + uri + ")");
6211 }
6212 if (pi.uriPermissionPatterns != null) {
6213 final int N = pi.uriPermissionPatterns.length;
6214 boolean allowed = false;
6215 for (int i=0; i<N; i++) {
6216 if (pi.uriPermissionPatterns[i] != null
6217 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6218 allowed = true;
6219 break;
6220 }
6221 }
6222 if (!allowed) {
6223 throw new SecurityException("Provider " + pi.packageName
6224 + "/" + pi.name
6225 + " does not allow granting of permission to path of Uri "
6226 + uri);
6227 }
6228 }
6229
6230 // Fourth... does the caller itself have permission to access
6231 // this uri?
6232 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6233 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6234 throw new SecurityException("Uid " + callingUid
6235 + " does not have permission to uri " + uri);
6236 }
6237 }
6238
6239 // Okay! So here we are: the caller has the assumed permission
6240 // to the uri, and the target doesn't. Let's now give this to
6241 // the target.
6242
6243 HashMap<Uri, UriPermission> targetUris
6244 = mGrantedUriPermissions.get(targetUid);
6245 if (targetUris == null) {
6246 targetUris = new HashMap<Uri, UriPermission>();
6247 mGrantedUriPermissions.put(targetUid, targetUris);
6248 }
6249
6250 UriPermission perm = targetUris.get(uri);
6251 if (perm == null) {
6252 perm = new UriPermission(targetUid, uri);
6253 targetUris.put(uri, perm);
6254
6255 }
6256 perm.modeFlags |= modeFlags;
6257 if (activity == null) {
6258 perm.globalModeFlags |= modeFlags;
6259 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6260 perm.readActivities.add(activity);
6261 if (activity.readUriPermissions == null) {
6262 activity.readUriPermissions = new HashSet<UriPermission>();
6263 }
6264 activity.readUriPermissions.add(perm);
6265 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6266 perm.writeActivities.add(activity);
6267 if (activity.writeUriPermissions == null) {
6268 activity.writeUriPermissions = new HashSet<UriPermission>();
6269 }
6270 activity.writeUriPermissions.add(perm);
6271 }
6272 }
6273
6274 private void grantUriPermissionFromIntentLocked(int callingUid,
6275 String targetPkg, Intent intent, HistoryRecord activity) {
6276 if (intent == null) {
6277 return;
6278 }
6279 Uri data = intent.getData();
6280 if (data == null) {
6281 return;
6282 }
6283 grantUriPermissionLocked(callingUid, targetPkg, data,
6284 intent.getFlags(), activity);
6285 }
6286
6287 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6288 Uri uri, int modeFlags) {
6289 synchronized(this) {
6290 final ProcessRecord r = getRecordForAppLocked(caller);
6291 if (r == null) {
6292 throw new SecurityException("Unable to find app for caller "
6293 + caller
6294 + " when granting permission to uri " + uri);
6295 }
6296 if (targetPkg == null) {
6297 Log.w(TAG, "grantUriPermission: null target");
6298 return;
6299 }
6300 if (uri == null) {
6301 Log.w(TAG, "grantUriPermission: null uri");
6302 return;
6303 }
6304
6305 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6306 null);
6307 }
6308 }
6309
6310 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6311 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6312 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6313 HashMap<Uri, UriPermission> perms
6314 = mGrantedUriPermissions.get(perm.uid);
6315 if (perms != null) {
6316 perms.remove(perm.uri);
6317 if (perms.size() == 0) {
6318 mGrantedUriPermissions.remove(perm.uid);
6319 }
6320 }
6321 }
6322 }
6323
6324 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6325 if (activity.readUriPermissions != null) {
6326 for (UriPermission perm : activity.readUriPermissions) {
6327 perm.readActivities.remove(activity);
6328 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6329 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6330 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6331 removeUriPermissionIfNeededLocked(perm);
6332 }
6333 }
6334 }
6335 if (activity.writeUriPermissions != null) {
6336 for (UriPermission perm : activity.writeUriPermissions) {
6337 perm.writeActivities.remove(activity);
6338 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6339 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6340 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6341 removeUriPermissionIfNeededLocked(perm);
6342 }
6343 }
6344 }
6345 }
6346
6347 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6348 int modeFlags) {
6349 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6350 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6351 if (modeFlags == 0) {
6352 return;
6353 }
6354
6355 final IPackageManager pm = ActivityThread.getPackageManager();
6356
6357 final String authority = uri.getAuthority();
6358 ProviderInfo pi = null;
6359 ContentProviderRecord cpr
6360 = (ContentProviderRecord)mProvidersByName.get(authority);
6361 if (cpr != null) {
6362 pi = cpr.info;
6363 } else {
6364 try {
6365 pi = pm.resolveContentProvider(authority,
6366 PackageManager.GET_URI_PERMISSION_PATTERNS);
6367 } catch (RemoteException ex) {
6368 }
6369 }
6370 if (pi == null) {
6371 Log.w(TAG, "No content provider found for: " + authority);
6372 return;
6373 }
6374
6375 // Does the caller have this permission on the URI?
6376 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6377 // Right now, if you are not the original owner of the permission,
6378 // you are not allowed to revoke it.
6379 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6380 throw new SecurityException("Uid " + callingUid
6381 + " does not have permission to uri " + uri);
6382 //}
6383 }
6384
6385 // Go through all of the permissions and remove any that match.
6386 final List<String> SEGMENTS = uri.getPathSegments();
6387 if (SEGMENTS != null) {
6388 final int NS = SEGMENTS.size();
6389 int N = mGrantedUriPermissions.size();
6390 for (int i=0; i<N; i++) {
6391 HashMap<Uri, UriPermission> perms
6392 = mGrantedUriPermissions.valueAt(i);
6393 Iterator<UriPermission> it = perms.values().iterator();
6394 toploop:
6395 while (it.hasNext()) {
6396 UriPermission perm = it.next();
6397 Uri targetUri = perm.uri;
6398 if (!authority.equals(targetUri.getAuthority())) {
6399 continue;
6400 }
6401 List<String> targetSegments = targetUri.getPathSegments();
6402 if (targetSegments == null) {
6403 continue;
6404 }
6405 if (targetSegments.size() < NS) {
6406 continue;
6407 }
6408 for (int j=0; j<NS; j++) {
6409 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6410 continue toploop;
6411 }
6412 }
6413 perm.clearModes(modeFlags);
6414 if (perm.modeFlags == 0) {
6415 it.remove();
6416 }
6417 }
6418 if (perms.size() == 0) {
6419 mGrantedUriPermissions.remove(
6420 mGrantedUriPermissions.keyAt(i));
6421 N--;
6422 i--;
6423 }
6424 }
6425 }
6426 }
6427
6428 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6429 int modeFlags) {
6430 synchronized(this) {
6431 final ProcessRecord r = getRecordForAppLocked(caller);
6432 if (r == null) {
6433 throw new SecurityException("Unable to find app for caller "
6434 + caller
6435 + " when revoking permission to uri " + uri);
6436 }
6437 if (uri == null) {
6438 Log.w(TAG, "revokeUriPermission: null uri");
6439 return;
6440 }
6441
6442 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6443 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6444 if (modeFlags == 0) {
6445 return;
6446 }
6447
6448 final IPackageManager pm = ActivityThread.getPackageManager();
6449
6450 final String authority = uri.getAuthority();
6451 ProviderInfo pi = null;
6452 ContentProviderRecord cpr
6453 = (ContentProviderRecord)mProvidersByName.get(authority);
6454 if (cpr != null) {
6455 pi = cpr.info;
6456 } else {
6457 try {
6458 pi = pm.resolveContentProvider(authority,
6459 PackageManager.GET_URI_PERMISSION_PATTERNS);
6460 } catch (RemoteException ex) {
6461 }
6462 }
6463 if (pi == null) {
6464 Log.w(TAG, "No content provider found for: " + authority);
6465 return;
6466 }
6467
6468 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6469 }
6470 }
6471
6472 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6473 synchronized (this) {
6474 ProcessRecord app =
6475 who != null ? getRecordForAppLocked(who) : null;
6476 if (app == null) return;
6477
6478 Message msg = Message.obtain();
6479 msg.what = WAIT_FOR_DEBUGGER_MSG;
6480 msg.obj = app;
6481 msg.arg1 = waiting ? 1 : 0;
6482 mHandler.sendMessage(msg);
6483 }
6484 }
6485
6486 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6487 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006488 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006489 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006490 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006491 }
6492
6493 // =========================================================
6494 // TASK MANAGEMENT
6495 // =========================================================
6496
6497 public List getTasks(int maxNum, int flags,
6498 IThumbnailReceiver receiver) {
6499 ArrayList list = new ArrayList();
6500
6501 PendingThumbnailsRecord pending = null;
6502 IApplicationThread topThumbnail = null;
6503 HistoryRecord topRecord = null;
6504
6505 synchronized(this) {
6506 if (localLOGV) Log.v(
6507 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6508 + ", receiver=" + receiver);
6509
6510 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6511 != PackageManager.PERMISSION_GRANTED) {
6512 if (receiver != null) {
6513 // If the caller wants to wait for pending thumbnails,
6514 // it ain't gonna get them.
6515 try {
6516 receiver.finished();
6517 } catch (RemoteException ex) {
6518 }
6519 }
6520 String msg = "Permission Denial: getTasks() from pid="
6521 + Binder.getCallingPid()
6522 + ", uid=" + Binder.getCallingUid()
6523 + " requires " + android.Manifest.permission.GET_TASKS;
6524 Log.w(TAG, msg);
6525 throw new SecurityException(msg);
6526 }
6527
6528 int pos = mHistory.size()-1;
6529 HistoryRecord next =
6530 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6531 HistoryRecord top = null;
6532 CharSequence topDescription = null;
6533 TaskRecord curTask = null;
6534 int numActivities = 0;
6535 int numRunning = 0;
6536 while (pos >= 0 && maxNum > 0) {
6537 final HistoryRecord r = next;
6538 pos--;
6539 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6540
6541 // Initialize state for next task if needed.
6542 if (top == null ||
6543 (top.state == ActivityState.INITIALIZING
6544 && top.task == r.task)) {
6545 top = r;
6546 topDescription = r.description;
6547 curTask = r.task;
6548 numActivities = numRunning = 0;
6549 }
6550
6551 // Add 'r' into the current task.
6552 numActivities++;
6553 if (r.app != null && r.app.thread != null) {
6554 numRunning++;
6555 }
6556 if (topDescription == null) {
6557 topDescription = r.description;
6558 }
6559
6560 if (localLOGV) Log.v(
6561 TAG, r.intent.getComponent().flattenToShortString()
6562 + ": task=" + r.task);
6563
6564 // If the next one is a different task, generate a new
6565 // TaskInfo entry for what we have.
6566 if (next == null || next.task != curTask) {
6567 ActivityManager.RunningTaskInfo ci
6568 = new ActivityManager.RunningTaskInfo();
6569 ci.id = curTask.taskId;
6570 ci.baseActivity = r.intent.getComponent();
6571 ci.topActivity = top.intent.getComponent();
6572 ci.thumbnail = top.thumbnail;
6573 ci.description = topDescription;
6574 ci.numActivities = numActivities;
6575 ci.numRunning = numRunning;
6576 //System.out.println(
6577 // "#" + maxNum + ": " + " descr=" + ci.description);
6578 if (ci.thumbnail == null && receiver != null) {
6579 if (localLOGV) Log.v(
6580 TAG, "State=" + top.state + "Idle=" + top.idle
6581 + " app=" + top.app
6582 + " thr=" + (top.app != null ? top.app.thread : null));
6583 if (top.state == ActivityState.RESUMED
6584 || top.state == ActivityState.PAUSING) {
6585 if (top.idle && top.app != null
6586 && top.app.thread != null) {
6587 topRecord = top;
6588 topThumbnail = top.app.thread;
6589 } else {
6590 top.thumbnailNeeded = true;
6591 }
6592 }
6593 if (pending == null) {
6594 pending = new PendingThumbnailsRecord(receiver);
6595 }
6596 pending.pendingRecords.add(top);
6597 }
6598 list.add(ci);
6599 maxNum--;
6600 top = null;
6601 }
6602 }
6603
6604 if (pending != null) {
6605 mPendingThumbnails.add(pending);
6606 }
6607 }
6608
6609 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6610
6611 if (topThumbnail != null) {
6612 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6613 try {
6614 topThumbnail.requestThumbnail(topRecord);
6615 } catch (Exception e) {
6616 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6617 sendPendingThumbnail(null, topRecord, null, null, true);
6618 }
6619 }
6620
6621 if (pending == null && receiver != null) {
6622 // In this case all thumbnails were available and the client
6623 // is being asked to be told when the remaining ones come in...
6624 // which is unusually, since the top-most currently running
6625 // activity should never have a canned thumbnail! Oh well.
6626 try {
6627 receiver.finished();
6628 } catch (RemoteException ex) {
6629 }
6630 }
6631
6632 return list;
6633 }
6634
6635 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6636 int flags) {
6637 synchronized (this) {
6638 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6639 "getRecentTasks()");
6640
6641 final int N = mRecentTasks.size();
6642 ArrayList<ActivityManager.RecentTaskInfo> res
6643 = new ArrayList<ActivityManager.RecentTaskInfo>(
6644 maxNum < N ? maxNum : N);
6645 for (int i=0; i<N && maxNum > 0; i++) {
6646 TaskRecord tr = mRecentTasks.get(i);
6647 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6648 || (tr.intent == null)
6649 || ((tr.intent.getFlags()
6650 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6651 ActivityManager.RecentTaskInfo rti
6652 = new ActivityManager.RecentTaskInfo();
6653 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6654 rti.baseIntent = new Intent(
6655 tr.intent != null ? tr.intent : tr.affinityIntent);
6656 rti.origActivity = tr.origActivity;
6657 res.add(rti);
6658 maxNum--;
6659 }
6660 }
6661 return res;
6662 }
6663 }
6664
6665 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6666 int j;
6667 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6668 TaskRecord jt = startTask;
6669
6670 // First look backwards
6671 for (j=startIndex-1; j>=0; j--) {
6672 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6673 if (r.task != jt) {
6674 jt = r.task;
6675 if (affinity.equals(jt.affinity)) {
6676 return j;
6677 }
6678 }
6679 }
6680
6681 // Now look forwards
6682 final int N = mHistory.size();
6683 jt = startTask;
6684 for (j=startIndex+1; j<N; j++) {
6685 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6686 if (r.task != jt) {
6687 if (affinity.equals(jt.affinity)) {
6688 return j;
6689 }
6690 jt = r.task;
6691 }
6692 }
6693
6694 // Might it be at the top?
6695 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6696 return N-1;
6697 }
6698
6699 return -1;
6700 }
6701
6702 /**
6703 * Perform a reset of the given task, if needed as part of launching it.
6704 * Returns the new HistoryRecord at the top of the task.
6705 */
6706 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6707 HistoryRecord newActivity) {
6708 boolean forceReset = (newActivity.info.flags
6709 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6710 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6711 if ((newActivity.info.flags
6712 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6713 forceReset = true;
6714 }
6715 }
6716
6717 final TaskRecord task = taskTop.task;
6718
6719 // We are going to move through the history list so that we can look
6720 // at each activity 'target' with 'below' either the interesting
6721 // activity immediately below it in the stack or null.
6722 HistoryRecord target = null;
6723 int targetI = 0;
6724 int taskTopI = -1;
6725 int replyChainEnd = -1;
6726 int lastReparentPos = -1;
6727 for (int i=mHistory.size()-1; i>=-1; i--) {
6728 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6729
6730 if (below != null && below.finishing) {
6731 continue;
6732 }
6733 if (target == null) {
6734 target = below;
6735 targetI = i;
6736 // If we were in the middle of a reply chain before this
6737 // task, it doesn't appear like the root of the chain wants
6738 // anything interesting, so drop it.
6739 replyChainEnd = -1;
6740 continue;
6741 }
6742
6743 final int flags = target.info.flags;
6744
6745 final boolean finishOnTaskLaunch =
6746 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6747 final boolean allowTaskReparenting =
6748 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6749
6750 if (target.task == task) {
6751 // We are inside of the task being reset... we'll either
6752 // finish this activity, push it out for another task,
6753 // or leave it as-is. We only do this
6754 // for activities that are not the root of the task (since
6755 // if we finish the root, we may no longer have the task!).
6756 if (taskTopI < 0) {
6757 taskTopI = targetI;
6758 }
6759 if (below != null && below.task == task) {
6760 final boolean clearWhenTaskReset =
6761 (target.intent.getFlags()
6762 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006763 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006764 // If this activity is sending a reply to a previous
6765 // activity, we can't do anything with it now until
6766 // we reach the start of the reply chain.
6767 // XXX note that we are assuming the result is always
6768 // to the previous activity, which is almost always
6769 // the case but we really shouldn't count on.
6770 if (replyChainEnd < 0) {
6771 replyChainEnd = targetI;
6772 }
Ed Heyl73798232009-03-24 21:32:21 -07006773 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006774 && target.taskAffinity != null
6775 && !target.taskAffinity.equals(task.affinity)) {
6776 // If this activity has an affinity for another
6777 // task, then we need to move it out of here. We will
6778 // move it as far out of the way as possible, to the
6779 // bottom of the activity stack. This also keeps it
6780 // correctly ordered with any activities we previously
6781 // moved.
6782 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6783 if (target.taskAffinity != null
6784 && target.taskAffinity.equals(p.task.affinity)) {
6785 // If the activity currently at the bottom has the
6786 // same task affinity as the one we are moving,
6787 // then merge it into the same task.
6788 target.task = p.task;
6789 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6790 + " out to bottom task " + p.task);
6791 } else {
6792 mCurTask++;
6793 if (mCurTask <= 0) {
6794 mCurTask = 1;
6795 }
6796 target.task = new TaskRecord(mCurTask, target.info, null,
6797 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6798 target.task.affinityIntent = target.intent;
6799 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6800 + " out to new task " + target.task);
6801 }
6802 mWindowManager.setAppGroupId(target, task.taskId);
6803 if (replyChainEnd < 0) {
6804 replyChainEnd = targetI;
6805 }
6806 int dstPos = 0;
6807 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6808 p = (HistoryRecord)mHistory.get(srcPos);
6809 if (p.finishing) {
6810 continue;
6811 }
6812 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6813 + " out to target's task " + target.task);
6814 task.numActivities--;
6815 p.task = target.task;
6816 target.task.numActivities++;
6817 mHistory.remove(srcPos);
6818 mHistory.add(dstPos, p);
6819 mWindowManager.moveAppToken(dstPos, p);
6820 mWindowManager.setAppGroupId(p, p.task.taskId);
6821 dstPos++;
6822 if (VALIDATE_TOKENS) {
6823 mWindowManager.validateAppTokens(mHistory);
6824 }
6825 i++;
6826 }
6827 if (taskTop == p) {
6828 taskTop = below;
6829 }
6830 if (taskTopI == replyChainEnd) {
6831 taskTopI = -1;
6832 }
6833 replyChainEnd = -1;
6834 addRecentTask(target.task);
6835 } else if (forceReset || finishOnTaskLaunch
6836 || clearWhenTaskReset) {
6837 // If the activity should just be removed -- either
6838 // because it asks for it, or the task should be
6839 // cleared -- then finish it and anything that is
6840 // part of its reply chain.
6841 if (clearWhenTaskReset) {
6842 // In this case, we want to finish this activity
6843 // and everything above it, so be sneaky and pretend
6844 // like these are all in the reply chain.
6845 replyChainEnd = targetI+1;
6846 while (replyChainEnd < mHistory.size() &&
6847 ((HistoryRecord)mHistory.get(
6848 replyChainEnd)).task == task) {
6849 replyChainEnd++;
6850 }
6851 replyChainEnd--;
6852 } else if (replyChainEnd < 0) {
6853 replyChainEnd = targetI;
6854 }
6855 HistoryRecord p = null;
6856 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6857 p = (HistoryRecord)mHistory.get(srcPos);
6858 if (p.finishing) {
6859 continue;
6860 }
6861 if (finishActivityLocked(p, srcPos,
6862 Activity.RESULT_CANCELED, null, "reset")) {
6863 replyChainEnd--;
6864 srcPos--;
6865 }
6866 }
6867 if (taskTop == p) {
6868 taskTop = below;
6869 }
6870 if (taskTopI == replyChainEnd) {
6871 taskTopI = -1;
6872 }
6873 replyChainEnd = -1;
6874 } else {
6875 // If we were in the middle of a chain, well the
6876 // activity that started it all doesn't want anything
6877 // special, so leave it all as-is.
6878 replyChainEnd = -1;
6879 }
6880 } else {
6881 // Reached the bottom of the task -- any reply chain
6882 // should be left as-is.
6883 replyChainEnd = -1;
6884 }
6885
6886 } else if (target.resultTo != null) {
6887 // If this activity is sending a reply to a previous
6888 // activity, we can't do anything with it now until
6889 // we reach the start of the reply chain.
6890 // XXX note that we are assuming the result is always
6891 // to the previous activity, which is almost always
6892 // the case but we really shouldn't count on.
6893 if (replyChainEnd < 0) {
6894 replyChainEnd = targetI;
6895 }
6896
6897 } else if (taskTopI >= 0 && allowTaskReparenting
6898 && task.affinity != null
6899 && task.affinity.equals(target.taskAffinity)) {
6900 // We are inside of another task... if this activity has
6901 // an affinity for our task, then either remove it if we are
6902 // clearing or move it over to our task. Note that
6903 // we currently punt on the case where we are resetting a
6904 // task that is not at the top but who has activities above
6905 // with an affinity to it... this is really not a normal
6906 // case, and we will need to later pull that task to the front
6907 // and usually at that point we will do the reset and pick
6908 // up those remaining activities. (This only happens if
6909 // someone starts an activity in a new task from an activity
6910 // in a task that is not currently on top.)
6911 if (forceReset || finishOnTaskLaunch) {
6912 if (replyChainEnd < 0) {
6913 replyChainEnd = targetI;
6914 }
6915 HistoryRecord p = null;
6916 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6917 p = (HistoryRecord)mHistory.get(srcPos);
6918 if (p.finishing) {
6919 continue;
6920 }
6921 if (finishActivityLocked(p, srcPos,
6922 Activity.RESULT_CANCELED, null, "reset")) {
6923 taskTopI--;
6924 lastReparentPos--;
6925 replyChainEnd--;
6926 srcPos--;
6927 }
6928 }
6929 replyChainEnd = -1;
6930 } else {
6931 if (replyChainEnd < 0) {
6932 replyChainEnd = targetI;
6933 }
6934 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6935 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6936 if (p.finishing) {
6937 continue;
6938 }
6939 if (lastReparentPos < 0) {
6940 lastReparentPos = taskTopI;
6941 taskTop = p;
6942 } else {
6943 lastReparentPos--;
6944 }
6945 mHistory.remove(srcPos);
6946 p.task.numActivities--;
6947 p.task = task;
6948 mHistory.add(lastReparentPos, p);
6949 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6950 + " in to resetting task " + task);
6951 task.numActivities++;
6952 mWindowManager.moveAppToken(lastReparentPos, p);
6953 mWindowManager.setAppGroupId(p, p.task.taskId);
6954 if (VALIDATE_TOKENS) {
6955 mWindowManager.validateAppTokens(mHistory);
6956 }
6957 }
6958 replyChainEnd = -1;
6959
6960 // Now we've moved it in to place... but what if this is
6961 // a singleTop activity and we have put it on top of another
6962 // instance of the same activity? Then we drop the instance
6963 // below so it remains singleTop.
6964 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6965 for (int j=lastReparentPos-1; j>=0; j--) {
6966 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6967 if (p.finishing) {
6968 continue;
6969 }
6970 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6971 if (finishActivityLocked(p, j,
6972 Activity.RESULT_CANCELED, null, "replace")) {
6973 taskTopI--;
6974 lastReparentPos--;
6975 }
6976 }
6977 }
6978 }
6979 }
6980 }
6981
6982 target = below;
6983 targetI = i;
6984 }
6985
6986 return taskTop;
6987 }
6988
6989 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006990 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006991 */
6992 public void moveTaskToFront(int task) {
6993 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6994 "moveTaskToFront()");
6995
6996 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006997 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6998 Binder.getCallingUid(), "Task to front")) {
6999 return;
7000 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007001 final long origId = Binder.clearCallingIdentity();
7002 try {
7003 int N = mRecentTasks.size();
7004 for (int i=0; i<N; i++) {
7005 TaskRecord tr = mRecentTasks.get(i);
7006 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007007 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007008 return;
7009 }
7010 }
7011 for (int i=mHistory.size()-1; i>=0; i--) {
7012 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
7013 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007014 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007015 return;
7016 }
7017 }
7018 } finally {
7019 Binder.restoreCallingIdentity(origId);
7020 }
7021 }
7022 }
7023
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007024 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007025 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7026
7027 final int task = tr.taskId;
7028 int top = mHistory.size()-1;
7029
7030 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7031 // nothing to do!
7032 return;
7033 }
7034
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007035 ArrayList moved = new ArrayList();
7036
7037 // Applying the affinities may have removed entries from the history,
7038 // so get the size again.
7039 top = mHistory.size()-1;
7040 int pos = top;
7041
7042 // Shift all activities with this task up to the top
7043 // of the stack, keeping them in the same internal order.
7044 while (pos >= 0) {
7045 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7046 if (localLOGV) Log.v(
7047 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7048 boolean first = true;
7049 if (r.task.taskId == task) {
7050 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7051 mHistory.remove(pos);
7052 mHistory.add(top, r);
7053 moved.add(0, r);
7054 top--;
7055 if (first) {
7056 addRecentTask(r.task);
7057 first = false;
7058 }
7059 }
7060 pos--;
7061 }
7062
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007063 if (DEBUG_TRANSITION) Log.v(TAG,
7064 "Prepare to front transition: task=" + tr);
7065 if (reason != null &&
7066 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7067 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7068 HistoryRecord r = topRunningActivityLocked(null);
7069 if (r != null) {
7070 mNoAnimActivities.add(r);
7071 }
7072 } else {
7073 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7074 }
7075
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007076 mWindowManager.moveAppTokensToTop(moved);
7077 if (VALIDATE_TOKENS) {
7078 mWindowManager.validateAppTokens(mHistory);
7079 }
7080
7081 finishTaskMove(task);
7082 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
7083 }
7084
7085 private final void finishTaskMove(int task) {
7086 resumeTopActivityLocked(null);
7087 }
7088
7089 public void moveTaskToBack(int task) {
7090 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7091 "moveTaskToBack()");
7092
7093 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007094 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7095 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7096 Binder.getCallingUid(), "Task to back")) {
7097 return;
7098 }
7099 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007100 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007101 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007102 Binder.restoreCallingIdentity(origId);
7103 }
7104 }
7105
7106 /**
7107 * Moves an activity, and all of the other activities within the same task, to the bottom
7108 * of the history stack. The activity's order within the task is unchanged.
7109 *
7110 * @param token A reference to the activity we wish to move
7111 * @param nonRoot If false then this only works if the activity is the root
7112 * of a task; if true it will work for any activity in a task.
7113 * @return Returns true if the move completed, false if not.
7114 */
7115 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7116 synchronized(this) {
7117 final long origId = Binder.clearCallingIdentity();
7118 int taskId = getTaskForActivityLocked(token, !nonRoot);
7119 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007120 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007121 }
7122 Binder.restoreCallingIdentity(origId);
7123 }
7124 return false;
7125 }
7126
7127 /**
7128 * Worker method for rearranging history stack. Implements the function of moving all
7129 * activities for a specific task (gathering them if disjoint) into a single group at the
7130 * bottom of the stack.
7131 *
7132 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7133 * to premeptively cancel the move.
7134 *
7135 * @param task The taskId to collect and move to the bottom.
7136 * @return Returns true if the move completed, false if not.
7137 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007138 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007139 Log.i(TAG, "moveTaskToBack: " + task);
7140
7141 // If we have a watcher, preflight the move before committing to it. First check
7142 // for *other* available tasks, but if none are available, then try again allowing the
7143 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007144 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007145 HistoryRecord next = topRunningActivityLocked(null, task);
7146 if (next == null) {
7147 next = topRunningActivityLocked(null, 0);
7148 }
7149 if (next != null) {
7150 // ask watcher if this is allowed
7151 boolean moveOK = true;
7152 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007153 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007154 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007155 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007156 }
7157 if (!moveOK) {
7158 return false;
7159 }
7160 }
7161 }
7162
7163 ArrayList moved = new ArrayList();
7164
7165 if (DEBUG_TRANSITION) Log.v(TAG,
7166 "Prepare to back transition: task=" + task);
7167 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
7168
7169 final int N = mHistory.size();
7170 int bottom = 0;
7171 int pos = 0;
7172
7173 // Shift all activities with this task down to the bottom
7174 // of the stack, keeping them in the same internal order.
7175 while (pos < N) {
7176 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7177 if (localLOGV) Log.v(
7178 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7179 if (r.task.taskId == task) {
7180 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7181 mHistory.remove(pos);
7182 mHistory.add(bottom, r);
7183 moved.add(r);
7184 bottom++;
7185 }
7186 pos++;
7187 }
7188
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007189 if (reason != null &&
7190 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7191 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7192 HistoryRecord r = topRunningActivityLocked(null);
7193 if (r != null) {
7194 mNoAnimActivities.add(r);
7195 }
7196 } else {
7197 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7198 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007199 mWindowManager.moveAppTokensToBottom(moved);
7200 if (VALIDATE_TOKENS) {
7201 mWindowManager.validateAppTokens(mHistory);
7202 }
7203
7204 finishTaskMove(task);
7205 return true;
7206 }
7207
7208 public void moveTaskBackwards(int task) {
7209 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7210 "moveTaskBackwards()");
7211
7212 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007213 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7214 Binder.getCallingUid(), "Task backwards")) {
7215 return;
7216 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007217 final long origId = Binder.clearCallingIdentity();
7218 moveTaskBackwardsLocked(task);
7219 Binder.restoreCallingIdentity(origId);
7220 }
7221 }
7222
7223 private final void moveTaskBackwardsLocked(int task) {
7224 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7225 }
7226
7227 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7228 synchronized(this) {
7229 return getTaskForActivityLocked(token, onlyRoot);
7230 }
7231 }
7232
7233 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7234 final int N = mHistory.size();
7235 TaskRecord lastTask = null;
7236 for (int i=0; i<N; i++) {
7237 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7238 if (r == token) {
7239 if (!onlyRoot || lastTask != r.task) {
7240 return r.task.taskId;
7241 }
7242 return -1;
7243 }
7244 lastTask = r.task;
7245 }
7246
7247 return -1;
7248 }
7249
7250 /**
7251 * Returns the top activity in any existing task matching the given
7252 * Intent. Returns null if no such task is found.
7253 */
7254 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7255 ComponentName cls = intent.getComponent();
7256 if (info.targetActivity != null) {
7257 cls = new ComponentName(info.packageName, info.targetActivity);
7258 }
7259
7260 TaskRecord cp = null;
7261
7262 final int N = mHistory.size();
7263 for (int i=(N-1); i>=0; i--) {
7264 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7265 if (!r.finishing && r.task != cp
7266 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7267 cp = r.task;
7268 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7269 // + "/aff=" + r.task.affinity + " to new cls="
7270 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7271 if (r.task.affinity != null) {
7272 if (r.task.affinity.equals(info.taskAffinity)) {
7273 //Log.i(TAG, "Found matching affinity!");
7274 return r;
7275 }
7276 } else if (r.task.intent != null
7277 && r.task.intent.getComponent().equals(cls)) {
7278 //Log.i(TAG, "Found matching class!");
7279 //dump();
7280 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7281 return r;
7282 } else if (r.task.affinityIntent != null
7283 && r.task.affinityIntent.getComponent().equals(cls)) {
7284 //Log.i(TAG, "Found matching class!");
7285 //dump();
7286 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7287 return r;
7288 }
7289 }
7290 }
7291
7292 return null;
7293 }
7294
7295 /**
7296 * Returns the first activity (starting from the top of the stack) that
7297 * is the same as the given activity. Returns null if no such activity
7298 * is found.
7299 */
7300 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7301 ComponentName cls = intent.getComponent();
7302 if (info.targetActivity != null) {
7303 cls = new ComponentName(info.packageName, info.targetActivity);
7304 }
7305
7306 final int N = mHistory.size();
7307 for (int i=(N-1); i>=0; i--) {
7308 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7309 if (!r.finishing) {
7310 if (r.intent.getComponent().equals(cls)) {
7311 //Log.i(TAG, "Found matching class!");
7312 //dump();
7313 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7314 return r;
7315 }
7316 }
7317 }
7318
7319 return null;
7320 }
7321
7322 public void finishOtherInstances(IBinder token, ComponentName className) {
7323 synchronized(this) {
7324 final long origId = Binder.clearCallingIdentity();
7325
7326 int N = mHistory.size();
7327 TaskRecord lastTask = null;
7328 for (int i=0; i<N; i++) {
7329 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7330 if (r.realActivity.equals(className)
7331 && r != token && lastTask != r.task) {
7332 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7333 null, "others")) {
7334 i--;
7335 N--;
7336 }
7337 }
7338 lastTask = r.task;
7339 }
7340
7341 Binder.restoreCallingIdentity(origId);
7342 }
7343 }
7344
7345 // =========================================================
7346 // THUMBNAILS
7347 // =========================================================
7348
7349 public void reportThumbnail(IBinder token,
7350 Bitmap thumbnail, CharSequence description) {
7351 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7352 final long origId = Binder.clearCallingIdentity();
7353 sendPendingThumbnail(null, token, thumbnail, description, true);
7354 Binder.restoreCallingIdentity(origId);
7355 }
7356
7357 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7358 Bitmap thumbnail, CharSequence description, boolean always) {
7359 TaskRecord task = null;
7360 ArrayList receivers = null;
7361
7362 //System.out.println("Send pending thumbnail: " + r);
7363
7364 synchronized(this) {
7365 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007366 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007367 if (index < 0) {
7368 return;
7369 }
7370 r = (HistoryRecord)mHistory.get(index);
7371 }
7372 if (thumbnail == null) {
7373 thumbnail = r.thumbnail;
7374 description = r.description;
7375 }
7376 if (thumbnail == null && !always) {
7377 // If there is no thumbnail, and this entry is not actually
7378 // going away, then abort for now and pick up the next
7379 // thumbnail we get.
7380 return;
7381 }
7382 task = r.task;
7383
7384 int N = mPendingThumbnails.size();
7385 int i=0;
7386 while (i<N) {
7387 PendingThumbnailsRecord pr =
7388 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7389 //System.out.println("Looking in " + pr.pendingRecords);
7390 if (pr.pendingRecords.remove(r)) {
7391 if (receivers == null) {
7392 receivers = new ArrayList();
7393 }
7394 receivers.add(pr);
7395 if (pr.pendingRecords.size() == 0) {
7396 pr.finished = true;
7397 mPendingThumbnails.remove(i);
7398 N--;
7399 continue;
7400 }
7401 }
7402 i++;
7403 }
7404 }
7405
7406 if (receivers != null) {
7407 final int N = receivers.size();
7408 for (int i=0; i<N; i++) {
7409 try {
7410 PendingThumbnailsRecord pr =
7411 (PendingThumbnailsRecord)receivers.get(i);
7412 pr.receiver.newThumbnail(
7413 task != null ? task.taskId : -1, thumbnail, description);
7414 if (pr.finished) {
7415 pr.receiver.finished();
7416 }
7417 } catch (Exception e) {
7418 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7419 }
7420 }
7421 }
7422 }
7423
7424 // =========================================================
7425 // CONTENT PROVIDERS
7426 // =========================================================
7427
7428 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7429 List providers = null;
7430 try {
7431 providers = ActivityThread.getPackageManager().
7432 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007433 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007434 } catch (RemoteException ex) {
7435 }
7436 if (providers != null) {
7437 final int N = providers.size();
7438 for (int i=0; i<N; i++) {
7439 ProviderInfo cpi =
7440 (ProviderInfo)providers.get(i);
7441 ContentProviderRecord cpr =
7442 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7443 if (cpr == null) {
7444 cpr = new ContentProviderRecord(cpi, app.info);
7445 mProvidersByClass.put(cpi.name, cpr);
7446 }
7447 app.pubProviders.put(cpi.name, cpr);
7448 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007449 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007450 }
7451 }
7452 return providers;
7453 }
7454
7455 private final String checkContentProviderPermissionLocked(
7456 ProviderInfo cpi, ProcessRecord r, int mode) {
7457 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7458 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7459 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7460 cpi.exported ? -1 : cpi.applicationInfo.uid)
7461 == PackageManager.PERMISSION_GRANTED
7462 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7463 return null;
7464 }
7465 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7466 cpi.exported ? -1 : cpi.applicationInfo.uid)
7467 == PackageManager.PERMISSION_GRANTED) {
7468 return null;
7469 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007470
7471 PathPermission[] pps = cpi.pathPermissions;
7472 if (pps != null) {
7473 int i = pps.length;
7474 while (i > 0) {
7475 i--;
7476 PathPermission pp = pps[i];
7477 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7478 cpi.exported ? -1 : cpi.applicationInfo.uid)
7479 == PackageManager.PERMISSION_GRANTED
7480 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7481 return null;
7482 }
7483 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7484 cpi.exported ? -1 : cpi.applicationInfo.uid)
7485 == PackageManager.PERMISSION_GRANTED) {
7486 return null;
7487 }
7488 }
7489 }
7490
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007491 String msg = "Permission Denial: opening provider " + cpi.name
7492 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7493 + ", uid=" + callingUid + ") requires "
7494 + cpi.readPermission + " or " + cpi.writePermission;
7495 Log.w(TAG, msg);
7496 return msg;
7497 }
7498
7499 private final ContentProviderHolder getContentProviderImpl(
7500 IApplicationThread caller, String name) {
7501 ContentProviderRecord cpr;
7502 ProviderInfo cpi = null;
7503
7504 synchronized(this) {
7505 ProcessRecord r = null;
7506 if (caller != null) {
7507 r = getRecordForAppLocked(caller);
7508 if (r == null) {
7509 throw new SecurityException(
7510 "Unable to find app for caller " + caller
7511 + " (pid=" + Binder.getCallingPid()
7512 + ") when getting content provider " + name);
7513 }
7514 }
7515
7516 // First check if this content provider has been published...
7517 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7518 if (cpr != null) {
7519 cpi = cpr.info;
7520 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7521 return new ContentProviderHolder(cpi,
7522 cpi.readPermission != null
7523 ? cpi.readPermission : cpi.writePermission);
7524 }
7525
7526 if (r != null && cpr.canRunHere(r)) {
7527 // This provider has been published or is in the process
7528 // of being published... but it is also allowed to run
7529 // in the caller's process, so don't make a connection
7530 // and just let the caller instantiate its own instance.
7531 if (cpr.provider != null) {
7532 // don't give caller the provider object, it needs
7533 // to make its own.
7534 cpr = new ContentProviderRecord(cpr);
7535 }
7536 return cpr;
7537 }
7538
7539 final long origId = Binder.clearCallingIdentity();
7540
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007541 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007542 // return it right away.
7543 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007544 if (DEBUG_PROVIDER) Log.v(TAG,
7545 "Adding provider requested by "
7546 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007547 + cpr.info.processName);
7548 Integer cnt = r.conProviders.get(cpr);
7549 if (cnt == null) {
7550 r.conProviders.put(cpr, new Integer(1));
7551 } else {
7552 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7553 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007554 cpr.clients.add(r);
7555 } else {
7556 cpr.externals++;
7557 }
7558
7559 if (cpr.app != null) {
7560 updateOomAdjLocked(cpr.app);
7561 }
7562
7563 Binder.restoreCallingIdentity(origId);
7564
7565 } else {
7566 try {
7567 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007568 resolveContentProvider(name,
7569 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007570 } catch (RemoteException ex) {
7571 }
7572 if (cpi == null) {
7573 return null;
7574 }
7575
7576 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7577 return new ContentProviderHolder(cpi,
7578 cpi.readPermission != null
7579 ? cpi.readPermission : cpi.writePermission);
7580 }
7581
7582 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7583 final boolean firstClass = cpr == null;
7584 if (firstClass) {
7585 try {
7586 ApplicationInfo ai =
7587 ActivityThread.getPackageManager().
7588 getApplicationInfo(
7589 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007590 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007591 if (ai == null) {
7592 Log.w(TAG, "No package info for content provider "
7593 + cpi.name);
7594 return null;
7595 }
7596 cpr = new ContentProviderRecord(cpi, ai);
7597 } catch (RemoteException ex) {
7598 // pm is in same process, this will never happen.
7599 }
7600 }
7601
7602 if (r != null && cpr.canRunHere(r)) {
7603 // If this is a multiprocess provider, then just return its
7604 // info and allow the caller to instantiate it. Only do
7605 // this if the provider is the same user as the caller's
7606 // process, or can run as root (so can be in any process).
7607 return cpr;
7608 }
7609
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007610 if (DEBUG_PROVIDER) {
7611 RuntimeException e = new RuntimeException("here");
7612 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7613 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007614 }
7615
7616 // This is single process, and our app is now connecting to it.
7617 // See if we are already in the process of launching this
7618 // provider.
7619 final int N = mLaunchingProviders.size();
7620 int i;
7621 for (i=0; i<N; i++) {
7622 if (mLaunchingProviders.get(i) == cpr) {
7623 break;
7624 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007625 }
7626
7627 // If the provider is not already being launched, then get it
7628 // started.
7629 if (i >= N) {
7630 final long origId = Binder.clearCallingIdentity();
7631 ProcessRecord proc = startProcessLocked(cpi.processName,
7632 cpr.appInfo, false, 0, "content provider",
7633 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007634 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007635 if (proc == null) {
7636 Log.w(TAG, "Unable to launch app "
7637 + cpi.applicationInfo.packageName + "/"
7638 + cpi.applicationInfo.uid + " for provider "
7639 + name + ": process is bad");
7640 return null;
7641 }
7642 cpr.launchingApp = proc;
7643 mLaunchingProviders.add(cpr);
7644 Binder.restoreCallingIdentity(origId);
7645 }
7646
7647 // Make sure the provider is published (the same provider class
7648 // may be published under multiple names).
7649 if (firstClass) {
7650 mProvidersByClass.put(cpi.name, cpr);
7651 }
7652 mProvidersByName.put(name, cpr);
7653
7654 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007655 if (DEBUG_PROVIDER) Log.v(TAG,
7656 "Adding provider requested by "
7657 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007658 + cpr.info.processName);
7659 Integer cnt = r.conProviders.get(cpr);
7660 if (cnt == null) {
7661 r.conProviders.put(cpr, new Integer(1));
7662 } else {
7663 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7664 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007665 cpr.clients.add(r);
7666 } else {
7667 cpr.externals++;
7668 }
7669 }
7670 }
7671
7672 // Wait for the provider to be published...
7673 synchronized (cpr) {
7674 while (cpr.provider == null) {
7675 if (cpr.launchingApp == null) {
7676 Log.w(TAG, "Unable to launch app "
7677 + cpi.applicationInfo.packageName + "/"
7678 + cpi.applicationInfo.uid + " for provider "
7679 + name + ": launching app became null");
7680 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7681 cpi.applicationInfo.packageName,
7682 cpi.applicationInfo.uid, name);
7683 return null;
7684 }
7685 try {
7686 cpr.wait();
7687 } catch (InterruptedException ex) {
7688 }
7689 }
7690 }
7691 return cpr;
7692 }
7693
7694 public final ContentProviderHolder getContentProvider(
7695 IApplicationThread caller, String name) {
7696 if (caller == null) {
7697 String msg = "null IApplicationThread when getting content provider "
7698 + name;
7699 Log.w(TAG, msg);
7700 throw new SecurityException(msg);
7701 }
7702
7703 return getContentProviderImpl(caller, name);
7704 }
7705
7706 private ContentProviderHolder getContentProviderExternal(String name) {
7707 return getContentProviderImpl(null, name);
7708 }
7709
7710 /**
7711 * Drop a content provider from a ProcessRecord's bookkeeping
7712 * @param cpr
7713 */
7714 public void removeContentProvider(IApplicationThread caller, String name) {
7715 synchronized (this) {
7716 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7717 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007718 // remove from mProvidersByClass
7719 if (DEBUG_PROVIDER) Log.v(TAG, name +
7720 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007721 return;
7722 }
7723 final ProcessRecord r = getRecordForAppLocked(caller);
7724 if (r == null) {
7725 throw new SecurityException(
7726 "Unable to find app for caller " + caller +
7727 " when removing content provider " + name);
7728 }
7729 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007730 ContentProviderRecord localCpr = (ContentProviderRecord)
7731 mProvidersByClass.get(cpr.info.name);
7732 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7733 + r.info.processName + " from process "
7734 + localCpr.appInfo.processName);
7735 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007736 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007737 Log.w(TAG, "removeContentProvider called on local provider: "
7738 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007739 return;
7740 } else {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007741 Integer cnt = r.conProviders.get(localCpr);
7742 if (cnt == null || cnt.intValue() <= 1) {
7743 localCpr.clients.remove(r);
7744 r.conProviders.remove(localCpr);
7745 } else {
7746 r.conProviders.put(localCpr, new Integer(cnt.intValue()-1));
7747 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007748 }
7749 updateOomAdjLocked();
7750 }
7751 }
7752
7753 private void removeContentProviderExternal(String name) {
7754 synchronized (this) {
7755 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7756 if(cpr == null) {
7757 //remove from mProvidersByClass
7758 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7759 return;
7760 }
7761
7762 //update content provider record entry info
7763 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7764 localCpr.externals--;
7765 if (localCpr.externals < 0) {
7766 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7767 }
7768 updateOomAdjLocked();
7769 }
7770 }
7771
7772 public final void publishContentProviders(IApplicationThread caller,
7773 List<ContentProviderHolder> providers) {
7774 if (providers == null) {
7775 return;
7776 }
7777
7778 synchronized(this) {
7779 final ProcessRecord r = getRecordForAppLocked(caller);
7780 if (r == null) {
7781 throw new SecurityException(
7782 "Unable to find app for caller " + caller
7783 + " (pid=" + Binder.getCallingPid()
7784 + ") when publishing content providers");
7785 }
7786
7787 final long origId = Binder.clearCallingIdentity();
7788
7789 final int N = providers.size();
7790 for (int i=0; i<N; i++) {
7791 ContentProviderHolder src = providers.get(i);
7792 if (src == null || src.info == null || src.provider == null) {
7793 continue;
7794 }
7795 ContentProviderRecord dst =
7796 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7797 if (dst != null) {
7798 mProvidersByClass.put(dst.info.name, dst);
7799 String names[] = dst.info.authority.split(";");
7800 for (int j = 0; j < names.length; j++) {
7801 mProvidersByName.put(names[j], dst);
7802 }
7803
7804 int NL = mLaunchingProviders.size();
7805 int j;
7806 for (j=0; j<NL; j++) {
7807 if (mLaunchingProviders.get(j) == dst) {
7808 mLaunchingProviders.remove(j);
7809 j--;
7810 NL--;
7811 }
7812 }
7813 synchronized (dst) {
7814 dst.provider = src.provider;
7815 dst.app = r;
7816 dst.notifyAll();
7817 }
7818 updateOomAdjLocked(r);
7819 }
7820 }
7821
7822 Binder.restoreCallingIdentity(origId);
7823 }
7824 }
7825
7826 public static final void installSystemProviders() {
7827 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7828 List providers = mSelf.generateApplicationProvidersLocked(app);
7829 mSystemThread.installSystemProviders(providers);
7830 }
7831
7832 // =========================================================
7833 // GLOBAL MANAGEMENT
7834 // =========================================================
7835
7836 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7837 ApplicationInfo info, String customProcess) {
7838 String proc = customProcess != null ? customProcess : info.processName;
7839 BatteryStatsImpl.Uid.Proc ps = null;
7840 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7841 synchronized (stats) {
7842 ps = stats.getProcessStatsLocked(info.uid, proc);
7843 }
7844 return new ProcessRecord(ps, thread, info, proc);
7845 }
7846
7847 final ProcessRecord addAppLocked(ApplicationInfo info) {
7848 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7849
7850 if (app == null) {
7851 app = newProcessRecordLocked(null, info, null);
7852 mProcessNames.put(info.processName, info.uid, app);
7853 updateLRUListLocked(app, true);
7854 }
7855
7856 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7857 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7858 app.persistent = true;
7859 app.maxAdj = CORE_SERVER_ADJ;
7860 }
7861 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7862 mPersistentStartingProcesses.add(app);
7863 startProcessLocked(app, "added application", app.processName);
7864 }
7865
7866 return app;
7867 }
7868
7869 public void unhandledBack() {
7870 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7871 "unhandledBack()");
7872
7873 synchronized(this) {
7874 int count = mHistory.size();
7875 if (Config.LOGD) Log.d(
7876 TAG, "Performing unhandledBack(): stack size = " + count);
7877 if (count > 1) {
7878 final long origId = Binder.clearCallingIdentity();
7879 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7880 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7881 Binder.restoreCallingIdentity(origId);
7882 }
7883 }
7884 }
7885
7886 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7887 String name = uri.getAuthority();
7888 ContentProviderHolder cph = getContentProviderExternal(name);
7889 ParcelFileDescriptor pfd = null;
7890 if (cph != null) {
7891 // We record the binder invoker's uid in thread-local storage before
7892 // going to the content provider to open the file. Later, in the code
7893 // that handles all permissions checks, we look for this uid and use
7894 // that rather than the Activity Manager's own uid. The effect is that
7895 // we do the check against the caller's permissions even though it looks
7896 // to the content provider like the Activity Manager itself is making
7897 // the request.
7898 sCallerIdentity.set(new Identity(
7899 Binder.getCallingPid(), Binder.getCallingUid()));
7900 try {
7901 pfd = cph.provider.openFile(uri, "r");
7902 } catch (FileNotFoundException e) {
7903 // do nothing; pfd will be returned null
7904 } finally {
7905 // Ensure that whatever happens, we clean up the identity state
7906 sCallerIdentity.remove();
7907 }
7908
7909 // We've got the fd now, so we're done with the provider.
7910 removeContentProviderExternal(name);
7911 } else {
7912 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7913 }
7914 return pfd;
7915 }
7916
7917 public void goingToSleep() {
7918 synchronized(this) {
7919 mSleeping = true;
7920 mWindowManager.setEventDispatching(false);
7921
7922 if (mResumedActivity != null) {
7923 pauseIfSleepingLocked();
7924 } else {
7925 Log.w(TAG, "goingToSleep with no resumed activity!");
7926 }
7927 }
7928 }
7929
Dianne Hackborn55280a92009-05-07 15:53:46 -07007930 public boolean shutdown(int timeout) {
7931 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7932 != PackageManager.PERMISSION_GRANTED) {
7933 throw new SecurityException("Requires permission "
7934 + android.Manifest.permission.SHUTDOWN);
7935 }
7936
7937 boolean timedout = false;
7938
7939 synchronized(this) {
7940 mShuttingDown = true;
7941 mWindowManager.setEventDispatching(false);
7942
7943 if (mResumedActivity != null) {
7944 pauseIfSleepingLocked();
7945 final long endTime = System.currentTimeMillis() + timeout;
7946 while (mResumedActivity != null || mPausingActivity != null) {
7947 long delay = endTime - System.currentTimeMillis();
7948 if (delay <= 0) {
7949 Log.w(TAG, "Activity manager shutdown timed out");
7950 timedout = true;
7951 break;
7952 }
7953 try {
7954 this.wait();
7955 } catch (InterruptedException e) {
7956 }
7957 }
7958 }
7959 }
7960
7961 mUsageStatsService.shutdown();
7962 mBatteryStatsService.shutdown();
7963
7964 return timedout;
7965 }
7966
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007967 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007968 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007969 if (!mGoingToSleep.isHeld()) {
7970 mGoingToSleep.acquire();
7971 if (mLaunchingActivity.isHeld()) {
7972 mLaunchingActivity.release();
7973 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7974 }
7975 }
7976
7977 // If we are not currently pausing an activity, get the current
7978 // one to pause. If we are pausing one, we will just let that stuff
7979 // run and release the wake lock when all done.
7980 if (mPausingActivity == null) {
7981 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7982 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7983 startPausingLocked(false, true);
7984 }
7985 }
7986 }
7987
7988 public void wakingUp() {
7989 synchronized(this) {
7990 if (mGoingToSleep.isHeld()) {
7991 mGoingToSleep.release();
7992 }
7993 mWindowManager.setEventDispatching(true);
7994 mSleeping = false;
7995 resumeTopActivityLocked(null);
7996 }
7997 }
7998
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007999 public void stopAppSwitches() {
8000 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8001 != PackageManager.PERMISSION_GRANTED) {
8002 throw new SecurityException("Requires permission "
8003 + android.Manifest.permission.STOP_APP_SWITCHES);
8004 }
8005
8006 synchronized(this) {
8007 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
8008 + APP_SWITCH_DELAY_TIME;
8009 mDidAppSwitch = false;
8010 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8011 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8012 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
8013 }
8014 }
8015
8016 public void resumeAppSwitches() {
8017 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8018 != PackageManager.PERMISSION_GRANTED) {
8019 throw new SecurityException("Requires permission "
8020 + android.Manifest.permission.STOP_APP_SWITCHES);
8021 }
8022
8023 synchronized(this) {
8024 // Note that we don't execute any pending app switches... we will
8025 // let those wait until either the timeout, or the next start
8026 // activity request.
8027 mAppSwitchesAllowedTime = 0;
8028 }
8029 }
8030
8031 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8032 String name) {
8033 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8034 return true;
8035 }
8036
8037 final int perm = checkComponentPermission(
8038 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8039 callingUid, -1);
8040 if (perm == PackageManager.PERMISSION_GRANTED) {
8041 return true;
8042 }
8043
8044 Log.w(TAG, name + " request from " + callingUid + " stopped");
8045 return false;
8046 }
8047
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008048 public void setDebugApp(String packageName, boolean waitForDebugger,
8049 boolean persistent) {
8050 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8051 "setDebugApp()");
8052
8053 // Note that this is not really thread safe if there are multiple
8054 // callers into it at the same time, but that's not a situation we
8055 // care about.
8056 if (persistent) {
8057 final ContentResolver resolver = mContext.getContentResolver();
8058 Settings.System.putString(
8059 resolver, Settings.System.DEBUG_APP,
8060 packageName);
8061 Settings.System.putInt(
8062 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8063 waitForDebugger ? 1 : 0);
8064 }
8065
8066 synchronized (this) {
8067 if (!persistent) {
8068 mOrigDebugApp = mDebugApp;
8069 mOrigWaitForDebugger = mWaitForDebugger;
8070 }
8071 mDebugApp = packageName;
8072 mWaitForDebugger = waitForDebugger;
8073 mDebugTransient = !persistent;
8074 if (packageName != null) {
8075 final long origId = Binder.clearCallingIdentity();
8076 uninstallPackageLocked(packageName, -1, false);
8077 Binder.restoreCallingIdentity(origId);
8078 }
8079 }
8080 }
8081
8082 public void setAlwaysFinish(boolean enabled) {
8083 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8084 "setAlwaysFinish()");
8085
8086 Settings.System.putInt(
8087 mContext.getContentResolver(),
8088 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8089
8090 synchronized (this) {
8091 mAlwaysFinishActivities = enabled;
8092 }
8093 }
8094
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008095 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008096 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008097 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008098 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008099 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008100 }
8101 }
8102
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008103 public void registerActivityWatcher(IActivityWatcher watcher) {
8104 mWatchers.register(watcher);
8105 }
8106
8107 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8108 mWatchers.unregister(watcher);
8109 }
8110
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008111 public final void enterSafeMode() {
8112 synchronized(this) {
8113 // It only makes sense to do this before the system is ready
8114 // and started launching other packages.
8115 if (!mSystemReady) {
8116 try {
8117 ActivityThread.getPackageManager().enterSafeMode();
8118 } catch (RemoteException e) {
8119 }
8120
8121 View v = LayoutInflater.from(mContext).inflate(
8122 com.android.internal.R.layout.safe_mode, null);
8123 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8124 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8125 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8126 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8127 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8128 lp.format = v.getBackground().getOpacity();
8129 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8130 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8131 ((WindowManager)mContext.getSystemService(
8132 Context.WINDOW_SERVICE)).addView(v, lp);
8133 }
8134 }
8135 }
8136
8137 public void noteWakeupAlarm(IIntentSender sender) {
8138 if (!(sender instanceof PendingIntentRecord)) {
8139 return;
8140 }
8141 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8142 synchronized (stats) {
8143 if (mBatteryStatsService.isOnBattery()) {
8144 mBatteryStatsService.enforceCallingPermission();
8145 PendingIntentRecord rec = (PendingIntentRecord)sender;
8146 int MY_UID = Binder.getCallingUid();
8147 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8148 BatteryStatsImpl.Uid.Pkg pkg =
8149 stats.getPackageStatsLocked(uid, rec.key.packageName);
8150 pkg.incWakeupsLocked();
8151 }
8152 }
8153 }
8154
8155 public boolean killPidsForMemory(int[] pids) {
8156 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8157 throw new SecurityException("killPidsForMemory only available to the system");
8158 }
8159
8160 // XXX Note: don't acquire main activity lock here, because the window
8161 // manager calls in with its locks held.
8162
8163 boolean killed = false;
8164 synchronized (mPidsSelfLocked) {
8165 int[] types = new int[pids.length];
8166 int worstType = 0;
8167 for (int i=0; i<pids.length; i++) {
8168 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8169 if (proc != null) {
8170 int type = proc.setAdj;
8171 types[i] = type;
8172 if (type > worstType) {
8173 worstType = type;
8174 }
8175 }
8176 }
8177
8178 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8179 // then constrain it so we will kill all hidden procs.
8180 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8181 worstType = HIDDEN_APP_MIN_ADJ;
8182 }
8183 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8184 for (int i=0; i<pids.length; i++) {
8185 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8186 if (proc == null) {
8187 continue;
8188 }
8189 int adj = proc.setAdj;
8190 if (adj >= worstType) {
8191 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8192 + adj + ")");
8193 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
8194 proc.processName, adj);
8195 killed = true;
8196 Process.killProcess(pids[i]);
8197 }
8198 }
8199 }
8200 return killed;
8201 }
8202
8203 public void reportPss(IApplicationThread caller, int pss) {
8204 Watchdog.PssRequestor req;
8205 String name;
8206 ProcessRecord callerApp;
8207 synchronized (this) {
8208 if (caller == null) {
8209 return;
8210 }
8211 callerApp = getRecordForAppLocked(caller);
8212 if (callerApp == null) {
8213 return;
8214 }
8215 callerApp.lastPss = pss;
8216 req = callerApp;
8217 name = callerApp.processName;
8218 }
8219 Watchdog.getInstance().reportPss(req, name, pss);
8220 if (!callerApp.persistent) {
8221 removeRequestedPss(callerApp);
8222 }
8223 }
8224
8225 public void requestPss(Runnable completeCallback) {
8226 ArrayList<ProcessRecord> procs;
8227 synchronized (this) {
8228 mRequestPssCallback = completeCallback;
8229 mRequestPssList.clear();
8230 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8231 ProcessRecord proc = mLRUProcesses.get(i);
8232 if (!proc.persistent) {
8233 mRequestPssList.add(proc);
8234 }
8235 }
8236 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8237 }
8238
8239 int oldPri = Process.getThreadPriority(Process.myTid());
8240 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8241 for (int i=procs.size()-1; i>=0; i--) {
8242 ProcessRecord proc = procs.get(i);
8243 proc.lastPss = 0;
8244 proc.requestPss();
8245 }
8246 Process.setThreadPriority(oldPri);
8247 }
8248
8249 void removeRequestedPss(ProcessRecord proc) {
8250 Runnable callback = null;
8251 synchronized (this) {
8252 if (mRequestPssList.remove(proc)) {
8253 if (mRequestPssList.size() == 0) {
8254 callback = mRequestPssCallback;
8255 mRequestPssCallback = null;
8256 }
8257 }
8258 }
8259
8260 if (callback != null) {
8261 callback.run();
8262 }
8263 }
8264
8265 public void collectPss(Watchdog.PssStats stats) {
8266 stats.mEmptyPss = 0;
8267 stats.mEmptyCount = 0;
8268 stats.mBackgroundPss = 0;
8269 stats.mBackgroundCount = 0;
8270 stats.mServicePss = 0;
8271 stats.mServiceCount = 0;
8272 stats.mVisiblePss = 0;
8273 stats.mVisibleCount = 0;
8274 stats.mForegroundPss = 0;
8275 stats.mForegroundCount = 0;
8276 stats.mNoPssCount = 0;
8277 synchronized (this) {
8278 int i;
8279 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8280 ? mProcDeaths.length : stats.mProcDeaths.length;
8281 int aggr = 0;
8282 for (i=0; i<NPD; i++) {
8283 aggr += mProcDeaths[i];
8284 stats.mProcDeaths[i] = aggr;
8285 }
8286 while (i<stats.mProcDeaths.length) {
8287 stats.mProcDeaths[i] = 0;
8288 i++;
8289 }
8290
8291 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8292 ProcessRecord proc = mLRUProcesses.get(i);
8293 if (proc.persistent) {
8294 continue;
8295 }
8296 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8297 if (proc.lastPss == 0) {
8298 stats.mNoPssCount++;
8299 continue;
8300 }
8301 if (proc.setAdj == EMPTY_APP_ADJ) {
8302 stats.mEmptyPss += proc.lastPss;
8303 stats.mEmptyCount++;
8304 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8305 stats.mEmptyPss += proc.lastPss;
8306 stats.mEmptyCount++;
8307 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8308 stats.mBackgroundPss += proc.lastPss;
8309 stats.mBackgroundCount++;
8310 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8311 stats.mVisiblePss += proc.lastPss;
8312 stats.mVisibleCount++;
8313 } else {
8314 stats.mForegroundPss += proc.lastPss;
8315 stats.mForegroundCount++;
8316 }
8317 }
8318 }
8319 }
8320
8321 public final void startRunning(String pkg, String cls, String action,
8322 String data) {
8323 synchronized(this) {
8324 if (mStartRunning) {
8325 return;
8326 }
8327 mStartRunning = true;
8328 mTopComponent = pkg != null && cls != null
8329 ? new ComponentName(pkg, cls) : null;
8330 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8331 mTopData = data;
8332 if (!mSystemReady) {
8333 return;
8334 }
8335 }
8336
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008337 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008338 }
8339
8340 private void retrieveSettings() {
8341 final ContentResolver resolver = mContext.getContentResolver();
8342 String debugApp = Settings.System.getString(
8343 resolver, Settings.System.DEBUG_APP);
8344 boolean waitForDebugger = Settings.System.getInt(
8345 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8346 boolean alwaysFinishActivities = Settings.System.getInt(
8347 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8348
8349 Configuration configuration = new Configuration();
8350 Settings.System.getConfiguration(resolver, configuration);
8351
8352 synchronized (this) {
8353 mDebugApp = mOrigDebugApp = debugApp;
8354 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8355 mAlwaysFinishActivities = alwaysFinishActivities;
8356 // This happens before any activities are started, so we can
8357 // change mConfiguration in-place.
8358 mConfiguration.updateFrom(configuration);
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008359 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008360 }
8361 }
8362
8363 public boolean testIsSystemReady() {
8364 // no need to synchronize(this) just to read & return the value
8365 return mSystemReady;
8366 }
8367
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008368 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008369 // In the simulator, startRunning will never have been called, which
8370 // normally sets a few crucial variables. Do it here instead.
8371 if (!Process.supportsProcesses()) {
8372 mStartRunning = true;
8373 mTopAction = Intent.ACTION_MAIN;
8374 }
8375
8376 synchronized(this) {
8377 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008378 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008379 return;
8380 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008381
8382 // Check to see if there are any update receivers to run.
8383 if (!mDidUpdate) {
8384 if (mWaitingUpdate) {
8385 return;
8386 }
8387 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8388 List<ResolveInfo> ris = null;
8389 try {
8390 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8391 intent, null, 0);
8392 } catch (RemoteException e) {
8393 }
8394 if (ris != null) {
8395 for (int i=ris.size()-1; i>=0; i--) {
8396 if ((ris.get(i).activityInfo.applicationInfo.flags
8397 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8398 ris.remove(i);
8399 }
8400 }
8401 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8402 for (int i=0; i<ris.size(); i++) {
8403 ActivityInfo ai = ris.get(i).activityInfo;
8404 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8405 IIntentReceiver finisher = null;
8406 if (i == 0) {
8407 finisher = new IIntentReceiver.Stub() {
8408 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -07008409 String data, Bundle extras, boolean ordered,
8410 boolean sticky)
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008411 throws RemoteException {
8412 synchronized (ActivityManagerService.this) {
8413 mDidUpdate = true;
8414 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008415 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008416 }
8417 };
8418 }
8419 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8420 broadcastIntentLocked(null, null, intent, null, finisher,
8421 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8422 if (i == 0) {
8423 mWaitingUpdate = true;
8424 }
8425 }
8426 }
8427 if (mWaitingUpdate) {
8428 return;
8429 }
8430 mDidUpdate = true;
8431 }
8432
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008433 mSystemReady = true;
8434 if (!mStartRunning) {
8435 return;
8436 }
8437 }
8438
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008439 ArrayList<ProcessRecord> procsToKill = null;
8440 synchronized(mPidsSelfLocked) {
8441 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8442 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8443 if (!isAllowedWhileBooting(proc.info)){
8444 if (procsToKill == null) {
8445 procsToKill = new ArrayList<ProcessRecord>();
8446 }
8447 procsToKill.add(proc);
8448 }
8449 }
8450 }
8451
8452 if (procsToKill != null) {
8453 synchronized(this) {
8454 for (int i=procsToKill.size()-1; i>=0; i--) {
8455 ProcessRecord proc = procsToKill.get(i);
8456 Log.i(TAG, "Removing system update proc: " + proc);
8457 removeProcessLocked(proc, true);
8458 }
8459 }
8460 }
8461
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008462 Log.i(TAG, "System now ready");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008463 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8464 SystemClock.uptimeMillis());
8465
8466 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008467 // Make sure we have no pre-ready processes sitting around.
8468
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008469 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8470 ResolveInfo ri = mContext.getPackageManager()
8471 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008472 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008473 CharSequence errorMsg = null;
8474 if (ri != null) {
8475 ActivityInfo ai = ri.activityInfo;
8476 ApplicationInfo app = ai.applicationInfo;
8477 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8478 mTopAction = Intent.ACTION_FACTORY_TEST;
8479 mTopData = null;
8480 mTopComponent = new ComponentName(app.packageName,
8481 ai.name);
8482 } else {
8483 errorMsg = mContext.getResources().getText(
8484 com.android.internal.R.string.factorytest_not_system);
8485 }
8486 } else {
8487 errorMsg = mContext.getResources().getText(
8488 com.android.internal.R.string.factorytest_no_action);
8489 }
8490 if (errorMsg != null) {
8491 mTopAction = null;
8492 mTopData = null;
8493 mTopComponent = null;
8494 Message msg = Message.obtain();
8495 msg.what = SHOW_FACTORY_ERROR_MSG;
8496 msg.getData().putCharSequence("msg", errorMsg);
8497 mHandler.sendMessage(msg);
8498 }
8499 }
8500 }
8501
8502 retrieveSettings();
8503
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008504 if (goingCallback != null) goingCallback.run();
8505
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008506 synchronized (this) {
8507 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8508 try {
8509 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008510 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008511 if (apps != null) {
8512 int N = apps.size();
8513 int i;
8514 for (i=0; i<N; i++) {
8515 ApplicationInfo info
8516 = (ApplicationInfo)apps.get(i);
8517 if (info != null &&
8518 !info.packageName.equals("android")) {
8519 addAppLocked(info);
8520 }
8521 }
8522 }
8523 } catch (RemoteException ex) {
8524 // pm is in same process, this will never happen.
8525 }
8526 }
8527
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008528 // Start up initial activity.
8529 mBooting = true;
8530
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008531 try {
8532 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8533 Message msg = Message.obtain();
8534 msg.what = SHOW_UID_ERROR_MSG;
8535 mHandler.sendMessage(msg);
8536 }
8537 } catch (RemoteException e) {
8538 }
8539
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008540 resumeTopActivityLocked(null);
8541 }
8542 }
8543
8544 boolean makeAppCrashingLocked(ProcessRecord app,
8545 String tag, String shortMsg, String longMsg, byte[] crashData) {
8546 app.crashing = true;
8547 app.crashingReport = generateProcessError(app,
8548 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8549 startAppProblemLocked(app);
8550 app.stopFreezingAllLocked();
8551 return handleAppCrashLocked(app);
8552 }
8553
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008554 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Jacek Surazskia2339432009-09-18 15:01:26 +02008555 // check if error reporting is enabled in Gservices
8556 int enabled = Settings.Gservices.getInt(mContext.getContentResolver(),
8557 Settings.Gservices.SEND_ACTION_APP_ERROR, 0);
8558 if (enabled == 0) {
8559 return null;
8560 }
8561
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008562 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008563
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008564 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008565 // look for receiver in the installer package
8566 String candidate = pm.getInstallerPackageName(app.info.packageName);
8567 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8568 if (result != null) {
8569 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008570 }
8571
Jacek Surazski82a73df2009-06-17 14:33:18 +02008572 // if the error app is on the system image, look for system apps
8573 // error receiver
8574 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8575 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8576 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8577 if (result != null) {
8578 return result;
8579 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008580 }
8581
Jacek Surazski82a73df2009-06-17 14:33:18 +02008582 // if there is a default receiver, try that
8583 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8584 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008585 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008586 // should not happen
8587 Log.e(TAG, "error talking to PackageManager", e);
8588 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008589 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008590 }
8591
8592 /**
8593 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8594 *
8595 * @param pm PackageManager isntance
8596 * @param errorPackage package which caused the error
8597 * @param receiverPackage candidate package to receive the error
8598 * @return activity component within receiverPackage which handles
8599 * ACTION_APP_ERROR, or null if not found
8600 */
8601 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8602 String receiverPackage) throws RemoteException {
8603 if (receiverPackage == null || receiverPackage.length() == 0) {
8604 return null;
8605 }
8606
8607 // break the loop if it's the error report receiver package that crashed
8608 if (receiverPackage.equals(errorPackage)) {
8609 return null;
8610 }
8611
8612 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8613 intent.setPackage(receiverPackage);
8614 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8615 if (info == null || info.activityInfo == null) {
8616 return null;
8617 }
8618 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008619 }
8620
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008621 void makeAppNotRespondingLocked(ProcessRecord app,
8622 String tag, String shortMsg, String longMsg, byte[] crashData) {
8623 app.notResponding = true;
8624 app.notRespondingReport = generateProcessError(app,
8625 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8626 crashData);
8627 startAppProblemLocked(app);
8628 app.stopFreezingAllLocked();
8629 }
8630
8631 /**
8632 * Generate a process error record, suitable for attachment to a ProcessRecord.
8633 *
8634 * @param app The ProcessRecord in which the error occurred.
8635 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8636 * ActivityManager.AppErrorStateInfo
8637 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8638 * @param shortMsg Short message describing the crash.
8639 * @param longMsg Long message describing the crash.
8640 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8641 *
8642 * @return Returns a fully-formed AppErrorStateInfo record.
8643 */
8644 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8645 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8646 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8647
8648 report.condition = condition;
8649 report.processName = app.processName;
8650 report.pid = app.pid;
8651 report.uid = app.info.uid;
8652 report.tag = tag;
8653 report.shortMsg = shortMsg;
8654 report.longMsg = longMsg;
8655 report.crashData = crashData;
8656
8657 return report;
8658 }
8659
8660 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8661 boolean crashed) {
8662 synchronized (this) {
8663 app.crashing = false;
8664 app.crashingReport = null;
8665 app.notResponding = false;
8666 app.notRespondingReport = null;
8667 if (app.anrDialog == fromDialog) {
8668 app.anrDialog = null;
8669 }
8670 if (app.waitDialog == fromDialog) {
8671 app.waitDialog = null;
8672 }
8673 if (app.pid > 0 && app.pid != MY_PID) {
8674 if (crashed) {
8675 handleAppCrashLocked(app);
8676 }
8677 Log.i(ActivityManagerService.TAG, "Killing process "
8678 + app.processName
8679 + " (pid=" + app.pid + ") at user's request");
8680 Process.killProcess(app.pid);
8681 }
8682
8683 }
8684 }
8685
8686 boolean handleAppCrashLocked(ProcessRecord app) {
8687 long now = SystemClock.uptimeMillis();
8688
8689 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8690 app.info.uid);
8691 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8692 // This process loses!
8693 Log.w(TAG, "Process " + app.info.processName
8694 + " has crashed too many times: killing!");
8695 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8696 app.info.processName, app.info.uid);
8697 killServicesLocked(app, false);
8698 for (int i=mHistory.size()-1; i>=0; i--) {
8699 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8700 if (r.app == app) {
8701 if (Config.LOGD) Log.d(
8702 TAG, " Force finishing activity "
8703 + r.intent.getComponent().flattenToShortString());
8704 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8705 }
8706 }
8707 if (!app.persistent) {
8708 // We don't want to start this process again until the user
8709 // explicitly does so... but for persistent process, we really
8710 // need to keep it running. If a persistent process is actually
8711 // repeatedly crashing, then badness for everyone.
8712 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8713 app.info.processName);
8714 mBadProcesses.put(app.info.processName, app.info.uid, now);
8715 app.bad = true;
8716 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8717 app.removed = true;
8718 removeProcessLocked(app, false);
8719 return false;
8720 }
8721 }
8722
8723 // Bump up the crash count of any services currently running in the proc.
8724 if (app.services.size() != 0) {
8725 // Any services running in the application need to be placed
8726 // back in the pending list.
8727 Iterator it = app.services.iterator();
8728 while (it.hasNext()) {
8729 ServiceRecord sr = (ServiceRecord)it.next();
8730 sr.crashCount++;
8731 }
8732 }
8733
8734 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8735 return true;
8736 }
8737
8738 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008739 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008740 skipCurrentReceiverLocked(app);
8741 }
8742
8743 void skipCurrentReceiverLocked(ProcessRecord app) {
8744 boolean reschedule = false;
8745 BroadcastRecord r = app.curReceiver;
8746 if (r != null) {
8747 // The current broadcast is waiting for this app's receiver
8748 // to be finished. Looks like that's not going to happen, so
8749 // let the broadcast continue.
8750 logBroadcastReceiverDiscard(r);
8751 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8752 r.resultExtras, r.resultAbort, true);
8753 reschedule = true;
8754 }
8755 r = mPendingBroadcast;
8756 if (r != null && r.curApp == app) {
8757 if (DEBUG_BROADCAST) Log.v(TAG,
8758 "skip & discard pending app " + r);
8759 logBroadcastReceiverDiscard(r);
8760 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8761 r.resultExtras, r.resultAbort, true);
8762 reschedule = true;
8763 }
8764 if (reschedule) {
8765 scheduleBroadcastsLocked();
8766 }
8767 }
8768
8769 public int handleApplicationError(IBinder app, int flags,
8770 String tag, String shortMsg, String longMsg, byte[] crashData) {
8771 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008772 ProcessRecord r = null;
8773 synchronized (this) {
8774 if (app != null) {
8775 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8776 final int NA = apps.size();
8777 for (int ia=0; ia<NA; ia++) {
8778 ProcessRecord p = apps.valueAt(ia);
8779 if (p.thread != null && p.thread.asBinder() == app) {
8780 r = p;
8781 break;
8782 }
8783 }
8784 }
8785 }
8786
8787 if (r != null) {
8788 // The application has crashed. Send the SIGQUIT to the process so
8789 // that it can dump its state.
8790 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8791 //Log.i(TAG, "Current system threads:");
8792 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8793 }
8794
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008795 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008796 try {
8797 String name = r != null ? r.processName : null;
8798 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008799 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008800 shortMsg, longMsg, crashData)) {
8801 Log.w(TAG, "Force-killing crashed app " + name
8802 + " at watcher's request");
8803 Process.killProcess(pid);
8804 return 0;
8805 }
8806 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008807 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008808 }
8809 }
8810
8811 final long origId = Binder.clearCallingIdentity();
8812
8813 // If this process is running instrumentation, finish it.
8814 if (r != null && r.instrumentationClass != null) {
8815 Log.w(TAG, "Error in app " + r.processName
8816 + " running instrumentation " + r.instrumentationClass + ":");
8817 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8818 if (longMsg != null) Log.w(TAG, " " + longMsg);
8819 Bundle info = new Bundle();
8820 info.putString("shortMsg", shortMsg);
8821 info.putString("longMsg", longMsg);
8822 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8823 Binder.restoreCallingIdentity(origId);
8824 return 0;
8825 }
8826
8827 if (r != null) {
8828 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8829 return 0;
8830 }
8831 } else {
8832 Log.w(TAG, "Some application object " + app + " tag " + tag
8833 + " has crashed, but I don't know who it is.");
8834 Log.w(TAG, "ShortMsg:" + shortMsg);
8835 Log.w(TAG, "LongMsg:" + longMsg);
8836 Binder.restoreCallingIdentity(origId);
8837 return 0;
8838 }
8839
8840 Message msg = Message.obtain();
8841 msg.what = SHOW_ERROR_MSG;
8842 HashMap data = new HashMap();
8843 data.put("result", result);
8844 data.put("app", r);
8845 data.put("flags", flags);
8846 data.put("shortMsg", shortMsg);
8847 data.put("longMsg", longMsg);
8848 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8849 // For system processes, submit crash data to the server.
8850 data.put("crashData", crashData);
8851 }
8852 msg.obj = data;
8853 mHandler.sendMessage(msg);
8854
8855 Binder.restoreCallingIdentity(origId);
8856 }
8857
8858 int res = result.get();
8859
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008860 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008861 synchronized (this) {
8862 if (r != null) {
8863 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8864 SystemClock.uptimeMillis());
8865 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008866 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8867 appErrorIntent = createAppErrorIntentLocked(r);
8868 res = AppErrorDialog.FORCE_QUIT;
8869 }
8870 }
8871
8872 if (appErrorIntent != null) {
8873 try {
8874 mContext.startActivity(appErrorIntent);
8875 } catch (ActivityNotFoundException e) {
8876 Log.w(TAG, "bug report receiver dissappeared", e);
8877 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008878 }
8879
8880 return res;
8881 }
8882
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008883 Intent createAppErrorIntentLocked(ProcessRecord r) {
8884 ApplicationErrorReport report = createAppErrorReportLocked(r);
8885 if (report == null) {
8886 return null;
8887 }
8888 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8889 result.setComponent(r.errorReportReceiver);
8890 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8891 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8892 return result;
8893 }
8894
8895 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8896 if (r.errorReportReceiver == null) {
8897 return null;
8898 }
8899
8900 if (!r.crashing && !r.notResponding) {
8901 return null;
8902 }
8903
8904 try {
8905 ApplicationErrorReport report = new ApplicationErrorReport();
8906 report.packageName = r.info.packageName;
8907 report.installerPackageName = r.errorReportReceiver.getPackageName();
8908 report.processName = r.processName;
8909
8910 if (r.crashing) {
8911 report.type = ApplicationErrorReport.TYPE_CRASH;
8912 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8913
8914 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8915 r.crashingReport.crashData);
8916 DataInputStream dataStream = new DataInputStream(byteStream);
8917 CrashData crashData = new CrashData(dataStream);
8918 ThrowableData throwData = crashData.getThrowableData();
8919
8920 report.time = crashData.getTime();
8921 report.crashInfo.stackTrace = throwData.toString();
8922
Jacek Surazskif829a782009-06-11 22:47:02 +02008923 // Extract the source of the exception, useful for report
8924 // clustering. Also extract the "deepest" non-null exception
8925 // message.
8926 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008927 while (throwData.getCause() != null) {
8928 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008929 String msg = throwData.getMessage();
8930 if (msg != null && msg.length() > 0) {
8931 exceptionMessage = msg;
8932 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008933 }
8934 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008935 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008936 report.crashInfo.exceptionClassName = throwData.getType();
8937 report.crashInfo.throwFileName = trace.getFileName();
8938 report.crashInfo.throwClassName = trace.getClassName();
8939 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008940 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008941 } else if (r.notResponding) {
8942 report.type = ApplicationErrorReport.TYPE_ANR;
8943 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8944
8945 report.anrInfo.activity = r.notRespondingReport.tag;
8946 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8947 report.anrInfo.info = r.notRespondingReport.longMsg;
8948 }
8949
8950 return report;
8951 } catch (IOException e) {
8952 // we don't send it
8953 }
8954
8955 return null;
8956 }
8957
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008958 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8959 // assume our apps are happy - lazy create the list
8960 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8961
8962 synchronized (this) {
8963
8964 // iterate across all processes
8965 final int N = mLRUProcesses.size();
8966 for (int i = 0; i < N; i++) {
8967 ProcessRecord app = mLRUProcesses.get(i);
8968 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8969 // This one's in trouble, so we'll generate a report for it
8970 // crashes are higher priority (in case there's a crash *and* an anr)
8971 ActivityManager.ProcessErrorStateInfo report = null;
8972 if (app.crashing) {
8973 report = app.crashingReport;
8974 } else if (app.notResponding) {
8975 report = app.notRespondingReport;
8976 }
8977
8978 if (report != null) {
8979 if (errList == null) {
8980 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8981 }
8982 errList.add(report);
8983 } else {
8984 Log.w(TAG, "Missing app error report, app = " + app.processName +
8985 " crashing = " + app.crashing +
8986 " notResponding = " + app.notResponding);
8987 }
8988 }
8989 }
8990 }
8991
8992 return errList;
8993 }
8994
8995 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8996 // Lazy instantiation of list
8997 List<ActivityManager.RunningAppProcessInfo> runList = null;
8998 synchronized (this) {
8999 // Iterate across all processes
9000 final int N = mLRUProcesses.size();
9001 for (int i = 0; i < N; i++) {
9002 ProcessRecord app = mLRUProcesses.get(i);
9003 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
9004 // Generate process state info for running application
9005 ActivityManager.RunningAppProcessInfo currApp =
9006 new ActivityManager.RunningAppProcessInfo(app.processName,
9007 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07009008 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009009 int adj = app.curAdj;
9010 if (adj >= CONTENT_PROVIDER_ADJ) {
9011 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
9012 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
9013 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08009014 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
9015 } else if (adj >= HOME_APP_ADJ) {
9016 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
9017 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009018 } else if (adj >= SECONDARY_SERVER_ADJ) {
9019 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
9020 } else if (adj >= VISIBLE_APP_ADJ) {
9021 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
9022 } else {
9023 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
9024 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009025 currApp.importanceReasonCode = app.adjTypeCode;
9026 if (app.adjSource instanceof ProcessRecord) {
9027 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9028 } else if (app.adjSource instanceof HistoryRecord) {
9029 HistoryRecord r = (HistoryRecord)app.adjSource;
9030 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9031 }
9032 if (app.adjTarget instanceof ComponentName) {
9033 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9034 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009035 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9036 // + " lru=" + currApp.lru);
9037 if (runList == null) {
9038 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9039 }
9040 runList.add(currApp);
9041 }
9042 }
9043 }
9044 return runList;
9045 }
9046
9047 @Override
9048 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9049 synchronized (this) {
9050 if (checkCallingPermission(android.Manifest.permission.DUMP)
9051 != PackageManager.PERMISSION_GRANTED) {
9052 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9053 + Binder.getCallingPid()
9054 + ", uid=" + Binder.getCallingUid()
9055 + " without permission "
9056 + android.Manifest.permission.DUMP);
9057 return;
9058 }
9059 if (args.length != 0 && "service".equals(args[0])) {
9060 dumpService(fd, pw, args);
9061 return;
9062 }
9063 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009064 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009065 pw.println(" ");
9066 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009067 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009068 if (mWaitingVisibleActivities.size() > 0) {
9069 pw.println(" ");
9070 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009071 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009072 }
9073 if (mStoppingActivities.size() > 0) {
9074 pw.println(" ");
9075 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009076 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009077 }
9078 if (mFinishingActivities.size() > 0) {
9079 pw.println(" ");
9080 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009081 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009082 }
9083
9084 pw.println(" ");
9085 pw.println(" mPausingActivity: " + mPausingActivity);
9086 pw.println(" mResumedActivity: " + mResumedActivity);
9087 pw.println(" mFocusedActivity: " + mFocusedActivity);
9088 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
9089
9090 if (mRecentTasks.size() > 0) {
9091 pw.println(" ");
9092 pw.println("Recent tasks in Current Activity Manager State:");
9093
9094 final int N = mRecentTasks.size();
9095 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009096 TaskRecord tr = mRecentTasks.get(i);
9097 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9098 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009099 mRecentTasks.get(i).dump(pw, " ");
9100 }
9101 }
9102
9103 pw.println(" ");
9104 pw.println(" mCurTask: " + mCurTask);
9105
9106 pw.println(" ");
9107 pw.println("Processes in Current Activity Manager State:");
9108
9109 boolean needSep = false;
9110 int numPers = 0;
9111
9112 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9113 final int NA = procs.size();
9114 for (int ia=0; ia<NA; ia++) {
9115 if (!needSep) {
9116 pw.println(" All known processes:");
9117 needSep = true;
9118 }
9119 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009120 pw.print(r.persistent ? " *PERS*" : " *APP*");
9121 pw.print(" UID "); pw.print(procs.keyAt(ia));
9122 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009123 r.dump(pw, " ");
9124 if (r.persistent) {
9125 numPers++;
9126 }
9127 }
9128 }
9129
9130 if (mLRUProcesses.size() > 0) {
9131 if (needSep) pw.println(" ");
9132 needSep = true;
9133 pw.println(" Running processes (most recent first):");
9134 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009135 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009136 needSep = true;
9137 }
9138
9139 synchronized (mPidsSelfLocked) {
9140 if (mPidsSelfLocked.size() > 0) {
9141 if (needSep) pw.println(" ");
9142 needSep = true;
9143 pw.println(" PID mappings:");
9144 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009145 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9146 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009147 }
9148 }
9149 }
9150
9151 if (mForegroundProcesses.size() > 0) {
9152 if (needSep) pw.println(" ");
9153 needSep = true;
9154 pw.println(" Foreground Processes:");
9155 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009156 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9157 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009158 }
9159 }
9160
9161 if (mPersistentStartingProcesses.size() > 0) {
9162 if (needSep) pw.println(" ");
9163 needSep = true;
9164 pw.println(" Persisent processes that are starting:");
9165 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009166 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009167 }
9168
9169 if (mStartingProcesses.size() > 0) {
9170 if (needSep) pw.println(" ");
9171 needSep = true;
9172 pw.println(" Processes that are starting:");
9173 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009174 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009175 }
9176
9177 if (mRemovedProcesses.size() > 0) {
9178 if (needSep) pw.println(" ");
9179 needSep = true;
9180 pw.println(" Processes that are being removed:");
9181 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009182 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009183 }
9184
9185 if (mProcessesOnHold.size() > 0) {
9186 if (needSep) pw.println(" ");
9187 needSep = true;
9188 pw.println(" Processes that are on old until the system is ready:");
9189 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009190 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009191 }
9192
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009193 if (mProcessesToGc.size() > 0) {
9194 if (needSep) pw.println(" ");
9195 needSep = true;
9196 pw.println(" Processes that are waiting to GC:");
9197 long now = SystemClock.uptimeMillis();
9198 for (int i=0; i<mProcessesToGc.size(); i++) {
9199 ProcessRecord proc = mProcessesToGc.get(i);
9200 pw.print(" Process "); pw.println(proc);
9201 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9202 pw.print(", last gced=");
9203 pw.print(now-proc.lastRequestedGc);
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -07009204 pw.print(" ms ago, last lowMem=");
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009205 pw.print(now-proc.lastLowMemory);
9206 pw.println(" ms ago");
9207
9208 }
9209 }
9210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009211 if (mProcessCrashTimes.getMap().size() > 0) {
9212 if (needSep) pw.println(" ");
9213 needSep = true;
9214 pw.println(" Time since processes crashed:");
9215 long now = SystemClock.uptimeMillis();
9216 for (Map.Entry<String, SparseArray<Long>> procs
9217 : mProcessCrashTimes.getMap().entrySet()) {
9218 SparseArray<Long> uids = procs.getValue();
9219 final int N = uids.size();
9220 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009221 pw.print(" Process "); pw.print(procs.getKey());
9222 pw.print(" uid "); pw.print(uids.keyAt(i));
9223 pw.print(": last crashed ");
9224 pw.print((now-uids.valueAt(i)));
9225 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009226 }
9227 }
9228 }
9229
9230 if (mBadProcesses.getMap().size() > 0) {
9231 if (needSep) pw.println(" ");
9232 needSep = true;
9233 pw.println(" Bad processes:");
9234 for (Map.Entry<String, SparseArray<Long>> procs
9235 : mBadProcesses.getMap().entrySet()) {
9236 SparseArray<Long> uids = procs.getValue();
9237 final int N = uids.size();
9238 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009239 pw.print(" Bad process "); pw.print(procs.getKey());
9240 pw.print(" uid "); pw.print(uids.keyAt(i));
9241 pw.print(": crashed at time ");
9242 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009243 }
9244 }
9245 }
9246
9247 pw.println(" ");
9248 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009249 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009250 pw.println(" mConfiguration: " + mConfiguration);
9251 pw.println(" mStartRunning=" + mStartRunning
9252 + " mSystemReady=" + mSystemReady
9253 + " mBooting=" + mBooting
9254 + " mBooted=" + mBooted
9255 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009256 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009257 pw.println(" mGoingToSleep=" + mGoingToSleep);
9258 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9259 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9260 + " mDebugTransient=" + mDebugTransient
9261 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9262 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009263 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009264 }
9265 }
9266
9267 /**
9268 * There are three ways to call this:
9269 * - no service specified: dump all the services
9270 * - a flattened component name that matched an existing service was specified as the
9271 * first arg: dump that one service
9272 * - the first arg isn't the flattened component name of an existing service:
9273 * dump all services whose component contains the first arg as a substring
9274 */
9275 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9276 String[] newArgs;
9277 String componentNameString;
9278 ServiceRecord r;
9279 if (args.length == 1) {
9280 componentNameString = null;
9281 newArgs = EMPTY_STRING_ARRAY;
9282 r = null;
9283 } else {
9284 componentNameString = args[1];
9285 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9286 r = componentName != null ? mServices.get(componentName) : null;
9287 newArgs = new String[args.length - 2];
9288 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9289 }
9290
9291 if (r != null) {
9292 dumpService(fd, pw, r, newArgs);
9293 } else {
9294 for (ServiceRecord r1 : mServices.values()) {
9295 if (componentNameString == null
9296 || r1.name.flattenToString().contains(componentNameString)) {
9297 dumpService(fd, pw, r1, newArgs);
9298 }
9299 }
9300 }
9301 }
9302
9303 /**
9304 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9305 * there is a thread associated with the service.
9306 */
9307 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9308 pw.println(" Service " + r.name.flattenToString());
9309 if (r.app != null && r.app.thread != null) {
9310 try {
9311 // flush anything that is already in the PrintWriter since the thread is going
9312 // to write to the file descriptor directly
9313 pw.flush();
9314 r.app.thread.dumpService(fd, r, args);
9315 pw.print("\n");
9316 } catch (RemoteException e) {
9317 pw.println("got a RemoteException while dumping the service");
9318 }
9319 }
9320 }
9321
9322 void dumpBroadcasts(PrintWriter pw) {
9323 synchronized (this) {
9324 if (checkCallingPermission(android.Manifest.permission.DUMP)
9325 != PackageManager.PERMISSION_GRANTED) {
9326 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9327 + Binder.getCallingPid()
9328 + ", uid=" + Binder.getCallingUid()
9329 + " without permission "
9330 + android.Manifest.permission.DUMP);
9331 return;
9332 }
9333 pw.println("Broadcasts in Current Activity Manager State:");
9334
9335 if (mRegisteredReceivers.size() > 0) {
9336 pw.println(" ");
9337 pw.println(" Registered Receivers:");
9338 Iterator it = mRegisteredReceivers.values().iterator();
9339 while (it.hasNext()) {
9340 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009341 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009342 r.dump(pw, " ");
9343 }
9344 }
9345
9346 pw.println(" ");
9347 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009348 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009349
9350 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9351 || mPendingBroadcast != null) {
9352 if (mParallelBroadcasts.size() > 0) {
9353 pw.println(" ");
9354 pw.println(" Active broadcasts:");
9355 }
9356 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9357 pw.println(" Broadcast #" + i + ":");
9358 mParallelBroadcasts.get(i).dump(pw, " ");
9359 }
9360 if (mOrderedBroadcasts.size() > 0) {
9361 pw.println(" ");
9362 pw.println(" Active serialized broadcasts:");
9363 }
9364 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9365 pw.println(" Serialized Broadcast #" + i + ":");
9366 mOrderedBroadcasts.get(i).dump(pw, " ");
9367 }
9368 pw.println(" ");
9369 pw.println(" Pending broadcast:");
9370 if (mPendingBroadcast != null) {
9371 mPendingBroadcast.dump(pw, " ");
9372 } else {
9373 pw.println(" (null)");
9374 }
9375 }
9376
9377 pw.println(" ");
9378 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9379 if (mStickyBroadcasts != null) {
9380 pw.println(" ");
9381 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009382 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009383 for (Map.Entry<String, ArrayList<Intent>> ent
9384 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009385 pw.print(" * Sticky action "); pw.print(ent.getKey());
9386 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009387 ArrayList<Intent> intents = ent.getValue();
9388 final int N = intents.size();
9389 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009390 sb.setLength(0);
9391 sb.append(" Intent: ");
9392 intents.get(i).toShortString(sb, true, false);
9393 pw.println(sb.toString());
9394 Bundle bundle = intents.get(i).getExtras();
9395 if (bundle != null) {
9396 pw.print(" ");
9397 pw.println(bundle.toString());
9398 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009399 }
9400 }
9401 }
9402
9403 pw.println(" ");
9404 pw.println(" mHandler:");
9405 mHandler.dump(new PrintWriterPrinter(pw), " ");
9406 }
9407 }
9408
9409 void dumpServices(PrintWriter pw) {
9410 synchronized (this) {
9411 if (checkCallingPermission(android.Manifest.permission.DUMP)
9412 != PackageManager.PERMISSION_GRANTED) {
9413 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9414 + Binder.getCallingPid()
9415 + ", uid=" + Binder.getCallingUid()
9416 + " without permission "
9417 + android.Manifest.permission.DUMP);
9418 return;
9419 }
9420 pw.println("Services in Current Activity Manager State:");
9421
9422 boolean needSep = false;
9423
9424 if (mServices.size() > 0) {
9425 pw.println(" Active services:");
9426 Iterator<ServiceRecord> it = mServices.values().iterator();
9427 while (it.hasNext()) {
9428 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009429 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009430 r.dump(pw, " ");
9431 }
9432 needSep = true;
9433 }
9434
9435 if (mPendingServices.size() > 0) {
9436 if (needSep) pw.println(" ");
9437 pw.println(" Pending services:");
9438 for (int i=0; i<mPendingServices.size(); i++) {
9439 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009440 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009441 r.dump(pw, " ");
9442 }
9443 needSep = true;
9444 }
9445
9446 if (mRestartingServices.size() > 0) {
9447 if (needSep) pw.println(" ");
9448 pw.println(" Restarting services:");
9449 for (int i=0; i<mRestartingServices.size(); i++) {
9450 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009451 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009452 r.dump(pw, " ");
9453 }
9454 needSep = true;
9455 }
9456
9457 if (mStoppingServices.size() > 0) {
9458 if (needSep) pw.println(" ");
9459 pw.println(" Stopping services:");
9460 for (int i=0; i<mStoppingServices.size(); i++) {
9461 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009462 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009463 r.dump(pw, " ");
9464 }
9465 needSep = true;
9466 }
9467
9468 if (mServiceConnections.size() > 0) {
9469 if (needSep) pw.println(" ");
9470 pw.println(" Connection bindings to services:");
9471 Iterator<ConnectionRecord> it
9472 = mServiceConnections.values().iterator();
9473 while (it.hasNext()) {
9474 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009475 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009476 r.dump(pw, " ");
9477 }
9478 }
9479 }
9480 }
9481
9482 void dumpProviders(PrintWriter pw) {
9483 synchronized (this) {
9484 if (checkCallingPermission(android.Manifest.permission.DUMP)
9485 != PackageManager.PERMISSION_GRANTED) {
9486 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9487 + Binder.getCallingPid()
9488 + ", uid=" + Binder.getCallingUid()
9489 + " without permission "
9490 + android.Manifest.permission.DUMP);
9491 return;
9492 }
9493
9494 pw.println("Content Providers in Current Activity Manager State:");
9495
9496 boolean needSep = false;
9497
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009498 if (mProvidersByClass.size() > 0) {
9499 if (needSep) pw.println(" ");
9500 pw.println(" Published content providers (by class):");
9501 Iterator it = mProvidersByClass.entrySet().iterator();
9502 while (it.hasNext()) {
9503 Map.Entry e = (Map.Entry)it.next();
9504 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009505 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009506 r.dump(pw, " ");
9507 }
9508 needSep = true;
9509 }
9510
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009511 if (mProvidersByName.size() > 0) {
9512 pw.println(" ");
9513 pw.println(" Authority to provider mappings:");
9514 Iterator it = mProvidersByName.entrySet().iterator();
9515 while (it.hasNext()) {
9516 Map.Entry e = (Map.Entry)it.next();
9517 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9518 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9519 pw.println(r);
9520 }
9521 needSep = true;
9522 }
9523
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009524 if (mLaunchingProviders.size() > 0) {
9525 if (needSep) pw.println(" ");
9526 pw.println(" Launching content providers:");
9527 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009528 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9529 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009530 }
9531 needSep = true;
9532 }
9533
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009534 if (mGrantedUriPermissions.size() > 0) {
9535 pw.println();
9536 pw.println("Granted Uri Permissions:");
9537 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9538 int uid = mGrantedUriPermissions.keyAt(i);
9539 HashMap<Uri, UriPermission> perms
9540 = mGrantedUriPermissions.valueAt(i);
9541 pw.print(" * UID "); pw.print(uid);
9542 pw.println(" holds:");
9543 for (UriPermission perm : perms.values()) {
9544 pw.print(" "); pw.println(perm);
9545 perm.dump(pw, " ");
9546 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009547 }
9548 }
9549 }
9550 }
9551
9552 void dumpSenders(PrintWriter pw) {
9553 synchronized (this) {
9554 if (checkCallingPermission(android.Manifest.permission.DUMP)
9555 != PackageManager.PERMISSION_GRANTED) {
9556 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9557 + Binder.getCallingPid()
9558 + ", uid=" + Binder.getCallingUid()
9559 + " without permission "
9560 + android.Manifest.permission.DUMP);
9561 return;
9562 }
9563
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009564 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009565
9566 if (this.mIntentSenderRecords.size() > 0) {
9567 Iterator<WeakReference<PendingIntentRecord>> it
9568 = mIntentSenderRecords.values().iterator();
9569 while (it.hasNext()) {
9570 WeakReference<PendingIntentRecord> ref = it.next();
9571 PendingIntentRecord rec = ref != null ? ref.get(): null;
9572 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009573 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009574 rec.dump(pw, " ");
9575 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009576 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009577 }
9578 }
9579 }
9580 }
9581 }
9582
9583 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009584 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009585 TaskRecord lastTask = null;
9586 for (int i=list.size()-1; i>=0; i--) {
9587 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009588 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009589 if (lastTask != r.task) {
9590 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009591 pw.print(prefix);
9592 pw.print(full ? "* " : " ");
9593 pw.println(lastTask);
9594 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009595 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009596 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009597 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009598 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9599 pw.print(" #"); pw.print(i); pw.print(": ");
9600 pw.println(r);
9601 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009602 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009603 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009604 }
9605 }
9606
9607 private static final int dumpProcessList(PrintWriter pw, List list,
9608 String prefix, String normalLabel, String persistentLabel,
9609 boolean inclOomAdj) {
9610 int numPers = 0;
9611 for (int i=list.size()-1; i>=0; i--) {
9612 ProcessRecord r = (ProcessRecord)list.get(i);
9613 if (false) {
9614 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9615 + " #" + i + ":");
9616 r.dump(pw, prefix + " ");
9617 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009618 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009619 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009620 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9621 if (r.adjSource != null || r.adjTarget != null) {
9622 pw.println(prefix + " " + r.adjTarget
9623 + " used by " + r.adjSource);
9624 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009625 } else {
9626 pw.println(String.format("%s%s #%2d: %s",
9627 prefix, (r.persistent ? persistentLabel : normalLabel),
9628 i, r.toString()));
9629 }
9630 if (r.persistent) {
9631 numPers++;
9632 }
9633 }
9634 return numPers;
9635 }
9636
9637 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9638 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009639 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009640 long uptime = SystemClock.uptimeMillis();
9641 long realtime = SystemClock.elapsedRealtime();
9642
9643 if (isCheckinRequest) {
9644 // short checkin version
9645 pw.println(uptime + "," + realtime);
9646 pw.flush();
9647 } else {
9648 pw.println("Applications Memory Usage (kB):");
9649 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9650 }
9651 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9652 ProcessRecord r = (ProcessRecord)list.get(i);
9653 if (r.thread != null) {
9654 if (!isCheckinRequest) {
9655 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9656 pw.flush();
9657 }
9658 try {
9659 r.thread.asBinder().dump(fd, args);
9660 } catch (RemoteException e) {
9661 if (!isCheckinRequest) {
9662 pw.println("Got RemoteException!");
9663 pw.flush();
9664 }
9665 }
9666 }
9667 }
9668 }
9669
9670 /**
9671 * Searches array of arguments for the specified string
9672 * @param args array of argument strings
9673 * @param value value to search for
9674 * @return true if the value is contained in the array
9675 */
9676 private static boolean scanArgs(String[] args, String value) {
9677 if (args != null) {
9678 for (String arg : args) {
9679 if (value.equals(arg)) {
9680 return true;
9681 }
9682 }
9683 }
9684 return false;
9685 }
9686
Dianne Hackborn75b03852009-06-12 15:43:26 -07009687 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009688 int count = mHistory.size();
9689
9690 // convert the token to an entry in the history.
9691 HistoryRecord r = null;
9692 int index = -1;
9693 for (int i=count-1; i>=0; i--) {
9694 Object o = mHistory.get(i);
9695 if (o == token) {
9696 r = (HistoryRecord)o;
9697 index = i;
9698 break;
9699 }
9700 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009701
9702 return index;
9703 }
9704
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009705 private final void killServicesLocked(ProcessRecord app,
9706 boolean allowRestart) {
9707 // Report disconnected services.
9708 if (false) {
9709 // XXX we are letting the client link to the service for
9710 // death notifications.
9711 if (app.services.size() > 0) {
9712 Iterator it = app.services.iterator();
9713 while (it.hasNext()) {
9714 ServiceRecord r = (ServiceRecord)it.next();
9715 if (r.connections.size() > 0) {
9716 Iterator<ConnectionRecord> jt
9717 = r.connections.values().iterator();
9718 while (jt.hasNext()) {
9719 ConnectionRecord c = jt.next();
9720 if (c.binding.client != app) {
9721 try {
9722 //c.conn.connected(r.className, null);
9723 } catch (Exception e) {
9724 // todo: this should be asynchronous!
9725 Log.w(TAG, "Exception thrown disconnected servce "
9726 + r.shortName
9727 + " from app " + app.processName, e);
9728 }
9729 }
9730 }
9731 }
9732 }
9733 }
9734 }
9735
9736 // Clean up any connections this application has to other services.
9737 if (app.connections.size() > 0) {
9738 Iterator<ConnectionRecord> it = app.connections.iterator();
9739 while (it.hasNext()) {
9740 ConnectionRecord r = it.next();
9741 removeConnectionLocked(r, app, null);
9742 }
9743 }
9744 app.connections.clear();
9745
9746 if (app.services.size() != 0) {
9747 // Any services running in the application need to be placed
9748 // back in the pending list.
9749 Iterator it = app.services.iterator();
9750 while (it.hasNext()) {
9751 ServiceRecord sr = (ServiceRecord)it.next();
9752 synchronized (sr.stats.getBatteryStats()) {
9753 sr.stats.stopLaunchedLocked();
9754 }
9755 sr.app = null;
9756 sr.executeNesting = 0;
9757 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009758
9759 boolean hasClients = sr.bindings.size() > 0;
9760 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009761 Iterator<IntentBindRecord> bindings
9762 = sr.bindings.values().iterator();
9763 while (bindings.hasNext()) {
9764 IntentBindRecord b = bindings.next();
9765 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9766 + ": shouldUnbind=" + b.hasBound);
9767 b.binder = null;
9768 b.requested = b.received = b.hasBound = false;
9769 }
9770 }
9771
9772 if (sr.crashCount >= 2) {
9773 Log.w(TAG, "Service crashed " + sr.crashCount
9774 + " times, stopping: " + sr);
9775 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9776 sr.crashCount, sr.shortName, app.pid);
9777 bringDownServiceLocked(sr, true);
9778 } else if (!allowRestart) {
9779 bringDownServiceLocked(sr, true);
9780 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009781 boolean canceled = scheduleServiceRestartLocked(sr, true);
9782
9783 // Should the service remain running? Note that in the
9784 // extreme case of so many attempts to deliver a command
9785 // that it failed, that we also will stop it here.
9786 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9787 if (sr.pendingStarts.size() == 0) {
9788 sr.startRequested = false;
9789 if (!hasClients) {
9790 // Whoops, no reason to restart!
9791 bringDownServiceLocked(sr, true);
9792 }
9793 }
9794 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009795 }
9796 }
9797
9798 if (!allowRestart) {
9799 app.services.clear();
9800 }
9801 }
9802
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009803 // Make sure we have no more records on the stopping list.
9804 int i = mStoppingServices.size();
9805 while (i > 0) {
9806 i--;
9807 ServiceRecord sr = mStoppingServices.get(i);
9808 if (sr.app == app) {
9809 mStoppingServices.remove(i);
9810 }
9811 }
9812
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009813 app.executingServices.clear();
9814 }
9815
9816 private final void removeDyingProviderLocked(ProcessRecord proc,
9817 ContentProviderRecord cpr) {
9818 synchronized (cpr) {
9819 cpr.launchingApp = null;
9820 cpr.notifyAll();
9821 }
9822
9823 mProvidersByClass.remove(cpr.info.name);
9824 String names[] = cpr.info.authority.split(";");
9825 for (int j = 0; j < names.length; j++) {
9826 mProvidersByName.remove(names[j]);
9827 }
9828
9829 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9830 while (cit.hasNext()) {
9831 ProcessRecord capp = cit.next();
9832 if (!capp.persistent && capp.thread != null
9833 && capp.pid != 0
9834 && capp.pid != MY_PID) {
9835 Log.i(TAG, "Killing app " + capp.processName
9836 + " (pid " + capp.pid
9837 + ") because provider " + cpr.info.name
9838 + " is in dying process " + proc.processName);
9839 Process.killProcess(capp.pid);
9840 }
9841 }
9842
9843 mLaunchingProviders.remove(cpr);
9844 }
9845
9846 /**
9847 * Main code for cleaning up a process when it has gone away. This is
9848 * called both as a result of the process dying, or directly when stopping
9849 * a process when running in single process mode.
9850 */
9851 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9852 boolean restarting, int index) {
9853 if (index >= 0) {
9854 mLRUProcesses.remove(index);
9855 }
9856
Dianne Hackborn36124872009-10-08 16:22:03 -07009857 mProcessesToGc.remove(app);
9858
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009859 // Dismiss any open dialogs.
9860 if (app.crashDialog != null) {
9861 app.crashDialog.dismiss();
9862 app.crashDialog = null;
9863 }
9864 if (app.anrDialog != null) {
9865 app.anrDialog.dismiss();
9866 app.anrDialog = null;
9867 }
9868 if (app.waitDialog != null) {
9869 app.waitDialog.dismiss();
9870 app.waitDialog = null;
9871 }
9872
9873 app.crashing = false;
9874 app.notResponding = false;
9875
9876 app.resetPackageList();
9877 app.thread = null;
9878 app.forcingToForeground = null;
9879 app.foregroundServices = false;
9880
9881 killServicesLocked(app, true);
9882
9883 boolean restart = false;
9884
9885 int NL = mLaunchingProviders.size();
9886
9887 // Remove published content providers.
9888 if (!app.pubProviders.isEmpty()) {
9889 Iterator it = app.pubProviders.values().iterator();
9890 while (it.hasNext()) {
9891 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9892 cpr.provider = null;
9893 cpr.app = null;
9894
9895 // See if someone is waiting for this provider... in which
9896 // case we don't remove it, but just let it restart.
9897 int i = 0;
9898 if (!app.bad) {
9899 for (; i<NL; i++) {
9900 if (mLaunchingProviders.get(i) == cpr) {
9901 restart = true;
9902 break;
9903 }
9904 }
9905 } else {
9906 i = NL;
9907 }
9908
9909 if (i >= NL) {
9910 removeDyingProviderLocked(app, cpr);
9911 NL = mLaunchingProviders.size();
9912 }
9913 }
9914 app.pubProviders.clear();
9915 }
9916
9917 // Look through the content providers we are waiting to have launched,
9918 // and if any run in this process then either schedule a restart of
9919 // the process or kill the client waiting for it if this process has
9920 // gone bad.
9921 for (int i=0; i<NL; i++) {
9922 ContentProviderRecord cpr = (ContentProviderRecord)
9923 mLaunchingProviders.get(i);
9924 if (cpr.launchingApp == app) {
9925 if (!app.bad) {
9926 restart = true;
9927 } else {
9928 removeDyingProviderLocked(app, cpr);
9929 NL = mLaunchingProviders.size();
9930 }
9931 }
9932 }
9933
9934 // Unregister from connected content providers.
9935 if (!app.conProviders.isEmpty()) {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07009936 Iterator it = app.conProviders.keySet().iterator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009937 while (it.hasNext()) {
9938 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9939 cpr.clients.remove(app);
9940 }
9941 app.conProviders.clear();
9942 }
9943
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009944 // At this point there may be remaining entries in mLaunchingProviders
9945 // where we were the only one waiting, so they are no longer of use.
9946 // Look for these and clean up if found.
9947 // XXX Commented out for now. Trying to figure out a way to reproduce
9948 // the actual situation to identify what is actually going on.
9949 if (false) {
9950 for (int i=0; i<NL; i++) {
9951 ContentProviderRecord cpr = (ContentProviderRecord)
9952 mLaunchingProviders.get(i);
9953 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9954 synchronized (cpr) {
9955 cpr.launchingApp = null;
9956 cpr.notifyAll();
9957 }
9958 }
9959 }
9960 }
9961
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009962 skipCurrentReceiverLocked(app);
9963
9964 // Unregister any receivers.
9965 if (app.receivers.size() > 0) {
9966 Iterator<ReceiverList> it = app.receivers.iterator();
9967 while (it.hasNext()) {
9968 removeReceiverLocked(it.next());
9969 }
9970 app.receivers.clear();
9971 }
9972
Christopher Tate181fafa2009-05-14 11:12:14 -07009973 // If the app is undergoing backup, tell the backup manager about it
9974 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9975 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9976 try {
9977 IBackupManager bm = IBackupManager.Stub.asInterface(
9978 ServiceManager.getService(Context.BACKUP_SERVICE));
9979 bm.agentDisconnected(app.info.packageName);
9980 } catch (RemoteException e) {
9981 // can't happen; backup manager is local
9982 }
9983 }
9984
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009985 // If the caller is restarting this app, then leave it in its
9986 // current lists and let the caller take care of it.
9987 if (restarting) {
9988 return;
9989 }
9990
9991 if (!app.persistent) {
9992 if (DEBUG_PROCESSES) Log.v(TAG,
9993 "Removing non-persistent process during cleanup: " + app);
9994 mProcessNames.remove(app.processName, app.info.uid);
9995 } else if (!app.removed) {
9996 // This app is persistent, so we need to keep its record around.
9997 // If it is not already on the pending app list, add it there
9998 // and start a new process for it.
9999 app.thread = null;
10000 app.forcingToForeground = null;
10001 app.foregroundServices = false;
10002 if (mPersistentStartingProcesses.indexOf(app) < 0) {
10003 mPersistentStartingProcesses.add(app);
10004 restart = true;
10005 }
10006 }
10007 mProcessesOnHold.remove(app);
10008
The Android Open Source Project4df24232009-03-05 14:34:35 -080010009 if (app == mHomeProcess) {
10010 mHomeProcess = null;
10011 }
10012
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010013 if (restart) {
10014 // We have components that still need to be running in the
10015 // process, so re-launch it.
10016 mProcessNames.put(app.processName, app.info.uid, app);
10017 startProcessLocked(app, "restart", app.processName);
10018 } else if (app.pid > 0 && app.pid != MY_PID) {
10019 // Goodbye!
10020 synchronized (mPidsSelfLocked) {
10021 mPidsSelfLocked.remove(app.pid);
10022 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
10023 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070010024 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010025 }
10026 }
10027
10028 // =========================================================
10029 // SERVICES
10030 // =========================================================
10031
10032 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10033 ActivityManager.RunningServiceInfo info =
10034 new ActivityManager.RunningServiceInfo();
10035 info.service = r.name;
10036 if (r.app != null) {
10037 info.pid = r.app.pid;
10038 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010039 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010040 info.process = r.processName;
10041 info.foreground = r.isForeground;
10042 info.activeSince = r.createTime;
10043 info.started = r.startRequested;
10044 info.clientCount = r.connections.size();
10045 info.crashCount = r.crashCount;
10046 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010047 if (r.isForeground) {
10048 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10049 }
10050 if (r.startRequested) {
10051 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10052 }
10053 if (r.app != null && r.app.pid == Process.myPid()) {
10054 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10055 }
10056 if (r.app != null && r.app.persistent) {
10057 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10058 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010059 for (ConnectionRecord conn : r.connections.values()) {
10060 if (conn.clientLabel != 0) {
10061 info.clientPackage = conn.binding.client.info.packageName;
10062 info.clientLabel = conn.clientLabel;
10063 break;
10064 }
10065 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010066 return info;
10067 }
10068
10069 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10070 int flags) {
10071 synchronized (this) {
10072 ArrayList<ActivityManager.RunningServiceInfo> res
10073 = new ArrayList<ActivityManager.RunningServiceInfo>();
10074
10075 if (mServices.size() > 0) {
10076 Iterator<ServiceRecord> it = mServices.values().iterator();
10077 while (it.hasNext() && res.size() < maxNum) {
10078 res.add(makeRunningServiceInfoLocked(it.next()));
10079 }
10080 }
10081
10082 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10083 ServiceRecord r = mRestartingServices.get(i);
10084 ActivityManager.RunningServiceInfo info =
10085 makeRunningServiceInfoLocked(r);
10086 info.restarting = r.nextRestartTime;
10087 res.add(info);
10088 }
10089
10090 return res;
10091 }
10092 }
10093
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010094 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10095 synchronized (this) {
10096 ServiceRecord r = mServices.get(name);
10097 if (r != null) {
10098 for (ConnectionRecord conn : r.connections.values()) {
10099 if (conn.clientIntent != null) {
10100 return conn.clientIntent;
10101 }
10102 }
10103 }
10104 }
10105 return null;
10106 }
10107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010108 private final ServiceRecord findServiceLocked(ComponentName name,
10109 IBinder token) {
10110 ServiceRecord r = mServices.get(name);
10111 return r == token ? r : null;
10112 }
10113
10114 private final class ServiceLookupResult {
10115 final ServiceRecord record;
10116 final String permission;
10117
10118 ServiceLookupResult(ServiceRecord _record, String _permission) {
10119 record = _record;
10120 permission = _permission;
10121 }
10122 };
10123
10124 private ServiceLookupResult findServiceLocked(Intent service,
10125 String resolvedType) {
10126 ServiceRecord r = null;
10127 if (service.getComponent() != null) {
10128 r = mServices.get(service.getComponent());
10129 }
10130 if (r == null) {
10131 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10132 r = mServicesByIntent.get(filter);
10133 }
10134
10135 if (r == null) {
10136 try {
10137 ResolveInfo rInfo =
10138 ActivityThread.getPackageManager().resolveService(
10139 service, resolvedType, 0);
10140 ServiceInfo sInfo =
10141 rInfo != null ? rInfo.serviceInfo : null;
10142 if (sInfo == null) {
10143 return null;
10144 }
10145
10146 ComponentName name = new ComponentName(
10147 sInfo.applicationInfo.packageName, sInfo.name);
10148 r = mServices.get(name);
10149 } catch (RemoteException ex) {
10150 // pm is in same process, this will never happen.
10151 }
10152 }
10153 if (r != null) {
10154 int callingPid = Binder.getCallingPid();
10155 int callingUid = Binder.getCallingUid();
10156 if (checkComponentPermission(r.permission,
10157 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10158 != PackageManager.PERMISSION_GRANTED) {
10159 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10160 + " from pid=" + callingPid
10161 + ", uid=" + callingUid
10162 + " requires " + r.permission);
10163 return new ServiceLookupResult(null, r.permission);
10164 }
10165 return new ServiceLookupResult(r, null);
10166 }
10167 return null;
10168 }
10169
10170 private class ServiceRestarter implements Runnable {
10171 private ServiceRecord mService;
10172
10173 void setService(ServiceRecord service) {
10174 mService = service;
10175 }
10176
10177 public void run() {
10178 synchronized(ActivityManagerService.this) {
10179 performServiceRestartLocked(mService);
10180 }
10181 }
10182 }
10183
10184 private ServiceLookupResult retrieveServiceLocked(Intent service,
10185 String resolvedType, int callingPid, int callingUid) {
10186 ServiceRecord r = null;
10187 if (service.getComponent() != null) {
10188 r = mServices.get(service.getComponent());
10189 }
10190 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10191 r = mServicesByIntent.get(filter);
10192 if (r == null) {
10193 try {
10194 ResolveInfo rInfo =
10195 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010196 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010197 ServiceInfo sInfo =
10198 rInfo != null ? rInfo.serviceInfo : null;
10199 if (sInfo == null) {
10200 Log.w(TAG, "Unable to start service " + service +
10201 ": not found");
10202 return null;
10203 }
10204
10205 ComponentName name = new ComponentName(
10206 sInfo.applicationInfo.packageName, sInfo.name);
10207 r = mServices.get(name);
10208 if (r == null) {
10209 filter = new Intent.FilterComparison(service.cloneFilter());
10210 ServiceRestarter res = new ServiceRestarter();
10211 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10212 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10213 synchronized (stats) {
10214 ss = stats.getServiceStatsLocked(
10215 sInfo.applicationInfo.uid, sInfo.packageName,
10216 sInfo.name);
10217 }
10218 r = new ServiceRecord(ss, name, filter, sInfo, res);
10219 res.setService(r);
10220 mServices.put(name, r);
10221 mServicesByIntent.put(filter, r);
10222
10223 // Make sure this component isn't in the pending list.
10224 int N = mPendingServices.size();
10225 for (int i=0; i<N; i++) {
10226 ServiceRecord pr = mPendingServices.get(i);
10227 if (pr.name.equals(name)) {
10228 mPendingServices.remove(i);
10229 i--;
10230 N--;
10231 }
10232 }
10233 }
10234 } catch (RemoteException ex) {
10235 // pm is in same process, this will never happen.
10236 }
10237 }
10238 if (r != null) {
10239 if (checkComponentPermission(r.permission,
10240 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10241 != PackageManager.PERMISSION_GRANTED) {
10242 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10243 + " from pid=" + Binder.getCallingPid()
10244 + ", uid=" + Binder.getCallingUid()
10245 + " requires " + r.permission);
10246 return new ServiceLookupResult(null, r.permission);
10247 }
10248 return new ServiceLookupResult(r, null);
10249 }
10250 return null;
10251 }
10252
10253 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10254 long now = SystemClock.uptimeMillis();
10255 if (r.executeNesting == 0 && r.app != null) {
10256 if (r.app.executingServices.size() == 0) {
10257 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10258 msg.obj = r.app;
10259 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10260 }
10261 r.app.executingServices.add(r);
10262 }
10263 r.executeNesting++;
10264 r.executingStart = now;
10265 }
10266
10267 private final void sendServiceArgsLocked(ServiceRecord r,
10268 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010269 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010270 if (N == 0) {
10271 return;
10272 }
10273
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010274 int i = 0;
10275 while (i < N) {
10276 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010277 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010278 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010279 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010280 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010281 // If somehow we got a dummy start at the front, then
10282 // just drop it here.
10283 i++;
10284 continue;
10285 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010286 bumpServiceExecutingLocked(r);
10287 if (!oomAdjusted) {
10288 oomAdjusted = true;
10289 updateOomAdjLocked(r.app);
10290 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010291 int flags = 0;
10292 if (si.deliveryCount > 0) {
10293 flags |= Service.START_FLAG_RETRY;
10294 }
10295 if (si.doneExecutingCount > 0) {
10296 flags |= Service.START_FLAG_REDELIVERY;
10297 }
10298 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10299 si.deliveredTime = SystemClock.uptimeMillis();
10300 r.deliveredStarts.add(si);
10301 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010302 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010303 } catch (RemoteException e) {
10304 // Remote process gone... we'll let the normal cleanup take
10305 // care of this.
10306 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010307 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010308 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010309 break;
10310 }
10311 }
10312 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010313 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010314 } else {
10315 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010316 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010317 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010318 }
10319 }
10320 }
10321
10322 private final boolean requestServiceBindingLocked(ServiceRecord r,
10323 IntentBindRecord i, boolean rebind) {
10324 if (r.app == null || r.app.thread == null) {
10325 // If service is not currently running, can't yet bind.
10326 return false;
10327 }
10328 if ((!i.requested || rebind) && i.apps.size() > 0) {
10329 try {
10330 bumpServiceExecutingLocked(r);
10331 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10332 + ": shouldUnbind=" + i.hasBound);
10333 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10334 if (!rebind) {
10335 i.requested = true;
10336 }
10337 i.hasBound = true;
10338 i.doRebind = false;
10339 } catch (RemoteException e) {
10340 return false;
10341 }
10342 }
10343 return true;
10344 }
10345
10346 private final void requestServiceBindingsLocked(ServiceRecord r) {
10347 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10348 while (bindings.hasNext()) {
10349 IntentBindRecord i = bindings.next();
10350 if (!requestServiceBindingLocked(r, i, false)) {
10351 break;
10352 }
10353 }
10354 }
10355
10356 private final void realStartServiceLocked(ServiceRecord r,
10357 ProcessRecord app) throws RemoteException {
10358 if (app.thread == null) {
10359 throw new RemoteException();
10360 }
10361
10362 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010363 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010364
10365 app.services.add(r);
10366 bumpServiceExecutingLocked(r);
10367 updateLRUListLocked(app, true);
10368
10369 boolean created = false;
10370 try {
10371 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10372 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010373 mStringBuilder.setLength(0);
10374 r.intent.getIntent().toShortString(mStringBuilder, false, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010375 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
10376 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010377 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010378 synchronized (r.stats.getBatteryStats()) {
10379 r.stats.startLaunchedLocked();
10380 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010381 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010382 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010383 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010384 created = true;
10385 } finally {
10386 if (!created) {
10387 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010388 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010389 }
10390 }
10391
10392 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010393
10394 // If the service is in the started state, and there are no
10395 // pending arguments, then fake up one so its onStartCommand() will
10396 // be called.
10397 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10398 r.lastStartId++;
10399 if (r.lastStartId < 1) {
10400 r.lastStartId = 1;
10401 }
10402 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10403 }
10404
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010405 sendServiceArgsLocked(r, true);
10406 }
10407
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010408 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10409 boolean allowCancel) {
10410 boolean canceled = false;
10411
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010412 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010413 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010414 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010415
10416 // Any delivered but not yet finished starts should be put back
10417 // on the pending list.
10418 final int N = r.deliveredStarts.size();
10419 if (N > 0) {
10420 for (int i=N-1; i>=0; i--) {
10421 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10422 if (si.intent == null) {
10423 // We'll generate this again if needed.
10424 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10425 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10426 r.pendingStarts.add(0, si);
10427 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10428 dur *= 2;
10429 if (minDuration < dur) minDuration = dur;
10430 if (resetTime < dur) resetTime = dur;
10431 } else {
10432 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10433 + r.name);
10434 canceled = true;
10435 }
10436 }
10437 r.deliveredStarts.clear();
10438 }
10439
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010440 r.totalRestartCount++;
10441 if (r.restartDelay == 0) {
10442 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010443 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010444 } else {
10445 // If it has been a "reasonably long time" since the service
10446 // was started, then reset our restart duration back to
10447 // the beginning, so we don't infinitely increase the duration
10448 // on a service that just occasionally gets killed (which is
10449 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010450 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010451 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010452 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010453 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010454 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010455 if (r.restartDelay < minDuration) {
10456 r.restartDelay = minDuration;
10457 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010458 }
10459 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010460
10461 r.nextRestartTime = now + r.restartDelay;
10462
10463 // Make sure that we don't end up restarting a bunch of services
10464 // all at the same time.
10465 boolean repeat;
10466 do {
10467 repeat = false;
10468 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10469 ServiceRecord r2 = mRestartingServices.get(i);
10470 if (r2 != r && r.nextRestartTime
10471 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10472 && r.nextRestartTime
10473 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10474 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10475 r.restartDelay = r.nextRestartTime - now;
10476 repeat = true;
10477 break;
10478 }
10479 }
10480 } while (repeat);
10481
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010482 if (!mRestartingServices.contains(r)) {
10483 mRestartingServices.add(r);
10484 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010485
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010486 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010487
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010488 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010489 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010490 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10491 Log.w(TAG, "Scheduling restart of crashed service "
10492 + r.shortName + " in " + r.restartDelay + "ms");
10493 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10494 r.shortName, r.restartDelay);
10495
10496 Message msg = Message.obtain();
10497 msg.what = SERVICE_ERROR_MSG;
10498 msg.obj = r;
10499 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010500
10501 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010502 }
10503
10504 final void performServiceRestartLocked(ServiceRecord r) {
10505 if (!mRestartingServices.contains(r)) {
10506 return;
10507 }
10508 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10509 }
10510
10511 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10512 if (r.restartDelay == 0) {
10513 return false;
10514 }
10515 r.resetRestartCounter();
10516 mRestartingServices.remove(r);
10517 mHandler.removeCallbacks(r.restarter);
10518 return true;
10519 }
10520
10521 private final boolean bringUpServiceLocked(ServiceRecord r,
10522 int intentFlags, boolean whileRestarting) {
10523 //Log.i(TAG, "Bring up service:");
10524 //r.dump(" ");
10525
Dianne Hackborn36124872009-10-08 16:22:03 -070010526 if (r.app != null && r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010527 sendServiceArgsLocked(r, false);
10528 return true;
10529 }
10530
10531 if (!whileRestarting && r.restartDelay > 0) {
10532 // If waiting for a restart, then do nothing.
10533 return true;
10534 }
10535
10536 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10537 + " " + r.intent);
10538
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010539 // We are now bringing the service up, so no longer in the
10540 // restarting state.
10541 mRestartingServices.remove(r);
10542
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010543 final String appName = r.processName;
10544 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10545 if (app != null && app.thread != null) {
10546 try {
10547 realStartServiceLocked(r, app);
10548 return true;
10549 } catch (RemoteException e) {
10550 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10551 }
10552
10553 // If a dead object exception was thrown -- fall through to
10554 // restart the application.
10555 }
10556
Dianne Hackborn36124872009-10-08 16:22:03 -070010557 // Not running -- get it started, and enqueue this service record
10558 // to be executed when the app comes up.
10559 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10560 "service", r.name, false) == null) {
10561 Log.w(TAG, "Unable to launch app "
10562 + r.appInfo.packageName + "/"
10563 + r.appInfo.uid + " for service "
10564 + r.intent.getIntent() + ": process is bad");
10565 bringDownServiceLocked(r, true);
10566 return false;
10567 }
10568
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010569 if (!mPendingServices.contains(r)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010570 mPendingServices.add(r);
10571 }
Dianne Hackborn36124872009-10-08 16:22:03 -070010572
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010573 return true;
10574 }
10575
10576 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10577 //Log.i(TAG, "Bring down service:");
10578 //r.dump(" ");
10579
10580 // Does it still need to run?
10581 if (!force && r.startRequested) {
10582 return;
10583 }
10584 if (r.connections.size() > 0) {
10585 if (!force) {
10586 // XXX should probably keep a count of the number of auto-create
10587 // connections directly in the service.
10588 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10589 while (it.hasNext()) {
10590 ConnectionRecord cr = it.next();
10591 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10592 return;
10593 }
10594 }
10595 }
10596
10597 // Report to all of the connections that the service is no longer
10598 // available.
10599 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10600 while (it.hasNext()) {
10601 ConnectionRecord c = it.next();
10602 try {
10603 // todo: shouldn't be a synchronous call!
10604 c.conn.connected(r.name, null);
10605 } catch (Exception e) {
10606 Log.w(TAG, "Failure disconnecting service " + r.name +
10607 " to connection " + c.conn.asBinder() +
10608 " (in " + c.binding.client.processName + ")", e);
10609 }
10610 }
10611 }
10612
10613 // Tell the service that it has been unbound.
10614 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10615 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10616 while (it.hasNext()) {
10617 IntentBindRecord ibr = it.next();
10618 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10619 + ": hasBound=" + ibr.hasBound);
10620 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10621 try {
10622 bumpServiceExecutingLocked(r);
10623 updateOomAdjLocked(r.app);
10624 ibr.hasBound = false;
10625 r.app.thread.scheduleUnbindService(r,
10626 ibr.intent.getIntent());
10627 } catch (Exception e) {
10628 Log.w(TAG, "Exception when unbinding service "
10629 + r.shortName, e);
10630 serviceDoneExecutingLocked(r, true);
10631 }
10632 }
10633 }
10634 }
10635
10636 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10637 + " " + r.intent);
10638 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10639 System.identityHashCode(r), r.shortName,
10640 (r.app != null) ? r.app.pid : -1);
10641
10642 mServices.remove(r.name);
10643 mServicesByIntent.remove(r.intent);
10644 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10645 r.totalRestartCount = 0;
10646 unscheduleServiceRestartLocked(r);
10647
10648 // Also make sure it is not on the pending list.
10649 int N = mPendingServices.size();
10650 for (int i=0; i<N; i++) {
10651 if (mPendingServices.get(i) == r) {
10652 mPendingServices.remove(i);
10653 if (DEBUG_SERVICE) Log.v(
10654 TAG, "Removed pending service: " + r.shortName);
10655 i--;
10656 N--;
10657 }
10658 }
10659
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010660 r.cancelNotification();
10661 r.isForeground = false;
10662 r.foregroundId = 0;
10663 r.foregroundNoti = null;
10664
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010665 // Clear start entries.
10666 r.deliveredStarts.clear();
10667 r.pendingStarts.clear();
10668
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010669 if (r.app != null) {
10670 synchronized (r.stats.getBatteryStats()) {
10671 r.stats.stopLaunchedLocked();
10672 }
10673 r.app.services.remove(r);
10674 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010675 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010676 if (DEBUG_SERVICE) Log.v(TAG,
10677 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010678 bumpServiceExecutingLocked(r);
10679 mStoppingServices.add(r);
10680 updateOomAdjLocked(r.app);
10681 r.app.thread.scheduleStopService(r);
10682 } catch (Exception e) {
10683 Log.w(TAG, "Exception when stopping service "
10684 + r.shortName, e);
10685 serviceDoneExecutingLocked(r, true);
10686 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010687 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010688 } else {
10689 if (DEBUG_SERVICE) Log.v(
10690 TAG, "Removed service that has no process: " + r.shortName);
10691 }
10692 } else {
10693 if (DEBUG_SERVICE) Log.v(
10694 TAG, "Removed service that is not running: " + r.shortName);
10695 }
10696 }
10697
10698 ComponentName startServiceLocked(IApplicationThread caller,
10699 Intent service, String resolvedType,
10700 int callingPid, int callingUid) {
10701 synchronized(this) {
10702 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10703 + " type=" + resolvedType + " args=" + service.getExtras());
10704
10705 if (caller != null) {
10706 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10707 if (callerApp == null) {
10708 throw new SecurityException(
10709 "Unable to find app for caller " + caller
10710 + " (pid=" + Binder.getCallingPid()
10711 + ") when starting service " + service);
10712 }
10713 }
10714
10715 ServiceLookupResult res =
10716 retrieveServiceLocked(service, resolvedType,
10717 callingPid, callingUid);
10718 if (res == null) {
10719 return null;
10720 }
10721 if (res.record == null) {
10722 return new ComponentName("!", res.permission != null
10723 ? res.permission : "private to package");
10724 }
10725 ServiceRecord r = res.record;
10726 if (unscheduleServiceRestartLocked(r)) {
10727 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10728 + r.shortName);
10729 }
10730 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010731 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010732 r.lastStartId++;
10733 if (r.lastStartId < 1) {
10734 r.lastStartId = 1;
10735 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010736 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010737 r.lastActivity = SystemClock.uptimeMillis();
10738 synchronized (r.stats.getBatteryStats()) {
10739 r.stats.startRunningLocked();
10740 }
10741 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10742 return new ComponentName("!", "Service process is bad");
10743 }
10744 return r.name;
10745 }
10746 }
10747
10748 public ComponentName startService(IApplicationThread caller, Intent service,
10749 String resolvedType) {
10750 // Refuse possible leaked file descriptors
10751 if (service != null && service.hasFileDescriptors() == true) {
10752 throw new IllegalArgumentException("File descriptors passed in Intent");
10753 }
10754
10755 synchronized(this) {
10756 final int callingPid = Binder.getCallingPid();
10757 final int callingUid = Binder.getCallingUid();
10758 final long origId = Binder.clearCallingIdentity();
10759 ComponentName res = startServiceLocked(caller, service,
10760 resolvedType, callingPid, callingUid);
10761 Binder.restoreCallingIdentity(origId);
10762 return res;
10763 }
10764 }
10765
10766 ComponentName startServiceInPackage(int uid,
10767 Intent service, String resolvedType) {
10768 synchronized(this) {
10769 final long origId = Binder.clearCallingIdentity();
10770 ComponentName res = startServiceLocked(null, service,
10771 resolvedType, -1, uid);
10772 Binder.restoreCallingIdentity(origId);
10773 return res;
10774 }
10775 }
10776
10777 public int stopService(IApplicationThread caller, Intent service,
10778 String resolvedType) {
10779 // Refuse possible leaked file descriptors
10780 if (service != null && service.hasFileDescriptors() == true) {
10781 throw new IllegalArgumentException("File descriptors passed in Intent");
10782 }
10783
10784 synchronized(this) {
10785 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10786 + " type=" + resolvedType);
10787
10788 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10789 if (caller != null && callerApp == null) {
10790 throw new SecurityException(
10791 "Unable to find app for caller " + caller
10792 + " (pid=" + Binder.getCallingPid()
10793 + ") when stopping service " + service);
10794 }
10795
10796 // If this service is active, make sure it is stopped.
10797 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10798 if (r != null) {
10799 if (r.record != null) {
10800 synchronized (r.record.stats.getBatteryStats()) {
10801 r.record.stats.stopRunningLocked();
10802 }
10803 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010804 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010805 final long origId = Binder.clearCallingIdentity();
10806 bringDownServiceLocked(r.record, false);
10807 Binder.restoreCallingIdentity(origId);
10808 return 1;
10809 }
10810 return -1;
10811 }
10812 }
10813
10814 return 0;
10815 }
10816
10817 public IBinder peekService(Intent service, String resolvedType) {
10818 // Refuse possible leaked file descriptors
10819 if (service != null && service.hasFileDescriptors() == true) {
10820 throw new IllegalArgumentException("File descriptors passed in Intent");
10821 }
10822
10823 IBinder ret = null;
10824
10825 synchronized(this) {
10826 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10827
10828 if (r != null) {
10829 // r.record is null if findServiceLocked() failed the caller permission check
10830 if (r.record == null) {
10831 throw new SecurityException(
10832 "Permission Denial: Accessing service " + r.record.name
10833 + " from pid=" + Binder.getCallingPid()
10834 + ", uid=" + Binder.getCallingUid()
10835 + " requires " + r.permission);
10836 }
10837 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10838 if (ib != null) {
10839 ret = ib.binder;
10840 }
10841 }
10842 }
10843
10844 return ret;
10845 }
10846
10847 public boolean stopServiceToken(ComponentName className, IBinder token,
10848 int startId) {
10849 synchronized(this) {
10850 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10851 + " " + token + " startId=" + startId);
10852 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010853 if (r != null) {
10854 if (startId >= 0) {
10855 // Asked to only stop if done with all work. Note that
10856 // to avoid leaks, we will take this as dropping all
10857 // start items up to and including this one.
10858 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10859 if (si != null) {
10860 while (r.deliveredStarts.size() > 0) {
10861 if (r.deliveredStarts.remove(0) == si) {
10862 break;
10863 }
10864 }
10865 }
10866
10867 if (r.lastStartId != startId) {
10868 return false;
10869 }
10870
10871 if (r.deliveredStarts.size() > 0) {
10872 Log.w(TAG, "stopServiceToken startId " + startId
10873 + " is last, but have " + r.deliveredStarts.size()
10874 + " remaining args");
10875 }
10876 }
10877
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010878 synchronized (r.stats.getBatteryStats()) {
10879 r.stats.stopRunningLocked();
10880 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010881 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010882 }
10883 final long origId = Binder.clearCallingIdentity();
10884 bringDownServiceLocked(r, false);
10885 Binder.restoreCallingIdentity(origId);
10886 return true;
10887 }
10888 }
10889 return false;
10890 }
10891
10892 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010893 int id, Notification notification, boolean removeNotification) {
10894 final long origId = Binder.clearCallingIdentity();
10895 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010896 synchronized(this) {
10897 ServiceRecord r = findServiceLocked(className, token);
10898 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010899 if (id != 0) {
10900 if (notification == null) {
10901 throw new IllegalArgumentException("null notification");
10902 }
10903 if (r.foregroundId != id) {
10904 r.cancelNotification();
10905 r.foregroundId = id;
10906 }
10907 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10908 r.foregroundNoti = notification;
10909 r.isForeground = true;
10910 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010911 if (r.app != null) {
10912 updateServiceForegroundLocked(r.app, true);
10913 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010914 } else {
10915 if (r.isForeground) {
10916 r.isForeground = false;
10917 if (r.app != null) {
10918 updateServiceForegroundLocked(r.app, true);
10919 }
10920 }
10921 if (removeNotification) {
10922 r.cancelNotification();
10923 r.foregroundId = 0;
10924 r.foregroundNoti = null;
10925 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010926 }
10927 }
10928 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010929 } finally {
10930 Binder.restoreCallingIdentity(origId);
10931 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010932 }
10933
10934 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10935 boolean anyForeground = false;
10936 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10937 if (sr.isForeground) {
10938 anyForeground = true;
10939 break;
10940 }
10941 }
10942 if (anyForeground != proc.foregroundServices) {
10943 proc.foregroundServices = anyForeground;
10944 if (oomAdj) {
10945 updateOomAdjLocked();
10946 }
10947 }
10948 }
10949
10950 public int bindService(IApplicationThread caller, IBinder token,
10951 Intent service, String resolvedType,
10952 IServiceConnection connection, int flags) {
10953 // Refuse possible leaked file descriptors
10954 if (service != null && service.hasFileDescriptors() == true) {
10955 throw new IllegalArgumentException("File descriptors passed in Intent");
10956 }
10957
10958 synchronized(this) {
10959 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10960 + " type=" + resolvedType + " conn=" + connection.asBinder()
10961 + " flags=0x" + Integer.toHexString(flags));
10962 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10963 if (callerApp == null) {
10964 throw new SecurityException(
10965 "Unable to find app for caller " + caller
10966 + " (pid=" + Binder.getCallingPid()
10967 + ") when binding service " + service);
10968 }
10969
10970 HistoryRecord activity = null;
10971 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010972 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010973 if (aindex < 0) {
10974 Log.w(TAG, "Binding with unknown activity: " + token);
10975 return 0;
10976 }
10977 activity = (HistoryRecord)mHistory.get(aindex);
10978 }
10979
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010980 int clientLabel = 0;
10981 PendingIntent clientIntent = null;
10982
10983 if (callerApp.info.uid == Process.SYSTEM_UID) {
10984 // Hacky kind of thing -- allow system stuff to tell us
10985 // what they are, so we can report this elsewhere for
10986 // others to know why certain services are running.
10987 try {
10988 clientIntent = (PendingIntent)service.getParcelableExtra(
10989 Intent.EXTRA_CLIENT_INTENT);
10990 } catch (RuntimeException e) {
10991 }
10992 if (clientIntent != null) {
10993 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
10994 if (clientLabel != 0) {
10995 // There are no useful extras in the intent, trash them.
10996 // System code calling with this stuff just needs to know
10997 // this will happen.
10998 service = service.cloneFilter();
10999 }
11000 }
11001 }
11002
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011003 ServiceLookupResult res =
11004 retrieveServiceLocked(service, resolvedType,
11005 Binder.getCallingPid(), Binder.getCallingUid());
11006 if (res == null) {
11007 return 0;
11008 }
11009 if (res.record == null) {
11010 return -1;
11011 }
11012 ServiceRecord s = res.record;
11013
11014 final long origId = Binder.clearCallingIdentity();
11015
11016 if (unscheduleServiceRestartLocked(s)) {
11017 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
11018 + s.shortName);
11019 }
11020
11021 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
11022 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011023 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011024
11025 IBinder binder = connection.asBinder();
11026 s.connections.put(binder, c);
11027 b.connections.add(c);
11028 if (activity != null) {
11029 if (activity.connections == null) {
11030 activity.connections = new HashSet<ConnectionRecord>();
11031 }
11032 activity.connections.add(c);
11033 }
11034 b.client.connections.add(c);
11035 mServiceConnections.put(binder, c);
11036
11037 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11038 s.lastActivity = SystemClock.uptimeMillis();
11039 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11040 return 0;
11041 }
11042 }
11043
11044 if (s.app != null) {
11045 // This could have made the service more important.
11046 updateOomAdjLocked(s.app);
11047 }
11048
11049 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11050 + ": received=" + b.intent.received
11051 + " apps=" + b.intent.apps.size()
11052 + " doRebind=" + b.intent.doRebind);
11053
11054 if (s.app != null && b.intent.received) {
11055 // Service is already running, so we can immediately
11056 // publish the connection.
11057 try {
11058 c.conn.connected(s.name, b.intent.binder);
11059 } catch (Exception e) {
11060 Log.w(TAG, "Failure sending service " + s.shortName
11061 + " to connection " + c.conn.asBinder()
11062 + " (in " + c.binding.client.processName + ")", e);
11063 }
11064
11065 // If this is the first app connected back to this binding,
11066 // and the service had previously asked to be told when
11067 // rebound, then do so.
11068 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11069 requestServiceBindingLocked(s, b.intent, true);
11070 }
11071 } else if (!b.intent.requested) {
11072 requestServiceBindingLocked(s, b.intent, false);
11073 }
11074
11075 Binder.restoreCallingIdentity(origId);
11076 }
11077
11078 return 1;
11079 }
11080
11081 private void removeConnectionLocked(
11082 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11083 IBinder binder = c.conn.asBinder();
11084 AppBindRecord b = c.binding;
11085 ServiceRecord s = b.service;
11086 s.connections.remove(binder);
11087 b.connections.remove(c);
11088 if (c.activity != null && c.activity != skipAct) {
11089 if (c.activity.connections != null) {
11090 c.activity.connections.remove(c);
11091 }
11092 }
11093 if (b.client != skipApp) {
11094 b.client.connections.remove(c);
11095 }
11096 mServiceConnections.remove(binder);
11097
11098 if (b.connections.size() == 0) {
11099 b.intent.apps.remove(b.client);
11100 }
11101
11102 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11103 + ": shouldUnbind=" + b.intent.hasBound);
11104 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11105 && b.intent.hasBound) {
11106 try {
11107 bumpServiceExecutingLocked(s);
11108 updateOomAdjLocked(s.app);
11109 b.intent.hasBound = false;
11110 // Assume the client doesn't want to know about a rebind;
11111 // we will deal with that later if it asks for one.
11112 b.intent.doRebind = false;
11113 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11114 } catch (Exception e) {
11115 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11116 serviceDoneExecutingLocked(s, true);
11117 }
11118 }
11119
11120 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11121 bringDownServiceLocked(s, false);
11122 }
11123 }
11124
11125 public boolean unbindService(IServiceConnection connection) {
11126 synchronized (this) {
11127 IBinder binder = connection.asBinder();
11128 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11129 ConnectionRecord r = mServiceConnections.get(binder);
11130 if (r == null) {
11131 Log.w(TAG, "Unbind failed: could not find connection for "
11132 + connection.asBinder());
11133 return false;
11134 }
11135
11136 final long origId = Binder.clearCallingIdentity();
11137
11138 removeConnectionLocked(r, null, null);
11139
11140 if (r.binding.service.app != null) {
11141 // This could have made the service less important.
11142 updateOomAdjLocked(r.binding.service.app);
11143 }
11144
11145 Binder.restoreCallingIdentity(origId);
11146 }
11147
11148 return true;
11149 }
11150
11151 public void publishService(IBinder token, Intent intent, IBinder service) {
11152 // Refuse possible leaked file descriptors
11153 if (intent != null && intent.hasFileDescriptors() == true) {
11154 throw new IllegalArgumentException("File descriptors passed in Intent");
11155 }
11156
11157 synchronized(this) {
11158 if (!(token instanceof ServiceRecord)) {
11159 throw new IllegalArgumentException("Invalid service token");
11160 }
11161 ServiceRecord r = (ServiceRecord)token;
11162
11163 final long origId = Binder.clearCallingIdentity();
11164
11165 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11166 + " " + intent + ": " + service);
11167 if (r != null) {
11168 Intent.FilterComparison filter
11169 = new Intent.FilterComparison(intent);
11170 IntentBindRecord b = r.bindings.get(filter);
11171 if (b != null && !b.received) {
11172 b.binder = service;
11173 b.requested = true;
11174 b.received = true;
11175 if (r.connections.size() > 0) {
11176 Iterator<ConnectionRecord> it
11177 = r.connections.values().iterator();
11178 while (it.hasNext()) {
11179 ConnectionRecord c = it.next();
11180 if (!filter.equals(c.binding.intent.intent)) {
11181 if (DEBUG_SERVICE) Log.v(
11182 TAG, "Not publishing to: " + c);
11183 if (DEBUG_SERVICE) Log.v(
11184 TAG, "Bound intent: " + c.binding.intent.intent);
11185 if (DEBUG_SERVICE) Log.v(
11186 TAG, "Published intent: " + intent);
11187 continue;
11188 }
11189 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11190 try {
11191 c.conn.connected(r.name, service);
11192 } catch (Exception e) {
11193 Log.w(TAG, "Failure sending service " + r.name +
11194 " to connection " + c.conn.asBinder() +
11195 " (in " + c.binding.client.processName + ")", e);
11196 }
11197 }
11198 }
11199 }
11200
11201 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11202
11203 Binder.restoreCallingIdentity(origId);
11204 }
11205 }
11206 }
11207
11208 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11209 // Refuse possible leaked file descriptors
11210 if (intent != null && intent.hasFileDescriptors() == true) {
11211 throw new IllegalArgumentException("File descriptors passed in Intent");
11212 }
11213
11214 synchronized(this) {
11215 if (!(token instanceof ServiceRecord)) {
11216 throw new IllegalArgumentException("Invalid service token");
11217 }
11218 ServiceRecord r = (ServiceRecord)token;
11219
11220 final long origId = Binder.clearCallingIdentity();
11221
11222 if (r != null) {
11223 Intent.FilterComparison filter
11224 = new Intent.FilterComparison(intent);
11225 IntentBindRecord b = r.bindings.get(filter);
11226 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11227 + " at " + b + ": apps="
11228 + (b != null ? b.apps.size() : 0));
11229 if (b != null) {
11230 if (b.apps.size() > 0) {
11231 // Applications have already bound since the last
11232 // unbind, so just rebind right here.
11233 requestServiceBindingLocked(r, b, true);
11234 } else {
11235 // Note to tell the service the next time there is
11236 // a new client.
11237 b.doRebind = true;
11238 }
11239 }
11240
11241 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11242
11243 Binder.restoreCallingIdentity(origId);
11244 }
11245 }
11246 }
11247
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011248 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011249 synchronized(this) {
11250 if (!(token instanceof ServiceRecord)) {
11251 throw new IllegalArgumentException("Invalid service token");
11252 }
11253 ServiceRecord r = (ServiceRecord)token;
11254 boolean inStopping = mStoppingServices.contains(token);
11255 if (r != null) {
11256 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11257 + ": nesting=" + r.executeNesting
11258 + ", inStopping=" + inStopping);
11259 if (r != token) {
11260 Log.w(TAG, "Done executing service " + r.name
11261 + " with incorrect token: given " + token
11262 + ", expected " + r);
11263 return;
11264 }
11265
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011266 if (type == 1) {
11267 // This is a call from a service start... take care of
11268 // book-keeping.
11269 r.callStart = true;
11270 switch (res) {
11271 case Service.START_STICKY_COMPATIBILITY:
11272 case Service.START_STICKY: {
11273 // We are done with the associated start arguments.
11274 r.findDeliveredStart(startId, true);
11275 // Don't stop if killed.
11276 r.stopIfKilled = false;
11277 break;
11278 }
11279 case Service.START_NOT_STICKY: {
11280 // We are done with the associated start arguments.
11281 r.findDeliveredStart(startId, true);
11282 if (r.lastStartId == startId) {
11283 // There is no more work, and this service
11284 // doesn't want to hang around if killed.
11285 r.stopIfKilled = true;
11286 }
11287 break;
11288 }
11289 case Service.START_REDELIVER_INTENT: {
11290 // We'll keep this item until they explicitly
11291 // call stop for it, but keep track of the fact
11292 // that it was delivered.
11293 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11294 if (si != null) {
11295 si.deliveryCount = 0;
11296 si.doneExecutingCount++;
11297 // Don't stop if killed.
11298 r.stopIfKilled = true;
11299 }
11300 break;
11301 }
11302 default:
11303 throw new IllegalArgumentException(
11304 "Unknown service start result: " + res);
11305 }
11306 if (res == Service.START_STICKY_COMPATIBILITY) {
11307 r.callStart = false;
11308 }
11309 }
11310
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011311 final long origId = Binder.clearCallingIdentity();
11312 serviceDoneExecutingLocked(r, inStopping);
11313 Binder.restoreCallingIdentity(origId);
11314 } else {
11315 Log.w(TAG, "Done executing unknown service " + r.name
11316 + " with token " + token);
11317 }
11318 }
11319 }
11320
11321 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11322 r.executeNesting--;
11323 if (r.executeNesting <= 0 && r.app != null) {
11324 r.app.executingServices.remove(r);
11325 if (r.app.executingServices.size() == 0) {
11326 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11327 }
11328 if (inStopping) {
11329 mStoppingServices.remove(r);
11330 }
11331 updateOomAdjLocked(r.app);
11332 }
11333 }
11334
11335 void serviceTimeout(ProcessRecord proc) {
11336 synchronized(this) {
11337 if (proc.executingServices.size() == 0 || proc.thread == null) {
11338 return;
11339 }
11340 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11341 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11342 ServiceRecord timeout = null;
11343 long nextTime = 0;
11344 while (it.hasNext()) {
11345 ServiceRecord sr = it.next();
11346 if (sr.executingStart < maxTime) {
11347 timeout = sr;
11348 break;
11349 }
11350 if (sr.executingStart > nextTime) {
11351 nextTime = sr.executingStart;
11352 }
11353 }
11354 if (timeout != null && mLRUProcesses.contains(proc)) {
11355 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011356 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011357 + timeout.name);
11358 } else {
11359 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11360 msg.obj = proc;
11361 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11362 }
11363 }
11364 }
11365
11366 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011367 // BACKUP AND RESTORE
11368 // =========================================================
11369
11370 // Cause the target app to be launched if necessary and its backup agent
11371 // instantiated. The backup agent will invoke backupAgentCreated() on the
11372 // activity manager to announce its creation.
11373 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11374 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11375 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11376
11377 synchronized(this) {
11378 // !!! TODO: currently no check here that we're already bound
11379 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11380 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11381 synchronized (stats) {
11382 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11383 }
11384
11385 BackupRecord r = new BackupRecord(ss, app, backupMode);
11386 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11387 // startProcessLocked() returns existing proc's record if it's already running
11388 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011389 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011390 if (proc == null) {
11391 Log.e(TAG, "Unable to start backup agent process " + r);
11392 return false;
11393 }
11394
11395 r.app = proc;
11396 mBackupTarget = r;
11397 mBackupAppName = app.packageName;
11398
Christopher Tate6fa95972009-06-05 18:43:55 -070011399 // Try not to kill the process during backup
11400 updateOomAdjLocked(proc);
11401
Christopher Tate181fafa2009-05-14 11:12:14 -070011402 // If the process is already attached, schedule the creation of the backup agent now.
11403 // If it is not yet live, this will be done when it attaches to the framework.
11404 if (proc.thread != null) {
11405 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11406 try {
11407 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11408 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011409 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011410 }
11411 } else {
11412 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11413 }
11414 // Invariants: at this point, the target app process exists and the application
11415 // is either already running or in the process of coming up. mBackupTarget and
11416 // mBackupAppName describe the app, so that when it binds back to the AM we
11417 // know that it's scheduled for a backup-agent operation.
11418 }
11419
11420 return true;
11421 }
11422
11423 // A backup agent has just come up
11424 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11425 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11426 + " = " + agent);
11427
11428 synchronized(this) {
11429 if (!agentPackageName.equals(mBackupAppName)) {
11430 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11431 return;
11432 }
11433
Christopher Tate043dadc2009-06-02 16:11:00 -070011434 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011435 try {
11436 IBackupManager bm = IBackupManager.Stub.asInterface(
11437 ServiceManager.getService(Context.BACKUP_SERVICE));
11438 bm.agentConnected(agentPackageName, agent);
11439 } catch (RemoteException e) {
11440 // can't happen; the backup manager service is local
11441 } catch (Exception e) {
11442 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11443 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011444 } finally {
11445 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011446 }
11447 }
11448 }
11449
11450 // done with this agent
11451 public void unbindBackupAgent(ApplicationInfo appInfo) {
11452 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011453 if (appInfo == null) {
11454 Log.w(TAG, "unbind backup agent for null app");
11455 return;
11456 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011457
11458 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011459 if (mBackupAppName == null) {
11460 Log.w(TAG, "Unbinding backup agent with no active backup");
11461 return;
11462 }
11463
Christopher Tate181fafa2009-05-14 11:12:14 -070011464 if (!mBackupAppName.equals(appInfo.packageName)) {
11465 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11466 return;
11467 }
11468
Christopher Tate6fa95972009-06-05 18:43:55 -070011469 ProcessRecord proc = mBackupTarget.app;
11470 mBackupTarget = null;
11471 mBackupAppName = null;
11472
11473 // Not backing this app up any more; reset its OOM adjustment
11474 updateOomAdjLocked(proc);
11475
Christopher Tatec7b31e32009-06-10 15:49:30 -070011476 // If the app crashed during backup, 'thread' will be null here
11477 if (proc.thread != null) {
11478 try {
11479 proc.thread.scheduleDestroyBackupAgent(appInfo);
11480 } catch (Exception e) {
11481 Log.e(TAG, "Exception when unbinding backup agent:");
11482 e.printStackTrace();
11483 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011484 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011485 }
11486 }
11487 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011488 // BROADCASTS
11489 // =========================================================
11490
11491 private final List getStickies(String action, IntentFilter filter,
11492 List cur) {
11493 final ContentResolver resolver = mContext.getContentResolver();
11494 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11495 if (list == null) {
11496 return cur;
11497 }
11498 int N = list.size();
11499 for (int i=0; i<N; i++) {
11500 Intent intent = list.get(i);
11501 if (filter.match(resolver, intent, true, TAG) >= 0) {
11502 if (cur == null) {
11503 cur = new ArrayList<Intent>();
11504 }
11505 cur.add(intent);
11506 }
11507 }
11508 return cur;
11509 }
11510
11511 private final void scheduleBroadcastsLocked() {
11512 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11513 + mBroadcastsScheduled);
11514
11515 if (mBroadcastsScheduled) {
11516 return;
11517 }
11518 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11519 mBroadcastsScheduled = true;
11520 }
11521
11522 public Intent registerReceiver(IApplicationThread caller,
11523 IIntentReceiver receiver, IntentFilter filter, String permission) {
11524 synchronized(this) {
11525 ProcessRecord callerApp = null;
11526 if (caller != null) {
11527 callerApp = getRecordForAppLocked(caller);
11528 if (callerApp == null) {
11529 throw new SecurityException(
11530 "Unable to find app for caller " + caller
11531 + " (pid=" + Binder.getCallingPid()
11532 + ") when registering receiver " + receiver);
11533 }
11534 }
11535
11536 List allSticky = null;
11537
11538 // Look for any matching sticky broadcasts...
11539 Iterator actions = filter.actionsIterator();
11540 if (actions != null) {
11541 while (actions.hasNext()) {
11542 String action = (String)actions.next();
11543 allSticky = getStickies(action, filter, allSticky);
11544 }
11545 } else {
11546 allSticky = getStickies(null, filter, allSticky);
11547 }
11548
11549 // The first sticky in the list is returned directly back to
11550 // the client.
11551 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11552
11553 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11554 + ": " + sticky);
11555
11556 if (receiver == null) {
11557 return sticky;
11558 }
11559
11560 ReceiverList rl
11561 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11562 if (rl == null) {
11563 rl = new ReceiverList(this, callerApp,
11564 Binder.getCallingPid(),
11565 Binder.getCallingUid(), receiver);
11566 if (rl.app != null) {
11567 rl.app.receivers.add(rl);
11568 } else {
11569 try {
11570 receiver.asBinder().linkToDeath(rl, 0);
11571 } catch (RemoteException e) {
11572 return sticky;
11573 }
11574 rl.linkedToDeath = true;
11575 }
11576 mRegisteredReceivers.put(receiver.asBinder(), rl);
11577 }
11578 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11579 rl.add(bf);
11580 if (!bf.debugCheck()) {
11581 Log.w(TAG, "==> For Dynamic broadast");
11582 }
11583 mReceiverResolver.addFilter(bf);
11584
11585 // Enqueue broadcasts for all existing stickies that match
11586 // this filter.
11587 if (allSticky != null) {
11588 ArrayList receivers = new ArrayList();
11589 receivers.add(bf);
11590
11591 int N = allSticky.size();
11592 for (int i=0; i<N; i++) {
11593 Intent intent = (Intent)allSticky.get(i);
11594 BroadcastRecord r = new BroadcastRecord(intent, null,
11595 null, -1, -1, null, receivers, null, 0, null, null,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070011596 false, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011597 if (mParallelBroadcasts.size() == 0) {
11598 scheduleBroadcastsLocked();
11599 }
11600 mParallelBroadcasts.add(r);
11601 }
11602 }
11603
11604 return sticky;
11605 }
11606 }
11607
11608 public void unregisterReceiver(IIntentReceiver receiver) {
11609 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11610
11611 boolean doNext = false;
11612
11613 synchronized(this) {
11614 ReceiverList rl
11615 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11616 if (rl != null) {
11617 if (rl.curBroadcast != null) {
11618 BroadcastRecord r = rl.curBroadcast;
11619 doNext = finishReceiverLocked(
11620 receiver.asBinder(), r.resultCode, r.resultData,
11621 r.resultExtras, r.resultAbort, true);
11622 }
11623
11624 if (rl.app != null) {
11625 rl.app.receivers.remove(rl);
11626 }
11627 removeReceiverLocked(rl);
11628 if (rl.linkedToDeath) {
11629 rl.linkedToDeath = false;
11630 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11631 }
11632 }
11633 }
11634
11635 if (!doNext) {
11636 return;
11637 }
11638
11639 final long origId = Binder.clearCallingIdentity();
11640 processNextBroadcast(false);
11641 trimApplications();
11642 Binder.restoreCallingIdentity(origId);
11643 }
11644
11645 void removeReceiverLocked(ReceiverList rl) {
11646 mRegisteredReceivers.remove(rl.receiver.asBinder());
11647 int N = rl.size();
11648 for (int i=0; i<N; i++) {
11649 mReceiverResolver.removeFilter(rl.get(i));
11650 }
11651 }
11652
11653 private final int broadcastIntentLocked(ProcessRecord callerApp,
11654 String callerPackage, Intent intent, String resolvedType,
11655 IIntentReceiver resultTo, int resultCode, String resultData,
11656 Bundle map, String requiredPermission,
11657 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11658 intent = new Intent(intent);
11659
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011660 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011661 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11662 + " ordered=" + ordered);
11663 if ((resultTo != null) && !ordered) {
11664 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11665 }
11666
11667 // Handle special intents: if this broadcast is from the package
11668 // manager about a package being removed, we need to remove all of
11669 // its activities from the history stack.
11670 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11671 intent.getAction());
11672 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11673 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11674 || uidRemoved) {
11675 if (checkComponentPermission(
11676 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11677 callingPid, callingUid, -1)
11678 == PackageManager.PERMISSION_GRANTED) {
11679 if (uidRemoved) {
11680 final Bundle intentExtras = intent.getExtras();
11681 final int uid = intentExtras != null
11682 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11683 if (uid >= 0) {
11684 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11685 synchronized (bs) {
11686 bs.removeUidStatsLocked(uid);
11687 }
11688 }
11689 } else {
11690 Uri data = intent.getData();
11691 String ssp;
11692 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11693 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11694 uninstallPackageLocked(ssp,
11695 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011696 AttributeCache ac = AttributeCache.instance();
11697 if (ac != null) {
11698 ac.removePackage(ssp);
11699 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011700 }
11701 }
11702 }
11703 } else {
11704 String msg = "Permission Denial: " + intent.getAction()
11705 + " broadcast from " + callerPackage + " (pid=" + callingPid
11706 + ", uid=" + callingUid + ")"
11707 + " requires "
11708 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11709 Log.w(TAG, msg);
11710 throw new SecurityException(msg);
11711 }
11712 }
11713
11714 /*
11715 * If this is the time zone changed action, queue up a message that will reset the timezone
11716 * of all currently running processes. This message will get queued up before the broadcast
11717 * happens.
11718 */
11719 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11720 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11721 }
11722
Dianne Hackborn854060af2009-07-09 18:14:31 -070011723 /*
11724 * Prevent non-system code (defined here to be non-persistent
11725 * processes) from sending protected broadcasts.
11726 */
11727 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11728 || callingUid == Process.SHELL_UID || callingUid == 0) {
11729 // Always okay.
11730 } else if (callerApp == null || !callerApp.persistent) {
11731 try {
11732 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11733 intent.getAction())) {
11734 String msg = "Permission Denial: not allowed to send broadcast "
11735 + intent.getAction() + " from pid="
11736 + callingPid + ", uid=" + callingUid;
11737 Log.w(TAG, msg);
11738 throw new SecurityException(msg);
11739 }
11740 } catch (RemoteException e) {
11741 Log.w(TAG, "Remote exception", e);
11742 return BROADCAST_SUCCESS;
11743 }
11744 }
11745
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011746 // Add to the sticky list if requested.
11747 if (sticky) {
11748 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11749 callingPid, callingUid)
11750 != PackageManager.PERMISSION_GRANTED) {
11751 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11752 + callingPid + ", uid=" + callingUid
11753 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11754 Log.w(TAG, msg);
11755 throw new SecurityException(msg);
11756 }
11757 if (requiredPermission != null) {
11758 Log.w(TAG, "Can't broadcast sticky intent " + intent
11759 + " and enforce permission " + requiredPermission);
11760 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11761 }
11762 if (intent.getComponent() != null) {
11763 throw new SecurityException(
11764 "Sticky broadcasts can't target a specific component");
11765 }
11766 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11767 if (list == null) {
11768 list = new ArrayList<Intent>();
11769 mStickyBroadcasts.put(intent.getAction(), list);
11770 }
11771 int N = list.size();
11772 int i;
11773 for (i=0; i<N; i++) {
11774 if (intent.filterEquals(list.get(i))) {
11775 // This sticky already exists, replace it.
11776 list.set(i, new Intent(intent));
11777 break;
11778 }
11779 }
11780 if (i >= N) {
11781 list.add(new Intent(intent));
11782 }
11783 }
11784
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011785 // Figure out who all will receive this broadcast.
11786 List receivers = null;
11787 List<BroadcastFilter> registeredReceivers = null;
11788 try {
11789 if (intent.getComponent() != null) {
11790 // Broadcast is going to one specific receiver class...
11791 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011792 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011793 if (ai != null) {
11794 receivers = new ArrayList();
11795 ResolveInfo ri = new ResolveInfo();
11796 ri.activityInfo = ai;
11797 receivers.add(ri);
11798 }
11799 } else {
11800 // Need to resolve the intent to interested receivers...
11801 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11802 == 0) {
11803 receivers =
11804 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011805 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011806 }
Mihai Preda074edef2009-05-18 17:13:31 +020011807 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011808 }
11809 } catch (RemoteException ex) {
11810 // pm is in same process, this will never happen.
11811 }
11812
11813 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11814 if (!ordered && NR > 0) {
11815 // If we are not serializing this broadcast, then send the
11816 // registered receivers separately so they don't wait for the
11817 // components to be launched.
11818 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11819 callerPackage, callingPid, callingUid, requiredPermission,
11820 registeredReceivers, resultTo, resultCode, resultData, map,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070011821 ordered, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011822 if (DEBUG_BROADCAST) Log.v(
11823 TAG, "Enqueueing parallel broadcast " + r
11824 + ": prev had " + mParallelBroadcasts.size());
11825 mParallelBroadcasts.add(r);
11826 scheduleBroadcastsLocked();
11827 registeredReceivers = null;
11828 NR = 0;
11829 }
11830
11831 // Merge into one list.
11832 int ir = 0;
11833 if (receivers != null) {
11834 // A special case for PACKAGE_ADDED: do not allow the package
11835 // being added to see this broadcast. This prevents them from
11836 // using this as a back door to get run as soon as they are
11837 // installed. Maybe in the future we want to have a special install
11838 // broadcast or such for apps, but we'd like to deliberately make
11839 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011840 boolean skip = false;
11841 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011842 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011843 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11844 skip = true;
11845 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11846 skip = true;
11847 }
11848 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011849 ? intent.getData().getSchemeSpecificPart()
11850 : null;
11851 if (skipPackage != null && receivers != null) {
11852 int NT = receivers.size();
11853 for (int it=0; it<NT; it++) {
11854 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11855 if (curt.activityInfo.packageName.equals(skipPackage)) {
11856 receivers.remove(it);
11857 it--;
11858 NT--;
11859 }
11860 }
11861 }
11862
11863 int NT = receivers != null ? receivers.size() : 0;
11864 int it = 0;
11865 ResolveInfo curt = null;
11866 BroadcastFilter curr = null;
11867 while (it < NT && ir < NR) {
11868 if (curt == null) {
11869 curt = (ResolveInfo)receivers.get(it);
11870 }
11871 if (curr == null) {
11872 curr = registeredReceivers.get(ir);
11873 }
11874 if (curr.getPriority() >= curt.priority) {
11875 // Insert this broadcast record into the final list.
11876 receivers.add(it, curr);
11877 ir++;
11878 curr = null;
11879 it++;
11880 NT++;
11881 } else {
11882 // Skip to the next ResolveInfo in the final list.
11883 it++;
11884 curt = null;
11885 }
11886 }
11887 }
11888 while (ir < NR) {
11889 if (receivers == null) {
11890 receivers = new ArrayList();
11891 }
11892 receivers.add(registeredReceivers.get(ir));
11893 ir++;
11894 }
11895
11896 if ((receivers != null && receivers.size() > 0)
11897 || resultTo != null) {
11898 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11899 callerPackage, callingPid, callingUid, requiredPermission,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070011900 receivers, resultTo, resultCode, resultData, map, ordered, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011901 if (DEBUG_BROADCAST) Log.v(
11902 TAG, "Enqueueing ordered broadcast " + r
11903 + ": prev had " + mOrderedBroadcasts.size());
11904 if (DEBUG_BROADCAST) {
11905 int seq = r.intent.getIntExtra("seq", -1);
11906 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11907 }
11908 mOrderedBroadcasts.add(r);
11909 scheduleBroadcastsLocked();
11910 }
11911
11912 return BROADCAST_SUCCESS;
11913 }
11914
11915 public final int broadcastIntent(IApplicationThread caller,
11916 Intent intent, String resolvedType, IIntentReceiver resultTo,
11917 int resultCode, String resultData, Bundle map,
11918 String requiredPermission, boolean serialized, boolean sticky) {
11919 // Refuse possible leaked file descriptors
11920 if (intent != null && intent.hasFileDescriptors() == true) {
11921 throw new IllegalArgumentException("File descriptors passed in Intent");
11922 }
11923
11924 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011925 int flags = intent.getFlags();
11926
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011927 if (!mSystemReady) {
11928 // if the caller really truly claims to know what they're doing, go
11929 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011930 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11931 intent = new Intent(intent);
11932 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11933 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11934 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11935 + " before boot completion");
11936 throw new IllegalStateException("Cannot broadcast before boot completed");
11937 }
11938 }
11939
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011940 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
11941 throw new IllegalArgumentException(
11942 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
11943 }
11944
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011945 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11946 final int callingPid = Binder.getCallingPid();
11947 final int callingUid = Binder.getCallingUid();
11948 final long origId = Binder.clearCallingIdentity();
11949 int res = broadcastIntentLocked(callerApp,
11950 callerApp != null ? callerApp.info.packageName : null,
11951 intent, resolvedType, resultTo,
11952 resultCode, resultData, map, requiredPermission, serialized,
11953 sticky, callingPid, callingUid);
11954 Binder.restoreCallingIdentity(origId);
11955 return res;
11956 }
11957 }
11958
11959 int broadcastIntentInPackage(String packageName, int uid,
11960 Intent intent, String resolvedType, IIntentReceiver resultTo,
11961 int resultCode, String resultData, Bundle map,
11962 String requiredPermission, boolean serialized, boolean sticky) {
11963 synchronized(this) {
11964 final long origId = Binder.clearCallingIdentity();
11965 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11966 resultTo, resultCode, resultData, map, requiredPermission,
11967 serialized, sticky, -1, uid);
11968 Binder.restoreCallingIdentity(origId);
11969 return res;
11970 }
11971 }
11972
11973 public final void unbroadcastIntent(IApplicationThread caller,
11974 Intent intent) {
11975 // Refuse possible leaked file descriptors
11976 if (intent != null && intent.hasFileDescriptors() == true) {
11977 throw new IllegalArgumentException("File descriptors passed in Intent");
11978 }
11979
11980 synchronized(this) {
11981 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11982 != PackageManager.PERMISSION_GRANTED) {
11983 String msg = "Permission Denial: unbroadcastIntent() from pid="
11984 + Binder.getCallingPid()
11985 + ", uid=" + Binder.getCallingUid()
11986 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11987 Log.w(TAG, msg);
11988 throw new SecurityException(msg);
11989 }
11990 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11991 if (list != null) {
11992 int N = list.size();
11993 int i;
11994 for (i=0; i<N; i++) {
11995 if (intent.filterEquals(list.get(i))) {
11996 list.remove(i);
11997 break;
11998 }
11999 }
12000 }
12001 }
12002 }
12003
12004 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
12005 String resultData, Bundle resultExtras, boolean resultAbort,
12006 boolean explicit) {
12007 if (mOrderedBroadcasts.size() == 0) {
12008 if (explicit) {
12009 Log.w(TAG, "finishReceiver called but no pending broadcasts");
12010 }
12011 return false;
12012 }
12013 BroadcastRecord r = mOrderedBroadcasts.get(0);
12014 if (r.receiver == null) {
12015 if (explicit) {
12016 Log.w(TAG, "finishReceiver called but none active");
12017 }
12018 return false;
12019 }
12020 if (r.receiver != receiver) {
12021 Log.w(TAG, "finishReceiver called but active receiver is different");
12022 return false;
12023 }
12024 int state = r.state;
12025 r.state = r.IDLE;
12026 if (state == r.IDLE) {
12027 if (explicit) {
12028 Log.w(TAG, "finishReceiver called but state is IDLE");
12029 }
12030 }
12031 r.receiver = null;
12032 r.intent.setComponent(null);
12033 if (r.curApp != null) {
12034 r.curApp.curReceiver = null;
12035 }
12036 if (r.curFilter != null) {
12037 r.curFilter.receiverList.curBroadcast = null;
12038 }
12039 r.curFilter = null;
12040 r.curApp = null;
12041 r.curComponent = null;
12042 r.curReceiver = null;
12043 mPendingBroadcast = null;
12044
12045 r.resultCode = resultCode;
12046 r.resultData = resultData;
12047 r.resultExtras = resultExtras;
12048 r.resultAbort = resultAbort;
12049
12050 // We will process the next receiver right now if this is finishing
12051 // an app receiver (which is always asynchronous) or after we have
12052 // come back from calling a receiver.
12053 return state == BroadcastRecord.APP_RECEIVE
12054 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12055 }
12056
12057 public void finishReceiver(IBinder who, int resultCode, String resultData,
12058 Bundle resultExtras, boolean resultAbort) {
12059 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12060
12061 // Refuse possible leaked file descriptors
12062 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12063 throw new IllegalArgumentException("File descriptors passed in Bundle");
12064 }
12065
12066 boolean doNext;
12067
12068 final long origId = Binder.clearCallingIdentity();
12069
12070 synchronized(this) {
12071 doNext = finishReceiverLocked(
12072 who, resultCode, resultData, resultExtras, resultAbort, true);
12073 }
12074
12075 if (doNext) {
12076 processNextBroadcast(false);
12077 }
12078 trimApplications();
12079
12080 Binder.restoreCallingIdentity(origId);
12081 }
12082
12083 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12084 if (r.nextReceiver > 0) {
12085 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12086 if (curReceiver instanceof BroadcastFilter) {
12087 BroadcastFilter bf = (BroadcastFilter) curReceiver;
12088 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
12089 System.identityHashCode(r),
12090 r.intent.getAction(),
12091 r.nextReceiver - 1,
12092 System.identityHashCode(bf));
12093 } else {
12094 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12095 System.identityHashCode(r),
12096 r.intent.getAction(),
12097 r.nextReceiver - 1,
12098 ((ResolveInfo)curReceiver).toString());
12099 }
12100 } else {
12101 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12102 + r);
12103 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12104 System.identityHashCode(r),
12105 r.intent.getAction(),
12106 r.nextReceiver,
12107 "NONE");
12108 }
12109 }
12110
12111 private final void broadcastTimeout() {
12112 synchronized (this) {
12113 if (mOrderedBroadcasts.size() == 0) {
12114 return;
12115 }
12116 long now = SystemClock.uptimeMillis();
12117 BroadcastRecord r = mOrderedBroadcasts.get(0);
12118 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
12119 if (DEBUG_BROADCAST) Log.v(TAG,
12120 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
12121 + (r.startTime + BROADCAST_TIMEOUT));
12122 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12123 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12124 return;
12125 }
12126
12127 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
12128 r.startTime = now;
12129 r.anrCount++;
12130
12131 // Current receiver has passed its expiration date.
12132 if (r.nextReceiver <= 0) {
12133 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12134 return;
12135 }
12136
12137 ProcessRecord app = null;
12138
12139 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12140 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12141 logBroadcastReceiverDiscard(r);
12142 if (curReceiver instanceof BroadcastFilter) {
12143 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12144 if (bf.receiverList.pid != 0
12145 && bf.receiverList.pid != MY_PID) {
12146 synchronized (this.mPidsSelfLocked) {
12147 app = this.mPidsSelfLocked.get(
12148 bf.receiverList.pid);
12149 }
12150 }
12151 } else {
12152 app = r.curApp;
12153 }
12154
12155 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070012156 appNotRespondingLocked(app, null, null,
12157 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012158 }
12159
12160 if (mPendingBroadcast == r) {
12161 mPendingBroadcast = null;
12162 }
12163
12164 // Move on to the next receiver.
12165 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12166 r.resultExtras, r.resultAbort, true);
12167 scheduleBroadcastsLocked();
12168 }
12169 }
12170
12171 private final void processCurBroadcastLocked(BroadcastRecord r,
12172 ProcessRecord app) throws RemoteException {
12173 if (app.thread == null) {
12174 throw new RemoteException();
12175 }
12176 r.receiver = app.thread.asBinder();
12177 r.curApp = app;
12178 app.curReceiver = r;
12179 updateLRUListLocked(app, true);
12180
12181 // Tell the application to launch this receiver.
12182 r.intent.setComponent(r.curComponent);
12183
12184 boolean started = false;
12185 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012186 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012187 "Delivering to component " + r.curComponent
12188 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012189 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012190 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12191 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12192 started = true;
12193 } finally {
12194 if (!started) {
12195 r.receiver = null;
12196 r.curApp = null;
12197 app.curReceiver = null;
12198 }
12199 }
12200
12201 }
12202
12203 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012204 Intent intent, int resultCode, String data, Bundle extras,
12205 boolean ordered, boolean sticky) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012206 if (app != null && app.thread != null) {
12207 // If we have an app thread, do the call through that so it is
12208 // correctly ordered with other one-way calls.
12209 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012210 data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012211 } else {
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012212 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012213 }
12214 }
12215
12216 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12217 BroadcastFilter filter, boolean ordered) {
12218 boolean skip = false;
12219 if (filter.requiredPermission != null) {
12220 int perm = checkComponentPermission(filter.requiredPermission,
12221 r.callingPid, r.callingUid, -1);
12222 if (perm != PackageManager.PERMISSION_GRANTED) {
12223 Log.w(TAG, "Permission Denial: broadcasting "
12224 + r.intent.toString()
12225 + " from " + r.callerPackage + " (pid="
12226 + r.callingPid + ", uid=" + r.callingUid + ")"
12227 + " requires " + filter.requiredPermission
12228 + " due to registered receiver " + filter);
12229 skip = true;
12230 }
12231 }
12232 if (r.requiredPermission != null) {
12233 int perm = checkComponentPermission(r.requiredPermission,
12234 filter.receiverList.pid, filter.receiverList.uid, -1);
12235 if (perm != PackageManager.PERMISSION_GRANTED) {
12236 Log.w(TAG, "Permission Denial: receiving "
12237 + r.intent.toString()
12238 + " to " + filter.receiverList.app
12239 + " (pid=" + filter.receiverList.pid
12240 + ", uid=" + filter.receiverList.uid + ")"
12241 + " requires " + r.requiredPermission
12242 + " due to sender " + r.callerPackage
12243 + " (uid " + r.callingUid + ")");
12244 skip = true;
12245 }
12246 }
12247
12248 if (!skip) {
12249 // If this is not being sent as an ordered broadcast, then we
12250 // don't want to touch the fields that keep track of the current
12251 // state of ordered broadcasts.
12252 if (ordered) {
12253 r.receiver = filter.receiverList.receiver.asBinder();
12254 r.curFilter = filter;
12255 filter.receiverList.curBroadcast = r;
12256 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012257 if (filter.receiverList.app != null) {
12258 // Bump hosting application to no longer be in background
12259 // scheduling class. Note that we can't do that if there
12260 // isn't an app... but we can only be in that case for
12261 // things that directly call the IActivityManager API, which
12262 // are already core system stuff so don't matter for this.
12263 r.curApp = filter.receiverList.app;
12264 filter.receiverList.app.curReceiver = r;
12265 updateOomAdjLocked();
12266 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012267 }
12268 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012269 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012270 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012271 Log.i(TAG, "Delivering to " + filter.receiverList.app
12272 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012273 }
12274 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12275 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012276 r.resultData, r.resultExtras, r.ordered, r.sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012277 if (ordered) {
12278 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12279 }
12280 } catch (RemoteException e) {
12281 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12282 if (ordered) {
12283 r.receiver = null;
12284 r.curFilter = null;
12285 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012286 if (filter.receiverList.app != null) {
12287 filter.receiverList.app.curReceiver = null;
12288 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012289 }
12290 }
12291 }
12292 }
12293
12294 private final void processNextBroadcast(boolean fromMsg) {
12295 synchronized(this) {
12296 BroadcastRecord r;
12297
12298 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12299 + mParallelBroadcasts.size() + " broadcasts, "
12300 + mOrderedBroadcasts.size() + " serialized broadcasts");
12301
12302 updateCpuStats();
12303
12304 if (fromMsg) {
12305 mBroadcastsScheduled = false;
12306 }
12307
12308 // First, deliver any non-serialized broadcasts right away.
12309 while (mParallelBroadcasts.size() > 0) {
12310 r = mParallelBroadcasts.remove(0);
12311 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012312 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12313 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012314 for (int i=0; i<N; i++) {
12315 Object target = r.receivers.get(i);
12316 if (DEBUG_BROADCAST) Log.v(TAG,
12317 "Delivering non-serialized to registered "
12318 + target + ": " + r);
12319 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12320 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012321 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12322 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012323 }
12324
12325 // Now take care of the next serialized one...
12326
12327 // If we are waiting for a process to come up to handle the next
12328 // broadcast, then do nothing at this point. Just in case, we
12329 // check that the process we're waiting for still exists.
12330 if (mPendingBroadcast != null) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070012331 if (DEBUG_BROADCAST_LIGHT) {
12332 Log.v(TAG, "processNextBroadcast: waiting for "
12333 + mPendingBroadcast.curApp);
12334 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012335
12336 boolean isDead;
12337 synchronized (mPidsSelfLocked) {
12338 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12339 }
12340 if (!isDead) {
12341 // It's still alive, so keep waiting
12342 return;
12343 } else {
12344 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12345 + " died before responding to broadcast");
12346 mPendingBroadcast = null;
12347 }
12348 }
12349
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012350 boolean looped = false;
12351
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012352 do {
12353 if (mOrderedBroadcasts.size() == 0) {
12354 // No more broadcasts pending, so all done!
12355 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012356 if (looped) {
12357 // If we had finished the last ordered broadcast, then
12358 // make sure all processes have correct oom and sched
12359 // adjustments.
12360 updateOomAdjLocked();
12361 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012362 return;
12363 }
12364 r = mOrderedBroadcasts.get(0);
12365 boolean forceReceive = false;
12366
12367 // Ensure that even if something goes awry with the timeout
12368 // detection, we catch "hung" broadcasts here, discard them,
12369 // and continue to make progress.
12370 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12371 long now = SystemClock.uptimeMillis();
12372 if (r.dispatchTime > 0) {
12373 if ((numReceivers > 0) &&
12374 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12375 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12376 + " now=" + now
12377 + " dispatchTime=" + r.dispatchTime
12378 + " startTime=" + r.startTime
12379 + " intent=" + r.intent
12380 + " numReceivers=" + numReceivers
12381 + " nextReceiver=" + r.nextReceiver
12382 + " state=" + r.state);
12383 broadcastTimeout(); // forcibly finish this broadcast
12384 forceReceive = true;
12385 r.state = BroadcastRecord.IDLE;
12386 }
12387 }
12388
12389 if (r.state != BroadcastRecord.IDLE) {
12390 if (DEBUG_BROADCAST) Log.d(TAG,
12391 "processNextBroadcast() called when not idle (state="
12392 + r.state + ")");
12393 return;
12394 }
12395
12396 if (r.receivers == null || r.nextReceiver >= numReceivers
12397 || r.resultAbort || forceReceive) {
12398 // No more receivers for this broadcast! Send the final
12399 // result if requested...
12400 if (r.resultTo != null) {
12401 try {
12402 if (DEBUG_BROADCAST) {
12403 int seq = r.intent.getIntExtra("seq", -1);
12404 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12405 + " seq=" + seq + " app=" + r.callerApp);
12406 }
12407 performReceive(r.callerApp, r.resultTo,
12408 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012409 r.resultData, r.resultExtras, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012410 } catch (RemoteException e) {
12411 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12412 }
12413 }
12414
12415 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12416 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12417
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012418 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12419 + r);
12420
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012421 // ... and on to the next...
12422 mOrderedBroadcasts.remove(0);
12423 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012424 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012425 continue;
12426 }
12427 } while (r == null);
12428
12429 // Get the next receiver...
12430 int recIdx = r.nextReceiver++;
12431
12432 // Keep track of when this receiver started, and make sure there
12433 // is a timeout message pending to kill it if need be.
12434 r.startTime = SystemClock.uptimeMillis();
12435 if (recIdx == 0) {
12436 r.dispatchTime = r.startTime;
12437
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012438 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12439 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012440 if (DEBUG_BROADCAST) Log.v(TAG,
12441 "Submitting BROADCAST_TIMEOUT_MSG for "
12442 + (r.startTime + BROADCAST_TIMEOUT));
12443 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12444 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12445 }
12446
12447 Object nextReceiver = r.receivers.get(recIdx);
12448 if (nextReceiver instanceof BroadcastFilter) {
12449 // Simple case: this is a registered receiver who gets
12450 // a direct call.
12451 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12452 if (DEBUG_BROADCAST) Log.v(TAG,
12453 "Delivering serialized to registered "
12454 + filter + ": " + r);
12455 deliverToRegisteredReceiver(r, filter, r.ordered);
12456 if (r.receiver == null || !r.ordered) {
12457 // The receiver has already finished, so schedule to
12458 // process the next one.
12459 r.state = BroadcastRecord.IDLE;
12460 scheduleBroadcastsLocked();
12461 }
12462 return;
12463 }
12464
12465 // Hard case: need to instantiate the receiver, possibly
12466 // starting its application process to host it.
12467
12468 ResolveInfo info =
12469 (ResolveInfo)nextReceiver;
12470
12471 boolean skip = false;
12472 int perm = checkComponentPermission(info.activityInfo.permission,
12473 r.callingPid, r.callingUid,
12474 info.activityInfo.exported
12475 ? -1 : info.activityInfo.applicationInfo.uid);
12476 if (perm != PackageManager.PERMISSION_GRANTED) {
12477 Log.w(TAG, "Permission Denial: broadcasting "
12478 + r.intent.toString()
12479 + " from " + r.callerPackage + " (pid=" + r.callingPid
12480 + ", uid=" + r.callingUid + ")"
12481 + " requires " + info.activityInfo.permission
12482 + " due to receiver " + info.activityInfo.packageName
12483 + "/" + info.activityInfo.name);
12484 skip = true;
12485 }
12486 if (r.callingUid != Process.SYSTEM_UID &&
12487 r.requiredPermission != null) {
12488 try {
12489 perm = ActivityThread.getPackageManager().
12490 checkPermission(r.requiredPermission,
12491 info.activityInfo.applicationInfo.packageName);
12492 } catch (RemoteException e) {
12493 perm = PackageManager.PERMISSION_DENIED;
12494 }
12495 if (perm != PackageManager.PERMISSION_GRANTED) {
12496 Log.w(TAG, "Permission Denial: receiving "
12497 + r.intent + " to "
12498 + info.activityInfo.applicationInfo.packageName
12499 + " requires " + r.requiredPermission
12500 + " due to sender " + r.callerPackage
12501 + " (uid " + r.callingUid + ")");
12502 skip = true;
12503 }
12504 }
12505 if (r.curApp != null && r.curApp.crashing) {
12506 // If the target process is crashing, just skip it.
12507 skip = true;
12508 }
12509
12510 if (skip) {
12511 r.receiver = null;
12512 r.curFilter = null;
12513 r.state = BroadcastRecord.IDLE;
12514 scheduleBroadcastsLocked();
12515 return;
12516 }
12517
12518 r.state = BroadcastRecord.APP_RECEIVE;
12519 String targetProcess = info.activityInfo.processName;
12520 r.curComponent = new ComponentName(
12521 info.activityInfo.applicationInfo.packageName,
12522 info.activityInfo.name);
12523 r.curReceiver = info.activityInfo;
12524
12525 // Is this receiver's application already running?
12526 ProcessRecord app = getProcessRecordLocked(targetProcess,
12527 info.activityInfo.applicationInfo.uid);
12528 if (app != null && app.thread != null) {
12529 try {
12530 processCurBroadcastLocked(r, app);
12531 return;
12532 } catch (RemoteException e) {
12533 Log.w(TAG, "Exception when sending broadcast to "
12534 + r.curComponent, e);
12535 }
12536
12537 // If a dead object exception was thrown -- fall through to
12538 // restart the application.
12539 }
12540
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012541 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012542 if ((r.curApp=startProcessLocked(targetProcess,
12543 info.activityInfo.applicationInfo, true,
12544 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012545 "broadcast", r.curComponent,
12546 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12547 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012548 // Ah, this recipient is unavailable. Finish it if necessary,
12549 // and mark the broadcast record as ready for the next.
12550 Log.w(TAG, "Unable to launch app "
12551 + info.activityInfo.applicationInfo.packageName + "/"
12552 + info.activityInfo.applicationInfo.uid + " for broadcast "
12553 + r.intent + ": process is bad");
12554 logBroadcastReceiverDiscard(r);
12555 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12556 r.resultExtras, r.resultAbort, true);
12557 scheduleBroadcastsLocked();
12558 r.state = BroadcastRecord.IDLE;
12559 return;
12560 }
12561
12562 mPendingBroadcast = r;
12563 }
12564 }
12565
12566 // =========================================================
12567 // INSTRUMENTATION
12568 // =========================================================
12569
12570 public boolean startInstrumentation(ComponentName className,
12571 String profileFile, int flags, Bundle arguments,
12572 IInstrumentationWatcher watcher) {
12573 // Refuse possible leaked file descriptors
12574 if (arguments != null && arguments.hasFileDescriptors()) {
12575 throw new IllegalArgumentException("File descriptors passed in Bundle");
12576 }
12577
12578 synchronized(this) {
12579 InstrumentationInfo ii = null;
12580 ApplicationInfo ai = null;
12581 try {
12582 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012583 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012584 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012585 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012586 } catch (PackageManager.NameNotFoundException e) {
12587 }
12588 if (ii == null) {
12589 reportStartInstrumentationFailure(watcher, className,
12590 "Unable to find instrumentation info for: " + className);
12591 return false;
12592 }
12593 if (ai == null) {
12594 reportStartInstrumentationFailure(watcher, className,
12595 "Unable to find instrumentation target package: " + ii.targetPackage);
12596 return false;
12597 }
12598
12599 int match = mContext.getPackageManager().checkSignatures(
12600 ii.targetPackage, ii.packageName);
12601 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12602 String msg = "Permission Denial: starting instrumentation "
12603 + className + " from pid="
12604 + Binder.getCallingPid()
12605 + ", uid=" + Binder.getCallingPid()
12606 + " not allowed because package " + ii.packageName
12607 + " does not have a signature matching the target "
12608 + ii.targetPackage;
12609 reportStartInstrumentationFailure(watcher, className, msg);
12610 throw new SecurityException(msg);
12611 }
12612
12613 final long origId = Binder.clearCallingIdentity();
12614 uninstallPackageLocked(ii.targetPackage, -1, true);
12615 ProcessRecord app = addAppLocked(ai);
12616 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012617 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012618 app.instrumentationProfileFile = profileFile;
12619 app.instrumentationArguments = arguments;
12620 app.instrumentationWatcher = watcher;
12621 app.instrumentationResultClass = className;
12622 Binder.restoreCallingIdentity(origId);
12623 }
12624
12625 return true;
12626 }
12627
12628 /**
12629 * Report errors that occur while attempting to start Instrumentation. Always writes the
12630 * error to the logs, but if somebody is watching, send the report there too. This enables
12631 * the "am" command to report errors with more information.
12632 *
12633 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12634 * @param cn The component name of the instrumentation.
12635 * @param report The error report.
12636 */
12637 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12638 ComponentName cn, String report) {
12639 Log.w(TAG, report);
12640 try {
12641 if (watcher != null) {
12642 Bundle results = new Bundle();
12643 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12644 results.putString("Error", report);
12645 watcher.instrumentationStatus(cn, -1, results);
12646 }
12647 } catch (RemoteException e) {
12648 Log.w(TAG, e);
12649 }
12650 }
12651
12652 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12653 if (app.instrumentationWatcher != null) {
12654 try {
12655 // NOTE: IInstrumentationWatcher *must* be oneway here
12656 app.instrumentationWatcher.instrumentationFinished(
12657 app.instrumentationClass,
12658 resultCode,
12659 results);
12660 } catch (RemoteException e) {
12661 }
12662 }
12663 app.instrumentationWatcher = null;
12664 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012665 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012666 app.instrumentationProfileFile = null;
12667 app.instrumentationArguments = null;
12668
12669 uninstallPackageLocked(app.processName, -1, false);
12670 }
12671
12672 public void finishInstrumentation(IApplicationThread target,
12673 int resultCode, Bundle results) {
12674 // Refuse possible leaked file descriptors
12675 if (results != null && results.hasFileDescriptors()) {
12676 throw new IllegalArgumentException("File descriptors passed in Intent");
12677 }
12678
12679 synchronized(this) {
12680 ProcessRecord app = getRecordForAppLocked(target);
12681 if (app == null) {
12682 Log.w(TAG, "finishInstrumentation: no app for " + target);
12683 return;
12684 }
12685 final long origId = Binder.clearCallingIdentity();
12686 finishInstrumentationLocked(app, resultCode, results);
12687 Binder.restoreCallingIdentity(origId);
12688 }
12689 }
12690
12691 // =========================================================
12692 // CONFIGURATION
12693 // =========================================================
12694
12695 public ConfigurationInfo getDeviceConfigurationInfo() {
12696 ConfigurationInfo config = new ConfigurationInfo();
12697 synchronized (this) {
12698 config.reqTouchScreen = mConfiguration.touchscreen;
12699 config.reqKeyboardType = mConfiguration.keyboard;
12700 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012701 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12702 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012703 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12704 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012705 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12706 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012707 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12708 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012709 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012710 }
12711 return config;
12712 }
12713
12714 public Configuration getConfiguration() {
12715 Configuration ci;
12716 synchronized(this) {
12717 ci = new Configuration(mConfiguration);
12718 }
12719 return ci;
12720 }
12721
12722 public void updateConfiguration(Configuration values) {
12723 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12724 "updateConfiguration()");
12725
12726 synchronized(this) {
12727 if (values == null && mWindowManager != null) {
12728 // sentinel: fetch the current configuration from the window manager
12729 values = mWindowManager.computeNewConfiguration();
12730 }
12731
12732 final long origId = Binder.clearCallingIdentity();
12733 updateConfigurationLocked(values, null);
12734 Binder.restoreCallingIdentity(origId);
12735 }
12736 }
12737
12738 /**
12739 * Do either or both things: (1) change the current configuration, and (2)
12740 * make sure the given activity is running with the (now) current
12741 * configuration. Returns true if the activity has been left running, or
12742 * false if <var>starting</var> is being destroyed to match the new
12743 * configuration.
12744 */
12745 public boolean updateConfigurationLocked(Configuration values,
12746 HistoryRecord starting) {
12747 int changes = 0;
12748
12749 boolean kept = true;
12750
12751 if (values != null) {
12752 Configuration newConfig = new Configuration(mConfiguration);
12753 changes = newConfig.updateFrom(values);
12754 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012755 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012756 Log.i(TAG, "Updating configuration to: " + values);
12757 }
12758
12759 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12760
12761 if (values.locale != null) {
12762 saveLocaleLocked(values.locale,
12763 !values.locale.equals(mConfiguration.locale),
12764 values.userSetLocale);
12765 }
12766
12767 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012768 Log.i(TAG, "Config changed: " + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012769
12770 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12771 msg.obj = new Configuration(mConfiguration);
12772 mHandler.sendMessage(msg);
12773
12774 final int N = mLRUProcesses.size();
12775 for (int i=0; i<N; i++) {
12776 ProcessRecord app = mLRUProcesses.get(i);
12777 try {
12778 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012779 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
12780 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012781 app.thread.scheduleConfigurationChanged(mConfiguration);
12782 }
12783 } catch (Exception e) {
12784 }
12785 }
12786 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12787 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12788 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012789
12790 AttributeCache ac = AttributeCache.instance();
12791 if (ac != null) {
12792 ac.updateConfiguration(mConfiguration);
12793 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012794 }
12795 }
12796
12797 if (changes != 0 && starting == null) {
12798 // If the configuration changed, and the caller is not already
12799 // in the process of starting an activity, then find the top
12800 // activity to check if its configuration needs to change.
12801 starting = topRunningActivityLocked(null);
12802 }
12803
12804 if (starting != null) {
12805 kept = ensureActivityConfigurationLocked(starting, changes);
12806 if (kept) {
12807 // If this didn't result in the starting activity being
12808 // destroyed, then we need to make sure at this point that all
12809 // other activities are made visible.
12810 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12811 + ", ensuring others are correct.");
12812 ensureActivitiesVisibleLocked(starting, changes);
12813 }
12814 }
12815
12816 return kept;
12817 }
12818
12819 private final boolean relaunchActivityLocked(HistoryRecord r,
12820 int changes, boolean andResume) {
12821 List<ResultInfo> results = null;
12822 List<Intent> newIntents = null;
12823 if (andResume) {
12824 results = r.results;
12825 newIntents = r.newIntents;
12826 }
12827 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12828 + " with results=" + results + " newIntents=" + newIntents
12829 + " andResume=" + andResume);
12830 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12831 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12832 r.task.taskId, r.shortComponentName);
12833
12834 r.startFreezingScreenLocked(r.app, 0);
12835
12836 try {
12837 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12838 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12839 changes, !andResume);
12840 // Note: don't need to call pauseIfSleepingLocked() here, because
12841 // the caller will only pass in 'andResume' if this activity is
12842 // currently resumed, which implies we aren't sleeping.
12843 } catch (RemoteException e) {
12844 return false;
12845 }
12846
12847 if (andResume) {
12848 r.results = null;
12849 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070012850 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012851 }
12852
12853 return true;
12854 }
12855
12856 /**
12857 * Make sure the given activity matches the current configuration. Returns
12858 * false if the activity had to be destroyed. Returns true if the
12859 * configuration is the same, or the activity will remain running as-is
12860 * for whatever reason. Ensures the HistoryRecord is updated with the
12861 * correct configuration and all other bookkeeping is handled.
12862 */
12863 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12864 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012865 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12866 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012867
12868 // Short circuit: if the two configurations are the exact same
12869 // object (the common case), then there is nothing to do.
12870 Configuration newConfig = mConfiguration;
12871 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012872 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12873 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012874 return true;
12875 }
12876
12877 // We don't worry about activities that are finishing.
12878 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012879 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012880 "Configuration doesn't matter in finishing " + r);
12881 r.stopFreezingScreenLocked(false);
12882 return true;
12883 }
12884
12885 // Okay we now are going to make this activity have the new config.
12886 // But then we need to figure out how it needs to deal with that.
12887 Configuration oldConfig = r.configuration;
12888 r.configuration = newConfig;
12889
12890 // If the activity isn't currently running, just leave the new
12891 // configuration and it will pick that up next time it starts.
12892 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012893 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012894 "Configuration doesn't matter not running " + r);
12895 r.stopFreezingScreenLocked(false);
12896 return true;
12897 }
12898
12899 // If the activity isn't persistent, there is a chance we will
12900 // need to restart it.
12901 if (!r.persistent) {
12902
12903 // Figure out what has changed between the two configurations.
12904 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012905 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
12906 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012907 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012908 + Integer.toHexString(r.info.configChanges)
12909 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012910 }
12911 if ((changes&(~r.info.configChanges)) != 0) {
12912 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12913 r.configChangeFlags |= changes;
12914 r.startFreezingScreenLocked(r.app, globalChanges);
12915 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012916 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12917 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012918 destroyActivityLocked(r, true);
12919 } else if (r.state == ActivityState.PAUSING) {
12920 // A little annoying: we are waiting for this activity to
12921 // finish pausing. Let's not do anything now, but just
12922 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012923 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12924 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012925 r.configDestroy = true;
12926 return true;
12927 } else if (r.state == ActivityState.RESUMED) {
12928 // Try to optimize this case: the configuration is changing
12929 // and we need to restart the top, resumed activity.
12930 // Instead of doing the normal handshaking, just say
12931 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012932 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12933 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012934 relaunchActivityLocked(r, r.configChangeFlags, true);
12935 r.configChangeFlags = 0;
12936 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012937 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12938 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012939 relaunchActivityLocked(r, r.configChangeFlags, false);
12940 r.configChangeFlags = 0;
12941 }
12942
12943 // All done... tell the caller we weren't able to keep this
12944 // activity around.
12945 return false;
12946 }
12947 }
12948
12949 // Default case: the activity can handle this new configuration, so
12950 // hand it over. Note that we don't need to give it the new
12951 // configuration, since we always send configuration changes to all
12952 // process when they happen so it can just use whatever configuration
12953 // it last got.
12954 if (r.app != null && r.app.thread != null) {
12955 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012956 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012957 r.app.thread.scheduleActivityConfigurationChanged(r);
12958 } catch (RemoteException e) {
12959 // If process died, whatever.
12960 }
12961 }
12962 r.stopFreezingScreenLocked(false);
12963
12964 return true;
12965 }
12966
12967 /**
12968 * Save the locale. You must be inside a synchronized (this) block.
12969 */
12970 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12971 if(isDiff) {
12972 SystemProperties.set("user.language", l.getLanguage());
12973 SystemProperties.set("user.region", l.getCountry());
12974 }
12975
12976 if(isPersist) {
12977 SystemProperties.set("persist.sys.language", l.getLanguage());
12978 SystemProperties.set("persist.sys.country", l.getCountry());
12979 SystemProperties.set("persist.sys.localevar", l.getVariant());
12980 }
12981 }
12982
12983 // =========================================================
12984 // LIFETIME MANAGEMENT
12985 // =========================================================
12986
12987 private final int computeOomAdjLocked(
12988 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12989 if (mAdjSeq == app.adjSeq) {
12990 // This adjustment has already been computed.
12991 return app.curAdj;
12992 }
12993
12994 if (app.thread == null) {
12995 app.adjSeq = mAdjSeq;
12996 return (app.curAdj=EMPTY_APP_ADJ);
12997 }
12998
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012999 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
13000 // The max adjustment doesn't allow this app to be anything
13001 // below foreground, so it is not worth doing work for it.
13002 app.adjType = "fixed";
13003 app.adjSeq = mAdjSeq;
13004 app.curRawAdj = app.maxAdj;
13005 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
13006 return (app.curAdj=app.maxAdj);
13007 }
13008
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013009 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013010 app.adjSource = null;
13011 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013012
The Android Open Source Project4df24232009-03-05 14:34:35 -080013013 // Determine the importance of the process, starting with most
13014 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013015 int adj;
13016 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013017 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013018 // The last app on the list is the foreground app.
13019 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013020 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013021 } else if (app.instrumentationClass != null) {
13022 // Don't want to kill running instrumentation.
13023 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013024 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013025 } else if (app.persistentActivities > 0) {
13026 // Special persistent activities... shouldn't be used these days.
13027 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013028 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013029 } else if (app.curReceiver != null ||
13030 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
13031 // An app that is currently receiving a broadcast also
13032 // counts as being in the foreground.
13033 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013034 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013035 } else if (app.executingServices.size() > 0) {
13036 // An app that is currently executing a service callback also
13037 // counts as being in the foreground.
13038 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013039 app.adjType = "exec-service";
13040 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013041 // The user is aware of this app, so make it visible.
13042 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013043 app.adjType = "foreground-service";
13044 } else if (app.forcingToForeground != null) {
13045 // The user is aware of this app, so make it visible.
13046 adj = VISIBLE_APP_ADJ;
13047 app.adjType = "force-foreground";
13048 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013049 } else if (app == mHomeProcess) {
13050 // This process is hosting what we currently consider to be the
13051 // home app, so we don't want to let it go into the background.
13052 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013053 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013054 } else if ((N=app.activities.size()) != 0) {
13055 // This app is in the background with paused activities.
13056 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013057 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013058 for (int j=0; j<N; j++) {
13059 if (((HistoryRecord)app.activities.get(j)).visible) {
13060 // This app has a visible activity!
13061 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013062 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013063 break;
13064 }
13065 }
13066 } else {
13067 // A very not-needed process.
13068 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013069 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013070 }
13071
The Android Open Source Project4df24232009-03-05 14:34:35 -080013072 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013073 // there are applications dependent on our services or providers, but
13074 // this gives us a baseline and makes sure we don't get into an
13075 // infinite recursion.
13076 app.adjSeq = mAdjSeq;
13077 app.curRawAdj = adj;
13078 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
13079
Christopher Tate6fa95972009-06-05 18:43:55 -070013080 if (mBackupTarget != null && app == mBackupTarget.app) {
13081 // If possible we want to avoid killing apps while they're being backed up
13082 if (adj > BACKUP_APP_ADJ) {
13083 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13084 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013085 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070013086 }
13087 }
13088
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013089 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013090 final long now = SystemClock.uptimeMillis();
13091 // This process is more important if the top activity is
13092 // bound to the service.
13093 Iterator jt = app.services.iterator();
13094 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13095 ServiceRecord s = (ServiceRecord)jt.next();
13096 if (s.startRequested) {
13097 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13098 // This service has seen some activity within
13099 // recent memory, so we will keep its process ahead
13100 // of the background processes.
13101 if (adj > SECONDARY_SERVER_ADJ) {
13102 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013103 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013104 }
13105 }
13106 }
13107 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
13108 Iterator<ConnectionRecord> kt
13109 = s.connections.values().iterator();
13110 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13111 // XXX should compute this based on the max of
13112 // all connected clients.
13113 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013114 if (cr.binding.client == app) {
13115 // Binding to ourself is not interesting.
13116 continue;
13117 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013118 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13119 ProcessRecord client = cr.binding.client;
13120 int myHiddenAdj = hiddenAdj;
13121 if (myHiddenAdj > client.hiddenAdj) {
13122 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13123 myHiddenAdj = client.hiddenAdj;
13124 } else {
13125 myHiddenAdj = VISIBLE_APP_ADJ;
13126 }
13127 }
13128 int clientAdj = computeOomAdjLocked(
13129 client, myHiddenAdj, TOP_APP);
13130 if (adj > clientAdj) {
13131 adj = clientAdj > VISIBLE_APP_ADJ
13132 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013133 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013134 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13135 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013136 app.adjSource = cr.binding.client;
13137 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013138 }
13139 }
13140 HistoryRecord a = cr.activity;
13141 //if (a != null) {
13142 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13143 //}
13144 if (a != null && adj > FOREGROUND_APP_ADJ &&
13145 (a.state == ActivityState.RESUMED
13146 || a.state == ActivityState.PAUSING)) {
13147 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013148 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013149 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13150 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013151 app.adjSource = a;
13152 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013153 }
13154 }
13155 }
13156 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013157
13158 // Finally, f this process has active services running in it, we
13159 // would like to avoid killing it unless it would prevent the current
13160 // application from running. By default we put the process in
13161 // with the rest of the background processes; as we scan through
13162 // its services we may bump it up from there.
13163 if (adj > hiddenAdj) {
13164 adj = hiddenAdj;
13165 app.adjType = "bg-services";
13166 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013167 }
13168
13169 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013170 Iterator jt = app.pubProviders.values().iterator();
13171 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13172 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13173 if (cpr.clients.size() != 0) {
13174 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13175 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13176 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013177 if (client == app) {
13178 // Being our own client is not interesting.
13179 continue;
13180 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013181 int myHiddenAdj = hiddenAdj;
13182 if (myHiddenAdj > client.hiddenAdj) {
13183 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13184 myHiddenAdj = client.hiddenAdj;
13185 } else {
13186 myHiddenAdj = FOREGROUND_APP_ADJ;
13187 }
13188 }
13189 int clientAdj = computeOomAdjLocked(
13190 client, myHiddenAdj, TOP_APP);
13191 if (adj > clientAdj) {
13192 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013193 ? clientAdj : FOREGROUND_APP_ADJ;
13194 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013195 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13196 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013197 app.adjSource = client;
13198 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013199 }
13200 }
13201 }
13202 // If the provider has external (non-framework) process
13203 // dependencies, ensure that its adjustment is at least
13204 // FOREGROUND_APP_ADJ.
13205 if (cpr.externals != 0) {
13206 if (adj > FOREGROUND_APP_ADJ) {
13207 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013208 app.adjType = "provider";
13209 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013210 }
13211 }
13212 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013213
13214 // Finally, if this process has published any content providers,
13215 // then its adjustment makes it at least as important as any of the
13216 // processes using those providers, and no less important than
13217 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
13218 if (adj > CONTENT_PROVIDER_ADJ) {
13219 adj = CONTENT_PROVIDER_ADJ;
13220 app.adjType = "pub-providers";
13221 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013222 }
13223
13224 app.curRawAdj = adj;
13225
13226 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13227 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13228 if (adj > app.maxAdj) {
13229 adj = app.maxAdj;
13230 }
13231
13232 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013233 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013234 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
13235 : Process.THREAD_GROUP_DEFAULT;
13236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013237 return adj;
13238 }
13239
13240 /**
13241 * Ask a given process to GC right now.
13242 */
13243 final void performAppGcLocked(ProcessRecord app) {
13244 try {
13245 app.lastRequestedGc = SystemClock.uptimeMillis();
13246 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013247 if (app.reportLowMemory) {
13248 app.reportLowMemory = false;
13249 app.thread.scheduleLowMemory();
13250 } else {
13251 app.thread.processInBackground();
13252 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013253 }
13254 } catch (Exception e) {
13255 // whatever.
13256 }
13257 }
13258
13259 /**
13260 * Returns true if things are idle enough to perform GCs.
13261 */
13262 private final boolean canGcNow() {
13263 return mParallelBroadcasts.size() == 0
13264 && mOrderedBroadcasts.size() == 0
13265 && (mSleeping || (mResumedActivity != null &&
13266 mResumedActivity.idle));
13267 }
13268
13269 /**
13270 * Perform GCs on all processes that are waiting for it, but only
13271 * if things are idle.
13272 */
13273 final void performAppGcsLocked() {
13274 final int N = mProcessesToGc.size();
13275 if (N <= 0) {
13276 return;
13277 }
13278 if (canGcNow()) {
13279 while (mProcessesToGc.size() > 0) {
13280 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013281 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13282 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13283 <= SystemClock.uptimeMillis()) {
13284 // To avoid spamming the system, we will GC processes one
13285 // at a time, waiting a few seconds between each.
13286 performAppGcLocked(proc);
13287 scheduleAppGcsLocked();
13288 return;
13289 } else {
13290 // It hasn't been long enough since we last GCed this
13291 // process... put it in the list to wait for its time.
13292 addProcessToGcListLocked(proc);
13293 break;
13294 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013295 }
13296 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013297
13298 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013299 }
13300 }
13301
13302 /**
13303 * If all looks good, perform GCs on all processes waiting for them.
13304 */
13305 final void performAppGcsIfAppropriateLocked() {
13306 if (canGcNow()) {
13307 performAppGcsLocked();
13308 return;
13309 }
13310 // Still not idle, wait some more.
13311 scheduleAppGcsLocked();
13312 }
13313
13314 /**
13315 * Schedule the execution of all pending app GCs.
13316 */
13317 final void scheduleAppGcsLocked() {
13318 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013319
13320 if (mProcessesToGc.size() > 0) {
13321 // Schedule a GC for the time to the next process.
13322 ProcessRecord proc = mProcessesToGc.get(0);
13323 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13324
13325 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13326 long now = SystemClock.uptimeMillis();
13327 if (when < (now+GC_TIMEOUT)) {
13328 when = now + GC_TIMEOUT;
13329 }
13330 mHandler.sendMessageAtTime(msg, when);
13331 }
13332 }
13333
13334 /**
13335 * Add a process to the array of processes waiting to be GCed. Keeps the
13336 * list in sorted order by the last GC time. The process can't already be
13337 * on the list.
13338 */
13339 final void addProcessToGcListLocked(ProcessRecord proc) {
13340 boolean added = false;
13341 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13342 if (mProcessesToGc.get(i).lastRequestedGc <
13343 proc.lastRequestedGc) {
13344 added = true;
13345 mProcessesToGc.add(i+1, proc);
13346 break;
13347 }
13348 }
13349 if (!added) {
13350 mProcessesToGc.add(0, proc);
13351 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013352 }
13353
13354 /**
13355 * Set up to ask a process to GC itself. This will either do it
13356 * immediately, or put it on the list of processes to gc the next
13357 * time things are idle.
13358 */
13359 final void scheduleAppGcLocked(ProcessRecord app) {
13360 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013361 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013362 return;
13363 }
13364 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013365 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013366 scheduleAppGcsLocked();
13367 }
13368 }
13369
13370 private final boolean updateOomAdjLocked(
13371 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13372 app.hiddenAdj = hiddenAdj;
13373
13374 if (app.thread == null) {
13375 return true;
13376 }
13377
13378 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
13379
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013380 if (app.pid != 0 && app.pid != MY_PID) {
13381 if (app.curRawAdj != app.setRawAdj) {
13382 if (app.curRawAdj > FOREGROUND_APP_ADJ
13383 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13384 // If this app is transitioning from foreground to
13385 // non-foreground, have it do a gc.
13386 scheduleAppGcLocked(app);
13387 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13388 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13389 // Likewise do a gc when an app is moving in to the
13390 // background (such as a service stopping).
13391 scheduleAppGcLocked(app);
13392 }
13393 app.setRawAdj = app.curRawAdj;
13394 }
13395 if (adj != app.setAdj) {
13396 if (Process.setOomAdj(app.pid, adj)) {
13397 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13398 TAG, "Set app " + app.processName +
13399 " oom adj to " + adj);
13400 app.setAdj = adj;
13401 } else {
13402 return false;
13403 }
13404 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013405 if (app.setSchedGroup != app.curSchedGroup) {
13406 app.setSchedGroup = app.curSchedGroup;
13407 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13408 "Setting process group of " + app.processName
13409 + " to " + app.curSchedGroup);
13410 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013411 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013412 try {
13413 Process.setProcessGroup(app.pid, app.curSchedGroup);
13414 } catch (Exception e) {
13415 Log.w(TAG, "Failed setting process group of " + app.pid
13416 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013417 e.printStackTrace();
13418 } finally {
13419 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013420 }
13421 }
13422 if (false) {
13423 if (app.thread != null) {
13424 try {
13425 app.thread.setSchedulingGroup(app.curSchedGroup);
13426 } catch (RemoteException e) {
13427 }
13428 }
13429 }
13430 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013431 }
13432
13433 return true;
13434 }
13435
13436 private final HistoryRecord resumedAppLocked() {
13437 HistoryRecord resumedActivity = mResumedActivity;
13438 if (resumedActivity == null || resumedActivity.app == null) {
13439 resumedActivity = mPausingActivity;
13440 if (resumedActivity == null || resumedActivity.app == null) {
13441 resumedActivity = topRunningActivityLocked(null);
13442 }
13443 }
13444 return resumedActivity;
13445 }
13446
13447 private final boolean updateOomAdjLocked(ProcessRecord app) {
13448 final HistoryRecord TOP_ACT = resumedAppLocked();
13449 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13450 int curAdj = app.curAdj;
13451 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13452 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13453
13454 mAdjSeq++;
13455
13456 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13457 if (res) {
13458 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13459 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13460 if (nowHidden != wasHidden) {
13461 // Changed to/from hidden state, so apps after it in the LRU
13462 // list may also be changed.
13463 updateOomAdjLocked();
13464 }
13465 }
13466 return res;
13467 }
13468
13469 private final boolean updateOomAdjLocked() {
13470 boolean didOomAdj = true;
13471 final HistoryRecord TOP_ACT = resumedAppLocked();
13472 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13473
13474 if (false) {
13475 RuntimeException e = new RuntimeException();
13476 e.fillInStackTrace();
13477 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13478 }
13479
13480 mAdjSeq++;
13481
13482 // First try updating the OOM adjustment for each of the
13483 // application processes based on their current state.
13484 int i = mLRUProcesses.size();
13485 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13486 while (i > 0) {
13487 i--;
13488 ProcessRecord app = mLRUProcesses.get(i);
13489 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13490 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13491 && app.curAdj == curHiddenAdj) {
13492 curHiddenAdj++;
13493 }
13494 } else {
13495 didOomAdj = false;
13496 }
13497 }
13498
13499 // todo: for now pretend like OOM ADJ didn't work, because things
13500 // aren't behaving as expected on Linux -- it's not killing processes.
13501 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13502 }
13503
13504 private final void trimApplications() {
13505 synchronized (this) {
13506 int i;
13507
13508 // First remove any unused application processes whose package
13509 // has been removed.
13510 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13511 final ProcessRecord app = mRemovedProcesses.get(i);
13512 if (app.activities.size() == 0
13513 && app.curReceiver == null && app.services.size() == 0) {
13514 Log.i(
13515 TAG, "Exiting empty application process "
13516 + app.processName + " ("
13517 + (app.thread != null ? app.thread.asBinder() : null)
13518 + ")\n");
13519 if (app.pid > 0 && app.pid != MY_PID) {
13520 Process.killProcess(app.pid);
13521 } else {
13522 try {
13523 app.thread.scheduleExit();
13524 } catch (Exception e) {
13525 // Ignore exceptions.
13526 }
13527 }
13528 cleanUpApplicationRecordLocked(app, false, -1);
13529 mRemovedProcesses.remove(i);
13530
13531 if (app.persistent) {
13532 if (app.persistent) {
13533 addAppLocked(app.info);
13534 }
13535 }
13536 }
13537 }
13538
13539 // Now try updating the OOM adjustment for each of the
13540 // application processes based on their current state.
13541 // If the setOomAdj() API is not supported, then go with our
13542 // back-up plan...
13543 if (!updateOomAdjLocked()) {
13544
13545 // Count how many processes are running services.
13546 int numServiceProcs = 0;
13547 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13548 final ProcessRecord app = mLRUProcesses.get(i);
13549
13550 if (app.persistent || app.services.size() != 0
13551 || app.curReceiver != null
13552 || app.persistentActivities > 0) {
13553 // Don't count processes holding services against our
13554 // maximum process count.
13555 if (localLOGV) Log.v(
13556 TAG, "Not trimming app " + app + " with services: "
13557 + app.services);
13558 numServiceProcs++;
13559 }
13560 }
13561
13562 int curMaxProcs = mProcessLimit;
13563 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13564 if (mAlwaysFinishActivities) {
13565 curMaxProcs = 1;
13566 }
13567 curMaxProcs += numServiceProcs;
13568
13569 // Quit as many processes as we can to get down to the desired
13570 // process count. First remove any processes that no longer
13571 // have activites running in them.
13572 for ( i=0;
13573 i<mLRUProcesses.size()
13574 && mLRUProcesses.size() > curMaxProcs;
13575 i++) {
13576 final ProcessRecord app = mLRUProcesses.get(i);
13577 // Quit an application only if it is not currently
13578 // running any activities.
13579 if (!app.persistent && app.activities.size() == 0
13580 && app.curReceiver == null && app.services.size() == 0) {
13581 Log.i(
13582 TAG, "Exiting empty application process "
13583 + app.processName + " ("
13584 + (app.thread != null ? app.thread.asBinder() : null)
13585 + ")\n");
13586 if (app.pid > 0 && app.pid != MY_PID) {
13587 Process.killProcess(app.pid);
13588 } else {
13589 try {
13590 app.thread.scheduleExit();
13591 } catch (Exception e) {
13592 // Ignore exceptions.
13593 }
13594 }
13595 // todo: For now we assume the application is not buggy
13596 // or evil, and will quit as a result of our request.
13597 // Eventually we need to drive this off of the death
13598 // notification, and kill the process if it takes too long.
13599 cleanUpApplicationRecordLocked(app, false, i);
13600 i--;
13601 }
13602 }
13603
13604 // If we still have too many processes, now from the least
13605 // recently used process we start finishing activities.
13606 if (Config.LOGV) Log.v(
13607 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13608 " of " + curMaxProcs + " processes");
13609 for ( i=0;
13610 i<mLRUProcesses.size()
13611 && mLRUProcesses.size() > curMaxProcs;
13612 i++) {
13613 final ProcessRecord app = mLRUProcesses.get(i);
13614 // Quit the application only if we have a state saved for
13615 // all of its activities.
13616 boolean canQuit = !app.persistent && app.curReceiver == null
13617 && app.services.size() == 0
13618 && app.persistentActivities == 0;
13619 int NUMA = app.activities.size();
13620 int j;
13621 if (Config.LOGV) Log.v(
13622 TAG, "Looking to quit " + app.processName);
13623 for (j=0; j<NUMA && canQuit; j++) {
13624 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13625 if (Config.LOGV) Log.v(
13626 TAG, " " + r.intent.getComponent().flattenToShortString()
13627 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13628 canQuit = (r.haveState || !r.stateNotNeeded)
13629 && !r.visible && r.stopped;
13630 }
13631 if (canQuit) {
13632 // Finish all of the activities, and then the app itself.
13633 for (j=0; j<NUMA; j++) {
13634 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13635 if (!r.finishing) {
13636 destroyActivityLocked(r, false);
13637 }
13638 r.resultTo = null;
13639 }
13640 Log.i(TAG, "Exiting application process "
13641 + app.processName + " ("
13642 + (app.thread != null ? app.thread.asBinder() : null)
13643 + ")\n");
13644 if (app.pid > 0 && app.pid != MY_PID) {
13645 Process.killProcess(app.pid);
13646 } else {
13647 try {
13648 app.thread.scheduleExit();
13649 } catch (Exception e) {
13650 // Ignore exceptions.
13651 }
13652 }
13653 // todo: For now we assume the application is not buggy
13654 // or evil, and will quit as a result of our request.
13655 // Eventually we need to drive this off of the death
13656 // notification, and kill the process if it takes too long.
13657 cleanUpApplicationRecordLocked(app, false, i);
13658 i--;
13659 //dump();
13660 }
13661 }
13662
13663 }
13664
13665 int curMaxActivities = MAX_ACTIVITIES;
13666 if (mAlwaysFinishActivities) {
13667 curMaxActivities = 1;
13668 }
13669
13670 // Finally, if there are too many activities now running, try to
13671 // finish as many as we can to get back down to the limit.
13672 for ( i=0;
13673 i<mLRUActivities.size()
13674 && mLRUActivities.size() > curMaxActivities;
13675 i++) {
13676 final HistoryRecord r
13677 = (HistoryRecord)mLRUActivities.get(i);
13678
13679 // We can finish this one if we have its icicle saved and
13680 // it is not persistent.
13681 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13682 && r.stopped && !r.persistent && !r.finishing) {
13683 final int origSize = mLRUActivities.size();
13684 destroyActivityLocked(r, true);
13685
13686 // This will remove it from the LRU list, so keep
13687 // our index at the same value. Note that this check to
13688 // see if the size changes is just paranoia -- if
13689 // something unexpected happens, we don't want to end up
13690 // in an infinite loop.
13691 if (origSize > mLRUActivities.size()) {
13692 i--;
13693 }
13694 }
13695 }
13696 }
13697 }
13698
13699 /** This method sends the specified signal to each of the persistent apps */
13700 public void signalPersistentProcesses(int sig) throws RemoteException {
13701 if (sig != Process.SIGNAL_USR1) {
13702 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13703 }
13704
13705 synchronized (this) {
13706 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13707 != PackageManager.PERMISSION_GRANTED) {
13708 throw new SecurityException("Requires permission "
13709 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13710 }
13711
13712 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13713 ProcessRecord r = mLRUProcesses.get(i);
13714 if (r.thread != null && r.persistent) {
13715 Process.sendSignal(r.pid, sig);
13716 }
13717 }
13718 }
13719 }
13720
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013721 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013722 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013723
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013724 try {
13725 synchronized (this) {
13726 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13727 // its own permission.
13728 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13729 != PackageManager.PERMISSION_GRANTED) {
13730 throw new SecurityException("Requires permission "
13731 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013732 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013733
13734 if (start && fd == null) {
13735 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013736 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013737
13738 ProcessRecord proc = null;
13739 try {
13740 int pid = Integer.parseInt(process);
13741 synchronized (mPidsSelfLocked) {
13742 proc = mPidsSelfLocked.get(pid);
13743 }
13744 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013745 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013746
13747 if (proc == null) {
13748 HashMap<String, SparseArray<ProcessRecord>> all
13749 = mProcessNames.getMap();
13750 SparseArray<ProcessRecord> procs = all.get(process);
13751 if (procs != null && procs.size() > 0) {
13752 proc = procs.valueAt(0);
13753 }
13754 }
13755
13756 if (proc == null || proc.thread == null) {
13757 throw new IllegalArgumentException("Unknown process: " + process);
13758 }
13759
13760 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13761 if (isSecure) {
13762 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13763 throw new SecurityException("Process not debuggable: " + proc);
13764 }
13765 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013766
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013767 proc.thread.profilerControl(start, path, fd);
13768 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013769 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013770 }
13771 } catch (RemoteException e) {
13772 throw new IllegalStateException("Process disappeared");
13773 } finally {
13774 if (fd != null) {
13775 try {
13776 fd.close();
13777 } catch (IOException e) {
13778 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013779 }
13780 }
13781 }
13782
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013783 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13784 public void monitor() {
13785 synchronized (this) { }
13786 }
13787}