blob: 3460d3ac98a302e1c825c2c106fe6865f9ef7a0e [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
1439 MY_PID = Process.myPid();
1440
1441 File dataDir = Environment.getDataDirectory();
1442 File systemDir = new File(dataDir, "system");
1443 systemDir.mkdirs();
1444 mBatteryStatsService = new BatteryStatsService(new File(
1445 systemDir, "batterystats.bin").toString());
1446 mBatteryStatsService.getActiveStatistics().readLocked();
1447 mBatteryStatsService.getActiveStatistics().writeLocked();
1448
1449 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001450 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451
Jack Palevichb90d28c2009-07-22 15:35:24 -07001452 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1453 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1454
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001455 mConfiguration.makeDefault();
1456 mProcessStats.init();
1457
1458 // Add ourself to the Watchdog monitors.
1459 Watchdog.getInstance().addMonitor(this);
1460
1461 // These values are set in system/rootdir/init.rc on startup.
1462 FOREGROUND_APP_ADJ =
1463 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1464 VISIBLE_APP_ADJ =
1465 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1466 SECONDARY_SERVER_ADJ =
1467 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001468 BACKUP_APP_ADJ =
1469 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001470 HOME_APP_ADJ =
1471 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472 HIDDEN_APP_MIN_ADJ =
1473 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1474 CONTENT_PROVIDER_ADJ =
1475 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1476 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1477 EMPTY_APP_ADJ =
1478 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1479 FOREGROUND_APP_MEM =
1480 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1481 VISIBLE_APP_MEM =
1482 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1483 SECONDARY_SERVER_MEM =
1484 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001485 BACKUP_APP_MEM =
1486 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001487 HOME_APP_MEM =
1488 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 HIDDEN_APP_MEM =
1490 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1491 EMPTY_APP_MEM =
1492 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1493
1494 mProcessStatsThread = new Thread("ProcessStats") {
1495 public void run() {
1496 while (true) {
1497 try {
1498 try {
1499 synchronized(this) {
1500 final long now = SystemClock.uptimeMillis();
1501 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1502 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1503 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1504 // + ", write delay=" + nextWriteDelay);
1505 if (nextWriteDelay < nextCpuDelay) {
1506 nextCpuDelay = nextWriteDelay;
1507 }
1508 if (nextCpuDelay > 0) {
1509 this.wait(nextCpuDelay);
1510 }
1511 }
1512 } catch (InterruptedException e) {
1513 }
1514
1515 updateCpuStatsNow();
1516 } catch (Exception e) {
1517 Log.e(TAG, "Unexpected exception collecting process stats", e);
1518 }
1519 }
1520 }
1521 };
1522 mProcessStatsThread.start();
1523 }
1524
1525 @Override
1526 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1527 throws RemoteException {
1528 try {
1529 return super.onTransact(code, data, reply, flags);
1530 } catch (RuntimeException e) {
1531 // The activity manager only throws security exceptions, so let's
1532 // log all others.
1533 if (!(e instanceof SecurityException)) {
1534 Log.e(TAG, "Activity Manager Crash", e);
1535 }
1536 throw e;
1537 }
1538 }
1539
1540 void updateCpuStats() {
1541 synchronized (mProcessStatsThread) {
1542 final long now = SystemClock.uptimeMillis();
1543 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1544 mProcessStatsThread.notify();
1545 }
1546 }
1547 }
1548
1549 void updateCpuStatsNow() {
1550 synchronized (mProcessStatsThread) {
1551 final long now = SystemClock.uptimeMillis();
1552 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 if (MONITOR_CPU_USAGE &&
1555 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1556 mLastCpuTime = now;
1557 haveNewCpuStats = true;
1558 mProcessStats.update();
1559 //Log.i(TAG, mProcessStats.printCurrentState());
1560 //Log.i(TAG, "Total CPU usage: "
1561 // + mProcessStats.getTotalCpuPercent() + "%");
1562
1563 // Log the cpu usage if the property is set.
1564 if ("true".equals(SystemProperties.get("events.cpu"))) {
1565 int user = mProcessStats.getLastUserTime();
1566 int system = mProcessStats.getLastSystemTime();
1567 int iowait = mProcessStats.getLastIoWaitTime();
1568 int irq = mProcessStats.getLastIrqTime();
1569 int softIrq = mProcessStats.getLastSoftIrqTime();
1570 int idle = mProcessStats.getLastIdleTime();
1571
1572 int total = user + system + iowait + irq + softIrq + idle;
1573 if (total == 0) total = 1;
1574
1575 EventLog.writeEvent(LOG_CPU,
1576 ((user+system+iowait+irq+softIrq) * 100) / total,
1577 (user * 100) / total,
1578 (system * 100) / total,
1579 (iowait * 100) / total,
1580 (irq * 100) / total,
1581 (softIrq * 100) / total);
1582 }
1583 }
1584
Amith Yamasanie43530a2009-08-21 13:11:37 -07001585 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001586 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001587 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001588 synchronized(mPidsSelfLocked) {
1589 if (haveNewCpuStats) {
1590 if (mBatteryStatsService.isOnBattery()) {
1591 final int N = mProcessStats.countWorkingStats();
1592 for (int i=0; i<N; i++) {
1593 ProcessStats.Stats st
1594 = mProcessStats.getWorkingStats(i);
1595 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1596 if (pr != null) {
1597 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1598 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001599 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001600 } else {
1601 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001602 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001603 if (ps != null) {
1604 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001605 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001606 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607 }
1608 }
1609 }
1610 }
1611 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001612
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001613 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1614 mLastWriteTime = now;
1615 mBatteryStatsService.getActiveStatistics().writeLocked();
1616 }
1617 }
1618 }
1619 }
1620
1621 /**
1622 * Initialize the application bind args. These are passed to each
1623 * process when the bindApplication() IPC is sent to the process. They're
1624 * lazily setup to make sure the services are running when they're asked for.
1625 */
1626 private HashMap<String, IBinder> getCommonServicesLocked() {
1627 if (mAppBindArgs == null) {
1628 mAppBindArgs = new HashMap<String, IBinder>();
1629
1630 // Setup the application init args
1631 mAppBindArgs.put("package", ServiceManager.getService("package"));
1632 mAppBindArgs.put("window", ServiceManager.getService("window"));
1633 mAppBindArgs.put(Context.ALARM_SERVICE,
1634 ServiceManager.getService(Context.ALARM_SERVICE));
1635 }
1636 return mAppBindArgs;
1637 }
1638
1639 private final void setFocusedActivityLocked(HistoryRecord r) {
1640 if (mFocusedActivity != r) {
1641 mFocusedActivity = r;
1642 mWindowManager.setFocusedApp(r, true);
1643 }
1644 }
1645
1646 private final void updateLRUListLocked(ProcessRecord app,
1647 boolean oomAdj) {
1648 // put it on the LRU to keep track of when it should be exited.
1649 int lrui = mLRUProcesses.indexOf(app);
1650 if (lrui >= 0) mLRUProcesses.remove(lrui);
1651 mLRUProcesses.add(app);
1652 //Log.i(TAG, "Putting proc to front: " + app.processName);
1653 if (oomAdj) {
1654 updateOomAdjLocked();
1655 }
1656 }
1657
1658 private final boolean updateLRUListLocked(HistoryRecord r) {
1659 final boolean hadit = mLRUActivities.remove(r);
1660 mLRUActivities.add(r);
1661 return hadit;
1662 }
1663
1664 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1665 int i = mHistory.size()-1;
1666 while (i >= 0) {
1667 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1668 if (!r.finishing && r != notTop) {
1669 return r;
1670 }
1671 i--;
1672 }
1673 return null;
1674 }
1675
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001676 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1677 int i = mHistory.size()-1;
1678 while (i >= 0) {
1679 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1680 if (!r.finishing && !r.delayedResume && r != notTop) {
1681 return r;
1682 }
1683 i--;
1684 }
1685 return null;
1686 }
1687
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001688 /**
1689 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001690 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 *
1692 * @param token If non-null, any history records matching this token will be skipped.
1693 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1694 *
1695 * @return Returns the HistoryRecord of the next activity on the stack.
1696 */
1697 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1698 int i = mHistory.size()-1;
1699 while (i >= 0) {
1700 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1701 // Note: the taskId check depends on real taskId fields being non-zero
1702 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1703 return r;
1704 }
1705 i--;
1706 }
1707 return null;
1708 }
1709
1710 private final ProcessRecord getProcessRecordLocked(
1711 String processName, int uid) {
1712 if (uid == Process.SYSTEM_UID) {
1713 // The system gets to run in any process. If there are multiple
1714 // processes with the same uid, just pick the first (this
1715 // should never happen).
1716 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1717 processName);
1718 return procs != null ? procs.valueAt(0) : null;
1719 }
1720 ProcessRecord proc = mProcessNames.get(processName, uid);
1721 return proc;
1722 }
1723
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001724 private void ensurePackageDexOpt(String packageName) {
1725 IPackageManager pm = ActivityThread.getPackageManager();
1726 try {
1727 if (pm.performDexOpt(packageName)) {
1728 mDidDexOpt = true;
1729 }
1730 } catch (RemoteException e) {
1731 }
1732 }
1733
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 private boolean isNextTransitionForward() {
1735 int transit = mWindowManager.getPendingAppTransition();
1736 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1737 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1738 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1739 }
1740
1741 private final boolean realStartActivityLocked(HistoryRecord r,
1742 ProcessRecord app, boolean andResume, boolean checkConfig)
1743 throws RemoteException {
1744
1745 r.startFreezingScreenLocked(app, 0);
1746 mWindowManager.setAppVisibility(r, true);
1747
1748 // Have the window manager re-evaluate the orientation of
1749 // the screen based on the new activity order. Note that
1750 // as a result of this, it can call back into the activity
1751 // manager with a new orientation. We don't care about that,
1752 // because the activity is not currently running so we are
1753 // just restarting it anyway.
1754 if (checkConfig) {
1755 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001756 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001757 r.mayFreezeScreenLocked(app) ? r : null);
1758 updateConfigurationLocked(config, r);
1759 }
1760
1761 r.app = app;
1762
1763 if (localLOGV) Log.v(TAG, "Launching: " + r);
1764
1765 int idx = app.activities.indexOf(r);
1766 if (idx < 0) {
1767 app.activities.add(r);
1768 }
1769 updateLRUListLocked(app, true);
1770
1771 try {
1772 if (app.thread == null) {
1773 throw new RemoteException();
1774 }
1775 List<ResultInfo> results = null;
1776 List<Intent> newIntents = null;
1777 if (andResume) {
1778 results = r.results;
1779 newIntents = r.newIntents;
1780 }
1781 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1782 + " icicle=" + r.icicle
1783 + " with results=" + results + " newIntents=" + newIntents
1784 + " andResume=" + andResume);
1785 if (andResume) {
1786 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1787 System.identityHashCode(r),
1788 r.task.taskId, r.shortComponentName);
1789 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001790 if (r.isHomeActivity) {
1791 mHomeProcess = app;
1792 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001793 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001794 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001795 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001796 r.info, r.icicle, results, newIntents, !andResume,
1797 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001798 } catch (RemoteException e) {
1799 if (r.launchFailed) {
1800 // This is the second time we failed -- finish activity
1801 // and give up.
1802 Log.e(TAG, "Second failure launching "
1803 + r.intent.getComponent().flattenToShortString()
1804 + ", giving up", e);
1805 appDiedLocked(app, app.pid, app.thread);
1806 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1807 "2nd-crash");
1808 return false;
1809 }
1810
1811 // This is the first time we failed -- restart process and
1812 // retry.
1813 app.activities.remove(r);
1814 throw e;
1815 }
1816
1817 r.launchFailed = false;
1818 if (updateLRUListLocked(r)) {
1819 Log.w(TAG, "Activity " + r
1820 + " being launched, but already in LRU list");
1821 }
1822
1823 if (andResume) {
1824 // As part of the process of launching, ActivityThread also performs
1825 // a resume.
1826 r.state = ActivityState.RESUMED;
1827 r.icicle = null;
1828 r.haveState = false;
1829 r.stopped = false;
1830 mResumedActivity = r;
1831 r.task.touchActiveTime();
1832 completeResumeLocked(r);
1833 pauseIfSleepingLocked();
1834 } else {
1835 // This activity is not starting in the resumed state... which
1836 // should look like we asked it to pause+stop (but remain visible),
1837 // and it has done so and reported back the current icicle and
1838 // other state.
1839 r.state = ActivityState.STOPPED;
1840 r.stopped = true;
1841 }
1842
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001843 // Launch the new version setup screen if needed. We do this -after-
1844 // launching the initial activity (that is, home), so that it can have
1845 // a chance to initialize itself while in the background, making the
1846 // switch back to it faster and look better.
1847 startSetupActivityLocked();
1848
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001849 return true;
1850 }
1851
1852 private final void startSpecificActivityLocked(HistoryRecord r,
1853 boolean andResume, boolean checkConfig) {
1854 // Is this activity's application already running?
1855 ProcessRecord app = getProcessRecordLocked(r.processName,
1856 r.info.applicationInfo.uid);
1857
1858 if (r.startTime == 0) {
1859 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001860 if (mInitialStartTime == 0) {
1861 mInitialStartTime = r.startTime;
1862 }
1863 } else if (mInitialStartTime == 0) {
1864 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001865 }
1866
1867 if (app != null && app.thread != null) {
1868 try {
1869 realStartActivityLocked(r, app, andResume, checkConfig);
1870 return;
1871 } catch (RemoteException e) {
1872 Log.w(TAG, "Exception when starting activity "
1873 + r.intent.getComponent().flattenToShortString(), e);
1874 }
1875
1876 // If a dead object exception was thrown -- fall through to
1877 // restart the application.
1878 }
1879
1880 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001881 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001882 }
1883
1884 private final ProcessRecord startProcessLocked(String processName,
1885 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001886 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001887 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1888 // We don't have to do anything more if:
1889 // (1) There is an existing application record; and
1890 // (2) The caller doesn't think it is dead, OR there is no thread
1891 // object attached to it so we know it couldn't have crashed; and
1892 // (3) There is a pid assigned to it, so it is either starting or
1893 // already running.
1894 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1895 + " app=" + app + " knownToBeDead=" + knownToBeDead
1896 + " thread=" + (app != null ? app.thread : null)
1897 + " pid=" + (app != null ? app.pid : -1));
1898 if (app != null &&
1899 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1900 return app;
1901 }
1902
1903 String hostingNameStr = hostingName != null
1904 ? hostingName.flattenToShortString() : null;
1905
1906 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1907 // If we are in the background, then check to see if this process
1908 // is bad. If so, we will just silently fail.
1909 if (mBadProcesses.get(info.processName, info.uid) != null) {
1910 return null;
1911 }
1912 } else {
1913 // When the user is explicitly starting a process, then clear its
1914 // crash count so that we won't make it bad until they see at
1915 // least one crash dialog again, and make the process good again
1916 // if it had been bad.
1917 mProcessCrashTimes.remove(info.processName, info.uid);
1918 if (mBadProcesses.get(info.processName, info.uid) != null) {
1919 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1920 info.processName);
1921 mBadProcesses.remove(info.processName, info.uid);
1922 if (app != null) {
1923 app.bad = false;
1924 }
1925 }
1926 }
1927
1928 if (app == null) {
1929 app = newProcessRecordLocked(null, info, processName);
1930 mProcessNames.put(processName, info.uid, app);
1931 } else {
1932 // If this is a new package in the process, add the package to the list
1933 app.addPackage(info.packageName);
1934 }
1935
1936 // If the system is not ready yet, then hold off on starting this
1937 // process until it is.
1938 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001939 && !isAllowedWhileBooting(info)
1940 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001941 if (!mProcessesOnHold.contains(app)) {
1942 mProcessesOnHold.add(app);
1943 }
1944 return app;
1945 }
1946
1947 startProcessLocked(app, hostingType, hostingNameStr);
1948 return (app.pid != 0) ? app : null;
1949 }
1950
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001951 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1952 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1953 }
1954
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001955 private final void startProcessLocked(ProcessRecord app,
1956 String hostingType, String hostingNameStr) {
1957 if (app.pid > 0 && app.pid != MY_PID) {
1958 synchronized (mPidsSelfLocked) {
1959 mPidsSelfLocked.remove(app.pid);
1960 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1961 }
1962 app.pid = 0;
1963 }
1964
1965 mProcessesOnHold.remove(app);
1966
1967 updateCpuStats();
1968
1969 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1970 mProcDeaths[0] = 0;
1971
1972 try {
1973 int uid = app.info.uid;
1974 int[] gids = null;
1975 try {
1976 gids = mContext.getPackageManager().getPackageGids(
1977 app.info.packageName);
1978 } catch (PackageManager.NameNotFoundException e) {
1979 Log.w(TAG, "Unable to retrieve gids", e);
1980 }
1981 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1982 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1983 && mTopComponent != null
1984 && app.processName.equals(mTopComponent.getPackageName())) {
1985 uid = 0;
1986 }
1987 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1988 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1989 uid = 0;
1990 }
1991 }
1992 int debugFlags = 0;
1993 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1994 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1995 }
1996 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1997 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1998 }
1999 if ("1".equals(SystemProperties.get("debug.assert"))) {
2000 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
2001 }
2002 int pid = Process.start("android.app.ActivityThread",
2003 mSimpleProcessManagement ? app.processName : null, uid, uid,
2004 gids, debugFlags, null);
2005 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
2006 synchronized (bs) {
2007 if (bs.isOnBattery()) {
2008 app.batteryStats.incStartsLocked();
2009 }
2010 }
2011
2012 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
2013 app.processName, hostingType,
2014 hostingNameStr != null ? hostingNameStr : "");
2015
2016 if (app.persistent) {
2017 Watchdog.getInstance().processStarted(app, app.processName, pid);
2018 }
2019
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07002020 StringBuilder buf = mStringBuilder;
2021 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002022 buf.append("Start proc ");
2023 buf.append(app.processName);
2024 buf.append(" for ");
2025 buf.append(hostingType);
2026 if (hostingNameStr != null) {
2027 buf.append(" ");
2028 buf.append(hostingNameStr);
2029 }
2030 buf.append(": pid=");
2031 buf.append(pid);
2032 buf.append(" uid=");
2033 buf.append(uid);
2034 buf.append(" gids={");
2035 if (gids != null) {
2036 for (int gi=0; gi<gids.length; gi++) {
2037 if (gi != 0) buf.append(", ");
2038 buf.append(gids[gi]);
2039
2040 }
2041 }
2042 buf.append("}");
2043 Log.i(TAG, buf.toString());
2044 if (pid == 0 || pid == MY_PID) {
2045 // Processes are being emulated with threads.
2046 app.pid = MY_PID;
2047 app.removed = false;
2048 mStartingProcesses.add(app);
2049 } else if (pid > 0) {
2050 app.pid = pid;
2051 app.removed = false;
2052 synchronized (mPidsSelfLocked) {
2053 this.mPidsSelfLocked.put(pid, app);
2054 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2055 msg.obj = app;
2056 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2057 }
2058 } else {
2059 app.pid = 0;
2060 RuntimeException e = new RuntimeException(
2061 "Failure starting process " + app.processName
2062 + ": returned pid=" + pid);
2063 Log.e(TAG, e.getMessage(), e);
2064 }
2065 } catch (RuntimeException e) {
2066 // XXX do better error recovery.
2067 app.pid = 0;
2068 Log.e(TAG, "Failure starting process " + app.processName, e);
2069 }
2070 }
2071
2072 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2073 if (mPausingActivity != null) {
2074 RuntimeException e = new RuntimeException();
2075 Log.e(TAG, "Trying to pause when pause is already pending for "
2076 + mPausingActivity, e);
2077 }
2078 HistoryRecord prev = mResumedActivity;
2079 if (prev == null) {
2080 RuntimeException e = new RuntimeException();
2081 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2082 resumeTopActivityLocked(null);
2083 return;
2084 }
2085 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2086 mResumedActivity = null;
2087 mPausingActivity = prev;
2088 mLastPausedActivity = prev;
2089 prev.state = ActivityState.PAUSING;
2090 prev.task.touchActiveTime();
2091
2092 updateCpuStats();
2093
2094 if (prev.app != null && prev.app.thread != null) {
2095 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2096 try {
2097 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2098 System.identityHashCode(prev),
2099 prev.shortComponentName);
2100 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2101 prev.configChangeFlags);
2102 updateUsageStats(prev, false);
2103 } catch (Exception e) {
2104 // Ignore exception, if process died other code will cleanup.
2105 Log.w(TAG, "Exception thrown during pause", e);
2106 mPausingActivity = null;
2107 mLastPausedActivity = null;
2108 }
2109 } else {
2110 mPausingActivity = null;
2111 mLastPausedActivity = null;
2112 }
2113
2114 // If we are not going to sleep, we want to ensure the device is
2115 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002116 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002117 mLaunchingActivity.acquire();
2118 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2119 // To be safe, don't allow the wake lock to be held for too long.
2120 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2121 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2122 }
2123 }
2124
2125
2126 if (mPausingActivity != null) {
2127 // Have the window manager pause its key dispatching until the new
2128 // activity has started. If we're pausing the activity just because
2129 // the screen is being turned off and the UI is sleeping, don't interrupt
2130 // key dispatch; the same activity will pick it up again on wakeup.
2131 if (!uiSleeping) {
2132 prev.pauseKeyDispatchingLocked();
2133 } else {
2134 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2135 }
2136
2137 // Schedule a pause timeout in case the app doesn't respond.
2138 // We don't give it much time because this directly impacts the
2139 // responsiveness seen by the user.
2140 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2141 msg.obj = prev;
2142 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2143 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2144 } else {
2145 // This activity failed to schedule the
2146 // pause, so just treat it as being paused now.
2147 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2148 resumeTopActivityLocked(null);
2149 }
2150 }
2151
2152 private final void completePauseLocked() {
2153 HistoryRecord prev = mPausingActivity;
2154 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2155
2156 if (prev != null) {
2157 if (prev.finishing) {
2158 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2159 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2160 } else if (prev.app != null) {
2161 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2162 if (prev.waitingVisible) {
2163 prev.waitingVisible = false;
2164 mWaitingVisibleActivities.remove(prev);
2165 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2166 TAG, "Complete pause, no longer waiting: " + prev);
2167 }
2168 if (prev.configDestroy) {
2169 // The previous is being paused because the configuration
2170 // is changing, which means it is actually stopping...
2171 // To juggle the fact that we are also starting a new
2172 // instance right now, we need to first completely stop
2173 // the current instance before starting the new one.
2174 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2175 destroyActivityLocked(prev, true);
2176 } else {
2177 mStoppingActivities.add(prev);
2178 if (mStoppingActivities.size() > 3) {
2179 // If we already have a few activities waiting to stop,
2180 // then give up on things going idle and start clearing
2181 // them out.
2182 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2183 Message msg = Message.obtain();
2184 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2185 mHandler.sendMessage(msg);
2186 }
2187 }
2188 } else {
2189 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2190 prev = null;
2191 }
2192 mPausingActivity = null;
2193 }
2194
Dianne Hackborn55280a92009-05-07 15:53:46 -07002195 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002196 resumeTopActivityLocked(prev);
2197 } else {
2198 if (mGoingToSleep.isHeld()) {
2199 mGoingToSleep.release();
2200 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002201 if (mShuttingDown) {
2202 notifyAll();
2203 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002204 }
2205
2206 if (prev != null) {
2207 prev.resumeKeyDispatchingLocked();
2208 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002209
2210 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2211 long diff = 0;
2212 synchronized (mProcessStatsThread) {
2213 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2214 }
2215 if (diff > 0) {
2216 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2217 synchronized (bsi) {
2218 BatteryStatsImpl.Uid.Proc ps =
2219 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2220 prev.info.packageName);
2221 if (ps != null) {
2222 ps.addForegroundTimeLocked(diff);
2223 }
2224 }
2225 }
2226 }
2227 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002228 }
2229
2230 /**
2231 * Once we know that we have asked an application to put an activity in
2232 * the resumed state (either by launching it or explicitly telling it),
2233 * this function updates the rest of our state to match that fact.
2234 */
2235 private final void completeResumeLocked(HistoryRecord next) {
2236 next.idle = false;
2237 next.results = null;
2238 next.newIntents = null;
2239
2240 // schedule an idle timeout in case the app doesn't do it for us.
2241 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2242 msg.obj = next;
2243 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2244
2245 if (false) {
2246 // The activity was never told to pause, so just keep
2247 // things going as-is. To maintain our own state,
2248 // we need to emulate it coming back and saying it is
2249 // idle.
2250 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2251 msg.obj = next;
2252 mHandler.sendMessage(msg);
2253 }
2254
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002255 reportResumedActivityLocked(next);
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002256
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002257 next.thumbnail = null;
2258 setFocusedActivityLocked(next);
2259 next.resumeKeyDispatchingLocked();
2260 ensureActivitiesVisibleLocked(null, 0);
2261 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002262 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002263
2264 // Mark the point when the activity is resuming
2265 // TODO: To be more accurate, the mark should be before the onCreate,
2266 // not after the onResume. But for subsequent starts, onResume is fine.
2267 if (next.app != null) {
2268 synchronized (mProcessStatsThread) {
2269 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2270 }
2271 } else {
2272 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2273 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002274 }
2275
2276 /**
2277 * Make sure that all activities that need to be visible (that is, they
2278 * currently can be seen by the user) actually are.
2279 */
2280 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2281 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2282 if (DEBUG_VISBILITY) Log.v(
2283 TAG, "ensureActivitiesVisible behind " + top
2284 + " configChanges=0x" + Integer.toHexString(configChanges));
2285
2286 // If the top activity is not fullscreen, then we need to
2287 // make sure any activities under it are now visible.
2288 final int count = mHistory.size();
2289 int i = count-1;
2290 while (mHistory.get(i) != top) {
2291 i--;
2292 }
2293 HistoryRecord r;
2294 boolean behindFullscreen = false;
2295 for (; i>=0; i--) {
2296 r = (HistoryRecord)mHistory.get(i);
2297 if (DEBUG_VISBILITY) Log.v(
2298 TAG, "Make visible? " + r + " finishing=" + r.finishing
2299 + " state=" + r.state);
2300 if (r.finishing) {
2301 continue;
2302 }
2303
2304 final boolean doThisProcess = onlyThisProcess == null
2305 || onlyThisProcess.equals(r.processName);
2306
2307 // First: if this is not the current activity being started, make
2308 // sure it matches the current configuration.
2309 if (r != starting && doThisProcess) {
2310 ensureActivityConfigurationLocked(r, 0);
2311 }
2312
2313 if (r.app == null || r.app.thread == null) {
2314 if (onlyThisProcess == null
2315 || onlyThisProcess.equals(r.processName)) {
2316 // This activity needs to be visible, but isn't even
2317 // running... get it started, but don't resume it
2318 // at this point.
2319 if (DEBUG_VISBILITY) Log.v(
2320 TAG, "Start and freeze screen for " + r);
2321 if (r != starting) {
2322 r.startFreezingScreenLocked(r.app, configChanges);
2323 }
2324 if (!r.visible) {
2325 if (DEBUG_VISBILITY) Log.v(
2326 TAG, "Starting and making visible: " + r);
2327 mWindowManager.setAppVisibility(r, true);
2328 }
2329 if (r != starting) {
2330 startSpecificActivityLocked(r, false, false);
2331 }
2332 }
2333
2334 } else if (r.visible) {
2335 // If this activity is already visible, then there is nothing
2336 // else to do here.
2337 if (DEBUG_VISBILITY) Log.v(
2338 TAG, "Skipping: already visible at " + r);
2339 r.stopFreezingScreenLocked(false);
2340
2341 } else if (onlyThisProcess == null) {
2342 // This activity is not currently visible, but is running.
2343 // Tell it to become visible.
2344 r.visible = true;
2345 if (r.state != ActivityState.RESUMED && r != starting) {
2346 // If this activity is paused, tell it
2347 // to now show its window.
2348 if (DEBUG_VISBILITY) Log.v(
2349 TAG, "Making visible and scheduling visibility: " + r);
2350 try {
2351 mWindowManager.setAppVisibility(r, true);
2352 r.app.thread.scheduleWindowVisibility(r, true);
2353 r.stopFreezingScreenLocked(false);
2354 } catch (Exception e) {
2355 // Just skip on any failure; we'll make it
2356 // visible when it next restarts.
2357 Log.w(TAG, "Exception thrown making visibile: "
2358 + r.intent.getComponent(), e);
2359 }
2360 }
2361 }
2362
2363 // Aggregate current change flags.
2364 configChanges |= r.configChangeFlags;
2365
2366 if (r.fullscreen) {
2367 // At this point, nothing else needs to be shown
2368 if (DEBUG_VISBILITY) Log.v(
2369 TAG, "Stopping: fullscreen at " + r);
2370 behindFullscreen = true;
2371 i--;
2372 break;
2373 }
2374 }
2375
2376 // Now for any activities that aren't visible to the user, make
2377 // sure they no longer are keeping the screen frozen.
2378 while (i >= 0) {
2379 r = (HistoryRecord)mHistory.get(i);
2380 if (DEBUG_VISBILITY) Log.v(
2381 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2382 + " state=" + r.state
2383 + " behindFullscreen=" + behindFullscreen);
2384 if (!r.finishing) {
2385 if (behindFullscreen) {
2386 if (r.visible) {
2387 if (DEBUG_VISBILITY) Log.v(
2388 TAG, "Making invisible: " + r);
2389 r.visible = false;
2390 try {
2391 mWindowManager.setAppVisibility(r, false);
2392 if ((r.state == ActivityState.STOPPING
2393 || r.state == ActivityState.STOPPED)
2394 && r.app != null && r.app.thread != null) {
2395 if (DEBUG_VISBILITY) Log.v(
2396 TAG, "Scheduling invisibility: " + r);
2397 r.app.thread.scheduleWindowVisibility(r, false);
2398 }
2399 } catch (Exception e) {
2400 // Just skip on any failure; we'll make it
2401 // visible when it next restarts.
2402 Log.w(TAG, "Exception thrown making hidden: "
2403 + r.intent.getComponent(), e);
2404 }
2405 } else {
2406 if (DEBUG_VISBILITY) Log.v(
2407 TAG, "Already invisible: " + r);
2408 }
2409 } else if (r.fullscreen) {
2410 if (DEBUG_VISBILITY) Log.v(
2411 TAG, "Now behindFullscreen: " + r);
2412 behindFullscreen = true;
2413 }
2414 }
2415 i--;
2416 }
2417 }
2418
2419 /**
2420 * Version of ensureActivitiesVisible that can easily be called anywhere.
2421 */
2422 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2423 int configChanges) {
2424 HistoryRecord r = topRunningActivityLocked(null);
2425 if (r != null) {
2426 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2427 }
2428 }
2429
2430 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2431 if (resumed) {
2432 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2433 } else {
2434 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2435 }
2436 }
2437
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002438 private boolean startHomeActivityLocked() {
2439 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2440 && mTopAction == null) {
2441 // We are running in factory test mode, but unable to find
2442 // the factory test app, so just sit around displaying the
2443 // error message and don't try to start anything.
2444 return false;
2445 }
2446 Intent intent = new Intent(
2447 mTopAction,
2448 mTopData != null ? Uri.parse(mTopData) : null);
2449 intent.setComponent(mTopComponent);
2450 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2451 intent.addCategory(Intent.CATEGORY_HOME);
2452 }
2453 ActivityInfo aInfo =
2454 intent.resolveActivityInfo(mContext.getPackageManager(),
2455 STOCK_PM_FLAGS);
2456 if (aInfo != null) {
2457 intent.setComponent(new ComponentName(
2458 aInfo.applicationInfo.packageName, aInfo.name));
2459 // Don't do this if the home app is currently being
2460 // instrumented.
2461 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2462 aInfo.applicationInfo.uid);
2463 if (app == null || app.instrumentationClass == null) {
2464 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2465 startActivityLocked(null, intent, null, null, 0, aInfo,
2466 null, null, 0, 0, 0, false, false);
2467 }
2468 }
2469
2470
2471 return true;
2472 }
2473
2474 /**
2475 * Starts the "new version setup screen" if appropriate.
2476 */
2477 private void startSetupActivityLocked() {
2478 // Only do this once per boot.
2479 if (mCheckedForSetup) {
2480 return;
2481 }
2482
2483 // We will show this screen if the current one is a different
2484 // version than the last one shown, and we are not running in
2485 // low-level factory test mode.
2486 final ContentResolver resolver = mContext.getContentResolver();
2487 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2488 Settings.Secure.getInt(resolver,
2489 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2490 mCheckedForSetup = true;
2491
2492 // See if we should be showing the platform update setup UI.
2493 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2494 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2495 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2496
2497 // We don't allow third party apps to replace this.
2498 ResolveInfo ri = null;
2499 for (int i=0; ris != null && i<ris.size(); i++) {
2500 if ((ris.get(i).activityInfo.applicationInfo.flags
2501 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2502 ri = ris.get(i);
2503 break;
2504 }
2505 }
2506
2507 if (ri != null) {
2508 String vers = ri.activityInfo.metaData != null
2509 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2510 : null;
2511 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2512 vers = ri.activityInfo.applicationInfo.metaData.getString(
2513 Intent.METADATA_SETUP_VERSION);
2514 }
2515 String lastVers = Settings.Secure.getString(
2516 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2517 if (vers != null && !vers.equals(lastVers)) {
2518 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2519 intent.setComponent(new ComponentName(
2520 ri.activityInfo.packageName, ri.activityInfo.name));
2521 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2522 null, null, 0, 0, 0, false, false);
2523 }
2524 }
2525 }
2526 }
2527
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002528 private void reportResumedActivityLocked(HistoryRecord r) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002529 //Log.i(TAG, "**** REPORT RESUME: " + r);
2530
2531 final int identHash = System.identityHashCode(r);
2532 updateUsageStats(r, true);
2533
2534 int i = mWatchers.beginBroadcast();
2535 while (i > 0) {
2536 i--;
2537 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2538 if (w != null) {
2539 try {
2540 w.activityResuming(identHash);
2541 } catch (RemoteException e) {
2542 }
2543 }
2544 }
2545 mWatchers.finishBroadcast();
2546 }
2547
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002548 /**
2549 * Ensure that the top activity in the stack is resumed.
2550 *
2551 * @param prev The previously resumed activity, for when in the process
2552 * of pausing; can be null to call from elsewhere.
2553 *
2554 * @return Returns true if something is being resumed, or false if
2555 * nothing happened.
2556 */
2557 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2558 // Find the first activity that is not finishing.
2559 HistoryRecord next = topRunningActivityLocked(null);
2560
2561 // Remember how we'll process this pause/resume situation, and ensure
2562 // that the state is reset however we wind up proceeding.
2563 final boolean userLeaving = mUserLeaving;
2564 mUserLeaving = false;
2565
2566 if (next == null) {
2567 // There are no more activities! Let's just start up the
2568 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002569 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002570 }
2571
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002572 next.delayedResume = false;
2573
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002574 // If the top activity is the resumed one, nothing to do.
2575 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2576 // Make sure we have executed any pending transitions, since there
2577 // should be nothing left to do at this point.
2578 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002579 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002580 return false;
2581 }
2582
2583 // If we are sleeping, and there is no resumed activity, and the top
2584 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002585 if ((mSleeping || mShuttingDown)
2586 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002587 // Make sure we have executed any pending transitions, since there
2588 // should be nothing left to do at this point.
2589 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002590 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002591 return false;
2592 }
2593
2594 // The activity may be waiting for stop, but that is no longer
2595 // appropriate for it.
2596 mStoppingActivities.remove(next);
2597 mWaitingVisibleActivities.remove(next);
2598
2599 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2600
2601 // If we are currently pausing an activity, then don't do anything
2602 // until that is done.
2603 if (mPausingActivity != null) {
2604 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2605 return false;
2606 }
2607
2608 // We need to start pausing the current activity so the top one
2609 // can be resumed...
2610 if (mResumedActivity != null) {
2611 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2612 startPausingLocked(userLeaving, false);
2613 return true;
2614 }
2615
2616 if (prev != null && prev != next) {
2617 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2618 prev.waitingVisible = true;
2619 mWaitingVisibleActivities.add(prev);
2620 if (DEBUG_SWITCH) Log.v(
2621 TAG, "Resuming top, waiting visible to hide: " + prev);
2622 } else {
2623 // The next activity is already visible, so hide the previous
2624 // activity's windows right now so we can show the new one ASAP.
2625 // We only do this if the previous is finishing, which should mean
2626 // it is on top of the one being resumed so hiding it quickly
2627 // is good. Otherwise, we want to do the normal route of allowing
2628 // the resumed activity to be shown so we can decide if the
2629 // previous should actually be hidden depending on whether the
2630 // new one is found to be full-screen or not.
2631 if (prev.finishing) {
2632 mWindowManager.setAppVisibility(prev, false);
2633 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2634 + prev + ", waitingVisible="
2635 + (prev != null ? prev.waitingVisible : null)
2636 + ", nowVisible=" + next.nowVisible);
2637 } else {
2638 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2639 + prev + ", waitingVisible="
2640 + (prev != null ? prev.waitingVisible : null)
2641 + ", nowVisible=" + next.nowVisible);
2642 }
2643 }
2644 }
2645
2646 // We are starting up the next activity, so tell the window manager
2647 // that the previous one will be hidden soon. This way it can know
2648 // to ignore it when computing the desired screen orientation.
2649 if (prev != null) {
2650 if (prev.finishing) {
2651 if (DEBUG_TRANSITION) Log.v(TAG,
2652 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002653 if (mNoAnimActivities.contains(prev)) {
2654 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2655 } else {
2656 mWindowManager.prepareAppTransition(prev.task == next.task
2657 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2658 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2659 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002660 mWindowManager.setAppWillBeHidden(prev);
2661 mWindowManager.setAppVisibility(prev, false);
2662 } else {
2663 if (DEBUG_TRANSITION) Log.v(TAG,
2664 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002665 if (mNoAnimActivities.contains(next)) {
2666 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2667 } else {
2668 mWindowManager.prepareAppTransition(prev.task == next.task
2669 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2670 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2671 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002672 }
2673 if (false) {
2674 mWindowManager.setAppWillBeHidden(prev);
2675 mWindowManager.setAppVisibility(prev, false);
2676 }
2677 } else if (mHistory.size() > 1) {
2678 if (DEBUG_TRANSITION) Log.v(TAG,
2679 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002680 if (mNoAnimActivities.contains(next)) {
2681 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2682 } else {
2683 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2684 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002685 }
2686
2687 if (next.app != null && next.app.thread != null) {
2688 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2689
2690 // This activity is now becoming visible.
2691 mWindowManager.setAppVisibility(next, true);
2692
2693 HistoryRecord lastResumedActivity = mResumedActivity;
2694 ActivityState lastState = next.state;
2695
2696 updateCpuStats();
2697
2698 next.state = ActivityState.RESUMED;
2699 mResumedActivity = next;
2700 next.task.touchActiveTime();
2701 updateLRUListLocked(next.app, true);
2702 updateLRUListLocked(next);
2703
2704 // Have the window manager re-evaluate the orientation of
2705 // the screen based on the new activity order.
2706 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002707 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002708 next.mayFreezeScreenLocked(next.app) ? next : null);
2709 if (config != null) {
2710 next.frozenBeforeDestroy = true;
2711 }
2712 if (!updateConfigurationLocked(config, next)) {
2713 // The configuration update wasn't able to keep the existing
2714 // instance of the activity, and instead started a new one.
2715 // We should be all done, but let's just make sure our activity
2716 // is still at the top and schedule another run if something
2717 // weird happened.
2718 HistoryRecord nextNext = topRunningActivityLocked(null);
2719 if (DEBUG_SWITCH) Log.i(TAG,
2720 "Activity config changed during resume: " + next
2721 + ", new next: " + nextNext);
2722 if (nextNext != next) {
2723 // Do over!
2724 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2725 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002726 setFocusedActivityLocked(next);
2727 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002728 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002729 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002730 return true;
2731 }
2732
2733 try {
2734 // Deliver all pending results.
2735 ArrayList a = next.results;
2736 if (a != null) {
2737 final int N = a.size();
2738 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002739 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002740 TAG, "Delivering results to " + next
2741 + ": " + a);
2742 next.app.thread.scheduleSendResult(next, a);
2743 }
2744 }
2745
2746 if (next.newIntents != null) {
2747 next.app.thread.scheduleNewIntent(next.newIntents, next);
2748 }
2749
2750 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2751 System.identityHashCode(next),
2752 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002753
2754 next.app.thread.scheduleResumeActivity(next,
2755 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002756
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002757 pauseIfSleepingLocked();
2758
2759 } catch (Exception e) {
2760 // Whoops, need to restart this activity!
2761 next.state = lastState;
2762 mResumedActivity = lastResumedActivity;
2763 if (Config.LOGD) Log.d(TAG,
2764 "Restarting because process died: " + next);
2765 if (!next.hasBeenLaunched) {
2766 next.hasBeenLaunched = true;
2767 } else {
2768 if (SHOW_APP_STARTING_ICON) {
2769 mWindowManager.setAppStartingWindow(
2770 next, next.packageName, next.theme,
2771 next.nonLocalizedLabel,
2772 next.labelRes, next.icon, null, true);
2773 }
2774 }
2775 startSpecificActivityLocked(next, true, false);
2776 return true;
2777 }
2778
2779 // From this point on, if something goes wrong there is no way
2780 // to recover the activity.
2781 try {
2782 next.visible = true;
2783 completeResumeLocked(next);
2784 } catch (Exception e) {
2785 // If any exception gets thrown, toss away this
2786 // activity and try the next one.
2787 Log.w(TAG, "Exception thrown during resume of " + next, e);
2788 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2789 "resume-exception");
2790 return true;
2791 }
2792
2793 // Didn't need to use the icicle, and it is now out of date.
2794 next.icicle = null;
2795 next.haveState = false;
2796 next.stopped = false;
2797
2798 } else {
2799 // Whoops, need to restart this activity!
2800 if (!next.hasBeenLaunched) {
2801 next.hasBeenLaunched = true;
2802 } else {
2803 if (SHOW_APP_STARTING_ICON) {
2804 mWindowManager.setAppStartingWindow(
2805 next, next.packageName, next.theme,
2806 next.nonLocalizedLabel,
2807 next.labelRes, next.icon, null, true);
2808 }
2809 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2810 }
2811 startSpecificActivityLocked(next, true, true);
2812 }
2813
2814 return true;
2815 }
2816
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002817 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2818 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002819 final int NH = mHistory.size();
2820
2821 int addPos = -1;
2822
2823 if (!newTask) {
2824 // If starting in an existing task, find where that is...
2825 HistoryRecord next = null;
2826 boolean startIt = true;
2827 for (int i = NH-1; i >= 0; i--) {
2828 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2829 if (p.finishing) {
2830 continue;
2831 }
2832 if (p.task == r.task) {
2833 // Here it is! Now, if this is not yet visible to the
2834 // user, then just add it without starting; it will
2835 // get started when the user navigates back to it.
2836 addPos = i+1;
2837 if (!startIt) {
2838 mHistory.add(addPos, r);
2839 r.inHistory = true;
2840 r.task.numActivities++;
2841 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2842 r.info.screenOrientation, r.fullscreen);
2843 if (VALIDATE_TOKENS) {
2844 mWindowManager.validateAppTokens(mHistory);
2845 }
2846 return;
2847 }
2848 break;
2849 }
2850 if (p.fullscreen) {
2851 startIt = false;
2852 }
2853 next = p;
2854 }
2855 }
2856
2857 // Place a new activity at top of stack, so it is next to interact
2858 // with the user.
2859 if (addPos < 0) {
2860 addPos = mHistory.size();
2861 }
2862
2863 // If we are not placing the new activity frontmost, we do not want
2864 // to deliver the onUserLeaving callback to the actual frontmost
2865 // activity
2866 if (addPos < NH) {
2867 mUserLeaving = false;
2868 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2869 }
2870
2871 // Slot the activity into the history stack and proceed
2872 mHistory.add(addPos, r);
2873 r.inHistory = true;
2874 r.frontOfTask = newTask;
2875 r.task.numActivities++;
2876 if (NH > 0) {
2877 // We want to show the starting preview window if we are
2878 // switching to a new task, or the next activity's process is
2879 // not currently running.
2880 boolean showStartingIcon = newTask;
2881 ProcessRecord proc = r.app;
2882 if (proc == null) {
2883 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2884 }
2885 if (proc == null || proc.thread == null) {
2886 showStartingIcon = true;
2887 }
2888 if (DEBUG_TRANSITION) Log.v(TAG,
2889 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002890 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2891 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2892 mNoAnimActivities.add(r);
2893 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2894 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2895 mNoAnimActivities.remove(r);
2896 } else {
2897 mWindowManager.prepareAppTransition(newTask
2898 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2899 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2900 mNoAnimActivities.remove(r);
2901 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002902 mWindowManager.addAppToken(
2903 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2904 boolean doShow = true;
2905 if (newTask) {
2906 // Even though this activity is starting fresh, we still need
2907 // to reset it to make sure we apply affinities to move any
2908 // existing activities from other tasks in to it.
2909 // If the caller has requested that the target task be
2910 // reset, then do so.
2911 if ((r.intent.getFlags()
2912 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2913 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002914 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002915 }
2916 }
2917 if (SHOW_APP_STARTING_ICON && doShow) {
2918 // Figure out if we are transitioning from another activity that is
2919 // "has the same starting icon" as the next one. This allows the
2920 // window manager to keep the previous window it had previously
2921 // created, if it still had one.
2922 HistoryRecord prev = mResumedActivity;
2923 if (prev != null) {
2924 // We don't want to reuse the previous starting preview if:
2925 // (1) The current activity is in a different task.
2926 if (prev.task != r.task) prev = null;
2927 // (2) The current activity is already displayed.
2928 else if (prev.nowVisible) prev = null;
2929 }
2930 mWindowManager.setAppStartingWindow(
2931 r, r.packageName, r.theme, r.nonLocalizedLabel,
2932 r.labelRes, r.icon, prev, showStartingIcon);
2933 }
2934 } else {
2935 // If this is the first activity, don't do any fancy animations,
2936 // because there is nothing for it to animate on top of.
2937 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2938 r.info.screenOrientation, r.fullscreen);
2939 }
2940 if (VALIDATE_TOKENS) {
2941 mWindowManager.validateAppTokens(mHistory);
2942 }
2943
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002944 if (doResume) {
2945 resumeTopActivityLocked(null);
2946 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002947 }
2948
2949 /**
2950 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002951 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2952 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002953 * an instance of that activity in the stack and, if found, finish all
2954 * activities on top of it and return the instance.
2955 *
2956 * @param newR Description of the new activity being started.
2957 * @return Returns the old activity that should be continue to be used,
2958 * or null if none was found.
2959 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002960 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002961 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002962 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002963
2964 // First find the requested task.
2965 while (i > 0) {
2966 i--;
2967 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2968 if (r.task.taskId == taskId) {
2969 i++;
2970 break;
2971 }
2972 }
2973
2974 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002975 while (i > 0) {
2976 i--;
2977 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2978 if (r.finishing) {
2979 continue;
2980 }
2981 if (r.task.taskId != taskId) {
2982 return null;
2983 }
2984 if (r.realActivity.equals(newR.realActivity)) {
2985 // Here it is! Now finish everything in front...
2986 HistoryRecord ret = r;
2987 if (doClear) {
2988 while (i < (mHistory.size()-1)) {
2989 i++;
2990 r = (HistoryRecord)mHistory.get(i);
2991 if (r.finishing) {
2992 continue;
2993 }
2994 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2995 null, "clear")) {
2996 i--;
2997 }
2998 }
2999 }
3000
3001 // Finally, if this is a normal launch mode (that is, not
3002 // expecting onNewIntent()), then we will finish the current
3003 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003004 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
3005 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003006 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003007 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003008 if (index >= 0) {
3009 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
3010 null, "clear");
3011 }
3012 return null;
3013 }
3014 }
3015
3016 return ret;
3017 }
3018 }
3019
3020 return null;
3021 }
3022
3023 /**
3024 * Find the activity in the history stack within the given task. Returns
3025 * the index within the history at which it's found, or < 0 if not found.
3026 */
3027 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3028 int i = mHistory.size();
3029 while (i > 0) {
3030 i--;
3031 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3032 if (candidate.task.taskId != task) {
3033 break;
3034 }
3035 if (candidate.realActivity.equals(r.realActivity)) {
3036 return i;
3037 }
3038 }
3039
3040 return -1;
3041 }
3042
3043 /**
3044 * Reorder the history stack so that the activity at the given index is
3045 * brought to the front.
3046 */
3047 private final HistoryRecord moveActivityToFrontLocked(int where) {
3048 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3049 int top = mHistory.size();
3050 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3051 mHistory.add(top, newTop);
3052 oldTop.frontOfTask = false;
3053 newTop.frontOfTask = true;
3054 return newTop;
3055 }
3056
3057 /**
3058 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3059 * method will be called at the proper time.
3060 */
3061 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3062 boolean sent = false;
3063 if (r.state == ActivityState.RESUMED
3064 && r.app != null && r.app.thread != null) {
3065 try {
3066 ArrayList<Intent> ar = new ArrayList<Intent>();
3067 ar.add(new Intent(intent));
3068 r.app.thread.scheduleNewIntent(ar, r);
3069 sent = true;
3070 } catch (Exception e) {
3071 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3072 }
3073 }
3074 if (!sent) {
3075 r.addNewIntentLocked(new Intent(intent));
3076 }
3077 }
3078
3079 private final void logStartActivity(int tag, HistoryRecord r,
3080 TaskRecord task) {
3081 EventLog.writeEvent(tag,
3082 System.identityHashCode(r), task.taskId,
3083 r.shortComponentName, r.intent.getAction(),
3084 r.intent.getType(), r.intent.getDataString(),
3085 r.intent.getFlags());
3086 }
3087
3088 private final int startActivityLocked(IApplicationThread caller,
3089 Intent intent, String resolvedType,
3090 Uri[] grantedUriPermissions,
3091 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3092 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003093 int callingPid, int callingUid, boolean onlyIfNeeded,
3094 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003095 Log.i(TAG, "Starting activity: " + intent);
3096
3097 HistoryRecord sourceRecord = null;
3098 HistoryRecord resultRecord = null;
3099 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003100 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003101 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003102 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3103 if (index >= 0) {
3104 sourceRecord = (HistoryRecord)mHistory.get(index);
3105 if (requestCode >= 0 && !sourceRecord.finishing) {
3106 resultRecord = sourceRecord;
3107 }
3108 }
3109 }
3110
3111 int launchFlags = intent.getFlags();
3112
3113 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3114 && sourceRecord != null) {
3115 // Transfer the result target from the source activity to the new
3116 // one being started, including any failures.
3117 if (requestCode >= 0) {
3118 return START_FORWARD_AND_REQUEST_CONFLICT;
3119 }
3120 resultRecord = sourceRecord.resultTo;
3121 resultWho = sourceRecord.resultWho;
3122 requestCode = sourceRecord.requestCode;
3123 sourceRecord.resultTo = null;
3124 if (resultRecord != null) {
3125 resultRecord.removeResultsLocked(
3126 sourceRecord, resultWho, requestCode);
3127 }
3128 }
3129
3130 int err = START_SUCCESS;
3131
3132 if (intent.getComponent() == null) {
3133 // We couldn't find a class that can handle the given Intent.
3134 // That's the end of that!
3135 err = START_INTENT_NOT_RESOLVED;
3136 }
3137
3138 if (err == START_SUCCESS && aInfo == null) {
3139 // We couldn't find the specific class specified in the Intent.
3140 // Also the end of the line.
3141 err = START_CLASS_NOT_FOUND;
3142 }
3143
3144 ProcessRecord callerApp = null;
3145 if (err == START_SUCCESS && caller != null) {
3146 callerApp = getRecordForAppLocked(caller);
3147 if (callerApp != null) {
3148 callingPid = callerApp.pid;
3149 callingUid = callerApp.info.uid;
3150 } else {
3151 Log.w(TAG, "Unable to find app for caller " + caller
3152 + " (pid=" + callingPid + ") when starting: "
3153 + intent.toString());
3154 err = START_PERMISSION_DENIED;
3155 }
3156 }
3157
3158 if (err != START_SUCCESS) {
3159 if (resultRecord != null) {
3160 sendActivityResultLocked(-1,
3161 resultRecord, resultWho, requestCode,
3162 Activity.RESULT_CANCELED, null);
3163 }
3164 return err;
3165 }
3166
3167 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3168 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3169 if (perm != PackageManager.PERMISSION_GRANTED) {
3170 if (resultRecord != null) {
3171 sendActivityResultLocked(-1,
3172 resultRecord, resultWho, requestCode,
3173 Activity.RESULT_CANCELED, null);
3174 }
3175 String msg = "Permission Denial: starting " + intent.toString()
3176 + " from " + callerApp + " (pid=" + callingPid
3177 + ", uid=" + callingUid + ")"
3178 + " requires " + aInfo.permission;
3179 Log.w(TAG, msg);
3180 throw new SecurityException(msg);
3181 }
3182
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003183 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003184 boolean abort = false;
3185 try {
3186 // The Intent we give to the watcher has the extra data
3187 // stripped off, since it can contain private information.
3188 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003189 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003190 aInfo.applicationInfo.packageName);
3191 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003192 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003193 }
3194
3195 if (abort) {
3196 if (resultRecord != null) {
3197 sendActivityResultLocked(-1,
3198 resultRecord, resultWho, requestCode,
3199 Activity.RESULT_CANCELED, null);
3200 }
3201 // We pretend to the caller that it was really started, but
3202 // they will just get a cancel result.
3203 return START_SUCCESS;
3204 }
3205 }
3206
3207 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3208 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003209 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003210
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003211 if (mResumedActivity == null
3212 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3213 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3214 PendingActivityLaunch pal = new PendingActivityLaunch();
3215 pal.r = r;
3216 pal.sourceRecord = sourceRecord;
3217 pal.grantedUriPermissions = grantedUriPermissions;
3218 pal.grantedMode = grantedMode;
3219 pal.onlyIfNeeded = onlyIfNeeded;
3220 mPendingActivityLaunches.add(pal);
3221 return START_SWITCHES_CANCELED;
3222 }
3223 }
3224
3225 if (mDidAppSwitch) {
3226 // This is the second allowed switch since we stopped switches,
3227 // so now just generally allow switches. Use case: user presses
3228 // home (switches disabled, switch to home, mDidAppSwitch now true);
3229 // user taps a home icon (coming from home so allowed, we hit here
3230 // and now allow anyone to switch again).
3231 mAppSwitchesAllowedTime = 0;
3232 } else {
3233 mDidAppSwitch = true;
3234 }
3235
3236 doPendingActivityLaunchesLocked(false);
3237
3238 return startActivityUncheckedLocked(r, sourceRecord,
3239 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3240 }
3241
3242 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3243 final int N = mPendingActivityLaunches.size();
3244 if (N <= 0) {
3245 return;
3246 }
3247 for (int i=0; i<N; i++) {
3248 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3249 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3250 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3251 doResume && i == (N-1));
3252 }
3253 mPendingActivityLaunches.clear();
3254 }
3255
3256 private final int startActivityUncheckedLocked(HistoryRecord r,
3257 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3258 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3259 final Intent intent = r.intent;
3260 final int callingUid = r.launchedFromUid;
3261
3262 int launchFlags = intent.getFlags();
3263
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003264 // We'll invoke onUserLeaving before onPause only if the launching
3265 // activity did not explicitly state that this is an automated launch.
3266 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3267 if (DEBUG_USER_LEAVING) Log.v(TAG,
3268 "startActivity() => mUserLeaving=" + mUserLeaving);
3269
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003270 // If the caller has asked not to resume at this point, we make note
3271 // of this in the record so that we can skip it when trying to find
3272 // the top running activity.
3273 if (!doResume) {
3274 r.delayedResume = true;
3275 }
3276
3277 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3278 != 0 ? r : null;
3279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003280 // If the onlyIfNeeded flag is set, then we can do this if the activity
3281 // being launched is the same as the one making the call... or, as
3282 // a special case, if we do not know the caller then we count the
3283 // current top activity as the caller.
3284 if (onlyIfNeeded) {
3285 HistoryRecord checkedCaller = sourceRecord;
3286 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003287 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003288 }
3289 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3290 // Caller is not the same as launcher, so always needed.
3291 onlyIfNeeded = false;
3292 }
3293 }
3294
3295 if (grantedUriPermissions != null && callingUid > 0) {
3296 for (int i=0; i<grantedUriPermissions.length; i++) {
3297 grantUriPermissionLocked(callingUid, r.packageName,
3298 grantedUriPermissions[i], grantedMode, r);
3299 }
3300 }
3301
3302 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3303 intent, r);
3304
3305 if (sourceRecord == null) {
3306 // This activity is not being started from another... in this
3307 // case we -always- start a new task.
3308 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3309 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3310 + intent);
3311 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3312 }
3313 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3314 // The original activity who is starting us is running as a single
3315 // instance... this new activity it is starting must go on its
3316 // own task.
3317 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3318 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3319 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3320 // The activity being started is a single instance... it always
3321 // gets launched into its own task.
3322 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3323 }
3324
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003325 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003326 // For whatever reason this activity is being launched into a new
3327 // task... yet the caller has requested a result back. Well, that
3328 // is pretty messed up, so instead immediately send back a cancel
3329 // and let the new task continue launched as normal without a
3330 // dependency on its originator.
3331 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3332 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003333 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003334 Activity.RESULT_CANCELED, null);
3335 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003336 }
3337
3338 boolean addingToTask = false;
3339 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3340 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3341 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3342 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3343 // If bring to front is requested, and no result is requested, and
3344 // we can find a task that was started with this same
3345 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003346 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003347 // See if there is a task to bring to the front. If this is
3348 // a SINGLE_INSTANCE activity, there can be one and only one
3349 // instance of it in the history, and it is always in its own
3350 // unique task, so we do a special search.
3351 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3352 ? findTaskLocked(intent, r.info)
3353 : findActivityLocked(intent, r.info);
3354 if (taskTop != null) {
3355 if (taskTop.task.intent == null) {
3356 // This task was started because of movement of
3357 // the activity based on affinity... now that we
3358 // are actually launching it, we can assign the
3359 // base intent.
3360 taskTop.task.setIntent(intent, r.info);
3361 }
3362 // If the target task is not in the front, then we need
3363 // to bring it to the front... except... well, with
3364 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3365 // to have the same behavior as if a new instance was
3366 // being started, which means not bringing it to the front
3367 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003368 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003369 if (curTop.task != taskTop.task) {
3370 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3371 boolean callerAtFront = sourceRecord == null
3372 || curTop.task == sourceRecord.task;
3373 if (callerAtFront) {
3374 // We really do want to push this one into the
3375 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003376 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003377 }
3378 }
3379 // If the caller has requested that the target task be
3380 // reset, then do so.
3381 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3382 taskTop = resetTaskIfNeededLocked(taskTop, r);
3383 }
3384 if (onlyIfNeeded) {
3385 // We don't need to start a new activity, and
3386 // the client said not to do anything if that
3387 // is the case, so this is it! And for paranoia, make
3388 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003389 if (doResume) {
3390 resumeTopActivityLocked(null);
3391 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003392 return START_RETURN_INTENT_TO_CALLER;
3393 }
3394 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3395 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3396 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3397 // In this situation we want to remove all activities
3398 // from the task up to the one being started. In most
3399 // cases this means we are resetting the task to its
3400 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003401 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003402 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003403 if (top != null) {
3404 if (top.frontOfTask) {
3405 // Activity aliases may mean we use different
3406 // intents for the top activity, so make sure
3407 // the task now has the identity of the new
3408 // intent.
3409 top.task.setIntent(r.intent, r.info);
3410 }
3411 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3412 deliverNewIntentLocked(top, r.intent);
3413 } else {
3414 // A special case: we need to
3415 // start the activity because it is not currently
3416 // running, and the caller has asked to clear the
3417 // current task to have this activity at the top.
3418 addingToTask = true;
3419 // Now pretend like this activity is being started
3420 // by the top of its task, so it is put in the
3421 // right place.
3422 sourceRecord = taskTop;
3423 }
3424 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3425 // In this case the top activity on the task is the
3426 // same as the one being launched, so we take that
3427 // as a request to bring the task to the foreground.
3428 // If the top activity in the task is the root
3429 // activity, deliver this new intent to it if it
3430 // desires.
3431 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3432 && taskTop.realActivity.equals(r.realActivity)) {
3433 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3434 if (taskTop.frontOfTask) {
3435 taskTop.task.setIntent(r.intent, r.info);
3436 }
3437 deliverNewIntentLocked(taskTop, r.intent);
3438 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3439 // In this case we are launching the root activity
3440 // of the task, but with a different intent. We
3441 // should start a new instance on top.
3442 addingToTask = true;
3443 sourceRecord = taskTop;
3444 }
3445 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3446 // In this case an activity is being launched in to an
3447 // existing task, without resetting that task. This
3448 // is typically the situation of launching an activity
3449 // from a notification or shortcut. We want to place
3450 // the new activity on top of the current task.
3451 addingToTask = true;
3452 sourceRecord = taskTop;
3453 } else if (!taskTop.task.rootWasReset) {
3454 // In this case we are launching in to an existing task
3455 // that has not yet been started from its front door.
3456 // The current task has been brought to the front.
3457 // Ideally, we'd probably like to place this new task
3458 // at the bottom of its stack, but that's a little hard
3459 // to do with the current organization of the code so
3460 // for now we'll just drop it.
3461 taskTop.task.setIntent(r.intent, r.info);
3462 }
3463 if (!addingToTask) {
3464 // We didn't do anything... but it was needed (a.k.a., client
3465 // don't use that intent!) And for paranoia, make
3466 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003467 if (doResume) {
3468 resumeTopActivityLocked(null);
3469 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003470 return START_TASK_TO_FRONT;
3471 }
3472 }
3473 }
3474 }
3475
3476 //String uri = r.intent.toURI();
3477 //Intent intent2 = new Intent(uri);
3478 //Log.i(TAG, "Given intent: " + r.intent);
3479 //Log.i(TAG, "URI is: " + uri);
3480 //Log.i(TAG, "To intent: " + intent2);
3481
3482 if (r.packageName != null) {
3483 // If the activity being launched is the same as the one currently
3484 // at the top, then we need to check if it should only be launched
3485 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003486 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3487 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003488 if (top.realActivity.equals(r.realActivity)) {
3489 if (top.app != null && top.app.thread != null) {
3490 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3491 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3492 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3493 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3494 // For paranoia, make sure we have correctly
3495 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003496 if (doResume) {
3497 resumeTopActivityLocked(null);
3498 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003499 if (onlyIfNeeded) {
3500 // We don't need to start a new activity, and
3501 // the client said not to do anything if that
3502 // is the case, so this is it!
3503 return START_RETURN_INTENT_TO_CALLER;
3504 }
3505 deliverNewIntentLocked(top, r.intent);
3506 return START_DELIVERED_TO_TOP;
3507 }
3508 }
3509 }
3510 }
3511
3512 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003513 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003514 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003515 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003516 Activity.RESULT_CANCELED, null);
3517 }
3518 return START_CLASS_NOT_FOUND;
3519 }
3520
3521 boolean newTask = false;
3522
3523 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003524 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003525 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3526 // todo: should do better management of integers.
3527 mCurTask++;
3528 if (mCurTask <= 0) {
3529 mCurTask = 1;
3530 }
3531 r.task = new TaskRecord(mCurTask, r.info, intent,
3532 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3533 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3534 + " in new task " + r.task);
3535 newTask = true;
3536 addRecentTask(r.task);
3537
3538 } else if (sourceRecord != null) {
3539 if (!addingToTask &&
3540 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3541 // In this case, we are adding the activity to an existing
3542 // task, but the caller has asked to clear that task if the
3543 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003544 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003545 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003546 if (top != null) {
3547 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3548 deliverNewIntentLocked(top, r.intent);
3549 // For paranoia, make sure we have correctly
3550 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003551 if (doResume) {
3552 resumeTopActivityLocked(null);
3553 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003554 return START_DELIVERED_TO_TOP;
3555 }
3556 } else if (!addingToTask &&
3557 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3558 // In this case, we are launching an activity in our own task
3559 // that may already be running somewhere in the history, and
3560 // we want to shuffle it to the front of the stack if so.
3561 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3562 if (where >= 0) {
3563 HistoryRecord top = moveActivityToFrontLocked(where);
3564 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3565 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003566 if (doResume) {
3567 resumeTopActivityLocked(null);
3568 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003569 return START_DELIVERED_TO_TOP;
3570 }
3571 }
3572 // An existing activity is starting this new activity, so we want
3573 // to keep the new one in the same task as the one that is starting
3574 // it.
3575 r.task = sourceRecord.task;
3576 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3577 + " in existing task " + r.task);
3578
3579 } else {
3580 // This not being started from an existing activity, and not part
3581 // of a new task... just put it in the top task, though these days
3582 // this case should never happen.
3583 final int N = mHistory.size();
3584 HistoryRecord prev =
3585 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3586 r.task = prev != null
3587 ? prev.task
3588 : new TaskRecord(mCurTask, r.info, intent,
3589 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3590 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3591 + " in new guessed " + r.task);
3592 }
3593 if (newTask) {
3594 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3595 }
3596 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003597 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003598 return START_SUCCESS;
3599 }
3600
3601 public final int startActivity(IApplicationThread caller,
3602 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3603 int grantedMode, IBinder resultTo,
3604 String resultWho, int requestCode, boolean onlyIfNeeded,
3605 boolean debug) {
3606 // Refuse possible leaked file descriptors
3607 if (intent != null && intent.hasFileDescriptors()) {
3608 throw new IllegalArgumentException("File descriptors passed in Intent");
3609 }
3610
The Android Open Source Project4df24232009-03-05 14:34:35 -08003611 final boolean componentSpecified = intent.getComponent() != null;
3612
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003613 // Don't modify the client's object!
3614 intent = new Intent(intent);
3615
3616 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003617 ActivityInfo aInfo;
3618 try {
3619 ResolveInfo rInfo =
3620 ActivityThread.getPackageManager().resolveIntent(
3621 intent, resolvedType,
3622 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003623 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003624 aInfo = rInfo != null ? rInfo.activityInfo : null;
3625 } catch (RemoteException e) {
3626 aInfo = null;
3627 }
3628
3629 if (aInfo != null) {
3630 // Store the found target back into the intent, because now that
3631 // we have it we never want to do this again. For example, if the
3632 // user navigates back to this point in the history, we should
3633 // always restart the exact same activity.
3634 intent.setComponent(new ComponentName(
3635 aInfo.applicationInfo.packageName, aInfo.name));
3636
3637 // Don't debug things in the system process
3638 if (debug) {
3639 if (!aInfo.processName.equals("system")) {
3640 setDebugApp(aInfo.processName, true, false);
3641 }
3642 }
3643 }
3644
3645 synchronized(this) {
3646 final long origId = Binder.clearCallingIdentity();
3647 int res = startActivityLocked(caller, intent, resolvedType,
3648 grantedUriPermissions, grantedMode, aInfo,
3649 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003650 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003651 Binder.restoreCallingIdentity(origId);
3652 return res;
3653 }
3654 }
3655
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003656 public int startActivityIntentSender(IApplicationThread caller,
3657 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003658 IBinder resultTo, String resultWho, int requestCode,
3659 int flagsMask, int flagsValues) {
3660 // Refuse possible leaked file descriptors
3661 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3662 throw new IllegalArgumentException("File descriptors passed in Intent");
3663 }
3664
3665 IIntentSender sender = intent.getTarget();
3666 if (!(sender instanceof PendingIntentRecord)) {
3667 throw new IllegalArgumentException("Bad PendingIntent object");
3668 }
3669
3670 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003671
3672 synchronized (this) {
3673 // If this is coming from the currently resumed activity, it is
3674 // effectively saying that app switches are allowed at this point.
3675 if (mResumedActivity != null
3676 && mResumedActivity.info.applicationInfo.uid ==
3677 Binder.getCallingUid()) {
3678 mAppSwitchesAllowedTime = 0;
3679 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003680 }
3681
3682 return pir.sendInner(0, fillInIntent, resolvedType,
3683 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3684 }
3685
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003686 public boolean startNextMatchingActivity(IBinder callingActivity,
3687 Intent intent) {
3688 // Refuse possible leaked file descriptors
3689 if (intent != null && intent.hasFileDescriptors() == true) {
3690 throw new IllegalArgumentException("File descriptors passed in Intent");
3691 }
3692
3693 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003694 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003695 if (index < 0) {
3696 return false;
3697 }
3698 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3699 if (r.app == null || r.app.thread == null) {
3700 // The caller is not running... d'oh!
3701 return false;
3702 }
3703 intent = new Intent(intent);
3704 // The caller is not allowed to change the data.
3705 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3706 // And we are resetting to find the next component...
3707 intent.setComponent(null);
3708
3709 ActivityInfo aInfo = null;
3710 try {
3711 List<ResolveInfo> resolves =
3712 ActivityThread.getPackageManager().queryIntentActivities(
3713 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003714 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003715
3716 // Look for the original activity in the list...
3717 final int N = resolves != null ? resolves.size() : 0;
3718 for (int i=0; i<N; i++) {
3719 ResolveInfo rInfo = resolves.get(i);
3720 if (rInfo.activityInfo.packageName.equals(r.packageName)
3721 && rInfo.activityInfo.name.equals(r.info.name)) {
3722 // We found the current one... the next matching is
3723 // after it.
3724 i++;
3725 if (i<N) {
3726 aInfo = resolves.get(i).activityInfo;
3727 }
3728 break;
3729 }
3730 }
3731 } catch (RemoteException e) {
3732 }
3733
3734 if (aInfo == null) {
3735 // Nobody who is next!
3736 return false;
3737 }
3738
3739 intent.setComponent(new ComponentName(
3740 aInfo.applicationInfo.packageName, aInfo.name));
3741 intent.setFlags(intent.getFlags()&~(
3742 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3743 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3744 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3745 Intent.FLAG_ACTIVITY_NEW_TASK));
3746
3747 // Okay now we need to start the new activity, replacing the
3748 // currently running activity. This is a little tricky because
3749 // we want to start the new one as if the current one is finished,
3750 // but not finish the current one first so that there is no flicker.
3751 // And thus...
3752 final boolean wasFinishing = r.finishing;
3753 r.finishing = true;
3754
3755 // Propagate reply information over to the new activity.
3756 final HistoryRecord resultTo = r.resultTo;
3757 final String resultWho = r.resultWho;
3758 final int requestCode = r.requestCode;
3759 r.resultTo = null;
3760 if (resultTo != null) {
3761 resultTo.removeResultsLocked(r, resultWho, requestCode);
3762 }
3763
3764 final long origId = Binder.clearCallingIdentity();
3765 // XXX we are not dealing with propagating grantedUriPermissions...
3766 // those are not yet exposed to user code, so there is no need.
3767 int res = startActivityLocked(r.app.thread, intent,
3768 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003769 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003770 Binder.restoreCallingIdentity(origId);
3771
3772 r.finishing = wasFinishing;
3773 if (res != START_SUCCESS) {
3774 return false;
3775 }
3776 return true;
3777 }
3778 }
3779
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003780 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003781 Intent intent, String resolvedType, IBinder resultTo,
3782 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003783
3784 // This is so super not safe, that only the system (or okay root)
3785 // can do it.
3786 final int callingUid = Binder.getCallingUid();
3787 if (callingUid != 0 && callingUid != Process.myUid()) {
3788 throw new SecurityException(
3789 "startActivityInPackage only available to the system");
3790 }
3791
The Android Open Source Project4df24232009-03-05 14:34:35 -08003792 final boolean componentSpecified = intent.getComponent() != null;
3793
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003794 // Don't modify the client's object!
3795 intent = new Intent(intent);
3796
3797 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003798 ActivityInfo aInfo;
3799 try {
3800 ResolveInfo rInfo =
3801 ActivityThread.getPackageManager().resolveIntent(
3802 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003803 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003804 aInfo = rInfo != null ? rInfo.activityInfo : null;
3805 } catch (RemoteException e) {
3806 aInfo = null;
3807 }
3808
3809 if (aInfo != null) {
3810 // Store the found target back into the intent, because now that
3811 // we have it we never want to do this again. For example, if the
3812 // user navigates back to this point in the history, we should
3813 // always restart the exact same activity.
3814 intent.setComponent(new ComponentName(
3815 aInfo.applicationInfo.packageName, aInfo.name));
3816 }
3817
3818 synchronized(this) {
3819 return startActivityLocked(null, intent, resolvedType,
3820 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003821 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003822 }
3823 }
3824
3825 private final void addRecentTask(TaskRecord task) {
3826 // Remove any existing entries that are the same kind of task.
3827 int N = mRecentTasks.size();
3828 for (int i=0; i<N; i++) {
3829 TaskRecord tr = mRecentTasks.get(i);
3830 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3831 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3832 mRecentTasks.remove(i);
3833 i--;
3834 N--;
3835 if (task.intent == null) {
3836 // If the new recent task we are adding is not fully
3837 // specified, then replace it with the existing recent task.
3838 task = tr;
3839 }
3840 }
3841 }
3842 if (N >= MAX_RECENT_TASKS) {
3843 mRecentTasks.remove(N-1);
3844 }
3845 mRecentTasks.add(0, task);
3846 }
3847
3848 public void setRequestedOrientation(IBinder token,
3849 int requestedOrientation) {
3850 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003851 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003852 if (index < 0) {
3853 return;
3854 }
3855 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3856 final long origId = Binder.clearCallingIdentity();
3857 mWindowManager.setAppOrientation(r, requestedOrientation);
3858 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003859 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003860 r.mayFreezeScreenLocked(r.app) ? r : null);
3861 if (config != null) {
3862 r.frozenBeforeDestroy = true;
3863 if (!updateConfigurationLocked(config, r)) {
3864 resumeTopActivityLocked(null);
3865 }
3866 }
3867 Binder.restoreCallingIdentity(origId);
3868 }
3869 }
3870
3871 public int getRequestedOrientation(IBinder token) {
3872 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003873 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003874 if (index < 0) {
3875 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3876 }
3877 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3878 return mWindowManager.getAppOrientation(r);
3879 }
3880 }
3881
3882 private final void stopActivityLocked(HistoryRecord r) {
3883 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3884 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3885 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3886 if (!r.finishing) {
3887 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3888 "no-history");
3889 }
3890 } else if (r.app != null && r.app.thread != null) {
3891 if (mFocusedActivity == r) {
3892 setFocusedActivityLocked(topRunningActivityLocked(null));
3893 }
3894 r.resumeKeyDispatchingLocked();
3895 try {
3896 r.stopped = false;
3897 r.state = ActivityState.STOPPING;
3898 if (DEBUG_VISBILITY) Log.v(
3899 TAG, "Stopping visible=" + r.visible + " for " + r);
3900 if (!r.visible) {
3901 mWindowManager.setAppVisibility(r, false);
3902 }
3903 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3904 } catch (Exception e) {
3905 // Maybe just ignore exceptions here... if the process
3906 // has crashed, our death notification will clean things
3907 // up.
3908 Log.w(TAG, "Exception thrown during pause", e);
3909 // Just in case, assume it to be stopped.
3910 r.stopped = true;
3911 r.state = ActivityState.STOPPED;
3912 if (r.configDestroy) {
3913 destroyActivityLocked(r, true);
3914 }
3915 }
3916 }
3917 }
3918
3919 /**
3920 * @return Returns true if the activity is being finished, false if for
3921 * some reason it is being left as-is.
3922 */
3923 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3924 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003925 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003926 TAG, "Finishing activity: token=" + token
3927 + ", result=" + resultCode + ", data=" + resultData);
3928
Dianne Hackborn75b03852009-06-12 15:43:26 -07003929 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003930 if (index < 0) {
3931 return false;
3932 }
3933 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3934
3935 // Is this the last activity left?
3936 boolean lastActivity = true;
3937 for (int i=mHistory.size()-1; i>=0; i--) {
3938 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3939 if (!p.finishing && p != r) {
3940 lastActivity = false;
3941 break;
3942 }
3943 }
3944
3945 // If this is the last activity, but it is the home activity, then
3946 // just don't finish it.
3947 if (lastActivity) {
3948 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3949 return false;
3950 }
3951 }
3952
3953 finishActivityLocked(r, index, resultCode, resultData, reason);
3954 return true;
3955 }
3956
3957 /**
3958 * @return Returns true if this activity has been removed from the history
3959 * list, or false if it is still in the list and will be removed later.
3960 */
3961 private final boolean finishActivityLocked(HistoryRecord r, int index,
3962 int resultCode, Intent resultData, String reason) {
3963 if (r.finishing) {
3964 Log.w(TAG, "Duplicate finish request for " + r);
3965 return false;
3966 }
3967
3968 r.finishing = true;
3969 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3970 System.identityHashCode(r),
3971 r.task.taskId, r.shortComponentName, reason);
3972 r.task.numActivities--;
3973 if (r.frontOfTask && index < (mHistory.size()-1)) {
3974 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3975 if (next.task == r.task) {
3976 next.frontOfTask = true;
3977 }
3978 }
3979
3980 r.pauseKeyDispatchingLocked();
3981 if (mFocusedActivity == r) {
3982 setFocusedActivityLocked(topRunningActivityLocked(null));
3983 }
3984
3985 // send the result
3986 HistoryRecord resultTo = r.resultTo;
3987 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003988 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3989 + " who=" + r.resultWho + " req=" + r.requestCode
3990 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003991 if (r.info.applicationInfo.uid > 0) {
3992 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3993 r.packageName, resultData, r);
3994 }
3995 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3996 resultData);
3997 r.resultTo = null;
3998 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003999 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004000
4001 // Make sure this HistoryRecord is not holding on to other resources,
4002 // because clients have remote IPC references to this object so we
4003 // can't assume that will go away and want to avoid circular IPC refs.
4004 r.results = null;
4005 r.pendingResults = null;
4006 r.newIntents = null;
4007 r.icicle = null;
4008
4009 if (mPendingThumbnails.size() > 0) {
4010 // There are clients waiting to receive thumbnails so, in case
4011 // this is an activity that someone is waiting for, add it
4012 // to the pending list so we can correctly update the clients.
4013 mCancelledThumbnails.add(r);
4014 }
4015
4016 if (mResumedActivity == r) {
4017 boolean endTask = index <= 0
4018 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
4019 if (DEBUG_TRANSITION) Log.v(TAG,
4020 "Prepare close transition: finishing " + r);
4021 mWindowManager.prepareAppTransition(endTask
4022 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
4023 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
4024
4025 // Tell window manager to prepare for this one to be removed.
4026 mWindowManager.setAppVisibility(r, false);
4027
4028 if (mPausingActivity == null) {
4029 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4030 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4031 startPausingLocked(false, false);
4032 }
4033
4034 } else if (r.state != ActivityState.PAUSING) {
4035 // If the activity is PAUSING, we will complete the finish once
4036 // it is done pausing; else we can just directly finish it here.
4037 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4038 return finishCurrentActivityLocked(r, index,
4039 FINISH_AFTER_PAUSE) == null;
4040 } else {
4041 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4042 }
4043
4044 return false;
4045 }
4046
4047 private static final int FINISH_IMMEDIATELY = 0;
4048 private static final int FINISH_AFTER_PAUSE = 1;
4049 private static final int FINISH_AFTER_VISIBLE = 2;
4050
4051 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4052 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004053 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004054 if (index < 0) {
4055 return null;
4056 }
4057
4058 return finishCurrentActivityLocked(r, index, mode);
4059 }
4060
4061 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4062 int index, int mode) {
4063 // First things first: if this activity is currently visible,
4064 // and the resumed activity is not yet visible, then hold off on
4065 // finishing until the resumed one becomes visible.
4066 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4067 if (!mStoppingActivities.contains(r)) {
4068 mStoppingActivities.add(r);
4069 if (mStoppingActivities.size() > 3) {
4070 // If we already have a few activities waiting to stop,
4071 // then give up on things going idle and start clearing
4072 // them out.
4073 Message msg = Message.obtain();
4074 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4075 mHandler.sendMessage(msg);
4076 }
4077 }
4078 r.state = ActivityState.STOPPING;
4079 updateOomAdjLocked();
4080 return r;
4081 }
4082
4083 // make sure the record is cleaned out of other places.
4084 mStoppingActivities.remove(r);
4085 mWaitingVisibleActivities.remove(r);
4086 if (mResumedActivity == r) {
4087 mResumedActivity = null;
4088 }
4089 final ActivityState prevState = r.state;
4090 r.state = ActivityState.FINISHING;
4091
4092 if (mode == FINISH_IMMEDIATELY
4093 || prevState == ActivityState.STOPPED
4094 || prevState == ActivityState.INITIALIZING) {
4095 // If this activity is already stopped, we can just finish
4096 // it right now.
4097 return destroyActivityLocked(r, true) ? null : r;
4098 } else {
4099 // Need to go through the full pause cycle to get this
4100 // activity into the stopped state and then finish it.
4101 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4102 mFinishingActivities.add(r);
4103 resumeTopActivityLocked(null);
4104 }
4105 return r;
4106 }
4107
4108 /**
4109 * This is the internal entry point for handling Activity.finish().
4110 *
4111 * @param token The Binder token referencing the Activity we want to finish.
4112 * @param resultCode Result code, if any, from this Activity.
4113 * @param resultData Result data (Intent), if any, from this Activity.
4114 *
4115 * @result Returns true if the activity successfully finished, or false if it is still running.
4116 */
4117 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4118 // Refuse possible leaked file descriptors
4119 if (resultData != null && resultData.hasFileDescriptors() == true) {
4120 throw new IllegalArgumentException("File descriptors passed in Intent");
4121 }
4122
4123 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004124 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004125 // Find the first activity that is not finishing.
4126 HistoryRecord next = topRunningActivityLocked(token, 0);
4127 if (next != null) {
4128 // ask watcher if this is allowed
4129 boolean resumeOK = true;
4130 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004131 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004132 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004133 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004134 }
4135
4136 if (!resumeOK) {
4137 return false;
4138 }
4139 }
4140 }
4141 final long origId = Binder.clearCallingIdentity();
4142 boolean res = requestFinishActivityLocked(token, resultCode,
4143 resultData, "app-request");
4144 Binder.restoreCallingIdentity(origId);
4145 return res;
4146 }
4147 }
4148
4149 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4150 String resultWho, int requestCode, int resultCode, Intent data) {
4151
4152 if (callingUid > 0) {
4153 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4154 data, r);
4155 }
4156
The Android Open Source Project10592532009-03-18 17:39:46 -07004157 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4158 + " : who=" + resultWho + " req=" + requestCode
4159 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004160 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4161 try {
4162 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4163 list.add(new ResultInfo(resultWho, requestCode,
4164 resultCode, data));
4165 r.app.thread.scheduleSendResult(r, list);
4166 return;
4167 } catch (Exception e) {
4168 Log.w(TAG, "Exception thrown sending result to " + r, e);
4169 }
4170 }
4171
4172 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4173 }
4174
4175 public final void finishSubActivity(IBinder token, String resultWho,
4176 int requestCode) {
4177 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004178 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004179 if (index < 0) {
4180 return;
4181 }
4182 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4183
4184 final long origId = Binder.clearCallingIdentity();
4185
4186 int i;
4187 for (i=mHistory.size()-1; i>=0; i--) {
4188 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4189 if (r.resultTo == self && r.requestCode == requestCode) {
4190 if ((r.resultWho == null && resultWho == null) ||
4191 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4192 finishActivityLocked(r, i,
4193 Activity.RESULT_CANCELED, null, "request-sub");
4194 }
4195 }
4196 }
4197
4198 Binder.restoreCallingIdentity(origId);
4199 }
4200 }
4201
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004202 public void overridePendingTransition(IBinder token, String packageName,
4203 int enterAnim, int exitAnim) {
4204 synchronized(this) {
4205 int index = indexOfTokenLocked(token);
4206 if (index < 0) {
4207 return;
4208 }
4209 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4210
4211 final long origId = Binder.clearCallingIdentity();
4212
4213 if (self.state == ActivityState.RESUMED
4214 || self.state == ActivityState.PAUSING) {
4215 mWindowManager.overridePendingAppTransition(packageName,
4216 enterAnim, exitAnim);
4217 }
4218
4219 Binder.restoreCallingIdentity(origId);
4220 }
4221 }
4222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004223 /**
4224 * Perform clean-up of service connections in an activity record.
4225 */
4226 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4227 // Throw away any services that have been bound by this activity.
4228 if (r.connections != null) {
4229 Iterator<ConnectionRecord> it = r.connections.iterator();
4230 while (it.hasNext()) {
4231 ConnectionRecord c = it.next();
4232 removeConnectionLocked(c, null, r);
4233 }
4234 r.connections = null;
4235 }
4236 }
4237
4238 /**
4239 * Perform the common clean-up of an activity record. This is called both
4240 * as part of destroyActivityLocked() (when destroying the client-side
4241 * representation) and cleaning things up as a result of its hosting
4242 * processing going away, in which case there is no remaining client-side
4243 * state to destroy so only the cleanup here is needed.
4244 */
4245 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4246 if (mResumedActivity == r) {
4247 mResumedActivity = null;
4248 }
4249 if (mFocusedActivity == r) {
4250 mFocusedActivity = null;
4251 }
4252
4253 r.configDestroy = false;
4254 r.frozenBeforeDestroy = false;
4255
4256 // Make sure this record is no longer in the pending finishes list.
4257 // This could happen, for example, if we are trimming activities
4258 // down to the max limit while they are still waiting to finish.
4259 mFinishingActivities.remove(r);
4260 mWaitingVisibleActivities.remove(r);
4261
4262 // Remove any pending results.
4263 if (r.finishing && r.pendingResults != null) {
4264 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4265 PendingIntentRecord rec = apr.get();
4266 if (rec != null) {
4267 cancelIntentSenderLocked(rec, false);
4268 }
4269 }
4270 r.pendingResults = null;
4271 }
4272
4273 if (cleanServices) {
4274 cleanUpActivityServicesLocked(r);
4275 }
4276
4277 if (mPendingThumbnails.size() > 0) {
4278 // There are clients waiting to receive thumbnails so, in case
4279 // this is an activity that someone is waiting for, add it
4280 // to the pending list so we can correctly update the clients.
4281 mCancelledThumbnails.add(r);
4282 }
4283
4284 // Get rid of any pending idle timeouts.
4285 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4286 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4287 }
4288
4289 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4290 if (r.state != ActivityState.DESTROYED) {
4291 mHistory.remove(r);
4292 r.inHistory = false;
4293 r.state = ActivityState.DESTROYED;
4294 mWindowManager.removeAppToken(r);
4295 if (VALIDATE_TOKENS) {
4296 mWindowManager.validateAppTokens(mHistory);
4297 }
4298 cleanUpActivityServicesLocked(r);
4299 removeActivityUriPermissionsLocked(r);
4300 }
4301 }
4302
4303 /**
4304 * Destroy the current CLIENT SIDE instance of an activity. This may be
4305 * called both when actually finishing an activity, or when performing
4306 * a configuration switch where we destroy the current client-side object
4307 * but then create a new client-side object for this same HistoryRecord.
4308 */
4309 private final boolean destroyActivityLocked(HistoryRecord r,
4310 boolean removeFromApp) {
4311 if (DEBUG_SWITCH) Log.v(
4312 TAG, "Removing activity: token=" + r
4313 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4314 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4315 System.identityHashCode(r),
4316 r.task.taskId, r.shortComponentName);
4317
4318 boolean removedFromHistory = false;
4319
4320 cleanUpActivityLocked(r, false);
4321
4322 if (r.app != null) {
4323 if (removeFromApp) {
4324 int idx = r.app.activities.indexOf(r);
4325 if (idx >= 0) {
4326 r.app.activities.remove(idx);
4327 }
4328 if (r.persistent) {
4329 decPersistentCountLocked(r.app);
4330 }
4331 }
4332
4333 boolean skipDestroy = false;
4334
4335 try {
4336 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4337 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4338 r.configChangeFlags);
4339 } catch (Exception e) {
4340 // We can just ignore exceptions here... if the process
4341 // has crashed, our death notification will clean things
4342 // up.
4343 //Log.w(TAG, "Exception thrown during finish", e);
4344 if (r.finishing) {
4345 removeActivityFromHistoryLocked(r);
4346 removedFromHistory = true;
4347 skipDestroy = true;
4348 }
4349 }
4350
4351 r.app = null;
4352 r.nowVisible = false;
4353
4354 if (r.finishing && !skipDestroy) {
4355 r.state = ActivityState.DESTROYING;
4356 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4357 msg.obj = r;
4358 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4359 } else {
4360 r.state = ActivityState.DESTROYED;
4361 }
4362 } else {
4363 // remove this record from the history.
4364 if (r.finishing) {
4365 removeActivityFromHistoryLocked(r);
4366 removedFromHistory = true;
4367 } else {
4368 r.state = ActivityState.DESTROYED;
4369 }
4370 }
4371
4372 r.configChangeFlags = 0;
4373
4374 if (!mLRUActivities.remove(r)) {
4375 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4376 }
4377
4378 return removedFromHistory;
4379 }
4380
4381 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4382 ProcessRecord app)
4383 {
4384 int i = list.size();
4385 if (localLOGV) Log.v(
4386 TAG, "Removing app " + app + " from list " + list
4387 + " with " + i + " entries");
4388 while (i > 0) {
4389 i--;
4390 HistoryRecord r = (HistoryRecord)list.get(i);
4391 if (localLOGV) Log.v(
4392 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4393 if (r.app == app) {
4394 if (localLOGV) Log.v(TAG, "Removing this entry!");
4395 list.remove(i);
4396 }
4397 }
4398 }
4399
4400 /**
4401 * Main function for removing an existing process from the activity manager
4402 * as a result of that process going away. Clears out all connections
4403 * to the process.
4404 */
4405 private final void handleAppDiedLocked(ProcessRecord app,
4406 boolean restarting) {
4407 cleanUpApplicationRecordLocked(app, restarting, -1);
4408 if (!restarting) {
4409 mLRUProcesses.remove(app);
4410 }
4411
4412 // Just in case...
4413 if (mPausingActivity != null && mPausingActivity.app == app) {
4414 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4415 mPausingActivity = null;
4416 }
4417 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4418 mLastPausedActivity = null;
4419 }
4420
4421 // Remove this application's activities from active lists.
4422 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4423 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4424 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4425 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4426
4427 boolean atTop = true;
4428 boolean hasVisibleActivities = false;
4429
4430 // Clean out the history list.
4431 int i = mHistory.size();
4432 if (localLOGV) Log.v(
4433 TAG, "Removing app " + app + " from history with " + i + " entries");
4434 while (i > 0) {
4435 i--;
4436 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4437 if (localLOGV) Log.v(
4438 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4439 if (r.app == app) {
4440 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4441 if (localLOGV) Log.v(
4442 TAG, "Removing this entry! frozen=" + r.haveState
4443 + " finishing=" + r.finishing);
4444 mHistory.remove(i);
4445
4446 r.inHistory = false;
4447 mWindowManager.removeAppToken(r);
4448 if (VALIDATE_TOKENS) {
4449 mWindowManager.validateAppTokens(mHistory);
4450 }
4451 removeActivityUriPermissionsLocked(r);
4452
4453 } else {
4454 // We have the current state for this activity, so
4455 // it can be restarted later when needed.
4456 if (localLOGV) Log.v(
4457 TAG, "Keeping entry, setting app to null");
4458 if (r.visible) {
4459 hasVisibleActivities = true;
4460 }
4461 r.app = null;
4462 r.nowVisible = false;
4463 if (!r.haveState) {
4464 r.icicle = null;
4465 }
4466 }
4467
4468 cleanUpActivityLocked(r, true);
4469 r.state = ActivityState.STOPPED;
4470 }
4471 atTop = false;
4472 }
4473
4474 app.activities.clear();
4475
4476 if (app.instrumentationClass != null) {
4477 Log.w(TAG, "Crash of app " + app.processName
4478 + " running instrumentation " + app.instrumentationClass);
4479 Bundle info = new Bundle();
4480 info.putString("shortMsg", "Process crashed.");
4481 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4482 }
4483
4484 if (!restarting) {
4485 if (!resumeTopActivityLocked(null)) {
4486 // If there was nothing to resume, and we are not already
4487 // restarting this process, but there is a visible activity that
4488 // is hosted by the process... then make sure all visible
4489 // activities are running, taking care of restarting this
4490 // process.
4491 if (hasVisibleActivities) {
4492 ensureActivitiesVisibleLocked(null, 0);
4493 }
4494 }
4495 }
4496 }
4497
4498 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4499 IBinder threadBinder = thread.asBinder();
4500
4501 // Find the application record.
4502 int count = mLRUProcesses.size();
4503 int i;
4504 for (i=0; i<count; i++) {
4505 ProcessRecord rec = mLRUProcesses.get(i);
4506 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4507 return i;
4508 }
4509 }
4510 return -1;
4511 }
4512
4513 private final ProcessRecord getRecordForAppLocked(
4514 IApplicationThread thread) {
4515 if (thread == null) {
4516 return null;
4517 }
4518
4519 int appIndex = getLRURecordIndexForAppLocked(thread);
4520 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4521 }
4522
4523 private final void appDiedLocked(ProcessRecord app, int pid,
4524 IApplicationThread thread) {
4525
4526 mProcDeaths[0]++;
4527
4528 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4529 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4530 + ") has died.");
4531 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4532 if (localLOGV) Log.v(
4533 TAG, "Dying app: " + app + ", pid: " + pid
4534 + ", thread: " + thread.asBinder());
4535 boolean doLowMem = app.instrumentationClass == null;
4536 handleAppDiedLocked(app, false);
4537
4538 if (doLowMem) {
4539 // If there are no longer any background processes running,
4540 // and the app that died was not running instrumentation,
4541 // then tell everyone we are now low on memory.
4542 boolean haveBg = false;
4543 int count = mLRUProcesses.size();
4544 int i;
4545 for (i=0; i<count; i++) {
4546 ProcessRecord rec = mLRUProcesses.get(i);
4547 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4548 haveBg = true;
4549 break;
4550 }
4551 }
4552
4553 if (!haveBg) {
4554 Log.i(TAG, "Low Memory: No more background processes.");
4555 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004556 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004557 for (i=0; i<count; i++) {
4558 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackborn36124872009-10-08 16:22:03 -07004559 if (rec != app && rec.thread != null &&
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004560 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4561 // The low memory report is overriding any current
4562 // state for a GC request. Make sure to do
4563 // visible/foreground processes first.
4564 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4565 rec.lastRequestedGc = 0;
4566 } else {
4567 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004568 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004569 rec.reportLowMemory = true;
4570 rec.lastLowMemory = now;
4571 mProcessesToGc.remove(rec);
4572 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004573 }
4574 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004575 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004576 }
4577 }
4578 } else if (Config.LOGD) {
4579 Log.d(TAG, "Received spurious death notification for thread "
4580 + thread.asBinder());
4581 }
4582 }
4583
4584 final String readFile(String filename) {
4585 try {
4586 FileInputStream fs = new FileInputStream(filename);
4587 byte[] inp = new byte[8192];
4588 int size = fs.read(inp);
4589 fs.close();
4590 return new String(inp, 0, 0, size);
4591 } catch (java.io.IOException e) {
4592 }
4593 return "";
4594 }
4595
4596 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004597 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004598 if (app.notResponding || app.crashing) {
4599 return;
4600 }
4601
4602 // Log the ANR to the event log.
4603 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4604
4605 // If we are on a secure build and the application is not interesting to the user (it is
4606 // not visible or in the background), just kill it instead of displaying a dialog.
4607 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4608 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4609 Process.killProcess(app.pid);
4610 return;
4611 }
4612
4613 // DeviceMonitor.start();
4614
4615 String processInfo = null;
4616 if (MONITOR_CPU_USAGE) {
4617 updateCpuStatsNow();
4618 synchronized (mProcessStatsThread) {
4619 processInfo = mProcessStats.printCurrentState();
4620 }
4621 }
4622
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004623 StringBuilder info = mStringBuilder;
4624 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004625 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004626 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004627 if (reportedActivity != null && reportedActivity.app != null) {
4628 info.append(" (last in ");
4629 info.append(reportedActivity.app.processName);
4630 info.append(")");
4631 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004632 if (annotation != null) {
4633 info.append("\nAnnotation: ");
4634 info.append(annotation);
4635 }
4636 if (MONITOR_CPU_USAGE) {
4637 info.append("\nCPU usage:\n");
4638 info.append(processInfo);
4639 }
4640 Log.i(TAG, info.toString());
4641
4642 // The application is not responding. Dump as many thread traces as we can.
4643 boolean fileDump = prepareTraceFile(true);
4644 if (!fileDump) {
4645 // Dumping traces to the log, just dump the process that isn't responding so
4646 // we don't overflow the log
4647 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4648 } else {
4649 // Dumping traces to a file so dump all active processes we know about
4650 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004651 // First, these are the most important processes.
4652 final int[] imppids = new int[3];
4653 int i=0;
4654 imppids[0] = app.pid;
4655 i++;
4656 if (reportedActivity != null && reportedActivity.app != null
4657 && reportedActivity.app.thread != null
4658 && reportedActivity.app.pid != app.pid) {
4659 imppids[i] = reportedActivity.app.pid;
4660 i++;
4661 }
4662 imppids[i] = Process.myPid();
4663 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4664 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4665 synchronized (this) {
4666 try {
4667 wait(200);
4668 } catch (InterruptedException e) {
4669 }
4670 }
4671 }
4672 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004673 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004674 boolean done = false;
4675 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4676 if (imppids[j] == r.pid) {
4677 done = true;
4678 break;
4679 }
4680 }
4681 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004682 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004683 synchronized (this) {
4684 try {
4685 wait(200);
4686 } catch (InterruptedException e) {
4687 }
4688 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004689 }
4690 }
4691 }
4692 }
4693
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004694 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004695 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004696 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004697 app.pid, info.toString());
4698 if (res != 0) {
4699 if (res < 0) {
4700 // wait until the SIGQUIT has had a chance to process before killing the
4701 // process.
4702 try {
4703 wait(2000);
4704 } catch (InterruptedException e) {
4705 }
4706
4707 Process.killProcess(app.pid);
4708 return;
4709 }
4710 }
4711 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004712 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004713 }
4714 }
4715
4716 makeAppNotRespondingLocked(app,
4717 activity != null ? activity.shortComponentName : null,
4718 annotation != null ? "ANR " + annotation : "ANR",
4719 info.toString(), null);
4720 Message msg = Message.obtain();
4721 HashMap map = new HashMap();
4722 msg.what = SHOW_NOT_RESPONDING_MSG;
4723 msg.obj = map;
4724 map.put("app", app);
4725 if (activity != null) {
4726 map.put("activity", activity);
4727 }
4728
4729 mHandler.sendMessage(msg);
4730 return;
4731 }
4732
4733 /**
4734 * If a stack trace file has been configured, prepare the filesystem
4735 * by creating the directory if it doesn't exist and optionally
4736 * removing the old trace file.
4737 *
4738 * @param removeExisting If set, the existing trace file will be removed.
4739 * @return Returns true if the trace file preparations succeeded
4740 */
4741 public static boolean prepareTraceFile(boolean removeExisting) {
4742 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4743 boolean fileReady = false;
4744 if (!TextUtils.isEmpty(tracesPath)) {
4745 File f = new File(tracesPath);
4746 if (!f.exists()) {
4747 // Ensure the enclosing directory exists
4748 File dir = f.getParentFile();
4749 if (!dir.exists()) {
4750 fileReady = dir.mkdirs();
4751 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004752 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004753 } else if (dir.isDirectory()) {
4754 fileReady = true;
4755 }
4756 } else if (removeExisting) {
4757 // Remove the previous traces file, so we don't fill the disk.
4758 // The VM will recreate it
4759 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4760 fileReady = f.delete();
4761 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004762
4763 if (removeExisting) {
4764 try {
4765 f.createNewFile();
4766 FileUtils.setPermissions(f.getAbsolutePath(),
4767 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4768 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4769 fileReady = true;
4770 } catch (IOException e) {
4771 Log.w(TAG, "Unable to make ANR traces file", e);
4772 }
4773 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004774 }
4775
4776 return fileReady;
4777 }
4778
4779
4780 private final void decPersistentCountLocked(ProcessRecord app)
4781 {
4782 app.persistentActivities--;
4783 if (app.persistentActivities > 0) {
4784 // Still more of 'em...
4785 return;
4786 }
4787 if (app.persistent) {
4788 // Ah, but the application itself is persistent. Whatever!
4789 return;
4790 }
4791
4792 // App is no longer persistent... make sure it and the ones
4793 // following it in the LRU list have the correc oom_adj.
4794 updateOomAdjLocked();
4795 }
4796
4797 public void setPersistent(IBinder token, boolean isPersistent) {
4798 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4799 != PackageManager.PERMISSION_GRANTED) {
4800 String msg = "Permission Denial: setPersistent() from pid="
4801 + Binder.getCallingPid()
4802 + ", uid=" + Binder.getCallingUid()
4803 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4804 Log.w(TAG, msg);
4805 throw new SecurityException(msg);
4806 }
4807
4808 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004809 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004810 if (index < 0) {
4811 return;
4812 }
4813 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4814 ProcessRecord app = r.app;
4815
4816 if (localLOGV) Log.v(
4817 TAG, "Setting persistence " + isPersistent + ": " + r);
4818
4819 if (isPersistent) {
4820 if (r.persistent) {
4821 // Okay okay, I heard you already!
4822 if (localLOGV) Log.v(TAG, "Already persistent!");
4823 return;
4824 }
4825 r.persistent = true;
4826 app.persistentActivities++;
4827 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4828 if (app.persistentActivities > 1) {
4829 // We aren't the first...
4830 if (localLOGV) Log.v(TAG, "Not the first!");
4831 return;
4832 }
4833 if (app.persistent) {
4834 // This would be redundant.
4835 if (localLOGV) Log.v(TAG, "App is persistent!");
4836 return;
4837 }
4838
4839 // App is now persistent... make sure it and the ones
4840 // following it now have the correct oom_adj.
4841 final long origId = Binder.clearCallingIdentity();
4842 updateOomAdjLocked();
4843 Binder.restoreCallingIdentity(origId);
4844
4845 } else {
4846 if (!r.persistent) {
4847 // Okay okay, I heard you already!
4848 return;
4849 }
4850 r.persistent = false;
4851 final long origId = Binder.clearCallingIdentity();
4852 decPersistentCountLocked(app);
4853 Binder.restoreCallingIdentity(origId);
4854
4855 }
4856 }
4857 }
4858
4859 public boolean clearApplicationUserData(final String packageName,
4860 final IPackageDataObserver observer) {
4861 int uid = Binder.getCallingUid();
4862 int pid = Binder.getCallingPid();
4863 long callingId = Binder.clearCallingIdentity();
4864 try {
4865 IPackageManager pm = ActivityThread.getPackageManager();
4866 int pkgUid = -1;
4867 synchronized(this) {
4868 try {
4869 pkgUid = pm.getPackageUid(packageName);
4870 } catch (RemoteException e) {
4871 }
4872 if (pkgUid == -1) {
4873 Log.w(TAG, "Invalid packageName:" + packageName);
4874 return false;
4875 }
4876 if (uid == pkgUid || checkComponentPermission(
4877 android.Manifest.permission.CLEAR_APP_USER_DATA,
4878 pid, uid, -1)
4879 == PackageManager.PERMISSION_GRANTED) {
4880 restartPackageLocked(packageName, pkgUid);
4881 } else {
4882 throw new SecurityException(pid+" does not have permission:"+
4883 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4884 "for process:"+packageName);
4885 }
4886 }
4887
4888 try {
4889 //clear application user data
4890 pm.clearApplicationUserData(packageName, observer);
4891 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4892 Uri.fromParts("package", packageName, null));
4893 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4894 broadcastIntentLocked(null, null, intent,
4895 null, null, 0, null, null, null,
4896 false, false, MY_PID, Process.SYSTEM_UID);
4897 } catch (RemoteException e) {
4898 }
4899 } finally {
4900 Binder.restoreCallingIdentity(callingId);
4901 }
4902 return true;
4903 }
4904
4905 public void restartPackage(final String packageName) {
4906 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4907 != PackageManager.PERMISSION_GRANTED) {
4908 String msg = "Permission Denial: restartPackage() from pid="
4909 + Binder.getCallingPid()
4910 + ", uid=" + Binder.getCallingUid()
4911 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4912 Log.w(TAG, msg);
4913 throw new SecurityException(msg);
4914 }
4915
4916 long callingId = Binder.clearCallingIdentity();
4917 try {
4918 IPackageManager pm = ActivityThread.getPackageManager();
4919 int pkgUid = -1;
4920 synchronized(this) {
4921 try {
4922 pkgUid = pm.getPackageUid(packageName);
4923 } catch (RemoteException e) {
4924 }
4925 if (pkgUid == -1) {
4926 Log.w(TAG, "Invalid packageName: " + packageName);
4927 return;
4928 }
4929 restartPackageLocked(packageName, pkgUid);
4930 }
4931 } finally {
4932 Binder.restoreCallingIdentity(callingId);
4933 }
4934 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004935
4936 /*
4937 * The pkg name and uid have to be specified.
4938 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4939 */
4940 public void killApplicationWithUid(String pkg, int uid) {
4941 if (pkg == null) {
4942 return;
4943 }
4944 // Make sure the uid is valid.
4945 if (uid < 0) {
4946 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4947 return;
4948 }
4949 int callerUid = Binder.getCallingUid();
4950 // Only the system server can kill an application
4951 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004952 // Post an aysnc message to kill the application
4953 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4954 msg.arg1 = uid;
4955 msg.arg2 = 0;
4956 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004957 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004958 } else {
4959 throw new SecurityException(callerUid + " cannot kill pkg: " +
4960 pkg);
4961 }
4962 }
4963
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004964 public void closeSystemDialogs(String reason) {
4965 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4966 if (reason != null) {
4967 intent.putExtra("reason", reason);
4968 }
4969
4970 final int uid = Binder.getCallingUid();
4971 final long origId = Binder.clearCallingIdentity();
4972 synchronized (this) {
4973 int i = mWatchers.beginBroadcast();
4974 while (i > 0) {
4975 i--;
4976 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4977 if (w != null) {
4978 try {
4979 w.closingSystemDialogs(reason);
4980 } catch (RemoteException e) {
4981 }
4982 }
4983 }
4984 mWatchers.finishBroadcast();
4985
Dianne Hackbornffa42482009-09-23 22:20:11 -07004986 mWindowManager.closeSystemDialogs(reason);
4987
4988 for (i=mHistory.size()-1; i>=0; i--) {
4989 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4990 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
4991 finishActivityLocked(r, i,
4992 Activity.RESULT_CANCELED, null, "close-sys");
4993 }
4994 }
4995
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004996 broadcastIntentLocked(null, null, intent, null,
4997 null, 0, null, null, null, false, false, -1, uid);
4998 }
4999 Binder.restoreCallingIdentity(origId);
5000 }
5001
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005002 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005003 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005004 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
5005 for (int i=pids.length-1; i>=0; i--) {
5006 infos[i] = new Debug.MemoryInfo();
5007 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005008 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005009 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005010 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07005011
5012 public void killApplicationProcess(String processName, int uid) {
5013 if (processName == null) {
5014 return;
5015 }
5016
5017 int callerUid = Binder.getCallingUid();
5018 // Only the system server can kill an application
5019 if (callerUid == Process.SYSTEM_UID) {
5020 synchronized (this) {
5021 ProcessRecord app = getProcessRecordLocked(processName, uid);
5022 if (app != null) {
5023 try {
5024 app.thread.scheduleSuicide();
5025 } catch (RemoteException e) {
5026 // If the other end already died, then our work here is done.
5027 }
5028 } else {
5029 Log.w(TAG, "Process/uid not found attempting kill of "
5030 + processName + " / " + uid);
5031 }
5032 }
5033 } else {
5034 throw new SecurityException(callerUid + " cannot kill app process: " +
5035 processName);
5036 }
5037 }
5038
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005039 private void restartPackageLocked(final String packageName, int uid) {
5040 uninstallPackageLocked(packageName, uid, false);
5041 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5042 Uri.fromParts("package", packageName, null));
5043 intent.putExtra(Intent.EXTRA_UID, uid);
5044 broadcastIntentLocked(null, null, intent,
5045 null, null, 0, null, null, null,
5046 false, false, MY_PID, Process.SYSTEM_UID);
5047 }
5048
5049 private final void uninstallPackageLocked(String name, int uid,
5050 boolean callerWillRestart) {
5051 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
5052
5053 int i, N;
5054
5055 final String procNamePrefix = name + ":";
5056 if (uid < 0) {
5057 try {
5058 uid = ActivityThread.getPackageManager().getPackageUid(name);
5059 } catch (RemoteException e) {
5060 }
5061 }
5062
5063 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5064 while (badApps.hasNext()) {
5065 SparseArray<Long> ba = badApps.next();
5066 if (ba.get(uid) != null) {
5067 badApps.remove();
5068 }
5069 }
5070
5071 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
5072
5073 // Remove all processes this package may have touched: all with the
5074 // same UID (except for the system or root user), and all whose name
5075 // matches the package name.
5076 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5077 final int NA = apps.size();
5078 for (int ia=0; ia<NA; ia++) {
5079 ProcessRecord app = apps.valueAt(ia);
5080 if (app.removed) {
5081 procs.add(app);
5082 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5083 || app.processName.equals(name)
5084 || app.processName.startsWith(procNamePrefix)) {
5085 app.removed = true;
5086 procs.add(app);
5087 }
5088 }
5089 }
5090
5091 N = procs.size();
5092 for (i=0; i<N; i++) {
5093 removeProcessLocked(procs.get(i), callerWillRestart);
5094 }
5095
5096 for (i=mHistory.size()-1; i>=0; i--) {
5097 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5098 if (r.packageName.equals(name)) {
5099 if (Config.LOGD) Log.d(
5100 TAG, " Force finishing activity "
5101 + r.intent.getComponent().flattenToShortString());
5102 if (r.app != null) {
5103 r.app.removed = true;
5104 }
5105 r.app = null;
5106 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5107 }
5108 }
5109
5110 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5111 for (ServiceRecord service : mServices.values()) {
5112 if (service.packageName.equals(name)) {
5113 if (service.app != null) {
5114 service.app.removed = true;
5115 }
5116 service.app = null;
5117 services.add(service);
5118 }
5119 }
5120
5121 N = services.size();
5122 for (i=0; i<N; i++) {
5123 bringDownServiceLocked(services.get(i), true);
5124 }
5125
5126 resumeTopActivityLocked(null);
5127 }
5128
5129 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5130 final String name = app.processName;
5131 final int uid = app.info.uid;
5132 if (Config.LOGD) Log.d(
5133 TAG, "Force removing process " + app + " (" + name
5134 + "/" + uid + ")");
5135
5136 mProcessNames.remove(name, uid);
5137 boolean needRestart = false;
5138 if (app.pid > 0 && app.pid != MY_PID) {
5139 int pid = app.pid;
5140 synchronized (mPidsSelfLocked) {
5141 mPidsSelfLocked.remove(pid);
5142 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5143 }
5144 handleAppDiedLocked(app, true);
5145 mLRUProcesses.remove(app);
5146 Process.killProcess(pid);
5147
5148 if (app.persistent) {
5149 if (!callerWillRestart) {
5150 addAppLocked(app.info);
5151 } else {
5152 needRestart = true;
5153 }
5154 }
5155 } else {
5156 mRemovedProcesses.add(app);
5157 }
5158
5159 return needRestart;
5160 }
5161
5162 private final void processStartTimedOutLocked(ProcessRecord app) {
5163 final int pid = app.pid;
5164 boolean gone = false;
5165 synchronized (mPidsSelfLocked) {
5166 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5167 if (knownApp != null && knownApp.thread == null) {
5168 mPidsSelfLocked.remove(pid);
5169 gone = true;
5170 }
5171 }
5172
5173 if (gone) {
5174 Log.w(TAG, "Process " + app + " failed to attach");
5175 mProcessNames.remove(app.processName, app.info.uid);
5176 Process.killProcess(pid);
5177 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5178 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5179 mPendingBroadcast = null;
5180 scheduleBroadcastsLocked();
5181 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005182 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5183 Log.w(TAG, "Unattached app died before backup, skipping");
5184 try {
5185 IBackupManager bm = IBackupManager.Stub.asInterface(
5186 ServiceManager.getService(Context.BACKUP_SERVICE));
5187 bm.agentDisconnected(app.info.packageName);
5188 } catch (RemoteException e) {
5189 // Can't happen; the backup manager is local
5190 }
5191 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005192 } else {
5193 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5194 }
5195 }
5196
5197 private final boolean attachApplicationLocked(IApplicationThread thread,
5198 int pid) {
5199
5200 // Find the application record that is being attached... either via
5201 // the pid if we are running in multiple processes, or just pull the
5202 // next app record if we are emulating process with anonymous threads.
5203 ProcessRecord app;
5204 if (pid != MY_PID && pid >= 0) {
5205 synchronized (mPidsSelfLocked) {
5206 app = mPidsSelfLocked.get(pid);
5207 }
5208 } else if (mStartingProcesses.size() > 0) {
5209 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005210 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005211 } else {
5212 app = null;
5213 }
5214
5215 if (app == null) {
5216 Log.w(TAG, "No pending application record for pid " + pid
5217 + " (IApplicationThread " + thread + "); dropping process");
5218 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5219 if (pid > 0 && pid != MY_PID) {
5220 Process.killProcess(pid);
5221 } else {
5222 try {
5223 thread.scheduleExit();
5224 } catch (Exception e) {
5225 // Ignore exceptions.
5226 }
5227 }
5228 return false;
5229 }
5230
5231 // If this application record is still attached to a previous
5232 // process, clean it up now.
5233 if (app.thread != null) {
5234 handleAppDiedLocked(app, true);
5235 }
5236
5237 // Tell the process all about itself.
5238
5239 if (localLOGV) Log.v(
5240 TAG, "Binding process pid " + pid + " to record " + app);
5241
5242 String processName = app.processName;
5243 try {
5244 thread.asBinder().linkToDeath(new AppDeathRecipient(
5245 app, pid, thread), 0);
5246 } catch (RemoteException e) {
5247 app.resetPackageList();
5248 startProcessLocked(app, "link fail", processName);
5249 return false;
5250 }
5251
5252 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5253
5254 app.thread = thread;
5255 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005256 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005257 app.forcingToForeground = null;
5258 app.foregroundServices = false;
5259 app.debugging = false;
5260
5261 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5262
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005263 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5264 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005265
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005266 if (!normalMode) {
5267 Log.i(TAG, "Launching preboot mode app: " + app);
5268 }
5269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005270 if (localLOGV) Log.v(
5271 TAG, "New app record " + app
5272 + " thread=" + thread.asBinder() + " pid=" + pid);
5273 try {
5274 int testMode = IApplicationThread.DEBUG_OFF;
5275 if (mDebugApp != null && mDebugApp.equals(processName)) {
5276 testMode = mWaitForDebugger
5277 ? IApplicationThread.DEBUG_WAIT
5278 : IApplicationThread.DEBUG_ON;
5279 app.debugging = true;
5280 if (mDebugTransient) {
5281 mDebugApp = mOrigDebugApp;
5282 mWaitForDebugger = mOrigWaitForDebugger;
5283 }
5284 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005285
Christopher Tate181fafa2009-05-14 11:12:14 -07005286 // If the app is being launched for restore or full backup, set it up specially
5287 boolean isRestrictedBackupMode = false;
5288 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5289 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5290 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5291 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005292
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005293 ensurePackageDexOpt(app.instrumentationInfo != null
5294 ? app.instrumentationInfo.packageName
5295 : app.info.packageName);
5296 if (app.instrumentationClass != null) {
5297 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005298 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005299 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5300 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005301 thread.bindApplication(processName, app.instrumentationInfo != null
5302 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005303 app.instrumentationClass, app.instrumentationProfileFile,
5304 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005305 isRestrictedBackupMode || !normalMode,
5306 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005307 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005308 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005309 } catch (Exception e) {
5310 // todo: Yikes! What should we do? For now we will try to
5311 // start another process, but that could easily get us in
5312 // an infinite loop of restarting processes...
5313 Log.w(TAG, "Exception thrown during bind!", e);
5314
5315 app.resetPackageList();
5316 startProcessLocked(app, "bind fail", processName);
5317 return false;
5318 }
5319
5320 // Remove this record from the list of starting applications.
5321 mPersistentStartingProcesses.remove(app);
5322 mProcessesOnHold.remove(app);
5323
5324 boolean badApp = false;
5325 boolean didSomething = false;
5326
5327 // See if the top visible activity is waiting to run in this process...
5328 HistoryRecord hr = topRunningActivityLocked(null);
5329 if (hr != null) {
5330 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5331 && processName.equals(hr.processName)) {
5332 try {
5333 if (realStartActivityLocked(hr, app, true, true)) {
5334 didSomething = true;
5335 }
5336 } catch (Exception e) {
5337 Log.w(TAG, "Exception in new application when starting activity "
5338 + hr.intent.getComponent().flattenToShortString(), e);
5339 badApp = true;
5340 }
5341 } else {
5342 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5343 }
5344 }
5345
5346 // Find any services that should be running in this process...
5347 if (!badApp && mPendingServices.size() > 0) {
5348 ServiceRecord sr = null;
5349 try {
5350 for (int i=0; i<mPendingServices.size(); i++) {
5351 sr = mPendingServices.get(i);
5352 if (app.info.uid != sr.appInfo.uid
5353 || !processName.equals(sr.processName)) {
5354 continue;
5355 }
5356
5357 mPendingServices.remove(i);
5358 i--;
5359 realStartServiceLocked(sr, app);
5360 didSomething = true;
5361 }
5362 } catch (Exception e) {
5363 Log.w(TAG, "Exception in new application when starting service "
5364 + sr.shortName, e);
5365 badApp = true;
5366 }
5367 }
5368
5369 // Check if the next broadcast receiver is in this process...
5370 BroadcastRecord br = mPendingBroadcast;
5371 if (!badApp && br != null && br.curApp == app) {
5372 try {
5373 mPendingBroadcast = null;
5374 processCurBroadcastLocked(br, app);
5375 didSomething = true;
5376 } catch (Exception e) {
5377 Log.w(TAG, "Exception in new application when starting receiver "
5378 + br.curComponent.flattenToShortString(), e);
5379 badApp = true;
5380 logBroadcastReceiverDiscard(br);
5381 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5382 br.resultExtras, br.resultAbort, true);
5383 scheduleBroadcastsLocked();
5384 }
5385 }
5386
Christopher Tate181fafa2009-05-14 11:12:14 -07005387 // Check whether the next backup agent is in this process...
5388 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5389 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005390 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005391 try {
5392 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5393 } catch (Exception e) {
5394 Log.w(TAG, "Exception scheduling backup agent creation: ");
5395 e.printStackTrace();
5396 }
5397 }
5398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005399 if (badApp) {
5400 // todo: Also need to kill application to deal with all
5401 // kinds of exceptions.
5402 handleAppDiedLocked(app, false);
5403 return false;
5404 }
5405
5406 if (!didSomething) {
5407 updateOomAdjLocked();
5408 }
5409
5410 return true;
5411 }
5412
5413 public final void attachApplication(IApplicationThread thread) {
5414 synchronized (this) {
5415 int callingPid = Binder.getCallingPid();
5416 final long origId = Binder.clearCallingIdentity();
5417 attachApplicationLocked(thread, callingPid);
5418 Binder.restoreCallingIdentity(origId);
5419 }
5420 }
5421
Dianne Hackborne88846e2009-09-30 21:34:25 -07005422 public final void activityIdle(IBinder token, Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005423 final long origId = Binder.clearCallingIdentity();
Dianne Hackborne88846e2009-09-30 21:34:25 -07005424 activityIdleInternal(token, false, config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005425 Binder.restoreCallingIdentity(origId);
5426 }
5427
5428 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5429 boolean remove) {
5430 int N = mStoppingActivities.size();
5431 if (N <= 0) return null;
5432
5433 ArrayList<HistoryRecord> stops = null;
5434
5435 final boolean nowVisible = mResumedActivity != null
5436 && mResumedActivity.nowVisible
5437 && !mResumedActivity.waitingVisible;
5438 for (int i=0; i<N; i++) {
5439 HistoryRecord s = mStoppingActivities.get(i);
5440 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5441 + nowVisible + " waitingVisible=" + s.waitingVisible
5442 + " finishing=" + s.finishing);
5443 if (s.waitingVisible && nowVisible) {
5444 mWaitingVisibleActivities.remove(s);
5445 s.waitingVisible = false;
5446 if (s.finishing) {
5447 // If this activity is finishing, it is sitting on top of
5448 // everyone else but we now know it is no longer needed...
5449 // so get rid of it. Otherwise, we need to go through the
5450 // normal flow and hide it once we determine that it is
5451 // hidden by the activities in front of it.
5452 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5453 mWindowManager.setAppVisibility(s, false);
5454 }
5455 }
5456 if (!s.waitingVisible && remove) {
5457 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5458 if (stops == null) {
5459 stops = new ArrayList<HistoryRecord>();
5460 }
5461 stops.add(s);
5462 mStoppingActivities.remove(i);
5463 N--;
5464 i--;
5465 }
5466 }
5467
5468 return stops;
5469 }
5470
5471 void enableScreenAfterBoot() {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005472 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5473 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005474 mWindowManager.enableScreenAfterBoot();
5475 }
5476
Dianne Hackborne88846e2009-09-30 21:34:25 -07005477 final void activityIdleInternal(IBinder token, boolean fromTimeout,
5478 Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005479 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5480
5481 ArrayList<HistoryRecord> stops = null;
5482 ArrayList<HistoryRecord> finishes = null;
5483 ArrayList<HistoryRecord> thumbnails = null;
5484 int NS = 0;
5485 int NF = 0;
5486 int NT = 0;
5487 IApplicationThread sendThumbnail = null;
5488 boolean booting = false;
5489 boolean enableScreen = false;
5490
5491 synchronized (this) {
5492 if (token != null) {
5493 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5494 }
5495
5496 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005497 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005498 if (index >= 0) {
5499 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5500
Dianne Hackborne88846e2009-09-30 21:34:25 -07005501 // This is a hack to semi-deal with a race condition
5502 // in the client where it can be constructed with a
5503 // newer configuration from when we asked it to launch.
5504 // We'll update with whatever configuration it now says
5505 // it used to launch.
5506 if (config != null) {
5507 r.configuration = config;
5508 }
5509
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005510 // No longer need to keep the device awake.
5511 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5512 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5513 mLaunchingActivity.release();
5514 }
5515
5516 // We are now idle. If someone is waiting for a thumbnail from
5517 // us, we can now deliver.
5518 r.idle = true;
5519 scheduleAppGcsLocked();
5520 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5521 sendThumbnail = r.app.thread;
5522 r.thumbnailNeeded = false;
5523 }
5524
5525 // If this activity is fullscreen, set up to hide those under it.
5526
5527 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5528 ensureActivitiesVisibleLocked(null, 0);
5529
5530 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5531 if (!mBooted && !fromTimeout) {
5532 mBooted = true;
5533 enableScreen = true;
5534 }
5535 }
5536
5537 // Atomically retrieve all of the other things to do.
5538 stops = processStoppingActivitiesLocked(true);
5539 NS = stops != null ? stops.size() : 0;
5540 if ((NF=mFinishingActivities.size()) > 0) {
5541 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5542 mFinishingActivities.clear();
5543 }
5544 if ((NT=mCancelledThumbnails.size()) > 0) {
5545 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5546 mCancelledThumbnails.clear();
5547 }
5548
5549 booting = mBooting;
5550 mBooting = false;
5551 }
5552
5553 int i;
5554
5555 // Send thumbnail if requested.
5556 if (sendThumbnail != null) {
5557 try {
5558 sendThumbnail.requestThumbnail(token);
5559 } catch (Exception e) {
5560 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5561 sendPendingThumbnail(null, token, null, null, true);
5562 }
5563 }
5564
5565 // Stop any activities that are scheduled to do so but have been
5566 // waiting for the next one to start.
5567 for (i=0; i<NS; i++) {
5568 HistoryRecord r = (HistoryRecord)stops.get(i);
5569 synchronized (this) {
5570 if (r.finishing) {
5571 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5572 } else {
5573 stopActivityLocked(r);
5574 }
5575 }
5576 }
5577
5578 // Finish any activities that are scheduled to do so but have been
5579 // waiting for the next one to start.
5580 for (i=0; i<NF; i++) {
5581 HistoryRecord r = (HistoryRecord)finishes.get(i);
5582 synchronized (this) {
5583 destroyActivityLocked(r, true);
5584 }
5585 }
5586
5587 // Report back to any thumbnail receivers.
5588 for (i=0; i<NT; i++) {
5589 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5590 sendPendingThumbnail(r, null, null, null, true);
5591 }
5592
5593 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005594 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005595 }
5596
5597 trimApplications();
5598 //dump();
5599 //mWindowManager.dump();
5600
5601 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005602 enableScreenAfterBoot();
5603 }
5604 }
5605
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005606 final void finishBooting() {
5607 // Ensure that any processes we had put on hold are now started
5608 // up.
5609 final int NP = mProcessesOnHold.size();
5610 if (NP > 0) {
5611 ArrayList<ProcessRecord> procs =
5612 new ArrayList<ProcessRecord>(mProcessesOnHold);
5613 for (int ip=0; ip<NP; ip++) {
5614 this.startProcessLocked(procs.get(ip), "on-hold", null);
5615 }
5616 }
5617 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5618 // Tell anyone interested that we are done booting!
5619 synchronized (this) {
5620 broadcastIntentLocked(null, null,
5621 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5622 null, null, 0, null, null,
5623 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5624 false, false, MY_PID, Process.SYSTEM_UID);
5625 }
5626 }
5627 }
5628
5629 final void ensureBootCompleted() {
5630 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005631 boolean enableScreen;
5632 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005633 booting = mBooting;
5634 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005635 enableScreen = !mBooted;
5636 mBooted = true;
5637 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005638
5639 if (booting) {
5640 finishBooting();
5641 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005642
5643 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005644 enableScreenAfterBoot();
5645 }
5646 }
5647
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005648 public final void activityPaused(IBinder token, Bundle icicle) {
5649 // Refuse possible leaked file descriptors
5650 if (icicle != null && icicle.hasFileDescriptors()) {
5651 throw new IllegalArgumentException("File descriptors passed in Bundle");
5652 }
5653
5654 final long origId = Binder.clearCallingIdentity();
5655 activityPaused(token, icicle, false);
5656 Binder.restoreCallingIdentity(origId);
5657 }
5658
5659 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5660 if (DEBUG_PAUSE) Log.v(
5661 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5662 + ", timeout=" + timeout);
5663
5664 HistoryRecord r = null;
5665
5666 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005667 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005668 if (index >= 0) {
5669 r = (HistoryRecord)mHistory.get(index);
5670 if (!timeout) {
5671 r.icicle = icicle;
5672 r.haveState = true;
5673 }
5674 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5675 if (mPausingActivity == r) {
5676 r.state = ActivityState.PAUSED;
5677 completePauseLocked();
5678 } else {
5679 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5680 System.identityHashCode(r), r.shortComponentName,
5681 mPausingActivity != null
5682 ? mPausingActivity.shortComponentName : "(none)");
5683 }
5684 }
5685 }
5686 }
5687
5688 public final void activityStopped(IBinder token, Bitmap thumbnail,
5689 CharSequence description) {
5690 if (localLOGV) Log.v(
5691 TAG, "Activity stopped: token=" + token);
5692
5693 HistoryRecord r = null;
5694
5695 final long origId = Binder.clearCallingIdentity();
5696
5697 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005698 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005699 if (index >= 0) {
5700 r = (HistoryRecord)mHistory.get(index);
5701 r.thumbnail = thumbnail;
5702 r.description = description;
5703 r.stopped = true;
5704 r.state = ActivityState.STOPPED;
5705 if (!r.finishing) {
5706 if (r.configDestroy) {
5707 destroyActivityLocked(r, true);
5708 resumeTopActivityLocked(null);
5709 }
5710 }
5711 }
5712 }
5713
5714 if (r != null) {
5715 sendPendingThumbnail(r, null, null, null, false);
5716 }
5717
5718 trimApplications();
5719
5720 Binder.restoreCallingIdentity(origId);
5721 }
5722
5723 public final void activityDestroyed(IBinder token) {
5724 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5725 synchronized (this) {
5726 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5727
Dianne Hackborn75b03852009-06-12 15:43:26 -07005728 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005729 if (index >= 0) {
5730 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5731 if (r.state == ActivityState.DESTROYING) {
5732 final long origId = Binder.clearCallingIdentity();
5733 removeActivityFromHistoryLocked(r);
5734 Binder.restoreCallingIdentity(origId);
5735 }
5736 }
5737 }
5738 }
5739
5740 public String getCallingPackage(IBinder token) {
5741 synchronized (this) {
5742 HistoryRecord r = getCallingRecordLocked(token);
5743 return r != null && r.app != null ? r.app.processName : null;
5744 }
5745 }
5746
5747 public ComponentName getCallingActivity(IBinder token) {
5748 synchronized (this) {
5749 HistoryRecord r = getCallingRecordLocked(token);
5750 return r != null ? r.intent.getComponent() : null;
5751 }
5752 }
5753
5754 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005755 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005756 if (index >= 0) {
5757 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5758 if (r != null) {
5759 return r.resultTo;
5760 }
5761 }
5762 return null;
5763 }
5764
5765 public ComponentName getActivityClassForToken(IBinder token) {
5766 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005767 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005768 if (index >= 0) {
5769 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5770 return r.intent.getComponent();
5771 }
5772 return null;
5773 }
5774 }
5775
5776 public String getPackageForToken(IBinder token) {
5777 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005778 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005779 if (index >= 0) {
5780 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5781 return r.packageName;
5782 }
5783 return null;
5784 }
5785 }
5786
5787 public IIntentSender getIntentSender(int type,
5788 String packageName, IBinder token, String resultWho,
5789 int requestCode, Intent intent, String resolvedType, int flags) {
5790 // Refuse possible leaked file descriptors
5791 if (intent != null && intent.hasFileDescriptors() == true) {
5792 throw new IllegalArgumentException("File descriptors passed in Intent");
5793 }
5794
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005795 if (type == INTENT_SENDER_BROADCAST) {
5796 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5797 throw new IllegalArgumentException(
5798 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5799 }
5800 }
5801
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005802 synchronized(this) {
5803 int callingUid = Binder.getCallingUid();
5804 try {
5805 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5806 Process.supportsProcesses()) {
5807 int uid = ActivityThread.getPackageManager()
5808 .getPackageUid(packageName);
5809 if (uid != Binder.getCallingUid()) {
5810 String msg = "Permission Denial: getIntentSender() from pid="
5811 + Binder.getCallingPid()
5812 + ", uid=" + Binder.getCallingUid()
5813 + ", (need uid=" + uid + ")"
5814 + " is not allowed to send as package " + packageName;
5815 Log.w(TAG, msg);
5816 throw new SecurityException(msg);
5817 }
5818 }
5819 } catch (RemoteException e) {
5820 throw new SecurityException(e);
5821 }
5822 HistoryRecord activity = null;
5823 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005824 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005825 if (index < 0) {
5826 return null;
5827 }
5828 activity = (HistoryRecord)mHistory.get(index);
5829 if (activity.finishing) {
5830 return null;
5831 }
5832 }
5833
5834 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5835 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5836 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5837 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5838 |PendingIntent.FLAG_UPDATE_CURRENT);
5839
5840 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5841 type, packageName, activity, resultWho,
5842 requestCode, intent, resolvedType, flags);
5843 WeakReference<PendingIntentRecord> ref;
5844 ref = mIntentSenderRecords.get(key);
5845 PendingIntentRecord rec = ref != null ? ref.get() : null;
5846 if (rec != null) {
5847 if (!cancelCurrent) {
5848 if (updateCurrent) {
5849 rec.key.requestIntent.replaceExtras(intent);
5850 }
5851 return rec;
5852 }
5853 rec.canceled = true;
5854 mIntentSenderRecords.remove(key);
5855 }
5856 if (noCreate) {
5857 return rec;
5858 }
5859 rec = new PendingIntentRecord(this, key, callingUid);
5860 mIntentSenderRecords.put(key, rec.ref);
5861 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5862 if (activity.pendingResults == null) {
5863 activity.pendingResults
5864 = new HashSet<WeakReference<PendingIntentRecord>>();
5865 }
5866 activity.pendingResults.add(rec.ref);
5867 }
5868 return rec;
5869 }
5870 }
5871
5872 public void cancelIntentSender(IIntentSender sender) {
5873 if (!(sender instanceof PendingIntentRecord)) {
5874 return;
5875 }
5876 synchronized(this) {
5877 PendingIntentRecord rec = (PendingIntentRecord)sender;
5878 try {
5879 int uid = ActivityThread.getPackageManager()
5880 .getPackageUid(rec.key.packageName);
5881 if (uid != Binder.getCallingUid()) {
5882 String msg = "Permission Denial: cancelIntentSender() from pid="
5883 + Binder.getCallingPid()
5884 + ", uid=" + Binder.getCallingUid()
5885 + " is not allowed to cancel packges "
5886 + rec.key.packageName;
5887 Log.w(TAG, msg);
5888 throw new SecurityException(msg);
5889 }
5890 } catch (RemoteException e) {
5891 throw new SecurityException(e);
5892 }
5893 cancelIntentSenderLocked(rec, true);
5894 }
5895 }
5896
5897 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5898 rec.canceled = true;
5899 mIntentSenderRecords.remove(rec.key);
5900 if (cleanActivity && rec.key.activity != null) {
5901 rec.key.activity.pendingResults.remove(rec.ref);
5902 }
5903 }
5904
5905 public String getPackageForIntentSender(IIntentSender pendingResult) {
5906 if (!(pendingResult instanceof PendingIntentRecord)) {
5907 return null;
5908 }
5909 synchronized(this) {
5910 try {
5911 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5912 return res.key.packageName;
5913 } catch (ClassCastException e) {
5914 }
5915 }
5916 return null;
5917 }
5918
5919 public void setProcessLimit(int max) {
5920 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5921 "setProcessLimit()");
5922 mProcessLimit = max;
5923 }
5924
5925 public int getProcessLimit() {
5926 return mProcessLimit;
5927 }
5928
5929 void foregroundTokenDied(ForegroundToken token) {
5930 synchronized (ActivityManagerService.this) {
5931 synchronized (mPidsSelfLocked) {
5932 ForegroundToken cur
5933 = mForegroundProcesses.get(token.pid);
5934 if (cur != token) {
5935 return;
5936 }
5937 mForegroundProcesses.remove(token.pid);
5938 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5939 if (pr == null) {
5940 return;
5941 }
5942 pr.forcingToForeground = null;
5943 pr.foregroundServices = false;
5944 }
5945 updateOomAdjLocked();
5946 }
5947 }
5948
5949 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5950 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5951 "setProcessForeground()");
5952 synchronized(this) {
5953 boolean changed = false;
5954
5955 synchronized (mPidsSelfLocked) {
5956 ProcessRecord pr = mPidsSelfLocked.get(pid);
5957 if (pr == null) {
5958 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5959 return;
5960 }
5961 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5962 if (oldToken != null) {
5963 oldToken.token.unlinkToDeath(oldToken, 0);
5964 mForegroundProcesses.remove(pid);
5965 pr.forcingToForeground = null;
5966 changed = true;
5967 }
5968 if (isForeground && token != null) {
5969 ForegroundToken newToken = new ForegroundToken() {
5970 public void binderDied() {
5971 foregroundTokenDied(this);
5972 }
5973 };
5974 newToken.pid = pid;
5975 newToken.token = token;
5976 try {
5977 token.linkToDeath(newToken, 0);
5978 mForegroundProcesses.put(pid, newToken);
5979 pr.forcingToForeground = token;
5980 changed = true;
5981 } catch (RemoteException e) {
5982 // If the process died while doing this, we will later
5983 // do the cleanup with the process death link.
5984 }
5985 }
5986 }
5987
5988 if (changed) {
5989 updateOomAdjLocked();
5990 }
5991 }
5992 }
5993
5994 // =========================================================
5995 // PERMISSIONS
5996 // =========================================================
5997
5998 static class PermissionController extends IPermissionController.Stub {
5999 ActivityManagerService mActivityManagerService;
6000 PermissionController(ActivityManagerService activityManagerService) {
6001 mActivityManagerService = activityManagerService;
6002 }
6003
6004 public boolean checkPermission(String permission, int pid, int uid) {
6005 return mActivityManagerService.checkPermission(permission, pid,
6006 uid) == PackageManager.PERMISSION_GRANTED;
6007 }
6008 }
6009
6010 /**
6011 * This can be called with or without the global lock held.
6012 */
6013 int checkComponentPermission(String permission, int pid, int uid,
6014 int reqUid) {
6015 // We might be performing an operation on behalf of an indirect binder
6016 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
6017 // client identity accordingly before proceeding.
6018 Identity tlsIdentity = sCallerIdentity.get();
6019 if (tlsIdentity != null) {
6020 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6021 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6022 uid = tlsIdentity.uid;
6023 pid = tlsIdentity.pid;
6024 }
6025
6026 // Root, system server and our own process get to do everything.
6027 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6028 !Process.supportsProcesses()) {
6029 return PackageManager.PERMISSION_GRANTED;
6030 }
6031 // If the target requires a specific UID, always fail for others.
6032 if (reqUid >= 0 && uid != reqUid) {
6033 return PackageManager.PERMISSION_DENIED;
6034 }
6035 if (permission == null) {
6036 return PackageManager.PERMISSION_GRANTED;
6037 }
6038 try {
6039 return ActivityThread.getPackageManager()
6040 .checkUidPermission(permission, uid);
6041 } catch (RemoteException e) {
6042 // Should never happen, but if it does... deny!
6043 Log.e(TAG, "PackageManager is dead?!?", e);
6044 }
6045 return PackageManager.PERMISSION_DENIED;
6046 }
6047
6048 /**
6049 * As the only public entry point for permissions checking, this method
6050 * can enforce the semantic that requesting a check on a null global
6051 * permission is automatically denied. (Internally a null permission
6052 * string is used when calling {@link #checkComponentPermission} in cases
6053 * when only uid-based security is needed.)
6054 *
6055 * This can be called with or without the global lock held.
6056 */
6057 public int checkPermission(String permission, int pid, int uid) {
6058 if (permission == null) {
6059 return PackageManager.PERMISSION_DENIED;
6060 }
6061 return checkComponentPermission(permission, pid, uid, -1);
6062 }
6063
6064 /**
6065 * Binder IPC calls go through the public entry point.
6066 * This can be called with or without the global lock held.
6067 */
6068 int checkCallingPermission(String permission) {
6069 return checkPermission(permission,
6070 Binder.getCallingPid(),
6071 Binder.getCallingUid());
6072 }
6073
6074 /**
6075 * This can be called with or without the global lock held.
6076 */
6077 void enforceCallingPermission(String permission, String func) {
6078 if (checkCallingPermission(permission)
6079 == PackageManager.PERMISSION_GRANTED) {
6080 return;
6081 }
6082
6083 String msg = "Permission Denial: " + func + " from pid="
6084 + Binder.getCallingPid()
6085 + ", uid=" + Binder.getCallingUid()
6086 + " requires " + permission;
6087 Log.w(TAG, msg);
6088 throw new SecurityException(msg);
6089 }
6090
6091 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6092 ProviderInfo pi, int uid, int modeFlags) {
6093 try {
6094 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6095 if ((pi.readPermission != null) &&
6096 (pm.checkUidPermission(pi.readPermission, uid)
6097 != PackageManager.PERMISSION_GRANTED)) {
6098 return false;
6099 }
6100 }
6101 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6102 if ((pi.writePermission != null) &&
6103 (pm.checkUidPermission(pi.writePermission, uid)
6104 != PackageManager.PERMISSION_GRANTED)) {
6105 return false;
6106 }
6107 }
6108 return true;
6109 } catch (RemoteException e) {
6110 return false;
6111 }
6112 }
6113
6114 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6115 int modeFlags) {
6116 // Root gets to do everything.
6117 if (uid == 0 || !Process.supportsProcesses()) {
6118 return true;
6119 }
6120 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6121 if (perms == null) return false;
6122 UriPermission perm = perms.get(uri);
6123 if (perm == null) return false;
6124 return (modeFlags&perm.modeFlags) == modeFlags;
6125 }
6126
6127 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6128 // Another redirected-binder-call permissions check as in
6129 // {@link checkComponentPermission}.
6130 Identity tlsIdentity = sCallerIdentity.get();
6131 if (tlsIdentity != null) {
6132 uid = tlsIdentity.uid;
6133 pid = tlsIdentity.pid;
6134 }
6135
6136 // Our own process gets to do everything.
6137 if (pid == MY_PID) {
6138 return PackageManager.PERMISSION_GRANTED;
6139 }
6140 synchronized(this) {
6141 return checkUriPermissionLocked(uri, uid, modeFlags)
6142 ? PackageManager.PERMISSION_GRANTED
6143 : PackageManager.PERMISSION_DENIED;
6144 }
6145 }
6146
6147 private void grantUriPermissionLocked(int callingUid,
6148 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6149 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6150 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6151 if (modeFlags == 0) {
6152 return;
6153 }
6154
6155 final IPackageManager pm = ActivityThread.getPackageManager();
6156
6157 // If this is not a content: uri, we can't do anything with it.
6158 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6159 return;
6160 }
6161
6162 String name = uri.getAuthority();
6163 ProviderInfo pi = null;
6164 ContentProviderRecord cpr
6165 = (ContentProviderRecord)mProvidersByName.get(name);
6166 if (cpr != null) {
6167 pi = cpr.info;
6168 } else {
6169 try {
6170 pi = pm.resolveContentProvider(name,
6171 PackageManager.GET_URI_PERMISSION_PATTERNS);
6172 } catch (RemoteException ex) {
6173 }
6174 }
6175 if (pi == null) {
6176 Log.w(TAG, "No content provider found for: " + name);
6177 return;
6178 }
6179
6180 int targetUid;
6181 try {
6182 targetUid = pm.getPackageUid(targetPkg);
6183 if (targetUid < 0) {
6184 return;
6185 }
6186 } catch (RemoteException ex) {
6187 return;
6188 }
6189
6190 // First... does the target actually need this permission?
6191 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6192 // No need to grant the target this permission.
6193 return;
6194 }
6195
6196 // Second... maybe someone else has already granted the
6197 // permission?
6198 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6199 // No need to grant the target this permission.
6200 return;
6201 }
6202
6203 // Third... is the provider allowing granting of URI permissions?
6204 if (!pi.grantUriPermissions) {
6205 throw new SecurityException("Provider " + pi.packageName
6206 + "/" + pi.name
6207 + " does not allow granting of Uri permissions (uri "
6208 + uri + ")");
6209 }
6210 if (pi.uriPermissionPatterns != null) {
6211 final int N = pi.uriPermissionPatterns.length;
6212 boolean allowed = false;
6213 for (int i=0; i<N; i++) {
6214 if (pi.uriPermissionPatterns[i] != null
6215 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6216 allowed = true;
6217 break;
6218 }
6219 }
6220 if (!allowed) {
6221 throw new SecurityException("Provider " + pi.packageName
6222 + "/" + pi.name
6223 + " does not allow granting of permission to path of Uri "
6224 + uri);
6225 }
6226 }
6227
6228 // Fourth... does the caller itself have permission to access
6229 // this uri?
6230 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6231 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6232 throw new SecurityException("Uid " + callingUid
6233 + " does not have permission to uri " + uri);
6234 }
6235 }
6236
6237 // Okay! So here we are: the caller has the assumed permission
6238 // to the uri, and the target doesn't. Let's now give this to
6239 // the target.
6240
6241 HashMap<Uri, UriPermission> targetUris
6242 = mGrantedUriPermissions.get(targetUid);
6243 if (targetUris == null) {
6244 targetUris = new HashMap<Uri, UriPermission>();
6245 mGrantedUriPermissions.put(targetUid, targetUris);
6246 }
6247
6248 UriPermission perm = targetUris.get(uri);
6249 if (perm == null) {
6250 perm = new UriPermission(targetUid, uri);
6251 targetUris.put(uri, perm);
6252
6253 }
6254 perm.modeFlags |= modeFlags;
6255 if (activity == null) {
6256 perm.globalModeFlags |= modeFlags;
6257 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6258 perm.readActivities.add(activity);
6259 if (activity.readUriPermissions == null) {
6260 activity.readUriPermissions = new HashSet<UriPermission>();
6261 }
6262 activity.readUriPermissions.add(perm);
6263 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6264 perm.writeActivities.add(activity);
6265 if (activity.writeUriPermissions == null) {
6266 activity.writeUriPermissions = new HashSet<UriPermission>();
6267 }
6268 activity.writeUriPermissions.add(perm);
6269 }
6270 }
6271
6272 private void grantUriPermissionFromIntentLocked(int callingUid,
6273 String targetPkg, Intent intent, HistoryRecord activity) {
6274 if (intent == null) {
6275 return;
6276 }
6277 Uri data = intent.getData();
6278 if (data == null) {
6279 return;
6280 }
6281 grantUriPermissionLocked(callingUid, targetPkg, data,
6282 intent.getFlags(), activity);
6283 }
6284
6285 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6286 Uri uri, int modeFlags) {
6287 synchronized(this) {
6288 final ProcessRecord r = getRecordForAppLocked(caller);
6289 if (r == null) {
6290 throw new SecurityException("Unable to find app for caller "
6291 + caller
6292 + " when granting permission to uri " + uri);
6293 }
6294 if (targetPkg == null) {
6295 Log.w(TAG, "grantUriPermission: null target");
6296 return;
6297 }
6298 if (uri == null) {
6299 Log.w(TAG, "grantUriPermission: null uri");
6300 return;
6301 }
6302
6303 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6304 null);
6305 }
6306 }
6307
6308 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6309 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6310 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6311 HashMap<Uri, UriPermission> perms
6312 = mGrantedUriPermissions.get(perm.uid);
6313 if (perms != null) {
6314 perms.remove(perm.uri);
6315 if (perms.size() == 0) {
6316 mGrantedUriPermissions.remove(perm.uid);
6317 }
6318 }
6319 }
6320 }
6321
6322 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6323 if (activity.readUriPermissions != null) {
6324 for (UriPermission perm : activity.readUriPermissions) {
6325 perm.readActivities.remove(activity);
6326 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6327 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6328 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6329 removeUriPermissionIfNeededLocked(perm);
6330 }
6331 }
6332 }
6333 if (activity.writeUriPermissions != null) {
6334 for (UriPermission perm : activity.writeUriPermissions) {
6335 perm.writeActivities.remove(activity);
6336 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6337 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6338 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6339 removeUriPermissionIfNeededLocked(perm);
6340 }
6341 }
6342 }
6343 }
6344
6345 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6346 int modeFlags) {
6347 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6348 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6349 if (modeFlags == 0) {
6350 return;
6351 }
6352
6353 final IPackageManager pm = ActivityThread.getPackageManager();
6354
6355 final String authority = uri.getAuthority();
6356 ProviderInfo pi = null;
6357 ContentProviderRecord cpr
6358 = (ContentProviderRecord)mProvidersByName.get(authority);
6359 if (cpr != null) {
6360 pi = cpr.info;
6361 } else {
6362 try {
6363 pi = pm.resolveContentProvider(authority,
6364 PackageManager.GET_URI_PERMISSION_PATTERNS);
6365 } catch (RemoteException ex) {
6366 }
6367 }
6368 if (pi == null) {
6369 Log.w(TAG, "No content provider found for: " + authority);
6370 return;
6371 }
6372
6373 // Does the caller have this permission on the URI?
6374 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6375 // Right now, if you are not the original owner of the permission,
6376 // you are not allowed to revoke it.
6377 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6378 throw new SecurityException("Uid " + callingUid
6379 + " does not have permission to uri " + uri);
6380 //}
6381 }
6382
6383 // Go through all of the permissions and remove any that match.
6384 final List<String> SEGMENTS = uri.getPathSegments();
6385 if (SEGMENTS != null) {
6386 final int NS = SEGMENTS.size();
6387 int N = mGrantedUriPermissions.size();
6388 for (int i=0; i<N; i++) {
6389 HashMap<Uri, UriPermission> perms
6390 = mGrantedUriPermissions.valueAt(i);
6391 Iterator<UriPermission> it = perms.values().iterator();
6392 toploop:
6393 while (it.hasNext()) {
6394 UriPermission perm = it.next();
6395 Uri targetUri = perm.uri;
6396 if (!authority.equals(targetUri.getAuthority())) {
6397 continue;
6398 }
6399 List<String> targetSegments = targetUri.getPathSegments();
6400 if (targetSegments == null) {
6401 continue;
6402 }
6403 if (targetSegments.size() < NS) {
6404 continue;
6405 }
6406 for (int j=0; j<NS; j++) {
6407 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6408 continue toploop;
6409 }
6410 }
6411 perm.clearModes(modeFlags);
6412 if (perm.modeFlags == 0) {
6413 it.remove();
6414 }
6415 }
6416 if (perms.size() == 0) {
6417 mGrantedUriPermissions.remove(
6418 mGrantedUriPermissions.keyAt(i));
6419 N--;
6420 i--;
6421 }
6422 }
6423 }
6424 }
6425
6426 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6427 int modeFlags) {
6428 synchronized(this) {
6429 final ProcessRecord r = getRecordForAppLocked(caller);
6430 if (r == null) {
6431 throw new SecurityException("Unable to find app for caller "
6432 + caller
6433 + " when revoking permission to uri " + uri);
6434 }
6435 if (uri == null) {
6436 Log.w(TAG, "revokeUriPermission: null uri");
6437 return;
6438 }
6439
6440 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6441 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6442 if (modeFlags == 0) {
6443 return;
6444 }
6445
6446 final IPackageManager pm = ActivityThread.getPackageManager();
6447
6448 final String authority = uri.getAuthority();
6449 ProviderInfo pi = null;
6450 ContentProviderRecord cpr
6451 = (ContentProviderRecord)mProvidersByName.get(authority);
6452 if (cpr != null) {
6453 pi = cpr.info;
6454 } else {
6455 try {
6456 pi = pm.resolveContentProvider(authority,
6457 PackageManager.GET_URI_PERMISSION_PATTERNS);
6458 } catch (RemoteException ex) {
6459 }
6460 }
6461 if (pi == null) {
6462 Log.w(TAG, "No content provider found for: " + authority);
6463 return;
6464 }
6465
6466 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6467 }
6468 }
6469
6470 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6471 synchronized (this) {
6472 ProcessRecord app =
6473 who != null ? getRecordForAppLocked(who) : null;
6474 if (app == null) return;
6475
6476 Message msg = Message.obtain();
6477 msg.what = WAIT_FOR_DEBUGGER_MSG;
6478 msg.obj = app;
6479 msg.arg1 = waiting ? 1 : 0;
6480 mHandler.sendMessage(msg);
6481 }
6482 }
6483
6484 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6485 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006486 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006487 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006488 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006489 }
6490
6491 // =========================================================
6492 // TASK MANAGEMENT
6493 // =========================================================
6494
6495 public List getTasks(int maxNum, int flags,
6496 IThumbnailReceiver receiver) {
6497 ArrayList list = new ArrayList();
6498
6499 PendingThumbnailsRecord pending = null;
6500 IApplicationThread topThumbnail = null;
6501 HistoryRecord topRecord = null;
6502
6503 synchronized(this) {
6504 if (localLOGV) Log.v(
6505 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6506 + ", receiver=" + receiver);
6507
6508 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6509 != PackageManager.PERMISSION_GRANTED) {
6510 if (receiver != null) {
6511 // If the caller wants to wait for pending thumbnails,
6512 // it ain't gonna get them.
6513 try {
6514 receiver.finished();
6515 } catch (RemoteException ex) {
6516 }
6517 }
6518 String msg = "Permission Denial: getTasks() from pid="
6519 + Binder.getCallingPid()
6520 + ", uid=" + Binder.getCallingUid()
6521 + " requires " + android.Manifest.permission.GET_TASKS;
6522 Log.w(TAG, msg);
6523 throw new SecurityException(msg);
6524 }
6525
6526 int pos = mHistory.size()-1;
6527 HistoryRecord next =
6528 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6529 HistoryRecord top = null;
6530 CharSequence topDescription = null;
6531 TaskRecord curTask = null;
6532 int numActivities = 0;
6533 int numRunning = 0;
6534 while (pos >= 0 && maxNum > 0) {
6535 final HistoryRecord r = next;
6536 pos--;
6537 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6538
6539 // Initialize state for next task if needed.
6540 if (top == null ||
6541 (top.state == ActivityState.INITIALIZING
6542 && top.task == r.task)) {
6543 top = r;
6544 topDescription = r.description;
6545 curTask = r.task;
6546 numActivities = numRunning = 0;
6547 }
6548
6549 // Add 'r' into the current task.
6550 numActivities++;
6551 if (r.app != null && r.app.thread != null) {
6552 numRunning++;
6553 }
6554 if (topDescription == null) {
6555 topDescription = r.description;
6556 }
6557
6558 if (localLOGV) Log.v(
6559 TAG, r.intent.getComponent().flattenToShortString()
6560 + ": task=" + r.task);
6561
6562 // If the next one is a different task, generate a new
6563 // TaskInfo entry for what we have.
6564 if (next == null || next.task != curTask) {
6565 ActivityManager.RunningTaskInfo ci
6566 = new ActivityManager.RunningTaskInfo();
6567 ci.id = curTask.taskId;
6568 ci.baseActivity = r.intent.getComponent();
6569 ci.topActivity = top.intent.getComponent();
6570 ci.thumbnail = top.thumbnail;
6571 ci.description = topDescription;
6572 ci.numActivities = numActivities;
6573 ci.numRunning = numRunning;
6574 //System.out.println(
6575 // "#" + maxNum + ": " + " descr=" + ci.description);
6576 if (ci.thumbnail == null && receiver != null) {
6577 if (localLOGV) Log.v(
6578 TAG, "State=" + top.state + "Idle=" + top.idle
6579 + " app=" + top.app
6580 + " thr=" + (top.app != null ? top.app.thread : null));
6581 if (top.state == ActivityState.RESUMED
6582 || top.state == ActivityState.PAUSING) {
6583 if (top.idle && top.app != null
6584 && top.app.thread != null) {
6585 topRecord = top;
6586 topThumbnail = top.app.thread;
6587 } else {
6588 top.thumbnailNeeded = true;
6589 }
6590 }
6591 if (pending == null) {
6592 pending = new PendingThumbnailsRecord(receiver);
6593 }
6594 pending.pendingRecords.add(top);
6595 }
6596 list.add(ci);
6597 maxNum--;
6598 top = null;
6599 }
6600 }
6601
6602 if (pending != null) {
6603 mPendingThumbnails.add(pending);
6604 }
6605 }
6606
6607 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6608
6609 if (topThumbnail != null) {
6610 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6611 try {
6612 topThumbnail.requestThumbnail(topRecord);
6613 } catch (Exception e) {
6614 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6615 sendPendingThumbnail(null, topRecord, null, null, true);
6616 }
6617 }
6618
6619 if (pending == null && receiver != null) {
6620 // In this case all thumbnails were available and the client
6621 // is being asked to be told when the remaining ones come in...
6622 // which is unusually, since the top-most currently running
6623 // activity should never have a canned thumbnail! Oh well.
6624 try {
6625 receiver.finished();
6626 } catch (RemoteException ex) {
6627 }
6628 }
6629
6630 return list;
6631 }
6632
6633 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6634 int flags) {
6635 synchronized (this) {
6636 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6637 "getRecentTasks()");
6638
6639 final int N = mRecentTasks.size();
6640 ArrayList<ActivityManager.RecentTaskInfo> res
6641 = new ArrayList<ActivityManager.RecentTaskInfo>(
6642 maxNum < N ? maxNum : N);
6643 for (int i=0; i<N && maxNum > 0; i++) {
6644 TaskRecord tr = mRecentTasks.get(i);
6645 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6646 || (tr.intent == null)
6647 || ((tr.intent.getFlags()
6648 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6649 ActivityManager.RecentTaskInfo rti
6650 = new ActivityManager.RecentTaskInfo();
6651 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6652 rti.baseIntent = new Intent(
6653 tr.intent != null ? tr.intent : tr.affinityIntent);
6654 rti.origActivity = tr.origActivity;
6655 res.add(rti);
6656 maxNum--;
6657 }
6658 }
6659 return res;
6660 }
6661 }
6662
6663 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6664 int j;
6665 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6666 TaskRecord jt = startTask;
6667
6668 // First look backwards
6669 for (j=startIndex-1; j>=0; j--) {
6670 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6671 if (r.task != jt) {
6672 jt = r.task;
6673 if (affinity.equals(jt.affinity)) {
6674 return j;
6675 }
6676 }
6677 }
6678
6679 // Now look forwards
6680 final int N = mHistory.size();
6681 jt = startTask;
6682 for (j=startIndex+1; j<N; j++) {
6683 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6684 if (r.task != jt) {
6685 if (affinity.equals(jt.affinity)) {
6686 return j;
6687 }
6688 jt = r.task;
6689 }
6690 }
6691
6692 // Might it be at the top?
6693 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6694 return N-1;
6695 }
6696
6697 return -1;
6698 }
6699
6700 /**
6701 * Perform a reset of the given task, if needed as part of launching it.
6702 * Returns the new HistoryRecord at the top of the task.
6703 */
6704 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6705 HistoryRecord newActivity) {
6706 boolean forceReset = (newActivity.info.flags
6707 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6708 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6709 if ((newActivity.info.flags
6710 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6711 forceReset = true;
6712 }
6713 }
6714
6715 final TaskRecord task = taskTop.task;
6716
6717 // We are going to move through the history list so that we can look
6718 // at each activity 'target' with 'below' either the interesting
6719 // activity immediately below it in the stack or null.
6720 HistoryRecord target = null;
6721 int targetI = 0;
6722 int taskTopI = -1;
6723 int replyChainEnd = -1;
6724 int lastReparentPos = -1;
6725 for (int i=mHistory.size()-1; i>=-1; i--) {
6726 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6727
6728 if (below != null && below.finishing) {
6729 continue;
6730 }
6731 if (target == null) {
6732 target = below;
6733 targetI = i;
6734 // If we were in the middle of a reply chain before this
6735 // task, it doesn't appear like the root of the chain wants
6736 // anything interesting, so drop it.
6737 replyChainEnd = -1;
6738 continue;
6739 }
6740
6741 final int flags = target.info.flags;
6742
6743 final boolean finishOnTaskLaunch =
6744 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6745 final boolean allowTaskReparenting =
6746 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6747
6748 if (target.task == task) {
6749 // We are inside of the task being reset... we'll either
6750 // finish this activity, push it out for another task,
6751 // or leave it as-is. We only do this
6752 // for activities that are not the root of the task (since
6753 // if we finish the root, we may no longer have the task!).
6754 if (taskTopI < 0) {
6755 taskTopI = targetI;
6756 }
6757 if (below != null && below.task == task) {
6758 final boolean clearWhenTaskReset =
6759 (target.intent.getFlags()
6760 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006761 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006762 // If this activity is sending a reply to a previous
6763 // activity, we can't do anything with it now until
6764 // we reach the start of the reply chain.
6765 // XXX note that we are assuming the result is always
6766 // to the previous activity, which is almost always
6767 // the case but we really shouldn't count on.
6768 if (replyChainEnd < 0) {
6769 replyChainEnd = targetI;
6770 }
Ed Heyl73798232009-03-24 21:32:21 -07006771 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006772 && target.taskAffinity != null
6773 && !target.taskAffinity.equals(task.affinity)) {
6774 // If this activity has an affinity for another
6775 // task, then we need to move it out of here. We will
6776 // move it as far out of the way as possible, to the
6777 // bottom of the activity stack. This also keeps it
6778 // correctly ordered with any activities we previously
6779 // moved.
6780 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6781 if (target.taskAffinity != null
6782 && target.taskAffinity.equals(p.task.affinity)) {
6783 // If the activity currently at the bottom has the
6784 // same task affinity as the one we are moving,
6785 // then merge it into the same task.
6786 target.task = p.task;
6787 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6788 + " out to bottom task " + p.task);
6789 } else {
6790 mCurTask++;
6791 if (mCurTask <= 0) {
6792 mCurTask = 1;
6793 }
6794 target.task = new TaskRecord(mCurTask, target.info, null,
6795 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6796 target.task.affinityIntent = target.intent;
6797 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6798 + " out to new task " + target.task);
6799 }
6800 mWindowManager.setAppGroupId(target, task.taskId);
6801 if (replyChainEnd < 0) {
6802 replyChainEnd = targetI;
6803 }
6804 int dstPos = 0;
6805 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6806 p = (HistoryRecord)mHistory.get(srcPos);
6807 if (p.finishing) {
6808 continue;
6809 }
6810 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6811 + " out to target's task " + target.task);
6812 task.numActivities--;
6813 p.task = target.task;
6814 target.task.numActivities++;
6815 mHistory.remove(srcPos);
6816 mHistory.add(dstPos, p);
6817 mWindowManager.moveAppToken(dstPos, p);
6818 mWindowManager.setAppGroupId(p, p.task.taskId);
6819 dstPos++;
6820 if (VALIDATE_TOKENS) {
6821 mWindowManager.validateAppTokens(mHistory);
6822 }
6823 i++;
6824 }
6825 if (taskTop == p) {
6826 taskTop = below;
6827 }
6828 if (taskTopI == replyChainEnd) {
6829 taskTopI = -1;
6830 }
6831 replyChainEnd = -1;
6832 addRecentTask(target.task);
6833 } else if (forceReset || finishOnTaskLaunch
6834 || clearWhenTaskReset) {
6835 // If the activity should just be removed -- either
6836 // because it asks for it, or the task should be
6837 // cleared -- then finish it and anything that is
6838 // part of its reply chain.
6839 if (clearWhenTaskReset) {
6840 // In this case, we want to finish this activity
6841 // and everything above it, so be sneaky and pretend
6842 // like these are all in the reply chain.
6843 replyChainEnd = targetI+1;
6844 while (replyChainEnd < mHistory.size() &&
6845 ((HistoryRecord)mHistory.get(
6846 replyChainEnd)).task == task) {
6847 replyChainEnd++;
6848 }
6849 replyChainEnd--;
6850 } else if (replyChainEnd < 0) {
6851 replyChainEnd = targetI;
6852 }
6853 HistoryRecord p = null;
6854 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6855 p = (HistoryRecord)mHistory.get(srcPos);
6856 if (p.finishing) {
6857 continue;
6858 }
6859 if (finishActivityLocked(p, srcPos,
6860 Activity.RESULT_CANCELED, null, "reset")) {
6861 replyChainEnd--;
6862 srcPos--;
6863 }
6864 }
6865 if (taskTop == p) {
6866 taskTop = below;
6867 }
6868 if (taskTopI == replyChainEnd) {
6869 taskTopI = -1;
6870 }
6871 replyChainEnd = -1;
6872 } else {
6873 // If we were in the middle of a chain, well the
6874 // activity that started it all doesn't want anything
6875 // special, so leave it all as-is.
6876 replyChainEnd = -1;
6877 }
6878 } else {
6879 // Reached the bottom of the task -- any reply chain
6880 // should be left as-is.
6881 replyChainEnd = -1;
6882 }
6883
6884 } else if (target.resultTo != null) {
6885 // If this activity is sending a reply to a previous
6886 // activity, we can't do anything with it now until
6887 // we reach the start of the reply chain.
6888 // XXX note that we are assuming the result is always
6889 // to the previous activity, which is almost always
6890 // the case but we really shouldn't count on.
6891 if (replyChainEnd < 0) {
6892 replyChainEnd = targetI;
6893 }
6894
6895 } else if (taskTopI >= 0 && allowTaskReparenting
6896 && task.affinity != null
6897 && task.affinity.equals(target.taskAffinity)) {
6898 // We are inside of another task... if this activity has
6899 // an affinity for our task, then either remove it if we are
6900 // clearing or move it over to our task. Note that
6901 // we currently punt on the case where we are resetting a
6902 // task that is not at the top but who has activities above
6903 // with an affinity to it... this is really not a normal
6904 // case, and we will need to later pull that task to the front
6905 // and usually at that point we will do the reset and pick
6906 // up those remaining activities. (This only happens if
6907 // someone starts an activity in a new task from an activity
6908 // in a task that is not currently on top.)
6909 if (forceReset || finishOnTaskLaunch) {
6910 if (replyChainEnd < 0) {
6911 replyChainEnd = targetI;
6912 }
6913 HistoryRecord p = null;
6914 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6915 p = (HistoryRecord)mHistory.get(srcPos);
6916 if (p.finishing) {
6917 continue;
6918 }
6919 if (finishActivityLocked(p, srcPos,
6920 Activity.RESULT_CANCELED, null, "reset")) {
6921 taskTopI--;
6922 lastReparentPos--;
6923 replyChainEnd--;
6924 srcPos--;
6925 }
6926 }
6927 replyChainEnd = -1;
6928 } else {
6929 if (replyChainEnd < 0) {
6930 replyChainEnd = targetI;
6931 }
6932 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6933 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6934 if (p.finishing) {
6935 continue;
6936 }
6937 if (lastReparentPos < 0) {
6938 lastReparentPos = taskTopI;
6939 taskTop = p;
6940 } else {
6941 lastReparentPos--;
6942 }
6943 mHistory.remove(srcPos);
6944 p.task.numActivities--;
6945 p.task = task;
6946 mHistory.add(lastReparentPos, p);
6947 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6948 + " in to resetting task " + task);
6949 task.numActivities++;
6950 mWindowManager.moveAppToken(lastReparentPos, p);
6951 mWindowManager.setAppGroupId(p, p.task.taskId);
6952 if (VALIDATE_TOKENS) {
6953 mWindowManager.validateAppTokens(mHistory);
6954 }
6955 }
6956 replyChainEnd = -1;
6957
6958 // Now we've moved it in to place... but what if this is
6959 // a singleTop activity and we have put it on top of another
6960 // instance of the same activity? Then we drop the instance
6961 // below so it remains singleTop.
6962 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6963 for (int j=lastReparentPos-1; j>=0; j--) {
6964 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6965 if (p.finishing) {
6966 continue;
6967 }
6968 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6969 if (finishActivityLocked(p, j,
6970 Activity.RESULT_CANCELED, null, "replace")) {
6971 taskTopI--;
6972 lastReparentPos--;
6973 }
6974 }
6975 }
6976 }
6977 }
6978 }
6979
6980 target = below;
6981 targetI = i;
6982 }
6983
6984 return taskTop;
6985 }
6986
6987 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006988 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006989 */
6990 public void moveTaskToFront(int task) {
6991 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6992 "moveTaskToFront()");
6993
6994 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006995 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6996 Binder.getCallingUid(), "Task to front")) {
6997 return;
6998 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006999 final long origId = Binder.clearCallingIdentity();
7000 try {
7001 int N = mRecentTasks.size();
7002 for (int i=0; i<N; i++) {
7003 TaskRecord tr = mRecentTasks.get(i);
7004 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007005 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007006 return;
7007 }
7008 }
7009 for (int i=mHistory.size()-1; i>=0; i--) {
7010 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
7011 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007012 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007013 return;
7014 }
7015 }
7016 } finally {
7017 Binder.restoreCallingIdentity(origId);
7018 }
7019 }
7020 }
7021
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007022 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007023 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7024
7025 final int task = tr.taskId;
7026 int top = mHistory.size()-1;
7027
7028 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7029 // nothing to do!
7030 return;
7031 }
7032
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007033 ArrayList moved = new ArrayList();
7034
7035 // Applying the affinities may have removed entries from the history,
7036 // so get the size again.
7037 top = mHistory.size()-1;
7038 int pos = top;
7039
7040 // Shift all activities with this task up to the top
7041 // of the stack, keeping them in the same internal order.
7042 while (pos >= 0) {
7043 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7044 if (localLOGV) Log.v(
7045 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7046 boolean first = true;
7047 if (r.task.taskId == task) {
7048 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7049 mHistory.remove(pos);
7050 mHistory.add(top, r);
7051 moved.add(0, r);
7052 top--;
7053 if (first) {
7054 addRecentTask(r.task);
7055 first = false;
7056 }
7057 }
7058 pos--;
7059 }
7060
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007061 if (DEBUG_TRANSITION) Log.v(TAG,
7062 "Prepare to front transition: task=" + tr);
7063 if (reason != null &&
7064 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7065 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7066 HistoryRecord r = topRunningActivityLocked(null);
7067 if (r != null) {
7068 mNoAnimActivities.add(r);
7069 }
7070 } else {
7071 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7072 }
7073
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007074 mWindowManager.moveAppTokensToTop(moved);
7075 if (VALIDATE_TOKENS) {
7076 mWindowManager.validateAppTokens(mHistory);
7077 }
7078
7079 finishTaskMove(task);
7080 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
7081 }
7082
7083 private final void finishTaskMove(int task) {
7084 resumeTopActivityLocked(null);
7085 }
7086
7087 public void moveTaskToBack(int task) {
7088 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7089 "moveTaskToBack()");
7090
7091 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007092 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7093 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7094 Binder.getCallingUid(), "Task to back")) {
7095 return;
7096 }
7097 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007098 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007099 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007100 Binder.restoreCallingIdentity(origId);
7101 }
7102 }
7103
7104 /**
7105 * Moves an activity, and all of the other activities within the same task, to the bottom
7106 * of the history stack. The activity's order within the task is unchanged.
7107 *
7108 * @param token A reference to the activity we wish to move
7109 * @param nonRoot If false then this only works if the activity is the root
7110 * of a task; if true it will work for any activity in a task.
7111 * @return Returns true if the move completed, false if not.
7112 */
7113 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7114 synchronized(this) {
7115 final long origId = Binder.clearCallingIdentity();
7116 int taskId = getTaskForActivityLocked(token, !nonRoot);
7117 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007118 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007119 }
7120 Binder.restoreCallingIdentity(origId);
7121 }
7122 return false;
7123 }
7124
7125 /**
7126 * Worker method for rearranging history stack. Implements the function of moving all
7127 * activities for a specific task (gathering them if disjoint) into a single group at the
7128 * bottom of the stack.
7129 *
7130 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7131 * to premeptively cancel the move.
7132 *
7133 * @param task The taskId to collect and move to the bottom.
7134 * @return Returns true if the move completed, false if not.
7135 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007136 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007137 Log.i(TAG, "moveTaskToBack: " + task);
7138
7139 // If we have a watcher, preflight the move before committing to it. First check
7140 // for *other* available tasks, but if none are available, then try again allowing the
7141 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007142 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007143 HistoryRecord next = topRunningActivityLocked(null, task);
7144 if (next == null) {
7145 next = topRunningActivityLocked(null, 0);
7146 }
7147 if (next != null) {
7148 // ask watcher if this is allowed
7149 boolean moveOK = true;
7150 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007151 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007152 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007153 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007154 }
7155 if (!moveOK) {
7156 return false;
7157 }
7158 }
7159 }
7160
7161 ArrayList moved = new ArrayList();
7162
7163 if (DEBUG_TRANSITION) Log.v(TAG,
7164 "Prepare to back transition: task=" + task);
7165 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
7166
7167 final int N = mHistory.size();
7168 int bottom = 0;
7169 int pos = 0;
7170
7171 // Shift all activities with this task down to the bottom
7172 // of the stack, keeping them in the same internal order.
7173 while (pos < N) {
7174 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7175 if (localLOGV) Log.v(
7176 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7177 if (r.task.taskId == task) {
7178 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7179 mHistory.remove(pos);
7180 mHistory.add(bottom, r);
7181 moved.add(r);
7182 bottom++;
7183 }
7184 pos++;
7185 }
7186
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007187 if (reason != null &&
7188 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7189 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7190 HistoryRecord r = topRunningActivityLocked(null);
7191 if (r != null) {
7192 mNoAnimActivities.add(r);
7193 }
7194 } else {
7195 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7196 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007197 mWindowManager.moveAppTokensToBottom(moved);
7198 if (VALIDATE_TOKENS) {
7199 mWindowManager.validateAppTokens(mHistory);
7200 }
7201
7202 finishTaskMove(task);
7203 return true;
7204 }
7205
7206 public void moveTaskBackwards(int task) {
7207 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7208 "moveTaskBackwards()");
7209
7210 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007211 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7212 Binder.getCallingUid(), "Task backwards")) {
7213 return;
7214 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007215 final long origId = Binder.clearCallingIdentity();
7216 moveTaskBackwardsLocked(task);
7217 Binder.restoreCallingIdentity(origId);
7218 }
7219 }
7220
7221 private final void moveTaskBackwardsLocked(int task) {
7222 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7223 }
7224
7225 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7226 synchronized(this) {
7227 return getTaskForActivityLocked(token, onlyRoot);
7228 }
7229 }
7230
7231 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7232 final int N = mHistory.size();
7233 TaskRecord lastTask = null;
7234 for (int i=0; i<N; i++) {
7235 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7236 if (r == token) {
7237 if (!onlyRoot || lastTask != r.task) {
7238 return r.task.taskId;
7239 }
7240 return -1;
7241 }
7242 lastTask = r.task;
7243 }
7244
7245 return -1;
7246 }
7247
7248 /**
7249 * Returns the top activity in any existing task matching the given
7250 * Intent. Returns null if no such task is found.
7251 */
7252 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7253 ComponentName cls = intent.getComponent();
7254 if (info.targetActivity != null) {
7255 cls = new ComponentName(info.packageName, info.targetActivity);
7256 }
7257
7258 TaskRecord cp = null;
7259
7260 final int N = mHistory.size();
7261 for (int i=(N-1); i>=0; i--) {
7262 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7263 if (!r.finishing && r.task != cp
7264 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7265 cp = r.task;
7266 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7267 // + "/aff=" + r.task.affinity + " to new cls="
7268 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7269 if (r.task.affinity != null) {
7270 if (r.task.affinity.equals(info.taskAffinity)) {
7271 //Log.i(TAG, "Found matching affinity!");
7272 return r;
7273 }
7274 } else if (r.task.intent != null
7275 && r.task.intent.getComponent().equals(cls)) {
7276 //Log.i(TAG, "Found matching class!");
7277 //dump();
7278 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7279 return r;
7280 } else if (r.task.affinityIntent != null
7281 && r.task.affinityIntent.getComponent().equals(cls)) {
7282 //Log.i(TAG, "Found matching class!");
7283 //dump();
7284 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7285 return r;
7286 }
7287 }
7288 }
7289
7290 return null;
7291 }
7292
7293 /**
7294 * Returns the first activity (starting from the top of the stack) that
7295 * is the same as the given activity. Returns null if no such activity
7296 * is found.
7297 */
7298 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7299 ComponentName cls = intent.getComponent();
7300 if (info.targetActivity != null) {
7301 cls = new ComponentName(info.packageName, info.targetActivity);
7302 }
7303
7304 final int N = mHistory.size();
7305 for (int i=(N-1); i>=0; i--) {
7306 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7307 if (!r.finishing) {
7308 if (r.intent.getComponent().equals(cls)) {
7309 //Log.i(TAG, "Found matching class!");
7310 //dump();
7311 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7312 return r;
7313 }
7314 }
7315 }
7316
7317 return null;
7318 }
7319
7320 public void finishOtherInstances(IBinder token, ComponentName className) {
7321 synchronized(this) {
7322 final long origId = Binder.clearCallingIdentity();
7323
7324 int N = mHistory.size();
7325 TaskRecord lastTask = null;
7326 for (int i=0; i<N; i++) {
7327 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7328 if (r.realActivity.equals(className)
7329 && r != token && lastTask != r.task) {
7330 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7331 null, "others")) {
7332 i--;
7333 N--;
7334 }
7335 }
7336 lastTask = r.task;
7337 }
7338
7339 Binder.restoreCallingIdentity(origId);
7340 }
7341 }
7342
7343 // =========================================================
7344 // THUMBNAILS
7345 // =========================================================
7346
7347 public void reportThumbnail(IBinder token,
7348 Bitmap thumbnail, CharSequence description) {
7349 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7350 final long origId = Binder.clearCallingIdentity();
7351 sendPendingThumbnail(null, token, thumbnail, description, true);
7352 Binder.restoreCallingIdentity(origId);
7353 }
7354
7355 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7356 Bitmap thumbnail, CharSequence description, boolean always) {
7357 TaskRecord task = null;
7358 ArrayList receivers = null;
7359
7360 //System.out.println("Send pending thumbnail: " + r);
7361
7362 synchronized(this) {
7363 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007364 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007365 if (index < 0) {
7366 return;
7367 }
7368 r = (HistoryRecord)mHistory.get(index);
7369 }
7370 if (thumbnail == null) {
7371 thumbnail = r.thumbnail;
7372 description = r.description;
7373 }
7374 if (thumbnail == null && !always) {
7375 // If there is no thumbnail, and this entry is not actually
7376 // going away, then abort for now and pick up the next
7377 // thumbnail we get.
7378 return;
7379 }
7380 task = r.task;
7381
7382 int N = mPendingThumbnails.size();
7383 int i=0;
7384 while (i<N) {
7385 PendingThumbnailsRecord pr =
7386 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7387 //System.out.println("Looking in " + pr.pendingRecords);
7388 if (pr.pendingRecords.remove(r)) {
7389 if (receivers == null) {
7390 receivers = new ArrayList();
7391 }
7392 receivers.add(pr);
7393 if (pr.pendingRecords.size() == 0) {
7394 pr.finished = true;
7395 mPendingThumbnails.remove(i);
7396 N--;
7397 continue;
7398 }
7399 }
7400 i++;
7401 }
7402 }
7403
7404 if (receivers != null) {
7405 final int N = receivers.size();
7406 for (int i=0; i<N; i++) {
7407 try {
7408 PendingThumbnailsRecord pr =
7409 (PendingThumbnailsRecord)receivers.get(i);
7410 pr.receiver.newThumbnail(
7411 task != null ? task.taskId : -1, thumbnail, description);
7412 if (pr.finished) {
7413 pr.receiver.finished();
7414 }
7415 } catch (Exception e) {
7416 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7417 }
7418 }
7419 }
7420 }
7421
7422 // =========================================================
7423 // CONTENT PROVIDERS
7424 // =========================================================
7425
7426 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7427 List providers = null;
7428 try {
7429 providers = ActivityThread.getPackageManager().
7430 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007431 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007432 } catch (RemoteException ex) {
7433 }
7434 if (providers != null) {
7435 final int N = providers.size();
7436 for (int i=0; i<N; i++) {
7437 ProviderInfo cpi =
7438 (ProviderInfo)providers.get(i);
7439 ContentProviderRecord cpr =
7440 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7441 if (cpr == null) {
7442 cpr = new ContentProviderRecord(cpi, app.info);
7443 mProvidersByClass.put(cpi.name, cpr);
7444 }
7445 app.pubProviders.put(cpi.name, cpr);
7446 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007447 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007448 }
7449 }
7450 return providers;
7451 }
7452
7453 private final String checkContentProviderPermissionLocked(
7454 ProviderInfo cpi, ProcessRecord r, int mode) {
7455 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7456 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7457 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7458 cpi.exported ? -1 : cpi.applicationInfo.uid)
7459 == PackageManager.PERMISSION_GRANTED
7460 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7461 return null;
7462 }
7463 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7464 cpi.exported ? -1 : cpi.applicationInfo.uid)
7465 == PackageManager.PERMISSION_GRANTED) {
7466 return null;
7467 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007468
7469 PathPermission[] pps = cpi.pathPermissions;
7470 if (pps != null) {
7471 int i = pps.length;
7472 while (i > 0) {
7473 i--;
7474 PathPermission pp = pps[i];
7475 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7476 cpi.exported ? -1 : cpi.applicationInfo.uid)
7477 == PackageManager.PERMISSION_GRANTED
7478 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7479 return null;
7480 }
7481 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7482 cpi.exported ? -1 : cpi.applicationInfo.uid)
7483 == PackageManager.PERMISSION_GRANTED) {
7484 return null;
7485 }
7486 }
7487 }
7488
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007489 String msg = "Permission Denial: opening provider " + cpi.name
7490 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7491 + ", uid=" + callingUid + ") requires "
7492 + cpi.readPermission + " or " + cpi.writePermission;
7493 Log.w(TAG, msg);
7494 return msg;
7495 }
7496
7497 private final ContentProviderHolder getContentProviderImpl(
7498 IApplicationThread caller, String name) {
7499 ContentProviderRecord cpr;
7500 ProviderInfo cpi = null;
7501
7502 synchronized(this) {
7503 ProcessRecord r = null;
7504 if (caller != null) {
7505 r = getRecordForAppLocked(caller);
7506 if (r == null) {
7507 throw new SecurityException(
7508 "Unable to find app for caller " + caller
7509 + " (pid=" + Binder.getCallingPid()
7510 + ") when getting content provider " + name);
7511 }
7512 }
7513
7514 // First check if this content provider has been published...
7515 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7516 if (cpr != null) {
7517 cpi = cpr.info;
7518 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7519 return new ContentProviderHolder(cpi,
7520 cpi.readPermission != null
7521 ? cpi.readPermission : cpi.writePermission);
7522 }
7523
7524 if (r != null && cpr.canRunHere(r)) {
7525 // This provider has been published or is in the process
7526 // of being published... but it is also allowed to run
7527 // in the caller's process, so don't make a connection
7528 // and just let the caller instantiate its own instance.
7529 if (cpr.provider != null) {
7530 // don't give caller the provider object, it needs
7531 // to make its own.
7532 cpr = new ContentProviderRecord(cpr);
7533 }
7534 return cpr;
7535 }
7536
7537 final long origId = Binder.clearCallingIdentity();
7538
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007539 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007540 // return it right away.
7541 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007542 if (DEBUG_PROVIDER) Log.v(TAG,
7543 "Adding provider requested by "
7544 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007545 + cpr.info.processName);
7546 Integer cnt = r.conProviders.get(cpr);
7547 if (cnt == null) {
7548 r.conProviders.put(cpr, new Integer(1));
7549 } else {
7550 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7551 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007552 cpr.clients.add(r);
7553 } else {
7554 cpr.externals++;
7555 }
7556
7557 if (cpr.app != null) {
7558 updateOomAdjLocked(cpr.app);
7559 }
7560
7561 Binder.restoreCallingIdentity(origId);
7562
7563 } else {
7564 try {
7565 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007566 resolveContentProvider(name,
7567 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007568 } catch (RemoteException ex) {
7569 }
7570 if (cpi == null) {
7571 return null;
7572 }
7573
7574 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7575 return new ContentProviderHolder(cpi,
7576 cpi.readPermission != null
7577 ? cpi.readPermission : cpi.writePermission);
7578 }
7579
7580 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7581 final boolean firstClass = cpr == null;
7582 if (firstClass) {
7583 try {
7584 ApplicationInfo ai =
7585 ActivityThread.getPackageManager().
7586 getApplicationInfo(
7587 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007588 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007589 if (ai == null) {
7590 Log.w(TAG, "No package info for content provider "
7591 + cpi.name);
7592 return null;
7593 }
7594 cpr = new ContentProviderRecord(cpi, ai);
7595 } catch (RemoteException ex) {
7596 // pm is in same process, this will never happen.
7597 }
7598 }
7599
7600 if (r != null && cpr.canRunHere(r)) {
7601 // If this is a multiprocess provider, then just return its
7602 // info and allow the caller to instantiate it. Only do
7603 // this if the provider is the same user as the caller's
7604 // process, or can run as root (so can be in any process).
7605 return cpr;
7606 }
7607
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007608 if (DEBUG_PROVIDER) {
7609 RuntimeException e = new RuntimeException("here");
7610 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7611 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007612 }
7613
7614 // This is single process, and our app is now connecting to it.
7615 // See if we are already in the process of launching this
7616 // provider.
7617 final int N = mLaunchingProviders.size();
7618 int i;
7619 for (i=0; i<N; i++) {
7620 if (mLaunchingProviders.get(i) == cpr) {
7621 break;
7622 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007623 }
7624
7625 // If the provider is not already being launched, then get it
7626 // started.
7627 if (i >= N) {
7628 final long origId = Binder.clearCallingIdentity();
7629 ProcessRecord proc = startProcessLocked(cpi.processName,
7630 cpr.appInfo, false, 0, "content provider",
7631 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007632 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007633 if (proc == null) {
7634 Log.w(TAG, "Unable to launch app "
7635 + cpi.applicationInfo.packageName + "/"
7636 + cpi.applicationInfo.uid + " for provider "
7637 + name + ": process is bad");
7638 return null;
7639 }
7640 cpr.launchingApp = proc;
7641 mLaunchingProviders.add(cpr);
7642 Binder.restoreCallingIdentity(origId);
7643 }
7644
7645 // Make sure the provider is published (the same provider class
7646 // may be published under multiple names).
7647 if (firstClass) {
7648 mProvidersByClass.put(cpi.name, cpr);
7649 }
7650 mProvidersByName.put(name, cpr);
7651
7652 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007653 if (DEBUG_PROVIDER) Log.v(TAG,
7654 "Adding provider requested by "
7655 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007656 + cpr.info.processName);
7657 Integer cnt = r.conProviders.get(cpr);
7658 if (cnt == null) {
7659 r.conProviders.put(cpr, new Integer(1));
7660 } else {
7661 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7662 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007663 cpr.clients.add(r);
7664 } else {
7665 cpr.externals++;
7666 }
7667 }
7668 }
7669
7670 // Wait for the provider to be published...
7671 synchronized (cpr) {
7672 while (cpr.provider == null) {
7673 if (cpr.launchingApp == null) {
7674 Log.w(TAG, "Unable to launch app "
7675 + cpi.applicationInfo.packageName + "/"
7676 + cpi.applicationInfo.uid + " for provider "
7677 + name + ": launching app became null");
7678 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7679 cpi.applicationInfo.packageName,
7680 cpi.applicationInfo.uid, name);
7681 return null;
7682 }
7683 try {
7684 cpr.wait();
7685 } catch (InterruptedException ex) {
7686 }
7687 }
7688 }
7689 return cpr;
7690 }
7691
7692 public final ContentProviderHolder getContentProvider(
7693 IApplicationThread caller, String name) {
7694 if (caller == null) {
7695 String msg = "null IApplicationThread when getting content provider "
7696 + name;
7697 Log.w(TAG, msg);
7698 throw new SecurityException(msg);
7699 }
7700
7701 return getContentProviderImpl(caller, name);
7702 }
7703
7704 private ContentProviderHolder getContentProviderExternal(String name) {
7705 return getContentProviderImpl(null, name);
7706 }
7707
7708 /**
7709 * Drop a content provider from a ProcessRecord's bookkeeping
7710 * @param cpr
7711 */
7712 public void removeContentProvider(IApplicationThread caller, String name) {
7713 synchronized (this) {
7714 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7715 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007716 // remove from mProvidersByClass
7717 if (DEBUG_PROVIDER) Log.v(TAG, name +
7718 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007719 return;
7720 }
7721 final ProcessRecord r = getRecordForAppLocked(caller);
7722 if (r == null) {
7723 throw new SecurityException(
7724 "Unable to find app for caller " + caller +
7725 " when removing content provider " + name);
7726 }
7727 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007728 ContentProviderRecord localCpr = (ContentProviderRecord)
7729 mProvidersByClass.get(cpr.info.name);
7730 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7731 + r.info.processName + " from process "
7732 + localCpr.appInfo.processName);
7733 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007734 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007735 Log.w(TAG, "removeContentProvider called on local provider: "
7736 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007737 return;
7738 } else {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007739 Integer cnt = r.conProviders.get(localCpr);
7740 if (cnt == null || cnt.intValue() <= 1) {
7741 localCpr.clients.remove(r);
7742 r.conProviders.remove(localCpr);
7743 } else {
7744 r.conProviders.put(localCpr, new Integer(cnt.intValue()-1));
7745 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007746 }
7747 updateOomAdjLocked();
7748 }
7749 }
7750
7751 private void removeContentProviderExternal(String name) {
7752 synchronized (this) {
7753 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7754 if(cpr == null) {
7755 //remove from mProvidersByClass
7756 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7757 return;
7758 }
7759
7760 //update content provider record entry info
7761 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7762 localCpr.externals--;
7763 if (localCpr.externals < 0) {
7764 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7765 }
7766 updateOomAdjLocked();
7767 }
7768 }
7769
7770 public final void publishContentProviders(IApplicationThread caller,
7771 List<ContentProviderHolder> providers) {
7772 if (providers == null) {
7773 return;
7774 }
7775
7776 synchronized(this) {
7777 final ProcessRecord r = getRecordForAppLocked(caller);
7778 if (r == null) {
7779 throw new SecurityException(
7780 "Unable to find app for caller " + caller
7781 + " (pid=" + Binder.getCallingPid()
7782 + ") when publishing content providers");
7783 }
7784
7785 final long origId = Binder.clearCallingIdentity();
7786
7787 final int N = providers.size();
7788 for (int i=0; i<N; i++) {
7789 ContentProviderHolder src = providers.get(i);
7790 if (src == null || src.info == null || src.provider == null) {
7791 continue;
7792 }
7793 ContentProviderRecord dst =
7794 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7795 if (dst != null) {
7796 mProvidersByClass.put(dst.info.name, dst);
7797 String names[] = dst.info.authority.split(";");
7798 for (int j = 0; j < names.length; j++) {
7799 mProvidersByName.put(names[j], dst);
7800 }
7801
7802 int NL = mLaunchingProviders.size();
7803 int j;
7804 for (j=0; j<NL; j++) {
7805 if (mLaunchingProviders.get(j) == dst) {
7806 mLaunchingProviders.remove(j);
7807 j--;
7808 NL--;
7809 }
7810 }
7811 synchronized (dst) {
7812 dst.provider = src.provider;
7813 dst.app = r;
7814 dst.notifyAll();
7815 }
7816 updateOomAdjLocked(r);
7817 }
7818 }
7819
7820 Binder.restoreCallingIdentity(origId);
7821 }
7822 }
7823
7824 public static final void installSystemProviders() {
7825 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7826 List providers = mSelf.generateApplicationProvidersLocked(app);
7827 mSystemThread.installSystemProviders(providers);
7828 }
7829
7830 // =========================================================
7831 // GLOBAL MANAGEMENT
7832 // =========================================================
7833
7834 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7835 ApplicationInfo info, String customProcess) {
7836 String proc = customProcess != null ? customProcess : info.processName;
7837 BatteryStatsImpl.Uid.Proc ps = null;
7838 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7839 synchronized (stats) {
7840 ps = stats.getProcessStatsLocked(info.uid, proc);
7841 }
7842 return new ProcessRecord(ps, thread, info, proc);
7843 }
7844
7845 final ProcessRecord addAppLocked(ApplicationInfo info) {
7846 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7847
7848 if (app == null) {
7849 app = newProcessRecordLocked(null, info, null);
7850 mProcessNames.put(info.processName, info.uid, app);
7851 updateLRUListLocked(app, true);
7852 }
7853
7854 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7855 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7856 app.persistent = true;
7857 app.maxAdj = CORE_SERVER_ADJ;
7858 }
7859 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7860 mPersistentStartingProcesses.add(app);
7861 startProcessLocked(app, "added application", app.processName);
7862 }
7863
7864 return app;
7865 }
7866
7867 public void unhandledBack() {
7868 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7869 "unhandledBack()");
7870
7871 synchronized(this) {
7872 int count = mHistory.size();
7873 if (Config.LOGD) Log.d(
7874 TAG, "Performing unhandledBack(): stack size = " + count);
7875 if (count > 1) {
7876 final long origId = Binder.clearCallingIdentity();
7877 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7878 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7879 Binder.restoreCallingIdentity(origId);
7880 }
7881 }
7882 }
7883
7884 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7885 String name = uri.getAuthority();
7886 ContentProviderHolder cph = getContentProviderExternal(name);
7887 ParcelFileDescriptor pfd = null;
7888 if (cph != null) {
7889 // We record the binder invoker's uid in thread-local storage before
7890 // going to the content provider to open the file. Later, in the code
7891 // that handles all permissions checks, we look for this uid and use
7892 // that rather than the Activity Manager's own uid. The effect is that
7893 // we do the check against the caller's permissions even though it looks
7894 // to the content provider like the Activity Manager itself is making
7895 // the request.
7896 sCallerIdentity.set(new Identity(
7897 Binder.getCallingPid(), Binder.getCallingUid()));
7898 try {
7899 pfd = cph.provider.openFile(uri, "r");
7900 } catch (FileNotFoundException e) {
7901 // do nothing; pfd will be returned null
7902 } finally {
7903 // Ensure that whatever happens, we clean up the identity state
7904 sCallerIdentity.remove();
7905 }
7906
7907 // We've got the fd now, so we're done with the provider.
7908 removeContentProviderExternal(name);
7909 } else {
7910 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7911 }
7912 return pfd;
7913 }
7914
7915 public void goingToSleep() {
7916 synchronized(this) {
7917 mSleeping = true;
7918 mWindowManager.setEventDispatching(false);
7919
7920 if (mResumedActivity != null) {
7921 pauseIfSleepingLocked();
7922 } else {
7923 Log.w(TAG, "goingToSleep with no resumed activity!");
7924 }
7925 }
7926 }
7927
Dianne Hackborn55280a92009-05-07 15:53:46 -07007928 public boolean shutdown(int timeout) {
7929 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7930 != PackageManager.PERMISSION_GRANTED) {
7931 throw new SecurityException("Requires permission "
7932 + android.Manifest.permission.SHUTDOWN);
7933 }
7934
7935 boolean timedout = false;
7936
7937 synchronized(this) {
7938 mShuttingDown = true;
7939 mWindowManager.setEventDispatching(false);
7940
7941 if (mResumedActivity != null) {
7942 pauseIfSleepingLocked();
7943 final long endTime = System.currentTimeMillis() + timeout;
7944 while (mResumedActivity != null || mPausingActivity != null) {
7945 long delay = endTime - System.currentTimeMillis();
7946 if (delay <= 0) {
7947 Log.w(TAG, "Activity manager shutdown timed out");
7948 timedout = true;
7949 break;
7950 }
7951 try {
7952 this.wait();
7953 } catch (InterruptedException e) {
7954 }
7955 }
7956 }
7957 }
7958
7959 mUsageStatsService.shutdown();
7960 mBatteryStatsService.shutdown();
7961
7962 return timedout;
7963 }
7964
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007965 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007966 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007967 if (!mGoingToSleep.isHeld()) {
7968 mGoingToSleep.acquire();
7969 if (mLaunchingActivity.isHeld()) {
7970 mLaunchingActivity.release();
7971 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7972 }
7973 }
7974
7975 // If we are not currently pausing an activity, get the current
7976 // one to pause. If we are pausing one, we will just let that stuff
7977 // run and release the wake lock when all done.
7978 if (mPausingActivity == null) {
7979 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7980 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7981 startPausingLocked(false, true);
7982 }
7983 }
7984 }
7985
7986 public void wakingUp() {
7987 synchronized(this) {
7988 if (mGoingToSleep.isHeld()) {
7989 mGoingToSleep.release();
7990 }
7991 mWindowManager.setEventDispatching(true);
7992 mSleeping = false;
7993 resumeTopActivityLocked(null);
7994 }
7995 }
7996
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007997 public void stopAppSwitches() {
7998 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7999 != PackageManager.PERMISSION_GRANTED) {
8000 throw new SecurityException("Requires permission "
8001 + android.Manifest.permission.STOP_APP_SWITCHES);
8002 }
8003
8004 synchronized(this) {
8005 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
8006 + APP_SWITCH_DELAY_TIME;
8007 mDidAppSwitch = false;
8008 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8009 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8010 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
8011 }
8012 }
8013
8014 public void resumeAppSwitches() {
8015 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8016 != PackageManager.PERMISSION_GRANTED) {
8017 throw new SecurityException("Requires permission "
8018 + android.Manifest.permission.STOP_APP_SWITCHES);
8019 }
8020
8021 synchronized(this) {
8022 // Note that we don't execute any pending app switches... we will
8023 // let those wait until either the timeout, or the next start
8024 // activity request.
8025 mAppSwitchesAllowedTime = 0;
8026 }
8027 }
8028
8029 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8030 String name) {
8031 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8032 return true;
8033 }
8034
8035 final int perm = checkComponentPermission(
8036 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8037 callingUid, -1);
8038 if (perm == PackageManager.PERMISSION_GRANTED) {
8039 return true;
8040 }
8041
8042 Log.w(TAG, name + " request from " + callingUid + " stopped");
8043 return false;
8044 }
8045
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008046 public void setDebugApp(String packageName, boolean waitForDebugger,
8047 boolean persistent) {
8048 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8049 "setDebugApp()");
8050
8051 // Note that this is not really thread safe if there are multiple
8052 // callers into it at the same time, but that's not a situation we
8053 // care about.
8054 if (persistent) {
8055 final ContentResolver resolver = mContext.getContentResolver();
8056 Settings.System.putString(
8057 resolver, Settings.System.DEBUG_APP,
8058 packageName);
8059 Settings.System.putInt(
8060 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8061 waitForDebugger ? 1 : 0);
8062 }
8063
8064 synchronized (this) {
8065 if (!persistent) {
8066 mOrigDebugApp = mDebugApp;
8067 mOrigWaitForDebugger = mWaitForDebugger;
8068 }
8069 mDebugApp = packageName;
8070 mWaitForDebugger = waitForDebugger;
8071 mDebugTransient = !persistent;
8072 if (packageName != null) {
8073 final long origId = Binder.clearCallingIdentity();
8074 uninstallPackageLocked(packageName, -1, false);
8075 Binder.restoreCallingIdentity(origId);
8076 }
8077 }
8078 }
8079
8080 public void setAlwaysFinish(boolean enabled) {
8081 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8082 "setAlwaysFinish()");
8083
8084 Settings.System.putInt(
8085 mContext.getContentResolver(),
8086 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8087
8088 synchronized (this) {
8089 mAlwaysFinishActivities = enabled;
8090 }
8091 }
8092
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008093 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008094 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008095 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008096 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008097 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008098 }
8099 }
8100
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008101 public void registerActivityWatcher(IActivityWatcher watcher) {
8102 mWatchers.register(watcher);
8103 }
8104
8105 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8106 mWatchers.unregister(watcher);
8107 }
8108
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008109 public final void enterSafeMode() {
8110 synchronized(this) {
8111 // It only makes sense to do this before the system is ready
8112 // and started launching other packages.
8113 if (!mSystemReady) {
8114 try {
8115 ActivityThread.getPackageManager().enterSafeMode();
8116 } catch (RemoteException e) {
8117 }
8118
8119 View v = LayoutInflater.from(mContext).inflate(
8120 com.android.internal.R.layout.safe_mode, null);
8121 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8122 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8123 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8124 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8125 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8126 lp.format = v.getBackground().getOpacity();
8127 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8128 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8129 ((WindowManager)mContext.getSystemService(
8130 Context.WINDOW_SERVICE)).addView(v, lp);
8131 }
8132 }
8133 }
8134
8135 public void noteWakeupAlarm(IIntentSender sender) {
8136 if (!(sender instanceof PendingIntentRecord)) {
8137 return;
8138 }
8139 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8140 synchronized (stats) {
8141 if (mBatteryStatsService.isOnBattery()) {
8142 mBatteryStatsService.enforceCallingPermission();
8143 PendingIntentRecord rec = (PendingIntentRecord)sender;
8144 int MY_UID = Binder.getCallingUid();
8145 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8146 BatteryStatsImpl.Uid.Pkg pkg =
8147 stats.getPackageStatsLocked(uid, rec.key.packageName);
8148 pkg.incWakeupsLocked();
8149 }
8150 }
8151 }
8152
8153 public boolean killPidsForMemory(int[] pids) {
8154 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8155 throw new SecurityException("killPidsForMemory only available to the system");
8156 }
8157
8158 // XXX Note: don't acquire main activity lock here, because the window
8159 // manager calls in with its locks held.
8160
8161 boolean killed = false;
8162 synchronized (mPidsSelfLocked) {
8163 int[] types = new int[pids.length];
8164 int worstType = 0;
8165 for (int i=0; i<pids.length; i++) {
8166 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8167 if (proc != null) {
8168 int type = proc.setAdj;
8169 types[i] = type;
8170 if (type > worstType) {
8171 worstType = type;
8172 }
8173 }
8174 }
8175
8176 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8177 // then constrain it so we will kill all hidden procs.
8178 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8179 worstType = HIDDEN_APP_MIN_ADJ;
8180 }
8181 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8182 for (int i=0; i<pids.length; i++) {
8183 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8184 if (proc == null) {
8185 continue;
8186 }
8187 int adj = proc.setAdj;
8188 if (adj >= worstType) {
8189 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8190 + adj + ")");
8191 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
8192 proc.processName, adj);
8193 killed = true;
8194 Process.killProcess(pids[i]);
8195 }
8196 }
8197 }
8198 return killed;
8199 }
8200
8201 public void reportPss(IApplicationThread caller, int pss) {
8202 Watchdog.PssRequestor req;
8203 String name;
8204 ProcessRecord callerApp;
8205 synchronized (this) {
8206 if (caller == null) {
8207 return;
8208 }
8209 callerApp = getRecordForAppLocked(caller);
8210 if (callerApp == null) {
8211 return;
8212 }
8213 callerApp.lastPss = pss;
8214 req = callerApp;
8215 name = callerApp.processName;
8216 }
8217 Watchdog.getInstance().reportPss(req, name, pss);
8218 if (!callerApp.persistent) {
8219 removeRequestedPss(callerApp);
8220 }
8221 }
8222
8223 public void requestPss(Runnable completeCallback) {
8224 ArrayList<ProcessRecord> procs;
8225 synchronized (this) {
8226 mRequestPssCallback = completeCallback;
8227 mRequestPssList.clear();
8228 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8229 ProcessRecord proc = mLRUProcesses.get(i);
8230 if (!proc.persistent) {
8231 mRequestPssList.add(proc);
8232 }
8233 }
8234 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8235 }
8236
8237 int oldPri = Process.getThreadPriority(Process.myTid());
8238 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8239 for (int i=procs.size()-1; i>=0; i--) {
8240 ProcessRecord proc = procs.get(i);
8241 proc.lastPss = 0;
8242 proc.requestPss();
8243 }
8244 Process.setThreadPriority(oldPri);
8245 }
8246
8247 void removeRequestedPss(ProcessRecord proc) {
8248 Runnable callback = null;
8249 synchronized (this) {
8250 if (mRequestPssList.remove(proc)) {
8251 if (mRequestPssList.size() == 0) {
8252 callback = mRequestPssCallback;
8253 mRequestPssCallback = null;
8254 }
8255 }
8256 }
8257
8258 if (callback != null) {
8259 callback.run();
8260 }
8261 }
8262
8263 public void collectPss(Watchdog.PssStats stats) {
8264 stats.mEmptyPss = 0;
8265 stats.mEmptyCount = 0;
8266 stats.mBackgroundPss = 0;
8267 stats.mBackgroundCount = 0;
8268 stats.mServicePss = 0;
8269 stats.mServiceCount = 0;
8270 stats.mVisiblePss = 0;
8271 stats.mVisibleCount = 0;
8272 stats.mForegroundPss = 0;
8273 stats.mForegroundCount = 0;
8274 stats.mNoPssCount = 0;
8275 synchronized (this) {
8276 int i;
8277 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8278 ? mProcDeaths.length : stats.mProcDeaths.length;
8279 int aggr = 0;
8280 for (i=0; i<NPD; i++) {
8281 aggr += mProcDeaths[i];
8282 stats.mProcDeaths[i] = aggr;
8283 }
8284 while (i<stats.mProcDeaths.length) {
8285 stats.mProcDeaths[i] = 0;
8286 i++;
8287 }
8288
8289 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8290 ProcessRecord proc = mLRUProcesses.get(i);
8291 if (proc.persistent) {
8292 continue;
8293 }
8294 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8295 if (proc.lastPss == 0) {
8296 stats.mNoPssCount++;
8297 continue;
8298 }
8299 if (proc.setAdj == EMPTY_APP_ADJ) {
8300 stats.mEmptyPss += proc.lastPss;
8301 stats.mEmptyCount++;
8302 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8303 stats.mEmptyPss += proc.lastPss;
8304 stats.mEmptyCount++;
8305 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8306 stats.mBackgroundPss += proc.lastPss;
8307 stats.mBackgroundCount++;
8308 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8309 stats.mVisiblePss += proc.lastPss;
8310 stats.mVisibleCount++;
8311 } else {
8312 stats.mForegroundPss += proc.lastPss;
8313 stats.mForegroundCount++;
8314 }
8315 }
8316 }
8317 }
8318
8319 public final void startRunning(String pkg, String cls, String action,
8320 String data) {
8321 synchronized(this) {
8322 if (mStartRunning) {
8323 return;
8324 }
8325 mStartRunning = true;
8326 mTopComponent = pkg != null && cls != null
8327 ? new ComponentName(pkg, cls) : null;
8328 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8329 mTopData = data;
8330 if (!mSystemReady) {
8331 return;
8332 }
8333 }
8334
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008335 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008336 }
8337
8338 private void retrieveSettings() {
8339 final ContentResolver resolver = mContext.getContentResolver();
8340 String debugApp = Settings.System.getString(
8341 resolver, Settings.System.DEBUG_APP);
8342 boolean waitForDebugger = Settings.System.getInt(
8343 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8344 boolean alwaysFinishActivities = Settings.System.getInt(
8345 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8346
8347 Configuration configuration = new Configuration();
8348 Settings.System.getConfiguration(resolver, configuration);
8349
8350 synchronized (this) {
8351 mDebugApp = mOrigDebugApp = debugApp;
8352 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8353 mAlwaysFinishActivities = alwaysFinishActivities;
8354 // This happens before any activities are started, so we can
8355 // change mConfiguration in-place.
8356 mConfiguration.updateFrom(configuration);
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008357 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008358 }
8359 }
8360
8361 public boolean testIsSystemReady() {
8362 // no need to synchronize(this) just to read & return the value
8363 return mSystemReady;
8364 }
8365
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008366 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008367 // In the simulator, startRunning will never have been called, which
8368 // normally sets a few crucial variables. Do it here instead.
8369 if (!Process.supportsProcesses()) {
8370 mStartRunning = true;
8371 mTopAction = Intent.ACTION_MAIN;
8372 }
8373
8374 synchronized(this) {
8375 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008376 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008377 return;
8378 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008379
8380 // Check to see if there are any update receivers to run.
8381 if (!mDidUpdate) {
8382 if (mWaitingUpdate) {
8383 return;
8384 }
8385 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8386 List<ResolveInfo> ris = null;
8387 try {
8388 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8389 intent, null, 0);
8390 } catch (RemoteException e) {
8391 }
8392 if (ris != null) {
8393 for (int i=ris.size()-1; i>=0; i--) {
8394 if ((ris.get(i).activityInfo.applicationInfo.flags
8395 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8396 ris.remove(i);
8397 }
8398 }
8399 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8400 for (int i=0; i<ris.size(); i++) {
8401 ActivityInfo ai = ris.get(i).activityInfo;
8402 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8403 IIntentReceiver finisher = null;
8404 if (i == 0) {
8405 finisher = new IIntentReceiver.Stub() {
8406 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -07008407 String data, Bundle extras, boolean ordered,
8408 boolean sticky)
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008409 throws RemoteException {
8410 synchronized (ActivityManagerService.this) {
8411 mDidUpdate = true;
8412 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008413 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008414 }
8415 };
8416 }
8417 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8418 broadcastIntentLocked(null, null, intent, null, finisher,
8419 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8420 if (i == 0) {
8421 mWaitingUpdate = true;
8422 }
8423 }
8424 }
8425 if (mWaitingUpdate) {
8426 return;
8427 }
8428 mDidUpdate = true;
8429 }
8430
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008431 mSystemReady = true;
8432 if (!mStartRunning) {
8433 return;
8434 }
8435 }
8436
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008437 ArrayList<ProcessRecord> procsToKill = null;
8438 synchronized(mPidsSelfLocked) {
8439 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8440 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8441 if (!isAllowedWhileBooting(proc.info)){
8442 if (procsToKill == null) {
8443 procsToKill = new ArrayList<ProcessRecord>();
8444 }
8445 procsToKill.add(proc);
8446 }
8447 }
8448 }
8449
8450 if (procsToKill != null) {
8451 synchronized(this) {
8452 for (int i=procsToKill.size()-1; i>=0; i--) {
8453 ProcessRecord proc = procsToKill.get(i);
8454 Log.i(TAG, "Removing system update proc: " + proc);
8455 removeProcessLocked(proc, true);
8456 }
8457 }
8458 }
8459
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008460 Log.i(TAG, "System now ready");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008461 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8462 SystemClock.uptimeMillis());
8463
8464 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008465 // Make sure we have no pre-ready processes sitting around.
8466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008467 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8468 ResolveInfo ri = mContext.getPackageManager()
8469 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008470 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008471 CharSequence errorMsg = null;
8472 if (ri != null) {
8473 ActivityInfo ai = ri.activityInfo;
8474 ApplicationInfo app = ai.applicationInfo;
8475 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8476 mTopAction = Intent.ACTION_FACTORY_TEST;
8477 mTopData = null;
8478 mTopComponent = new ComponentName(app.packageName,
8479 ai.name);
8480 } else {
8481 errorMsg = mContext.getResources().getText(
8482 com.android.internal.R.string.factorytest_not_system);
8483 }
8484 } else {
8485 errorMsg = mContext.getResources().getText(
8486 com.android.internal.R.string.factorytest_no_action);
8487 }
8488 if (errorMsg != null) {
8489 mTopAction = null;
8490 mTopData = null;
8491 mTopComponent = null;
8492 Message msg = Message.obtain();
8493 msg.what = SHOW_FACTORY_ERROR_MSG;
8494 msg.getData().putCharSequence("msg", errorMsg);
8495 mHandler.sendMessage(msg);
8496 }
8497 }
8498 }
8499
8500 retrieveSettings();
8501
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008502 if (goingCallback != null) goingCallback.run();
8503
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008504 synchronized (this) {
8505 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8506 try {
8507 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008508 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008509 if (apps != null) {
8510 int N = apps.size();
8511 int i;
8512 for (i=0; i<N; i++) {
8513 ApplicationInfo info
8514 = (ApplicationInfo)apps.get(i);
8515 if (info != null &&
8516 !info.packageName.equals("android")) {
8517 addAppLocked(info);
8518 }
8519 }
8520 }
8521 } catch (RemoteException ex) {
8522 // pm is in same process, this will never happen.
8523 }
8524 }
8525
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008526 // Start up initial activity.
8527 mBooting = true;
8528
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008529 try {
8530 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8531 Message msg = Message.obtain();
8532 msg.what = SHOW_UID_ERROR_MSG;
8533 mHandler.sendMessage(msg);
8534 }
8535 } catch (RemoteException e) {
8536 }
8537
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008538 resumeTopActivityLocked(null);
8539 }
8540 }
8541
8542 boolean makeAppCrashingLocked(ProcessRecord app,
8543 String tag, String shortMsg, String longMsg, byte[] crashData) {
8544 app.crashing = true;
8545 app.crashingReport = generateProcessError(app,
8546 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8547 startAppProblemLocked(app);
8548 app.stopFreezingAllLocked();
8549 return handleAppCrashLocked(app);
8550 }
8551
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008552 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Jacek Surazskia2339432009-09-18 15:01:26 +02008553 // check if error reporting is enabled in Gservices
8554 int enabled = Settings.Gservices.getInt(mContext.getContentResolver(),
8555 Settings.Gservices.SEND_ACTION_APP_ERROR, 0);
8556 if (enabled == 0) {
8557 return null;
8558 }
8559
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008560 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008561
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008562 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008563 // look for receiver in the installer package
8564 String candidate = pm.getInstallerPackageName(app.info.packageName);
8565 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8566 if (result != null) {
8567 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008568 }
8569
Jacek Surazski82a73df2009-06-17 14:33:18 +02008570 // if the error app is on the system image, look for system apps
8571 // error receiver
8572 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8573 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8574 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8575 if (result != null) {
8576 return result;
8577 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008578 }
8579
Jacek Surazski82a73df2009-06-17 14:33:18 +02008580 // if there is a default receiver, try that
8581 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8582 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008583 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008584 // should not happen
8585 Log.e(TAG, "error talking to PackageManager", e);
8586 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008587 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008588 }
8589
8590 /**
8591 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8592 *
8593 * @param pm PackageManager isntance
8594 * @param errorPackage package which caused the error
8595 * @param receiverPackage candidate package to receive the error
8596 * @return activity component within receiverPackage which handles
8597 * ACTION_APP_ERROR, or null if not found
8598 */
8599 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8600 String receiverPackage) throws RemoteException {
8601 if (receiverPackage == null || receiverPackage.length() == 0) {
8602 return null;
8603 }
8604
8605 // break the loop if it's the error report receiver package that crashed
8606 if (receiverPackage.equals(errorPackage)) {
8607 return null;
8608 }
8609
8610 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8611 intent.setPackage(receiverPackage);
8612 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8613 if (info == null || info.activityInfo == null) {
8614 return null;
8615 }
8616 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008617 }
8618
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008619 void makeAppNotRespondingLocked(ProcessRecord app,
8620 String tag, String shortMsg, String longMsg, byte[] crashData) {
8621 app.notResponding = true;
8622 app.notRespondingReport = generateProcessError(app,
8623 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8624 crashData);
8625 startAppProblemLocked(app);
8626 app.stopFreezingAllLocked();
8627 }
8628
8629 /**
8630 * Generate a process error record, suitable for attachment to a ProcessRecord.
8631 *
8632 * @param app The ProcessRecord in which the error occurred.
8633 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8634 * ActivityManager.AppErrorStateInfo
8635 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8636 * @param shortMsg Short message describing the crash.
8637 * @param longMsg Long message describing the crash.
8638 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8639 *
8640 * @return Returns a fully-formed AppErrorStateInfo record.
8641 */
8642 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8643 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8644 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8645
8646 report.condition = condition;
8647 report.processName = app.processName;
8648 report.pid = app.pid;
8649 report.uid = app.info.uid;
8650 report.tag = tag;
8651 report.shortMsg = shortMsg;
8652 report.longMsg = longMsg;
8653 report.crashData = crashData;
8654
8655 return report;
8656 }
8657
8658 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8659 boolean crashed) {
8660 synchronized (this) {
8661 app.crashing = false;
8662 app.crashingReport = null;
8663 app.notResponding = false;
8664 app.notRespondingReport = null;
8665 if (app.anrDialog == fromDialog) {
8666 app.anrDialog = null;
8667 }
8668 if (app.waitDialog == fromDialog) {
8669 app.waitDialog = null;
8670 }
8671 if (app.pid > 0 && app.pid != MY_PID) {
8672 if (crashed) {
8673 handleAppCrashLocked(app);
8674 }
8675 Log.i(ActivityManagerService.TAG, "Killing process "
8676 + app.processName
8677 + " (pid=" + app.pid + ") at user's request");
8678 Process.killProcess(app.pid);
8679 }
8680
8681 }
8682 }
8683
8684 boolean handleAppCrashLocked(ProcessRecord app) {
8685 long now = SystemClock.uptimeMillis();
8686
8687 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8688 app.info.uid);
8689 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8690 // This process loses!
8691 Log.w(TAG, "Process " + app.info.processName
8692 + " has crashed too many times: killing!");
8693 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8694 app.info.processName, app.info.uid);
8695 killServicesLocked(app, false);
8696 for (int i=mHistory.size()-1; i>=0; i--) {
8697 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8698 if (r.app == app) {
8699 if (Config.LOGD) Log.d(
8700 TAG, " Force finishing activity "
8701 + r.intent.getComponent().flattenToShortString());
8702 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8703 }
8704 }
8705 if (!app.persistent) {
8706 // We don't want to start this process again until the user
8707 // explicitly does so... but for persistent process, we really
8708 // need to keep it running. If a persistent process is actually
8709 // repeatedly crashing, then badness for everyone.
8710 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8711 app.info.processName);
8712 mBadProcesses.put(app.info.processName, app.info.uid, now);
8713 app.bad = true;
8714 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8715 app.removed = true;
8716 removeProcessLocked(app, false);
8717 return false;
8718 }
8719 }
8720
8721 // Bump up the crash count of any services currently running in the proc.
8722 if (app.services.size() != 0) {
8723 // Any services running in the application need to be placed
8724 // back in the pending list.
8725 Iterator it = app.services.iterator();
8726 while (it.hasNext()) {
8727 ServiceRecord sr = (ServiceRecord)it.next();
8728 sr.crashCount++;
8729 }
8730 }
8731
8732 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8733 return true;
8734 }
8735
8736 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008737 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008738 skipCurrentReceiverLocked(app);
8739 }
8740
8741 void skipCurrentReceiverLocked(ProcessRecord app) {
8742 boolean reschedule = false;
8743 BroadcastRecord r = app.curReceiver;
8744 if (r != null) {
8745 // The current broadcast is waiting for this app's receiver
8746 // to be finished. Looks like that's not going to happen, so
8747 // let the broadcast continue.
8748 logBroadcastReceiverDiscard(r);
8749 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8750 r.resultExtras, r.resultAbort, true);
8751 reschedule = true;
8752 }
8753 r = mPendingBroadcast;
8754 if (r != null && r.curApp == app) {
8755 if (DEBUG_BROADCAST) Log.v(TAG,
8756 "skip & discard pending app " + r);
8757 logBroadcastReceiverDiscard(r);
8758 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8759 r.resultExtras, r.resultAbort, true);
8760 reschedule = true;
8761 }
8762 if (reschedule) {
8763 scheduleBroadcastsLocked();
8764 }
8765 }
8766
8767 public int handleApplicationError(IBinder app, int flags,
8768 String tag, String shortMsg, String longMsg, byte[] crashData) {
8769 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008770 ProcessRecord r = null;
8771 synchronized (this) {
8772 if (app != null) {
8773 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8774 final int NA = apps.size();
8775 for (int ia=0; ia<NA; ia++) {
8776 ProcessRecord p = apps.valueAt(ia);
8777 if (p.thread != null && p.thread.asBinder() == app) {
8778 r = p;
8779 break;
8780 }
8781 }
8782 }
8783 }
8784
8785 if (r != null) {
8786 // The application has crashed. Send the SIGQUIT to the process so
8787 // that it can dump its state.
8788 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8789 //Log.i(TAG, "Current system threads:");
8790 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8791 }
8792
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008793 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008794 try {
8795 String name = r != null ? r.processName : null;
8796 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008797 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008798 shortMsg, longMsg, crashData)) {
8799 Log.w(TAG, "Force-killing crashed app " + name
8800 + " at watcher's request");
8801 Process.killProcess(pid);
8802 return 0;
8803 }
8804 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008805 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008806 }
8807 }
8808
8809 final long origId = Binder.clearCallingIdentity();
8810
8811 // If this process is running instrumentation, finish it.
8812 if (r != null && r.instrumentationClass != null) {
8813 Log.w(TAG, "Error in app " + r.processName
8814 + " running instrumentation " + r.instrumentationClass + ":");
8815 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8816 if (longMsg != null) Log.w(TAG, " " + longMsg);
8817 Bundle info = new Bundle();
8818 info.putString("shortMsg", shortMsg);
8819 info.putString("longMsg", longMsg);
8820 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8821 Binder.restoreCallingIdentity(origId);
8822 return 0;
8823 }
8824
8825 if (r != null) {
8826 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8827 return 0;
8828 }
8829 } else {
8830 Log.w(TAG, "Some application object " + app + " tag " + tag
8831 + " has crashed, but I don't know who it is.");
8832 Log.w(TAG, "ShortMsg:" + shortMsg);
8833 Log.w(TAG, "LongMsg:" + longMsg);
8834 Binder.restoreCallingIdentity(origId);
8835 return 0;
8836 }
8837
8838 Message msg = Message.obtain();
8839 msg.what = SHOW_ERROR_MSG;
8840 HashMap data = new HashMap();
8841 data.put("result", result);
8842 data.put("app", r);
8843 data.put("flags", flags);
8844 data.put("shortMsg", shortMsg);
8845 data.put("longMsg", longMsg);
8846 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8847 // For system processes, submit crash data to the server.
8848 data.put("crashData", crashData);
8849 }
8850 msg.obj = data;
8851 mHandler.sendMessage(msg);
8852
8853 Binder.restoreCallingIdentity(origId);
8854 }
8855
8856 int res = result.get();
8857
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008858 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008859 synchronized (this) {
8860 if (r != null) {
8861 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8862 SystemClock.uptimeMillis());
8863 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008864 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8865 appErrorIntent = createAppErrorIntentLocked(r);
8866 res = AppErrorDialog.FORCE_QUIT;
8867 }
8868 }
8869
8870 if (appErrorIntent != null) {
8871 try {
8872 mContext.startActivity(appErrorIntent);
8873 } catch (ActivityNotFoundException e) {
8874 Log.w(TAG, "bug report receiver dissappeared", e);
8875 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008876 }
8877
8878 return res;
8879 }
8880
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008881 Intent createAppErrorIntentLocked(ProcessRecord r) {
8882 ApplicationErrorReport report = createAppErrorReportLocked(r);
8883 if (report == null) {
8884 return null;
8885 }
8886 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8887 result.setComponent(r.errorReportReceiver);
8888 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8889 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8890 return result;
8891 }
8892
8893 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8894 if (r.errorReportReceiver == null) {
8895 return null;
8896 }
8897
8898 if (!r.crashing && !r.notResponding) {
8899 return null;
8900 }
8901
8902 try {
8903 ApplicationErrorReport report = new ApplicationErrorReport();
8904 report.packageName = r.info.packageName;
8905 report.installerPackageName = r.errorReportReceiver.getPackageName();
8906 report.processName = r.processName;
8907
8908 if (r.crashing) {
8909 report.type = ApplicationErrorReport.TYPE_CRASH;
8910 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8911
8912 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8913 r.crashingReport.crashData);
8914 DataInputStream dataStream = new DataInputStream(byteStream);
8915 CrashData crashData = new CrashData(dataStream);
8916 ThrowableData throwData = crashData.getThrowableData();
8917
8918 report.time = crashData.getTime();
8919 report.crashInfo.stackTrace = throwData.toString();
8920
Jacek Surazskif829a782009-06-11 22:47:02 +02008921 // Extract the source of the exception, useful for report
8922 // clustering. Also extract the "deepest" non-null exception
8923 // message.
8924 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008925 while (throwData.getCause() != null) {
8926 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008927 String msg = throwData.getMessage();
8928 if (msg != null && msg.length() > 0) {
8929 exceptionMessage = msg;
8930 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008931 }
8932 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008933 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008934 report.crashInfo.exceptionClassName = throwData.getType();
8935 report.crashInfo.throwFileName = trace.getFileName();
8936 report.crashInfo.throwClassName = trace.getClassName();
8937 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008938 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008939 } else if (r.notResponding) {
8940 report.type = ApplicationErrorReport.TYPE_ANR;
8941 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8942
8943 report.anrInfo.activity = r.notRespondingReport.tag;
8944 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8945 report.anrInfo.info = r.notRespondingReport.longMsg;
8946 }
8947
8948 return report;
8949 } catch (IOException e) {
8950 // we don't send it
8951 }
8952
8953 return null;
8954 }
8955
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008956 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8957 // assume our apps are happy - lazy create the list
8958 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8959
8960 synchronized (this) {
8961
8962 // iterate across all processes
8963 final int N = mLRUProcesses.size();
8964 for (int i = 0; i < N; i++) {
8965 ProcessRecord app = mLRUProcesses.get(i);
8966 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8967 // This one's in trouble, so we'll generate a report for it
8968 // crashes are higher priority (in case there's a crash *and* an anr)
8969 ActivityManager.ProcessErrorStateInfo report = null;
8970 if (app.crashing) {
8971 report = app.crashingReport;
8972 } else if (app.notResponding) {
8973 report = app.notRespondingReport;
8974 }
8975
8976 if (report != null) {
8977 if (errList == null) {
8978 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8979 }
8980 errList.add(report);
8981 } else {
8982 Log.w(TAG, "Missing app error report, app = " + app.processName +
8983 " crashing = " + app.crashing +
8984 " notResponding = " + app.notResponding);
8985 }
8986 }
8987 }
8988 }
8989
8990 return errList;
8991 }
8992
8993 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8994 // Lazy instantiation of list
8995 List<ActivityManager.RunningAppProcessInfo> runList = null;
8996 synchronized (this) {
8997 // Iterate across all processes
8998 final int N = mLRUProcesses.size();
8999 for (int i = 0; i < N; i++) {
9000 ProcessRecord app = mLRUProcesses.get(i);
9001 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
9002 // Generate process state info for running application
9003 ActivityManager.RunningAppProcessInfo currApp =
9004 new ActivityManager.RunningAppProcessInfo(app.processName,
9005 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07009006 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009007 int adj = app.curAdj;
9008 if (adj >= CONTENT_PROVIDER_ADJ) {
9009 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
9010 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
9011 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08009012 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
9013 } else if (adj >= HOME_APP_ADJ) {
9014 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
9015 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009016 } else if (adj >= SECONDARY_SERVER_ADJ) {
9017 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
9018 } else if (adj >= VISIBLE_APP_ADJ) {
9019 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
9020 } else {
9021 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
9022 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009023 currApp.importanceReasonCode = app.adjTypeCode;
9024 if (app.adjSource instanceof ProcessRecord) {
9025 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9026 } else if (app.adjSource instanceof HistoryRecord) {
9027 HistoryRecord r = (HistoryRecord)app.adjSource;
9028 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9029 }
9030 if (app.adjTarget instanceof ComponentName) {
9031 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9032 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009033 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9034 // + " lru=" + currApp.lru);
9035 if (runList == null) {
9036 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9037 }
9038 runList.add(currApp);
9039 }
9040 }
9041 }
9042 return runList;
9043 }
9044
9045 @Override
9046 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9047 synchronized (this) {
9048 if (checkCallingPermission(android.Manifest.permission.DUMP)
9049 != PackageManager.PERMISSION_GRANTED) {
9050 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9051 + Binder.getCallingPid()
9052 + ", uid=" + Binder.getCallingUid()
9053 + " without permission "
9054 + android.Manifest.permission.DUMP);
9055 return;
9056 }
9057 if (args.length != 0 && "service".equals(args[0])) {
9058 dumpService(fd, pw, args);
9059 return;
9060 }
9061 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009062 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009063 pw.println(" ");
9064 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009065 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009066 if (mWaitingVisibleActivities.size() > 0) {
9067 pw.println(" ");
9068 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009069 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009070 }
9071 if (mStoppingActivities.size() > 0) {
9072 pw.println(" ");
9073 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009074 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009075 }
9076 if (mFinishingActivities.size() > 0) {
9077 pw.println(" ");
9078 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009079 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009080 }
9081
9082 pw.println(" ");
9083 pw.println(" mPausingActivity: " + mPausingActivity);
9084 pw.println(" mResumedActivity: " + mResumedActivity);
9085 pw.println(" mFocusedActivity: " + mFocusedActivity);
9086 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
9087
9088 if (mRecentTasks.size() > 0) {
9089 pw.println(" ");
9090 pw.println("Recent tasks in Current Activity Manager State:");
9091
9092 final int N = mRecentTasks.size();
9093 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009094 TaskRecord tr = mRecentTasks.get(i);
9095 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9096 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009097 mRecentTasks.get(i).dump(pw, " ");
9098 }
9099 }
9100
9101 pw.println(" ");
9102 pw.println(" mCurTask: " + mCurTask);
9103
9104 pw.println(" ");
9105 pw.println("Processes in Current Activity Manager State:");
9106
9107 boolean needSep = false;
9108 int numPers = 0;
9109
9110 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9111 final int NA = procs.size();
9112 for (int ia=0; ia<NA; ia++) {
9113 if (!needSep) {
9114 pw.println(" All known processes:");
9115 needSep = true;
9116 }
9117 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009118 pw.print(r.persistent ? " *PERS*" : " *APP*");
9119 pw.print(" UID "); pw.print(procs.keyAt(ia));
9120 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009121 r.dump(pw, " ");
9122 if (r.persistent) {
9123 numPers++;
9124 }
9125 }
9126 }
9127
9128 if (mLRUProcesses.size() > 0) {
9129 if (needSep) pw.println(" ");
9130 needSep = true;
9131 pw.println(" Running processes (most recent first):");
9132 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009133 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009134 needSep = true;
9135 }
9136
9137 synchronized (mPidsSelfLocked) {
9138 if (mPidsSelfLocked.size() > 0) {
9139 if (needSep) pw.println(" ");
9140 needSep = true;
9141 pw.println(" PID mappings:");
9142 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009143 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9144 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009145 }
9146 }
9147 }
9148
9149 if (mForegroundProcesses.size() > 0) {
9150 if (needSep) pw.println(" ");
9151 needSep = true;
9152 pw.println(" Foreground Processes:");
9153 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009154 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9155 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009156 }
9157 }
9158
9159 if (mPersistentStartingProcesses.size() > 0) {
9160 if (needSep) pw.println(" ");
9161 needSep = true;
9162 pw.println(" Persisent processes that are starting:");
9163 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009164 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009165 }
9166
9167 if (mStartingProcesses.size() > 0) {
9168 if (needSep) pw.println(" ");
9169 needSep = true;
9170 pw.println(" Processes that are starting:");
9171 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009172 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009173 }
9174
9175 if (mRemovedProcesses.size() > 0) {
9176 if (needSep) pw.println(" ");
9177 needSep = true;
9178 pw.println(" Processes that are being removed:");
9179 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009180 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009181 }
9182
9183 if (mProcessesOnHold.size() > 0) {
9184 if (needSep) pw.println(" ");
9185 needSep = true;
9186 pw.println(" Processes that are on old until the system is ready:");
9187 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009188 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009189 }
9190
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009191 if (mProcessesToGc.size() > 0) {
9192 if (needSep) pw.println(" ");
9193 needSep = true;
9194 pw.println(" Processes that are waiting to GC:");
9195 long now = SystemClock.uptimeMillis();
9196 for (int i=0; i<mProcessesToGc.size(); i++) {
9197 ProcessRecord proc = mProcessesToGc.get(i);
9198 pw.print(" Process "); pw.println(proc);
9199 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9200 pw.print(", last gced=");
9201 pw.print(now-proc.lastRequestedGc);
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -07009202 pw.print(" ms ago, last lowMem=");
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009203 pw.print(now-proc.lastLowMemory);
9204 pw.println(" ms ago");
9205
9206 }
9207 }
9208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009209 if (mProcessCrashTimes.getMap().size() > 0) {
9210 if (needSep) pw.println(" ");
9211 needSep = true;
9212 pw.println(" Time since processes crashed:");
9213 long now = SystemClock.uptimeMillis();
9214 for (Map.Entry<String, SparseArray<Long>> procs
9215 : mProcessCrashTimes.getMap().entrySet()) {
9216 SparseArray<Long> uids = procs.getValue();
9217 final int N = uids.size();
9218 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009219 pw.print(" Process "); pw.print(procs.getKey());
9220 pw.print(" uid "); pw.print(uids.keyAt(i));
9221 pw.print(": last crashed ");
9222 pw.print((now-uids.valueAt(i)));
9223 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009224 }
9225 }
9226 }
9227
9228 if (mBadProcesses.getMap().size() > 0) {
9229 if (needSep) pw.println(" ");
9230 needSep = true;
9231 pw.println(" Bad processes:");
9232 for (Map.Entry<String, SparseArray<Long>> procs
9233 : mBadProcesses.getMap().entrySet()) {
9234 SparseArray<Long> uids = procs.getValue();
9235 final int N = uids.size();
9236 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009237 pw.print(" Bad process "); pw.print(procs.getKey());
9238 pw.print(" uid "); pw.print(uids.keyAt(i));
9239 pw.print(": crashed at time ");
9240 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009241 }
9242 }
9243 }
9244
9245 pw.println(" ");
9246 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009247 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009248 pw.println(" mConfiguration: " + mConfiguration);
9249 pw.println(" mStartRunning=" + mStartRunning
9250 + " mSystemReady=" + mSystemReady
9251 + " mBooting=" + mBooting
9252 + " mBooted=" + mBooted
9253 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009254 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009255 pw.println(" mGoingToSleep=" + mGoingToSleep);
9256 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9257 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9258 + " mDebugTransient=" + mDebugTransient
9259 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9260 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009261 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009262 }
9263 }
9264
9265 /**
9266 * There are three ways to call this:
9267 * - no service specified: dump all the services
9268 * - a flattened component name that matched an existing service was specified as the
9269 * first arg: dump that one service
9270 * - the first arg isn't the flattened component name of an existing service:
9271 * dump all services whose component contains the first arg as a substring
9272 */
9273 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9274 String[] newArgs;
9275 String componentNameString;
9276 ServiceRecord r;
9277 if (args.length == 1) {
9278 componentNameString = null;
9279 newArgs = EMPTY_STRING_ARRAY;
9280 r = null;
9281 } else {
9282 componentNameString = args[1];
9283 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9284 r = componentName != null ? mServices.get(componentName) : null;
9285 newArgs = new String[args.length - 2];
9286 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9287 }
9288
9289 if (r != null) {
9290 dumpService(fd, pw, r, newArgs);
9291 } else {
9292 for (ServiceRecord r1 : mServices.values()) {
9293 if (componentNameString == null
9294 || r1.name.flattenToString().contains(componentNameString)) {
9295 dumpService(fd, pw, r1, newArgs);
9296 }
9297 }
9298 }
9299 }
9300
9301 /**
9302 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9303 * there is a thread associated with the service.
9304 */
9305 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9306 pw.println(" Service " + r.name.flattenToString());
9307 if (r.app != null && r.app.thread != null) {
9308 try {
9309 // flush anything that is already in the PrintWriter since the thread is going
9310 // to write to the file descriptor directly
9311 pw.flush();
9312 r.app.thread.dumpService(fd, r, args);
9313 pw.print("\n");
9314 } catch (RemoteException e) {
9315 pw.println("got a RemoteException while dumping the service");
9316 }
9317 }
9318 }
9319
9320 void dumpBroadcasts(PrintWriter pw) {
9321 synchronized (this) {
9322 if (checkCallingPermission(android.Manifest.permission.DUMP)
9323 != PackageManager.PERMISSION_GRANTED) {
9324 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9325 + Binder.getCallingPid()
9326 + ", uid=" + Binder.getCallingUid()
9327 + " without permission "
9328 + android.Manifest.permission.DUMP);
9329 return;
9330 }
9331 pw.println("Broadcasts in Current Activity Manager State:");
9332
9333 if (mRegisteredReceivers.size() > 0) {
9334 pw.println(" ");
9335 pw.println(" Registered Receivers:");
9336 Iterator it = mRegisteredReceivers.values().iterator();
9337 while (it.hasNext()) {
9338 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009339 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009340 r.dump(pw, " ");
9341 }
9342 }
9343
9344 pw.println(" ");
9345 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009346 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009347
9348 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9349 || mPendingBroadcast != null) {
9350 if (mParallelBroadcasts.size() > 0) {
9351 pw.println(" ");
9352 pw.println(" Active broadcasts:");
9353 }
9354 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9355 pw.println(" Broadcast #" + i + ":");
9356 mParallelBroadcasts.get(i).dump(pw, " ");
9357 }
9358 if (mOrderedBroadcasts.size() > 0) {
9359 pw.println(" ");
9360 pw.println(" Active serialized broadcasts:");
9361 }
9362 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9363 pw.println(" Serialized Broadcast #" + i + ":");
9364 mOrderedBroadcasts.get(i).dump(pw, " ");
9365 }
9366 pw.println(" ");
9367 pw.println(" Pending broadcast:");
9368 if (mPendingBroadcast != null) {
9369 mPendingBroadcast.dump(pw, " ");
9370 } else {
9371 pw.println(" (null)");
9372 }
9373 }
9374
9375 pw.println(" ");
9376 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9377 if (mStickyBroadcasts != null) {
9378 pw.println(" ");
9379 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009380 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009381 for (Map.Entry<String, ArrayList<Intent>> ent
9382 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009383 pw.print(" * Sticky action "); pw.print(ent.getKey());
9384 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009385 ArrayList<Intent> intents = ent.getValue();
9386 final int N = intents.size();
9387 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009388 sb.setLength(0);
9389 sb.append(" Intent: ");
9390 intents.get(i).toShortString(sb, true, false);
9391 pw.println(sb.toString());
9392 Bundle bundle = intents.get(i).getExtras();
9393 if (bundle != null) {
9394 pw.print(" ");
9395 pw.println(bundle.toString());
9396 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009397 }
9398 }
9399 }
9400
9401 pw.println(" ");
9402 pw.println(" mHandler:");
9403 mHandler.dump(new PrintWriterPrinter(pw), " ");
9404 }
9405 }
9406
9407 void dumpServices(PrintWriter pw) {
9408 synchronized (this) {
9409 if (checkCallingPermission(android.Manifest.permission.DUMP)
9410 != PackageManager.PERMISSION_GRANTED) {
9411 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9412 + Binder.getCallingPid()
9413 + ", uid=" + Binder.getCallingUid()
9414 + " without permission "
9415 + android.Manifest.permission.DUMP);
9416 return;
9417 }
9418 pw.println("Services in Current Activity Manager State:");
9419
9420 boolean needSep = false;
9421
9422 if (mServices.size() > 0) {
9423 pw.println(" Active services:");
9424 Iterator<ServiceRecord> it = mServices.values().iterator();
9425 while (it.hasNext()) {
9426 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009427 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009428 r.dump(pw, " ");
9429 }
9430 needSep = true;
9431 }
9432
9433 if (mPendingServices.size() > 0) {
9434 if (needSep) pw.println(" ");
9435 pw.println(" Pending services:");
9436 for (int i=0; i<mPendingServices.size(); i++) {
9437 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009438 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009439 r.dump(pw, " ");
9440 }
9441 needSep = true;
9442 }
9443
9444 if (mRestartingServices.size() > 0) {
9445 if (needSep) pw.println(" ");
9446 pw.println(" Restarting services:");
9447 for (int i=0; i<mRestartingServices.size(); i++) {
9448 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009449 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009450 r.dump(pw, " ");
9451 }
9452 needSep = true;
9453 }
9454
9455 if (mStoppingServices.size() > 0) {
9456 if (needSep) pw.println(" ");
9457 pw.println(" Stopping services:");
9458 for (int i=0; i<mStoppingServices.size(); i++) {
9459 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009460 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009461 r.dump(pw, " ");
9462 }
9463 needSep = true;
9464 }
9465
9466 if (mServiceConnections.size() > 0) {
9467 if (needSep) pw.println(" ");
9468 pw.println(" Connection bindings to services:");
9469 Iterator<ConnectionRecord> it
9470 = mServiceConnections.values().iterator();
9471 while (it.hasNext()) {
9472 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009473 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009474 r.dump(pw, " ");
9475 }
9476 }
9477 }
9478 }
9479
9480 void dumpProviders(PrintWriter pw) {
9481 synchronized (this) {
9482 if (checkCallingPermission(android.Manifest.permission.DUMP)
9483 != PackageManager.PERMISSION_GRANTED) {
9484 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9485 + Binder.getCallingPid()
9486 + ", uid=" + Binder.getCallingUid()
9487 + " without permission "
9488 + android.Manifest.permission.DUMP);
9489 return;
9490 }
9491
9492 pw.println("Content Providers in Current Activity Manager State:");
9493
9494 boolean needSep = false;
9495
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009496 if (mProvidersByClass.size() > 0) {
9497 if (needSep) pw.println(" ");
9498 pw.println(" Published content providers (by class):");
9499 Iterator it = mProvidersByClass.entrySet().iterator();
9500 while (it.hasNext()) {
9501 Map.Entry e = (Map.Entry)it.next();
9502 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009503 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009504 r.dump(pw, " ");
9505 }
9506 needSep = true;
9507 }
9508
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009509 if (mProvidersByName.size() > 0) {
9510 pw.println(" ");
9511 pw.println(" Authority to provider mappings:");
9512 Iterator it = mProvidersByName.entrySet().iterator();
9513 while (it.hasNext()) {
9514 Map.Entry e = (Map.Entry)it.next();
9515 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9516 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9517 pw.println(r);
9518 }
9519 needSep = true;
9520 }
9521
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009522 if (mLaunchingProviders.size() > 0) {
9523 if (needSep) pw.println(" ");
9524 pw.println(" Launching content providers:");
9525 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009526 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9527 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009528 }
9529 needSep = true;
9530 }
9531
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009532 if (mGrantedUriPermissions.size() > 0) {
9533 pw.println();
9534 pw.println("Granted Uri Permissions:");
9535 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9536 int uid = mGrantedUriPermissions.keyAt(i);
9537 HashMap<Uri, UriPermission> perms
9538 = mGrantedUriPermissions.valueAt(i);
9539 pw.print(" * UID "); pw.print(uid);
9540 pw.println(" holds:");
9541 for (UriPermission perm : perms.values()) {
9542 pw.print(" "); pw.println(perm);
9543 perm.dump(pw, " ");
9544 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009545 }
9546 }
9547 }
9548 }
9549
9550 void dumpSenders(PrintWriter pw) {
9551 synchronized (this) {
9552 if (checkCallingPermission(android.Manifest.permission.DUMP)
9553 != PackageManager.PERMISSION_GRANTED) {
9554 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9555 + Binder.getCallingPid()
9556 + ", uid=" + Binder.getCallingUid()
9557 + " without permission "
9558 + android.Manifest.permission.DUMP);
9559 return;
9560 }
9561
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009562 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009563
9564 if (this.mIntentSenderRecords.size() > 0) {
9565 Iterator<WeakReference<PendingIntentRecord>> it
9566 = mIntentSenderRecords.values().iterator();
9567 while (it.hasNext()) {
9568 WeakReference<PendingIntentRecord> ref = it.next();
9569 PendingIntentRecord rec = ref != null ? ref.get(): null;
9570 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009571 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009572 rec.dump(pw, " ");
9573 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009574 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009575 }
9576 }
9577 }
9578 }
9579 }
9580
9581 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009582 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009583 TaskRecord lastTask = null;
9584 for (int i=list.size()-1; i>=0; i--) {
9585 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009586 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009587 if (lastTask != r.task) {
9588 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009589 pw.print(prefix);
9590 pw.print(full ? "* " : " ");
9591 pw.println(lastTask);
9592 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009593 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009594 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009595 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009596 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9597 pw.print(" #"); pw.print(i); pw.print(": ");
9598 pw.println(r);
9599 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009600 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009601 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009602 }
9603 }
9604
9605 private static final int dumpProcessList(PrintWriter pw, List list,
9606 String prefix, String normalLabel, String persistentLabel,
9607 boolean inclOomAdj) {
9608 int numPers = 0;
9609 for (int i=list.size()-1; i>=0; i--) {
9610 ProcessRecord r = (ProcessRecord)list.get(i);
9611 if (false) {
9612 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9613 + " #" + i + ":");
9614 r.dump(pw, prefix + " ");
9615 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009616 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009617 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009618 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9619 if (r.adjSource != null || r.adjTarget != null) {
9620 pw.println(prefix + " " + r.adjTarget
9621 + " used by " + r.adjSource);
9622 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009623 } else {
9624 pw.println(String.format("%s%s #%2d: %s",
9625 prefix, (r.persistent ? persistentLabel : normalLabel),
9626 i, r.toString()));
9627 }
9628 if (r.persistent) {
9629 numPers++;
9630 }
9631 }
9632 return numPers;
9633 }
9634
9635 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9636 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009637 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009638 long uptime = SystemClock.uptimeMillis();
9639 long realtime = SystemClock.elapsedRealtime();
9640
9641 if (isCheckinRequest) {
9642 // short checkin version
9643 pw.println(uptime + "," + realtime);
9644 pw.flush();
9645 } else {
9646 pw.println("Applications Memory Usage (kB):");
9647 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9648 }
9649 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9650 ProcessRecord r = (ProcessRecord)list.get(i);
9651 if (r.thread != null) {
9652 if (!isCheckinRequest) {
9653 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9654 pw.flush();
9655 }
9656 try {
9657 r.thread.asBinder().dump(fd, args);
9658 } catch (RemoteException e) {
9659 if (!isCheckinRequest) {
9660 pw.println("Got RemoteException!");
9661 pw.flush();
9662 }
9663 }
9664 }
9665 }
9666 }
9667
9668 /**
9669 * Searches array of arguments for the specified string
9670 * @param args array of argument strings
9671 * @param value value to search for
9672 * @return true if the value is contained in the array
9673 */
9674 private static boolean scanArgs(String[] args, String value) {
9675 if (args != null) {
9676 for (String arg : args) {
9677 if (value.equals(arg)) {
9678 return true;
9679 }
9680 }
9681 }
9682 return false;
9683 }
9684
Dianne Hackborn75b03852009-06-12 15:43:26 -07009685 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009686 int count = mHistory.size();
9687
9688 // convert the token to an entry in the history.
9689 HistoryRecord r = null;
9690 int index = -1;
9691 for (int i=count-1; i>=0; i--) {
9692 Object o = mHistory.get(i);
9693 if (o == token) {
9694 r = (HistoryRecord)o;
9695 index = i;
9696 break;
9697 }
9698 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009699
9700 return index;
9701 }
9702
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009703 private final void killServicesLocked(ProcessRecord app,
9704 boolean allowRestart) {
9705 // Report disconnected services.
9706 if (false) {
9707 // XXX we are letting the client link to the service for
9708 // death notifications.
9709 if (app.services.size() > 0) {
9710 Iterator it = app.services.iterator();
9711 while (it.hasNext()) {
9712 ServiceRecord r = (ServiceRecord)it.next();
9713 if (r.connections.size() > 0) {
9714 Iterator<ConnectionRecord> jt
9715 = r.connections.values().iterator();
9716 while (jt.hasNext()) {
9717 ConnectionRecord c = jt.next();
9718 if (c.binding.client != app) {
9719 try {
9720 //c.conn.connected(r.className, null);
9721 } catch (Exception e) {
9722 // todo: this should be asynchronous!
9723 Log.w(TAG, "Exception thrown disconnected servce "
9724 + r.shortName
9725 + " from app " + app.processName, e);
9726 }
9727 }
9728 }
9729 }
9730 }
9731 }
9732 }
9733
9734 // Clean up any connections this application has to other services.
9735 if (app.connections.size() > 0) {
9736 Iterator<ConnectionRecord> it = app.connections.iterator();
9737 while (it.hasNext()) {
9738 ConnectionRecord r = it.next();
9739 removeConnectionLocked(r, app, null);
9740 }
9741 }
9742 app.connections.clear();
9743
9744 if (app.services.size() != 0) {
9745 // Any services running in the application need to be placed
9746 // back in the pending list.
9747 Iterator it = app.services.iterator();
9748 while (it.hasNext()) {
9749 ServiceRecord sr = (ServiceRecord)it.next();
9750 synchronized (sr.stats.getBatteryStats()) {
9751 sr.stats.stopLaunchedLocked();
9752 }
9753 sr.app = null;
9754 sr.executeNesting = 0;
9755 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009756
9757 boolean hasClients = sr.bindings.size() > 0;
9758 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009759 Iterator<IntentBindRecord> bindings
9760 = sr.bindings.values().iterator();
9761 while (bindings.hasNext()) {
9762 IntentBindRecord b = bindings.next();
9763 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9764 + ": shouldUnbind=" + b.hasBound);
9765 b.binder = null;
9766 b.requested = b.received = b.hasBound = false;
9767 }
9768 }
9769
9770 if (sr.crashCount >= 2) {
9771 Log.w(TAG, "Service crashed " + sr.crashCount
9772 + " times, stopping: " + sr);
9773 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9774 sr.crashCount, sr.shortName, app.pid);
9775 bringDownServiceLocked(sr, true);
9776 } else if (!allowRestart) {
9777 bringDownServiceLocked(sr, true);
9778 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009779 boolean canceled = scheduleServiceRestartLocked(sr, true);
9780
9781 // Should the service remain running? Note that in the
9782 // extreme case of so many attempts to deliver a command
9783 // that it failed, that we also will stop it here.
9784 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9785 if (sr.pendingStarts.size() == 0) {
9786 sr.startRequested = false;
9787 if (!hasClients) {
9788 // Whoops, no reason to restart!
9789 bringDownServiceLocked(sr, true);
9790 }
9791 }
9792 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009793 }
9794 }
9795
9796 if (!allowRestart) {
9797 app.services.clear();
9798 }
9799 }
9800
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009801 // Make sure we have no more records on the stopping list.
9802 int i = mStoppingServices.size();
9803 while (i > 0) {
9804 i--;
9805 ServiceRecord sr = mStoppingServices.get(i);
9806 if (sr.app == app) {
9807 mStoppingServices.remove(i);
9808 }
9809 }
9810
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009811 app.executingServices.clear();
9812 }
9813
9814 private final void removeDyingProviderLocked(ProcessRecord proc,
9815 ContentProviderRecord cpr) {
9816 synchronized (cpr) {
9817 cpr.launchingApp = null;
9818 cpr.notifyAll();
9819 }
9820
9821 mProvidersByClass.remove(cpr.info.name);
9822 String names[] = cpr.info.authority.split(";");
9823 for (int j = 0; j < names.length; j++) {
9824 mProvidersByName.remove(names[j]);
9825 }
9826
9827 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9828 while (cit.hasNext()) {
9829 ProcessRecord capp = cit.next();
9830 if (!capp.persistent && capp.thread != null
9831 && capp.pid != 0
9832 && capp.pid != MY_PID) {
9833 Log.i(TAG, "Killing app " + capp.processName
9834 + " (pid " + capp.pid
9835 + ") because provider " + cpr.info.name
9836 + " is in dying process " + proc.processName);
9837 Process.killProcess(capp.pid);
9838 }
9839 }
9840
9841 mLaunchingProviders.remove(cpr);
9842 }
9843
9844 /**
9845 * Main code for cleaning up a process when it has gone away. This is
9846 * called both as a result of the process dying, or directly when stopping
9847 * a process when running in single process mode.
9848 */
9849 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9850 boolean restarting, int index) {
9851 if (index >= 0) {
9852 mLRUProcesses.remove(index);
9853 }
9854
Dianne Hackborn36124872009-10-08 16:22:03 -07009855 mProcessesToGc.remove(app);
9856
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009857 // Dismiss any open dialogs.
9858 if (app.crashDialog != null) {
9859 app.crashDialog.dismiss();
9860 app.crashDialog = null;
9861 }
9862 if (app.anrDialog != null) {
9863 app.anrDialog.dismiss();
9864 app.anrDialog = null;
9865 }
9866 if (app.waitDialog != null) {
9867 app.waitDialog.dismiss();
9868 app.waitDialog = null;
9869 }
9870
9871 app.crashing = false;
9872 app.notResponding = false;
9873
9874 app.resetPackageList();
9875 app.thread = null;
9876 app.forcingToForeground = null;
9877 app.foregroundServices = false;
9878
9879 killServicesLocked(app, true);
9880
9881 boolean restart = false;
9882
9883 int NL = mLaunchingProviders.size();
9884
9885 // Remove published content providers.
9886 if (!app.pubProviders.isEmpty()) {
9887 Iterator it = app.pubProviders.values().iterator();
9888 while (it.hasNext()) {
9889 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9890 cpr.provider = null;
9891 cpr.app = null;
9892
9893 // See if someone is waiting for this provider... in which
9894 // case we don't remove it, but just let it restart.
9895 int i = 0;
9896 if (!app.bad) {
9897 for (; i<NL; i++) {
9898 if (mLaunchingProviders.get(i) == cpr) {
9899 restart = true;
9900 break;
9901 }
9902 }
9903 } else {
9904 i = NL;
9905 }
9906
9907 if (i >= NL) {
9908 removeDyingProviderLocked(app, cpr);
9909 NL = mLaunchingProviders.size();
9910 }
9911 }
9912 app.pubProviders.clear();
9913 }
9914
9915 // Look through the content providers we are waiting to have launched,
9916 // and if any run in this process then either schedule a restart of
9917 // the process or kill the client waiting for it if this process has
9918 // gone bad.
9919 for (int i=0; i<NL; i++) {
9920 ContentProviderRecord cpr = (ContentProviderRecord)
9921 mLaunchingProviders.get(i);
9922 if (cpr.launchingApp == app) {
9923 if (!app.bad) {
9924 restart = true;
9925 } else {
9926 removeDyingProviderLocked(app, cpr);
9927 NL = mLaunchingProviders.size();
9928 }
9929 }
9930 }
9931
9932 // Unregister from connected content providers.
9933 if (!app.conProviders.isEmpty()) {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07009934 Iterator it = app.conProviders.keySet().iterator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009935 while (it.hasNext()) {
9936 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9937 cpr.clients.remove(app);
9938 }
9939 app.conProviders.clear();
9940 }
9941
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009942 // At this point there may be remaining entries in mLaunchingProviders
9943 // where we were the only one waiting, so they are no longer of use.
9944 // Look for these and clean up if found.
9945 // XXX Commented out for now. Trying to figure out a way to reproduce
9946 // the actual situation to identify what is actually going on.
9947 if (false) {
9948 for (int i=0; i<NL; i++) {
9949 ContentProviderRecord cpr = (ContentProviderRecord)
9950 mLaunchingProviders.get(i);
9951 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9952 synchronized (cpr) {
9953 cpr.launchingApp = null;
9954 cpr.notifyAll();
9955 }
9956 }
9957 }
9958 }
9959
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009960 skipCurrentReceiverLocked(app);
9961
9962 // Unregister any receivers.
9963 if (app.receivers.size() > 0) {
9964 Iterator<ReceiverList> it = app.receivers.iterator();
9965 while (it.hasNext()) {
9966 removeReceiverLocked(it.next());
9967 }
9968 app.receivers.clear();
9969 }
9970
Christopher Tate181fafa2009-05-14 11:12:14 -07009971 // If the app is undergoing backup, tell the backup manager about it
9972 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9973 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9974 try {
9975 IBackupManager bm = IBackupManager.Stub.asInterface(
9976 ServiceManager.getService(Context.BACKUP_SERVICE));
9977 bm.agentDisconnected(app.info.packageName);
9978 } catch (RemoteException e) {
9979 // can't happen; backup manager is local
9980 }
9981 }
9982
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009983 // If the caller is restarting this app, then leave it in its
9984 // current lists and let the caller take care of it.
9985 if (restarting) {
9986 return;
9987 }
9988
9989 if (!app.persistent) {
9990 if (DEBUG_PROCESSES) Log.v(TAG,
9991 "Removing non-persistent process during cleanup: " + app);
9992 mProcessNames.remove(app.processName, app.info.uid);
9993 } else if (!app.removed) {
9994 // This app is persistent, so we need to keep its record around.
9995 // If it is not already on the pending app list, add it there
9996 // and start a new process for it.
9997 app.thread = null;
9998 app.forcingToForeground = null;
9999 app.foregroundServices = false;
10000 if (mPersistentStartingProcesses.indexOf(app) < 0) {
10001 mPersistentStartingProcesses.add(app);
10002 restart = true;
10003 }
10004 }
10005 mProcessesOnHold.remove(app);
10006
The Android Open Source Project4df24232009-03-05 14:34:35 -080010007 if (app == mHomeProcess) {
10008 mHomeProcess = null;
10009 }
10010
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010011 if (restart) {
10012 // We have components that still need to be running in the
10013 // process, so re-launch it.
10014 mProcessNames.put(app.processName, app.info.uid, app);
10015 startProcessLocked(app, "restart", app.processName);
10016 } else if (app.pid > 0 && app.pid != MY_PID) {
10017 // Goodbye!
10018 synchronized (mPidsSelfLocked) {
10019 mPidsSelfLocked.remove(app.pid);
10020 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
10021 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070010022 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010023 }
10024 }
10025
10026 // =========================================================
10027 // SERVICES
10028 // =========================================================
10029
10030 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10031 ActivityManager.RunningServiceInfo info =
10032 new ActivityManager.RunningServiceInfo();
10033 info.service = r.name;
10034 if (r.app != null) {
10035 info.pid = r.app.pid;
10036 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010037 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010038 info.process = r.processName;
10039 info.foreground = r.isForeground;
10040 info.activeSince = r.createTime;
10041 info.started = r.startRequested;
10042 info.clientCount = r.connections.size();
10043 info.crashCount = r.crashCount;
10044 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010045 if (r.isForeground) {
10046 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10047 }
10048 if (r.startRequested) {
10049 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10050 }
10051 if (r.app != null && r.app.pid == Process.myPid()) {
10052 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10053 }
10054 if (r.app != null && r.app.persistent) {
10055 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10056 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010057 for (ConnectionRecord conn : r.connections.values()) {
10058 if (conn.clientLabel != 0) {
10059 info.clientPackage = conn.binding.client.info.packageName;
10060 info.clientLabel = conn.clientLabel;
10061 break;
10062 }
10063 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010064 return info;
10065 }
10066
10067 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10068 int flags) {
10069 synchronized (this) {
10070 ArrayList<ActivityManager.RunningServiceInfo> res
10071 = new ArrayList<ActivityManager.RunningServiceInfo>();
10072
10073 if (mServices.size() > 0) {
10074 Iterator<ServiceRecord> it = mServices.values().iterator();
10075 while (it.hasNext() && res.size() < maxNum) {
10076 res.add(makeRunningServiceInfoLocked(it.next()));
10077 }
10078 }
10079
10080 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10081 ServiceRecord r = mRestartingServices.get(i);
10082 ActivityManager.RunningServiceInfo info =
10083 makeRunningServiceInfoLocked(r);
10084 info.restarting = r.nextRestartTime;
10085 res.add(info);
10086 }
10087
10088 return res;
10089 }
10090 }
10091
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010092 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10093 synchronized (this) {
10094 ServiceRecord r = mServices.get(name);
10095 if (r != null) {
10096 for (ConnectionRecord conn : r.connections.values()) {
10097 if (conn.clientIntent != null) {
10098 return conn.clientIntent;
10099 }
10100 }
10101 }
10102 }
10103 return null;
10104 }
10105
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010106 private final ServiceRecord findServiceLocked(ComponentName name,
10107 IBinder token) {
10108 ServiceRecord r = mServices.get(name);
10109 return r == token ? r : null;
10110 }
10111
10112 private final class ServiceLookupResult {
10113 final ServiceRecord record;
10114 final String permission;
10115
10116 ServiceLookupResult(ServiceRecord _record, String _permission) {
10117 record = _record;
10118 permission = _permission;
10119 }
10120 };
10121
10122 private ServiceLookupResult findServiceLocked(Intent service,
10123 String resolvedType) {
10124 ServiceRecord r = null;
10125 if (service.getComponent() != null) {
10126 r = mServices.get(service.getComponent());
10127 }
10128 if (r == null) {
10129 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10130 r = mServicesByIntent.get(filter);
10131 }
10132
10133 if (r == null) {
10134 try {
10135 ResolveInfo rInfo =
10136 ActivityThread.getPackageManager().resolveService(
10137 service, resolvedType, 0);
10138 ServiceInfo sInfo =
10139 rInfo != null ? rInfo.serviceInfo : null;
10140 if (sInfo == null) {
10141 return null;
10142 }
10143
10144 ComponentName name = new ComponentName(
10145 sInfo.applicationInfo.packageName, sInfo.name);
10146 r = mServices.get(name);
10147 } catch (RemoteException ex) {
10148 // pm is in same process, this will never happen.
10149 }
10150 }
10151 if (r != null) {
10152 int callingPid = Binder.getCallingPid();
10153 int callingUid = Binder.getCallingUid();
10154 if (checkComponentPermission(r.permission,
10155 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10156 != PackageManager.PERMISSION_GRANTED) {
10157 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10158 + " from pid=" + callingPid
10159 + ", uid=" + callingUid
10160 + " requires " + r.permission);
10161 return new ServiceLookupResult(null, r.permission);
10162 }
10163 return new ServiceLookupResult(r, null);
10164 }
10165 return null;
10166 }
10167
10168 private class ServiceRestarter implements Runnable {
10169 private ServiceRecord mService;
10170
10171 void setService(ServiceRecord service) {
10172 mService = service;
10173 }
10174
10175 public void run() {
10176 synchronized(ActivityManagerService.this) {
10177 performServiceRestartLocked(mService);
10178 }
10179 }
10180 }
10181
10182 private ServiceLookupResult retrieveServiceLocked(Intent service,
10183 String resolvedType, int callingPid, int callingUid) {
10184 ServiceRecord r = null;
10185 if (service.getComponent() != null) {
10186 r = mServices.get(service.getComponent());
10187 }
10188 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10189 r = mServicesByIntent.get(filter);
10190 if (r == null) {
10191 try {
10192 ResolveInfo rInfo =
10193 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010194 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010195 ServiceInfo sInfo =
10196 rInfo != null ? rInfo.serviceInfo : null;
10197 if (sInfo == null) {
10198 Log.w(TAG, "Unable to start service " + service +
10199 ": not found");
10200 return null;
10201 }
10202
10203 ComponentName name = new ComponentName(
10204 sInfo.applicationInfo.packageName, sInfo.name);
10205 r = mServices.get(name);
10206 if (r == null) {
10207 filter = new Intent.FilterComparison(service.cloneFilter());
10208 ServiceRestarter res = new ServiceRestarter();
10209 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10210 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10211 synchronized (stats) {
10212 ss = stats.getServiceStatsLocked(
10213 sInfo.applicationInfo.uid, sInfo.packageName,
10214 sInfo.name);
10215 }
10216 r = new ServiceRecord(ss, name, filter, sInfo, res);
10217 res.setService(r);
10218 mServices.put(name, r);
10219 mServicesByIntent.put(filter, r);
10220
10221 // Make sure this component isn't in the pending list.
10222 int N = mPendingServices.size();
10223 for (int i=0; i<N; i++) {
10224 ServiceRecord pr = mPendingServices.get(i);
10225 if (pr.name.equals(name)) {
10226 mPendingServices.remove(i);
10227 i--;
10228 N--;
10229 }
10230 }
10231 }
10232 } catch (RemoteException ex) {
10233 // pm is in same process, this will never happen.
10234 }
10235 }
10236 if (r != null) {
10237 if (checkComponentPermission(r.permission,
10238 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10239 != PackageManager.PERMISSION_GRANTED) {
10240 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10241 + " from pid=" + Binder.getCallingPid()
10242 + ", uid=" + Binder.getCallingUid()
10243 + " requires " + r.permission);
10244 return new ServiceLookupResult(null, r.permission);
10245 }
10246 return new ServiceLookupResult(r, null);
10247 }
10248 return null;
10249 }
10250
10251 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10252 long now = SystemClock.uptimeMillis();
10253 if (r.executeNesting == 0 && r.app != null) {
10254 if (r.app.executingServices.size() == 0) {
10255 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10256 msg.obj = r.app;
10257 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10258 }
10259 r.app.executingServices.add(r);
10260 }
10261 r.executeNesting++;
10262 r.executingStart = now;
10263 }
10264
10265 private final void sendServiceArgsLocked(ServiceRecord r,
10266 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010267 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010268 if (N == 0) {
10269 return;
10270 }
10271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010272 int i = 0;
10273 while (i < N) {
10274 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010275 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010276 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010277 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010278 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010279 // If somehow we got a dummy start at the front, then
10280 // just drop it here.
10281 i++;
10282 continue;
10283 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010284 bumpServiceExecutingLocked(r);
10285 if (!oomAdjusted) {
10286 oomAdjusted = true;
10287 updateOomAdjLocked(r.app);
10288 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010289 int flags = 0;
10290 if (si.deliveryCount > 0) {
10291 flags |= Service.START_FLAG_RETRY;
10292 }
10293 if (si.doneExecutingCount > 0) {
10294 flags |= Service.START_FLAG_REDELIVERY;
10295 }
10296 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10297 si.deliveredTime = SystemClock.uptimeMillis();
10298 r.deliveredStarts.add(si);
10299 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010300 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010301 } catch (RemoteException e) {
10302 // Remote process gone... we'll let the normal cleanup take
10303 // care of this.
10304 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010305 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010306 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010307 break;
10308 }
10309 }
10310 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010311 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010312 } else {
10313 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010314 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010315 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010316 }
10317 }
10318 }
10319
10320 private final boolean requestServiceBindingLocked(ServiceRecord r,
10321 IntentBindRecord i, boolean rebind) {
10322 if (r.app == null || r.app.thread == null) {
10323 // If service is not currently running, can't yet bind.
10324 return false;
10325 }
10326 if ((!i.requested || rebind) && i.apps.size() > 0) {
10327 try {
10328 bumpServiceExecutingLocked(r);
10329 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10330 + ": shouldUnbind=" + i.hasBound);
10331 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10332 if (!rebind) {
10333 i.requested = true;
10334 }
10335 i.hasBound = true;
10336 i.doRebind = false;
10337 } catch (RemoteException e) {
10338 return false;
10339 }
10340 }
10341 return true;
10342 }
10343
10344 private final void requestServiceBindingsLocked(ServiceRecord r) {
10345 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10346 while (bindings.hasNext()) {
10347 IntentBindRecord i = bindings.next();
10348 if (!requestServiceBindingLocked(r, i, false)) {
10349 break;
10350 }
10351 }
10352 }
10353
10354 private final void realStartServiceLocked(ServiceRecord r,
10355 ProcessRecord app) throws RemoteException {
10356 if (app.thread == null) {
10357 throw new RemoteException();
10358 }
10359
10360 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010361 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010362
10363 app.services.add(r);
10364 bumpServiceExecutingLocked(r);
10365 updateLRUListLocked(app, true);
10366
10367 boolean created = false;
10368 try {
10369 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10370 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010371 mStringBuilder.setLength(0);
10372 r.intent.getIntent().toShortString(mStringBuilder, false, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010373 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
10374 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010375 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010376 synchronized (r.stats.getBatteryStats()) {
10377 r.stats.startLaunchedLocked();
10378 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010379 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010380 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010381 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010382 created = true;
10383 } finally {
10384 if (!created) {
10385 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010386 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010387 }
10388 }
10389
10390 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010391
10392 // If the service is in the started state, and there are no
10393 // pending arguments, then fake up one so its onStartCommand() will
10394 // be called.
10395 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10396 r.lastStartId++;
10397 if (r.lastStartId < 1) {
10398 r.lastStartId = 1;
10399 }
10400 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10401 }
10402
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010403 sendServiceArgsLocked(r, true);
10404 }
10405
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010406 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10407 boolean allowCancel) {
10408 boolean canceled = false;
10409
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010410 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010411 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010412 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010413
10414 // Any delivered but not yet finished starts should be put back
10415 // on the pending list.
10416 final int N = r.deliveredStarts.size();
10417 if (N > 0) {
10418 for (int i=N-1; i>=0; i--) {
10419 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10420 if (si.intent == null) {
10421 // We'll generate this again if needed.
10422 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10423 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10424 r.pendingStarts.add(0, si);
10425 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10426 dur *= 2;
10427 if (minDuration < dur) minDuration = dur;
10428 if (resetTime < dur) resetTime = dur;
10429 } else {
10430 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10431 + r.name);
10432 canceled = true;
10433 }
10434 }
10435 r.deliveredStarts.clear();
10436 }
10437
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010438 r.totalRestartCount++;
10439 if (r.restartDelay == 0) {
10440 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010441 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010442 } else {
10443 // If it has been a "reasonably long time" since the service
10444 // was started, then reset our restart duration back to
10445 // the beginning, so we don't infinitely increase the duration
10446 // on a service that just occasionally gets killed (which is
10447 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010448 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010449 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010450 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010451 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010452 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010453 if (r.restartDelay < minDuration) {
10454 r.restartDelay = minDuration;
10455 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010456 }
10457 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010458
10459 r.nextRestartTime = now + r.restartDelay;
10460
10461 // Make sure that we don't end up restarting a bunch of services
10462 // all at the same time.
10463 boolean repeat;
10464 do {
10465 repeat = false;
10466 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10467 ServiceRecord r2 = mRestartingServices.get(i);
10468 if (r2 != r && r.nextRestartTime
10469 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10470 && r.nextRestartTime
10471 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10472 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10473 r.restartDelay = r.nextRestartTime - now;
10474 repeat = true;
10475 break;
10476 }
10477 }
10478 } while (repeat);
10479
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010480 if (!mRestartingServices.contains(r)) {
10481 mRestartingServices.add(r);
10482 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010483
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010484 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010485
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010486 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010487 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010488 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10489 Log.w(TAG, "Scheduling restart of crashed service "
10490 + r.shortName + " in " + r.restartDelay + "ms");
10491 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10492 r.shortName, r.restartDelay);
10493
10494 Message msg = Message.obtain();
10495 msg.what = SERVICE_ERROR_MSG;
10496 msg.obj = r;
10497 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010498
10499 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010500 }
10501
10502 final void performServiceRestartLocked(ServiceRecord r) {
10503 if (!mRestartingServices.contains(r)) {
10504 return;
10505 }
10506 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10507 }
10508
10509 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10510 if (r.restartDelay == 0) {
10511 return false;
10512 }
10513 r.resetRestartCounter();
10514 mRestartingServices.remove(r);
10515 mHandler.removeCallbacks(r.restarter);
10516 return true;
10517 }
10518
10519 private final boolean bringUpServiceLocked(ServiceRecord r,
10520 int intentFlags, boolean whileRestarting) {
10521 //Log.i(TAG, "Bring up service:");
10522 //r.dump(" ");
10523
Dianne Hackborn36124872009-10-08 16:22:03 -070010524 if (r.app != null && r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010525 sendServiceArgsLocked(r, false);
10526 return true;
10527 }
10528
10529 if (!whileRestarting && r.restartDelay > 0) {
10530 // If waiting for a restart, then do nothing.
10531 return true;
10532 }
10533
10534 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10535 + " " + r.intent);
10536
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010537 // We are now bringing the service up, so no longer in the
10538 // restarting state.
10539 mRestartingServices.remove(r);
10540
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010541 final String appName = r.processName;
10542 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10543 if (app != null && app.thread != null) {
10544 try {
10545 realStartServiceLocked(r, app);
10546 return true;
10547 } catch (RemoteException e) {
10548 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10549 }
10550
10551 // If a dead object exception was thrown -- fall through to
10552 // restart the application.
10553 }
10554
Dianne Hackborn36124872009-10-08 16:22:03 -070010555 // Not running -- get it started, and enqueue this service record
10556 // to be executed when the app comes up.
10557 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10558 "service", r.name, false) == null) {
10559 Log.w(TAG, "Unable to launch app "
10560 + r.appInfo.packageName + "/"
10561 + r.appInfo.uid + " for service "
10562 + r.intent.getIntent() + ": process is bad");
10563 bringDownServiceLocked(r, true);
10564 return false;
10565 }
10566
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010567 if (!mPendingServices.contains(r)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010568 mPendingServices.add(r);
10569 }
Dianne Hackborn36124872009-10-08 16:22:03 -070010570
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010571 return true;
10572 }
10573
10574 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10575 //Log.i(TAG, "Bring down service:");
10576 //r.dump(" ");
10577
10578 // Does it still need to run?
10579 if (!force && r.startRequested) {
10580 return;
10581 }
10582 if (r.connections.size() > 0) {
10583 if (!force) {
10584 // XXX should probably keep a count of the number of auto-create
10585 // connections directly in the service.
10586 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10587 while (it.hasNext()) {
10588 ConnectionRecord cr = it.next();
10589 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10590 return;
10591 }
10592 }
10593 }
10594
10595 // Report to all of the connections that the service is no longer
10596 // available.
10597 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10598 while (it.hasNext()) {
10599 ConnectionRecord c = it.next();
10600 try {
10601 // todo: shouldn't be a synchronous call!
10602 c.conn.connected(r.name, null);
10603 } catch (Exception e) {
10604 Log.w(TAG, "Failure disconnecting service " + r.name +
10605 " to connection " + c.conn.asBinder() +
10606 " (in " + c.binding.client.processName + ")", e);
10607 }
10608 }
10609 }
10610
10611 // Tell the service that it has been unbound.
10612 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10613 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10614 while (it.hasNext()) {
10615 IntentBindRecord ibr = it.next();
10616 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10617 + ": hasBound=" + ibr.hasBound);
10618 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10619 try {
10620 bumpServiceExecutingLocked(r);
10621 updateOomAdjLocked(r.app);
10622 ibr.hasBound = false;
10623 r.app.thread.scheduleUnbindService(r,
10624 ibr.intent.getIntent());
10625 } catch (Exception e) {
10626 Log.w(TAG, "Exception when unbinding service "
10627 + r.shortName, e);
10628 serviceDoneExecutingLocked(r, true);
10629 }
10630 }
10631 }
10632 }
10633
10634 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10635 + " " + r.intent);
10636 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10637 System.identityHashCode(r), r.shortName,
10638 (r.app != null) ? r.app.pid : -1);
10639
10640 mServices.remove(r.name);
10641 mServicesByIntent.remove(r.intent);
10642 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10643 r.totalRestartCount = 0;
10644 unscheduleServiceRestartLocked(r);
10645
10646 // Also make sure it is not on the pending list.
10647 int N = mPendingServices.size();
10648 for (int i=0; i<N; i++) {
10649 if (mPendingServices.get(i) == r) {
10650 mPendingServices.remove(i);
10651 if (DEBUG_SERVICE) Log.v(
10652 TAG, "Removed pending service: " + r.shortName);
10653 i--;
10654 N--;
10655 }
10656 }
10657
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010658 r.cancelNotification();
10659 r.isForeground = false;
10660 r.foregroundId = 0;
10661 r.foregroundNoti = null;
10662
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010663 // Clear start entries.
10664 r.deliveredStarts.clear();
10665 r.pendingStarts.clear();
10666
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010667 if (r.app != null) {
10668 synchronized (r.stats.getBatteryStats()) {
10669 r.stats.stopLaunchedLocked();
10670 }
10671 r.app.services.remove(r);
10672 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010673 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010674 if (DEBUG_SERVICE) Log.v(TAG,
10675 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010676 bumpServiceExecutingLocked(r);
10677 mStoppingServices.add(r);
10678 updateOomAdjLocked(r.app);
10679 r.app.thread.scheduleStopService(r);
10680 } catch (Exception e) {
10681 Log.w(TAG, "Exception when stopping service "
10682 + r.shortName, e);
10683 serviceDoneExecutingLocked(r, true);
10684 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010685 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010686 } else {
10687 if (DEBUG_SERVICE) Log.v(
10688 TAG, "Removed service that has no process: " + r.shortName);
10689 }
10690 } else {
10691 if (DEBUG_SERVICE) Log.v(
10692 TAG, "Removed service that is not running: " + r.shortName);
10693 }
10694 }
10695
10696 ComponentName startServiceLocked(IApplicationThread caller,
10697 Intent service, String resolvedType,
10698 int callingPid, int callingUid) {
10699 synchronized(this) {
10700 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10701 + " type=" + resolvedType + " args=" + service.getExtras());
10702
10703 if (caller != null) {
10704 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10705 if (callerApp == null) {
10706 throw new SecurityException(
10707 "Unable to find app for caller " + caller
10708 + " (pid=" + Binder.getCallingPid()
10709 + ") when starting service " + service);
10710 }
10711 }
10712
10713 ServiceLookupResult res =
10714 retrieveServiceLocked(service, resolvedType,
10715 callingPid, callingUid);
10716 if (res == null) {
10717 return null;
10718 }
10719 if (res.record == null) {
10720 return new ComponentName("!", res.permission != null
10721 ? res.permission : "private to package");
10722 }
10723 ServiceRecord r = res.record;
10724 if (unscheduleServiceRestartLocked(r)) {
10725 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10726 + r.shortName);
10727 }
10728 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010729 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010730 r.lastStartId++;
10731 if (r.lastStartId < 1) {
10732 r.lastStartId = 1;
10733 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010734 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010735 r.lastActivity = SystemClock.uptimeMillis();
10736 synchronized (r.stats.getBatteryStats()) {
10737 r.stats.startRunningLocked();
10738 }
10739 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10740 return new ComponentName("!", "Service process is bad");
10741 }
10742 return r.name;
10743 }
10744 }
10745
10746 public ComponentName startService(IApplicationThread caller, Intent service,
10747 String resolvedType) {
10748 // Refuse possible leaked file descriptors
10749 if (service != null && service.hasFileDescriptors() == true) {
10750 throw new IllegalArgumentException("File descriptors passed in Intent");
10751 }
10752
10753 synchronized(this) {
10754 final int callingPid = Binder.getCallingPid();
10755 final int callingUid = Binder.getCallingUid();
10756 final long origId = Binder.clearCallingIdentity();
10757 ComponentName res = startServiceLocked(caller, service,
10758 resolvedType, callingPid, callingUid);
10759 Binder.restoreCallingIdentity(origId);
10760 return res;
10761 }
10762 }
10763
10764 ComponentName startServiceInPackage(int uid,
10765 Intent service, String resolvedType) {
10766 synchronized(this) {
10767 final long origId = Binder.clearCallingIdentity();
10768 ComponentName res = startServiceLocked(null, service,
10769 resolvedType, -1, uid);
10770 Binder.restoreCallingIdentity(origId);
10771 return res;
10772 }
10773 }
10774
10775 public int stopService(IApplicationThread caller, Intent service,
10776 String resolvedType) {
10777 // Refuse possible leaked file descriptors
10778 if (service != null && service.hasFileDescriptors() == true) {
10779 throw new IllegalArgumentException("File descriptors passed in Intent");
10780 }
10781
10782 synchronized(this) {
10783 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10784 + " type=" + resolvedType);
10785
10786 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10787 if (caller != null && callerApp == null) {
10788 throw new SecurityException(
10789 "Unable to find app for caller " + caller
10790 + " (pid=" + Binder.getCallingPid()
10791 + ") when stopping service " + service);
10792 }
10793
10794 // If this service is active, make sure it is stopped.
10795 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10796 if (r != null) {
10797 if (r.record != null) {
10798 synchronized (r.record.stats.getBatteryStats()) {
10799 r.record.stats.stopRunningLocked();
10800 }
10801 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010802 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010803 final long origId = Binder.clearCallingIdentity();
10804 bringDownServiceLocked(r.record, false);
10805 Binder.restoreCallingIdentity(origId);
10806 return 1;
10807 }
10808 return -1;
10809 }
10810 }
10811
10812 return 0;
10813 }
10814
10815 public IBinder peekService(Intent service, String resolvedType) {
10816 // Refuse possible leaked file descriptors
10817 if (service != null && service.hasFileDescriptors() == true) {
10818 throw new IllegalArgumentException("File descriptors passed in Intent");
10819 }
10820
10821 IBinder ret = null;
10822
10823 synchronized(this) {
10824 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10825
10826 if (r != null) {
10827 // r.record is null if findServiceLocked() failed the caller permission check
10828 if (r.record == null) {
10829 throw new SecurityException(
10830 "Permission Denial: Accessing service " + r.record.name
10831 + " from pid=" + Binder.getCallingPid()
10832 + ", uid=" + Binder.getCallingUid()
10833 + " requires " + r.permission);
10834 }
10835 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10836 if (ib != null) {
10837 ret = ib.binder;
10838 }
10839 }
10840 }
10841
10842 return ret;
10843 }
10844
10845 public boolean stopServiceToken(ComponentName className, IBinder token,
10846 int startId) {
10847 synchronized(this) {
10848 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10849 + " " + token + " startId=" + startId);
10850 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010851 if (r != null) {
10852 if (startId >= 0) {
10853 // Asked to only stop if done with all work. Note that
10854 // to avoid leaks, we will take this as dropping all
10855 // start items up to and including this one.
10856 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10857 if (si != null) {
10858 while (r.deliveredStarts.size() > 0) {
10859 if (r.deliveredStarts.remove(0) == si) {
10860 break;
10861 }
10862 }
10863 }
10864
10865 if (r.lastStartId != startId) {
10866 return false;
10867 }
10868
10869 if (r.deliveredStarts.size() > 0) {
10870 Log.w(TAG, "stopServiceToken startId " + startId
10871 + " is last, but have " + r.deliveredStarts.size()
10872 + " remaining args");
10873 }
10874 }
10875
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010876 synchronized (r.stats.getBatteryStats()) {
10877 r.stats.stopRunningLocked();
10878 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010879 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010880 }
10881 final long origId = Binder.clearCallingIdentity();
10882 bringDownServiceLocked(r, false);
10883 Binder.restoreCallingIdentity(origId);
10884 return true;
10885 }
10886 }
10887 return false;
10888 }
10889
10890 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010891 int id, Notification notification, boolean removeNotification) {
10892 final long origId = Binder.clearCallingIdentity();
10893 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010894 synchronized(this) {
10895 ServiceRecord r = findServiceLocked(className, token);
10896 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010897 if (id != 0) {
10898 if (notification == null) {
10899 throw new IllegalArgumentException("null notification");
10900 }
10901 if (r.foregroundId != id) {
10902 r.cancelNotification();
10903 r.foregroundId = id;
10904 }
10905 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10906 r.foregroundNoti = notification;
10907 r.isForeground = true;
10908 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010909 if (r.app != null) {
10910 updateServiceForegroundLocked(r.app, true);
10911 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010912 } else {
10913 if (r.isForeground) {
10914 r.isForeground = false;
10915 if (r.app != null) {
10916 updateServiceForegroundLocked(r.app, true);
10917 }
10918 }
10919 if (removeNotification) {
10920 r.cancelNotification();
10921 r.foregroundId = 0;
10922 r.foregroundNoti = null;
10923 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010924 }
10925 }
10926 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010927 } finally {
10928 Binder.restoreCallingIdentity(origId);
10929 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010930 }
10931
10932 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10933 boolean anyForeground = false;
10934 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10935 if (sr.isForeground) {
10936 anyForeground = true;
10937 break;
10938 }
10939 }
10940 if (anyForeground != proc.foregroundServices) {
10941 proc.foregroundServices = anyForeground;
10942 if (oomAdj) {
10943 updateOomAdjLocked();
10944 }
10945 }
10946 }
10947
10948 public int bindService(IApplicationThread caller, IBinder token,
10949 Intent service, String resolvedType,
10950 IServiceConnection connection, int flags) {
10951 // Refuse possible leaked file descriptors
10952 if (service != null && service.hasFileDescriptors() == true) {
10953 throw new IllegalArgumentException("File descriptors passed in Intent");
10954 }
10955
10956 synchronized(this) {
10957 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10958 + " type=" + resolvedType + " conn=" + connection.asBinder()
10959 + " flags=0x" + Integer.toHexString(flags));
10960 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10961 if (callerApp == null) {
10962 throw new SecurityException(
10963 "Unable to find app for caller " + caller
10964 + " (pid=" + Binder.getCallingPid()
10965 + ") when binding service " + service);
10966 }
10967
10968 HistoryRecord activity = null;
10969 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010970 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010971 if (aindex < 0) {
10972 Log.w(TAG, "Binding with unknown activity: " + token);
10973 return 0;
10974 }
10975 activity = (HistoryRecord)mHistory.get(aindex);
10976 }
10977
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010978 int clientLabel = 0;
10979 PendingIntent clientIntent = null;
10980
10981 if (callerApp.info.uid == Process.SYSTEM_UID) {
10982 // Hacky kind of thing -- allow system stuff to tell us
10983 // what they are, so we can report this elsewhere for
10984 // others to know why certain services are running.
10985 try {
10986 clientIntent = (PendingIntent)service.getParcelableExtra(
10987 Intent.EXTRA_CLIENT_INTENT);
10988 } catch (RuntimeException e) {
10989 }
10990 if (clientIntent != null) {
10991 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
10992 if (clientLabel != 0) {
10993 // There are no useful extras in the intent, trash them.
10994 // System code calling with this stuff just needs to know
10995 // this will happen.
10996 service = service.cloneFilter();
10997 }
10998 }
10999 }
11000
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011001 ServiceLookupResult res =
11002 retrieveServiceLocked(service, resolvedType,
11003 Binder.getCallingPid(), Binder.getCallingUid());
11004 if (res == null) {
11005 return 0;
11006 }
11007 if (res.record == null) {
11008 return -1;
11009 }
11010 ServiceRecord s = res.record;
11011
11012 final long origId = Binder.clearCallingIdentity();
11013
11014 if (unscheduleServiceRestartLocked(s)) {
11015 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
11016 + s.shortName);
11017 }
11018
11019 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
11020 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011021 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011022
11023 IBinder binder = connection.asBinder();
11024 s.connections.put(binder, c);
11025 b.connections.add(c);
11026 if (activity != null) {
11027 if (activity.connections == null) {
11028 activity.connections = new HashSet<ConnectionRecord>();
11029 }
11030 activity.connections.add(c);
11031 }
11032 b.client.connections.add(c);
11033 mServiceConnections.put(binder, c);
11034
11035 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11036 s.lastActivity = SystemClock.uptimeMillis();
11037 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11038 return 0;
11039 }
11040 }
11041
11042 if (s.app != null) {
11043 // This could have made the service more important.
11044 updateOomAdjLocked(s.app);
11045 }
11046
11047 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11048 + ": received=" + b.intent.received
11049 + " apps=" + b.intent.apps.size()
11050 + " doRebind=" + b.intent.doRebind);
11051
11052 if (s.app != null && b.intent.received) {
11053 // Service is already running, so we can immediately
11054 // publish the connection.
11055 try {
11056 c.conn.connected(s.name, b.intent.binder);
11057 } catch (Exception e) {
11058 Log.w(TAG, "Failure sending service " + s.shortName
11059 + " to connection " + c.conn.asBinder()
11060 + " (in " + c.binding.client.processName + ")", e);
11061 }
11062
11063 // If this is the first app connected back to this binding,
11064 // and the service had previously asked to be told when
11065 // rebound, then do so.
11066 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11067 requestServiceBindingLocked(s, b.intent, true);
11068 }
11069 } else if (!b.intent.requested) {
11070 requestServiceBindingLocked(s, b.intent, false);
11071 }
11072
11073 Binder.restoreCallingIdentity(origId);
11074 }
11075
11076 return 1;
11077 }
11078
11079 private void removeConnectionLocked(
11080 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11081 IBinder binder = c.conn.asBinder();
11082 AppBindRecord b = c.binding;
11083 ServiceRecord s = b.service;
11084 s.connections.remove(binder);
11085 b.connections.remove(c);
11086 if (c.activity != null && c.activity != skipAct) {
11087 if (c.activity.connections != null) {
11088 c.activity.connections.remove(c);
11089 }
11090 }
11091 if (b.client != skipApp) {
11092 b.client.connections.remove(c);
11093 }
11094 mServiceConnections.remove(binder);
11095
11096 if (b.connections.size() == 0) {
11097 b.intent.apps.remove(b.client);
11098 }
11099
11100 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11101 + ": shouldUnbind=" + b.intent.hasBound);
11102 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11103 && b.intent.hasBound) {
11104 try {
11105 bumpServiceExecutingLocked(s);
11106 updateOomAdjLocked(s.app);
11107 b.intent.hasBound = false;
11108 // Assume the client doesn't want to know about a rebind;
11109 // we will deal with that later if it asks for one.
11110 b.intent.doRebind = false;
11111 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11112 } catch (Exception e) {
11113 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11114 serviceDoneExecutingLocked(s, true);
11115 }
11116 }
11117
11118 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11119 bringDownServiceLocked(s, false);
11120 }
11121 }
11122
11123 public boolean unbindService(IServiceConnection connection) {
11124 synchronized (this) {
11125 IBinder binder = connection.asBinder();
11126 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11127 ConnectionRecord r = mServiceConnections.get(binder);
11128 if (r == null) {
11129 Log.w(TAG, "Unbind failed: could not find connection for "
11130 + connection.asBinder());
11131 return false;
11132 }
11133
11134 final long origId = Binder.clearCallingIdentity();
11135
11136 removeConnectionLocked(r, null, null);
11137
11138 if (r.binding.service.app != null) {
11139 // This could have made the service less important.
11140 updateOomAdjLocked(r.binding.service.app);
11141 }
11142
11143 Binder.restoreCallingIdentity(origId);
11144 }
11145
11146 return true;
11147 }
11148
11149 public void publishService(IBinder token, Intent intent, IBinder service) {
11150 // Refuse possible leaked file descriptors
11151 if (intent != null && intent.hasFileDescriptors() == true) {
11152 throw new IllegalArgumentException("File descriptors passed in Intent");
11153 }
11154
11155 synchronized(this) {
11156 if (!(token instanceof ServiceRecord)) {
11157 throw new IllegalArgumentException("Invalid service token");
11158 }
11159 ServiceRecord r = (ServiceRecord)token;
11160
11161 final long origId = Binder.clearCallingIdentity();
11162
11163 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11164 + " " + intent + ": " + service);
11165 if (r != null) {
11166 Intent.FilterComparison filter
11167 = new Intent.FilterComparison(intent);
11168 IntentBindRecord b = r.bindings.get(filter);
11169 if (b != null && !b.received) {
11170 b.binder = service;
11171 b.requested = true;
11172 b.received = true;
11173 if (r.connections.size() > 0) {
11174 Iterator<ConnectionRecord> it
11175 = r.connections.values().iterator();
11176 while (it.hasNext()) {
11177 ConnectionRecord c = it.next();
11178 if (!filter.equals(c.binding.intent.intent)) {
11179 if (DEBUG_SERVICE) Log.v(
11180 TAG, "Not publishing to: " + c);
11181 if (DEBUG_SERVICE) Log.v(
11182 TAG, "Bound intent: " + c.binding.intent.intent);
11183 if (DEBUG_SERVICE) Log.v(
11184 TAG, "Published intent: " + intent);
11185 continue;
11186 }
11187 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11188 try {
11189 c.conn.connected(r.name, service);
11190 } catch (Exception e) {
11191 Log.w(TAG, "Failure sending service " + r.name +
11192 " to connection " + c.conn.asBinder() +
11193 " (in " + c.binding.client.processName + ")", e);
11194 }
11195 }
11196 }
11197 }
11198
11199 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11200
11201 Binder.restoreCallingIdentity(origId);
11202 }
11203 }
11204 }
11205
11206 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11207 // Refuse possible leaked file descriptors
11208 if (intent != null && intent.hasFileDescriptors() == true) {
11209 throw new IllegalArgumentException("File descriptors passed in Intent");
11210 }
11211
11212 synchronized(this) {
11213 if (!(token instanceof ServiceRecord)) {
11214 throw new IllegalArgumentException("Invalid service token");
11215 }
11216 ServiceRecord r = (ServiceRecord)token;
11217
11218 final long origId = Binder.clearCallingIdentity();
11219
11220 if (r != null) {
11221 Intent.FilterComparison filter
11222 = new Intent.FilterComparison(intent);
11223 IntentBindRecord b = r.bindings.get(filter);
11224 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11225 + " at " + b + ": apps="
11226 + (b != null ? b.apps.size() : 0));
11227 if (b != null) {
11228 if (b.apps.size() > 0) {
11229 // Applications have already bound since the last
11230 // unbind, so just rebind right here.
11231 requestServiceBindingLocked(r, b, true);
11232 } else {
11233 // Note to tell the service the next time there is
11234 // a new client.
11235 b.doRebind = true;
11236 }
11237 }
11238
11239 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11240
11241 Binder.restoreCallingIdentity(origId);
11242 }
11243 }
11244 }
11245
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011246 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011247 synchronized(this) {
11248 if (!(token instanceof ServiceRecord)) {
11249 throw new IllegalArgumentException("Invalid service token");
11250 }
11251 ServiceRecord r = (ServiceRecord)token;
11252 boolean inStopping = mStoppingServices.contains(token);
11253 if (r != null) {
11254 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11255 + ": nesting=" + r.executeNesting
11256 + ", inStopping=" + inStopping);
11257 if (r != token) {
11258 Log.w(TAG, "Done executing service " + r.name
11259 + " with incorrect token: given " + token
11260 + ", expected " + r);
11261 return;
11262 }
11263
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011264 if (type == 1) {
11265 // This is a call from a service start... take care of
11266 // book-keeping.
11267 r.callStart = true;
11268 switch (res) {
11269 case Service.START_STICKY_COMPATIBILITY:
11270 case Service.START_STICKY: {
11271 // We are done with the associated start arguments.
11272 r.findDeliveredStart(startId, true);
11273 // Don't stop if killed.
11274 r.stopIfKilled = false;
11275 break;
11276 }
11277 case Service.START_NOT_STICKY: {
11278 // We are done with the associated start arguments.
11279 r.findDeliveredStart(startId, true);
11280 if (r.lastStartId == startId) {
11281 // There is no more work, and this service
11282 // doesn't want to hang around if killed.
11283 r.stopIfKilled = true;
11284 }
11285 break;
11286 }
11287 case Service.START_REDELIVER_INTENT: {
11288 // We'll keep this item until they explicitly
11289 // call stop for it, but keep track of the fact
11290 // that it was delivered.
11291 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11292 if (si != null) {
11293 si.deliveryCount = 0;
11294 si.doneExecutingCount++;
11295 // Don't stop if killed.
11296 r.stopIfKilled = true;
11297 }
11298 break;
11299 }
11300 default:
11301 throw new IllegalArgumentException(
11302 "Unknown service start result: " + res);
11303 }
11304 if (res == Service.START_STICKY_COMPATIBILITY) {
11305 r.callStart = false;
11306 }
11307 }
11308
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011309 final long origId = Binder.clearCallingIdentity();
11310 serviceDoneExecutingLocked(r, inStopping);
11311 Binder.restoreCallingIdentity(origId);
11312 } else {
11313 Log.w(TAG, "Done executing unknown service " + r.name
11314 + " with token " + token);
11315 }
11316 }
11317 }
11318
11319 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11320 r.executeNesting--;
11321 if (r.executeNesting <= 0 && r.app != null) {
11322 r.app.executingServices.remove(r);
11323 if (r.app.executingServices.size() == 0) {
11324 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11325 }
11326 if (inStopping) {
11327 mStoppingServices.remove(r);
11328 }
11329 updateOomAdjLocked(r.app);
11330 }
11331 }
11332
11333 void serviceTimeout(ProcessRecord proc) {
11334 synchronized(this) {
11335 if (proc.executingServices.size() == 0 || proc.thread == null) {
11336 return;
11337 }
11338 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11339 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11340 ServiceRecord timeout = null;
11341 long nextTime = 0;
11342 while (it.hasNext()) {
11343 ServiceRecord sr = it.next();
11344 if (sr.executingStart < maxTime) {
11345 timeout = sr;
11346 break;
11347 }
11348 if (sr.executingStart > nextTime) {
11349 nextTime = sr.executingStart;
11350 }
11351 }
11352 if (timeout != null && mLRUProcesses.contains(proc)) {
11353 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011354 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011355 + timeout.name);
11356 } else {
11357 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11358 msg.obj = proc;
11359 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11360 }
11361 }
11362 }
11363
11364 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011365 // BACKUP AND RESTORE
11366 // =========================================================
11367
11368 // Cause the target app to be launched if necessary and its backup agent
11369 // instantiated. The backup agent will invoke backupAgentCreated() on the
11370 // activity manager to announce its creation.
11371 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11372 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11373 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11374
11375 synchronized(this) {
11376 // !!! TODO: currently no check here that we're already bound
11377 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11378 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11379 synchronized (stats) {
11380 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11381 }
11382
11383 BackupRecord r = new BackupRecord(ss, app, backupMode);
11384 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11385 // startProcessLocked() returns existing proc's record if it's already running
11386 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011387 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011388 if (proc == null) {
11389 Log.e(TAG, "Unable to start backup agent process " + r);
11390 return false;
11391 }
11392
11393 r.app = proc;
11394 mBackupTarget = r;
11395 mBackupAppName = app.packageName;
11396
Christopher Tate6fa95972009-06-05 18:43:55 -070011397 // Try not to kill the process during backup
11398 updateOomAdjLocked(proc);
11399
Christopher Tate181fafa2009-05-14 11:12:14 -070011400 // If the process is already attached, schedule the creation of the backup agent now.
11401 // If it is not yet live, this will be done when it attaches to the framework.
11402 if (proc.thread != null) {
11403 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11404 try {
11405 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11406 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011407 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011408 }
11409 } else {
11410 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11411 }
11412 // Invariants: at this point, the target app process exists and the application
11413 // is either already running or in the process of coming up. mBackupTarget and
11414 // mBackupAppName describe the app, so that when it binds back to the AM we
11415 // know that it's scheduled for a backup-agent operation.
11416 }
11417
11418 return true;
11419 }
11420
11421 // A backup agent has just come up
11422 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11423 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11424 + " = " + agent);
11425
11426 synchronized(this) {
11427 if (!agentPackageName.equals(mBackupAppName)) {
11428 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11429 return;
11430 }
11431
Christopher Tate043dadc2009-06-02 16:11:00 -070011432 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011433 try {
11434 IBackupManager bm = IBackupManager.Stub.asInterface(
11435 ServiceManager.getService(Context.BACKUP_SERVICE));
11436 bm.agentConnected(agentPackageName, agent);
11437 } catch (RemoteException e) {
11438 // can't happen; the backup manager service is local
11439 } catch (Exception e) {
11440 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11441 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011442 } finally {
11443 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011444 }
11445 }
11446 }
11447
11448 // done with this agent
11449 public void unbindBackupAgent(ApplicationInfo appInfo) {
11450 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011451 if (appInfo == null) {
11452 Log.w(TAG, "unbind backup agent for null app");
11453 return;
11454 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011455
11456 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011457 if (mBackupAppName == null) {
11458 Log.w(TAG, "Unbinding backup agent with no active backup");
11459 return;
11460 }
11461
Christopher Tate181fafa2009-05-14 11:12:14 -070011462 if (!mBackupAppName.equals(appInfo.packageName)) {
11463 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11464 return;
11465 }
11466
Christopher Tate6fa95972009-06-05 18:43:55 -070011467 ProcessRecord proc = mBackupTarget.app;
11468 mBackupTarget = null;
11469 mBackupAppName = null;
11470
11471 // Not backing this app up any more; reset its OOM adjustment
11472 updateOomAdjLocked(proc);
11473
Christopher Tatec7b31e32009-06-10 15:49:30 -070011474 // If the app crashed during backup, 'thread' will be null here
11475 if (proc.thread != null) {
11476 try {
11477 proc.thread.scheduleDestroyBackupAgent(appInfo);
11478 } catch (Exception e) {
11479 Log.e(TAG, "Exception when unbinding backup agent:");
11480 e.printStackTrace();
11481 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011482 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011483 }
11484 }
11485 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011486 // BROADCASTS
11487 // =========================================================
11488
11489 private final List getStickies(String action, IntentFilter filter,
11490 List cur) {
11491 final ContentResolver resolver = mContext.getContentResolver();
11492 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11493 if (list == null) {
11494 return cur;
11495 }
11496 int N = list.size();
11497 for (int i=0; i<N; i++) {
11498 Intent intent = list.get(i);
11499 if (filter.match(resolver, intent, true, TAG) >= 0) {
11500 if (cur == null) {
11501 cur = new ArrayList<Intent>();
11502 }
11503 cur.add(intent);
11504 }
11505 }
11506 return cur;
11507 }
11508
11509 private final void scheduleBroadcastsLocked() {
11510 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11511 + mBroadcastsScheduled);
11512
11513 if (mBroadcastsScheduled) {
11514 return;
11515 }
11516 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11517 mBroadcastsScheduled = true;
11518 }
11519
11520 public Intent registerReceiver(IApplicationThread caller,
11521 IIntentReceiver receiver, IntentFilter filter, String permission) {
11522 synchronized(this) {
11523 ProcessRecord callerApp = null;
11524 if (caller != null) {
11525 callerApp = getRecordForAppLocked(caller);
11526 if (callerApp == null) {
11527 throw new SecurityException(
11528 "Unable to find app for caller " + caller
11529 + " (pid=" + Binder.getCallingPid()
11530 + ") when registering receiver " + receiver);
11531 }
11532 }
11533
11534 List allSticky = null;
11535
11536 // Look for any matching sticky broadcasts...
11537 Iterator actions = filter.actionsIterator();
11538 if (actions != null) {
11539 while (actions.hasNext()) {
11540 String action = (String)actions.next();
11541 allSticky = getStickies(action, filter, allSticky);
11542 }
11543 } else {
11544 allSticky = getStickies(null, filter, allSticky);
11545 }
11546
11547 // The first sticky in the list is returned directly back to
11548 // the client.
11549 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11550
11551 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11552 + ": " + sticky);
11553
11554 if (receiver == null) {
11555 return sticky;
11556 }
11557
11558 ReceiverList rl
11559 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11560 if (rl == null) {
11561 rl = new ReceiverList(this, callerApp,
11562 Binder.getCallingPid(),
11563 Binder.getCallingUid(), receiver);
11564 if (rl.app != null) {
11565 rl.app.receivers.add(rl);
11566 } else {
11567 try {
11568 receiver.asBinder().linkToDeath(rl, 0);
11569 } catch (RemoteException e) {
11570 return sticky;
11571 }
11572 rl.linkedToDeath = true;
11573 }
11574 mRegisteredReceivers.put(receiver.asBinder(), rl);
11575 }
11576 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11577 rl.add(bf);
11578 if (!bf.debugCheck()) {
11579 Log.w(TAG, "==> For Dynamic broadast");
11580 }
11581 mReceiverResolver.addFilter(bf);
11582
11583 // Enqueue broadcasts for all existing stickies that match
11584 // this filter.
11585 if (allSticky != null) {
11586 ArrayList receivers = new ArrayList();
11587 receivers.add(bf);
11588
11589 int N = allSticky.size();
11590 for (int i=0; i<N; i++) {
11591 Intent intent = (Intent)allSticky.get(i);
11592 BroadcastRecord r = new BroadcastRecord(intent, null,
11593 null, -1, -1, null, receivers, null, 0, null, null,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070011594 false, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011595 if (mParallelBroadcasts.size() == 0) {
11596 scheduleBroadcastsLocked();
11597 }
11598 mParallelBroadcasts.add(r);
11599 }
11600 }
11601
11602 return sticky;
11603 }
11604 }
11605
11606 public void unregisterReceiver(IIntentReceiver receiver) {
11607 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11608
11609 boolean doNext = false;
11610
11611 synchronized(this) {
11612 ReceiverList rl
11613 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11614 if (rl != null) {
11615 if (rl.curBroadcast != null) {
11616 BroadcastRecord r = rl.curBroadcast;
11617 doNext = finishReceiverLocked(
11618 receiver.asBinder(), r.resultCode, r.resultData,
11619 r.resultExtras, r.resultAbort, true);
11620 }
11621
11622 if (rl.app != null) {
11623 rl.app.receivers.remove(rl);
11624 }
11625 removeReceiverLocked(rl);
11626 if (rl.linkedToDeath) {
11627 rl.linkedToDeath = false;
11628 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11629 }
11630 }
11631 }
11632
11633 if (!doNext) {
11634 return;
11635 }
11636
11637 final long origId = Binder.clearCallingIdentity();
11638 processNextBroadcast(false);
11639 trimApplications();
11640 Binder.restoreCallingIdentity(origId);
11641 }
11642
11643 void removeReceiverLocked(ReceiverList rl) {
11644 mRegisteredReceivers.remove(rl.receiver.asBinder());
11645 int N = rl.size();
11646 for (int i=0; i<N; i++) {
11647 mReceiverResolver.removeFilter(rl.get(i));
11648 }
11649 }
11650
11651 private final int broadcastIntentLocked(ProcessRecord callerApp,
11652 String callerPackage, Intent intent, String resolvedType,
11653 IIntentReceiver resultTo, int resultCode, String resultData,
11654 Bundle map, String requiredPermission,
11655 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11656 intent = new Intent(intent);
11657
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011658 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011659 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11660 + " ordered=" + ordered);
11661 if ((resultTo != null) && !ordered) {
11662 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11663 }
11664
11665 // Handle special intents: if this broadcast is from the package
11666 // manager about a package being removed, we need to remove all of
11667 // its activities from the history stack.
11668 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11669 intent.getAction());
11670 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11671 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11672 || uidRemoved) {
11673 if (checkComponentPermission(
11674 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11675 callingPid, callingUid, -1)
11676 == PackageManager.PERMISSION_GRANTED) {
11677 if (uidRemoved) {
11678 final Bundle intentExtras = intent.getExtras();
11679 final int uid = intentExtras != null
11680 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11681 if (uid >= 0) {
11682 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11683 synchronized (bs) {
11684 bs.removeUidStatsLocked(uid);
11685 }
11686 }
11687 } else {
11688 Uri data = intent.getData();
11689 String ssp;
11690 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11691 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11692 uninstallPackageLocked(ssp,
11693 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011694 AttributeCache ac = AttributeCache.instance();
11695 if (ac != null) {
11696 ac.removePackage(ssp);
11697 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011698 }
11699 }
11700 }
11701 } else {
11702 String msg = "Permission Denial: " + intent.getAction()
11703 + " broadcast from " + callerPackage + " (pid=" + callingPid
11704 + ", uid=" + callingUid + ")"
11705 + " requires "
11706 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11707 Log.w(TAG, msg);
11708 throw new SecurityException(msg);
11709 }
11710 }
11711
11712 /*
11713 * If this is the time zone changed action, queue up a message that will reset the timezone
11714 * of all currently running processes. This message will get queued up before the broadcast
11715 * happens.
11716 */
11717 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11718 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11719 }
11720
Dianne Hackborn854060af2009-07-09 18:14:31 -070011721 /*
11722 * Prevent non-system code (defined here to be non-persistent
11723 * processes) from sending protected broadcasts.
11724 */
11725 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11726 || callingUid == Process.SHELL_UID || callingUid == 0) {
11727 // Always okay.
11728 } else if (callerApp == null || !callerApp.persistent) {
11729 try {
11730 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11731 intent.getAction())) {
11732 String msg = "Permission Denial: not allowed to send broadcast "
11733 + intent.getAction() + " from pid="
11734 + callingPid + ", uid=" + callingUid;
11735 Log.w(TAG, msg);
11736 throw new SecurityException(msg);
11737 }
11738 } catch (RemoteException e) {
11739 Log.w(TAG, "Remote exception", e);
11740 return BROADCAST_SUCCESS;
11741 }
11742 }
11743
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011744 // Add to the sticky list if requested.
11745 if (sticky) {
11746 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11747 callingPid, callingUid)
11748 != PackageManager.PERMISSION_GRANTED) {
11749 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11750 + callingPid + ", uid=" + callingUid
11751 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11752 Log.w(TAG, msg);
11753 throw new SecurityException(msg);
11754 }
11755 if (requiredPermission != null) {
11756 Log.w(TAG, "Can't broadcast sticky intent " + intent
11757 + " and enforce permission " + requiredPermission);
11758 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11759 }
11760 if (intent.getComponent() != null) {
11761 throw new SecurityException(
11762 "Sticky broadcasts can't target a specific component");
11763 }
11764 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11765 if (list == null) {
11766 list = new ArrayList<Intent>();
11767 mStickyBroadcasts.put(intent.getAction(), list);
11768 }
11769 int N = list.size();
11770 int i;
11771 for (i=0; i<N; i++) {
11772 if (intent.filterEquals(list.get(i))) {
11773 // This sticky already exists, replace it.
11774 list.set(i, new Intent(intent));
11775 break;
11776 }
11777 }
11778 if (i >= N) {
11779 list.add(new Intent(intent));
11780 }
11781 }
11782
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011783 // Figure out who all will receive this broadcast.
11784 List receivers = null;
11785 List<BroadcastFilter> registeredReceivers = null;
11786 try {
11787 if (intent.getComponent() != null) {
11788 // Broadcast is going to one specific receiver class...
11789 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011790 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011791 if (ai != null) {
11792 receivers = new ArrayList();
11793 ResolveInfo ri = new ResolveInfo();
11794 ri.activityInfo = ai;
11795 receivers.add(ri);
11796 }
11797 } else {
11798 // Need to resolve the intent to interested receivers...
11799 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11800 == 0) {
11801 receivers =
11802 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011803 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011804 }
Mihai Preda074edef2009-05-18 17:13:31 +020011805 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011806 }
11807 } catch (RemoteException ex) {
11808 // pm is in same process, this will never happen.
11809 }
11810
11811 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11812 if (!ordered && NR > 0) {
11813 // If we are not serializing this broadcast, then send the
11814 // registered receivers separately so they don't wait for the
11815 // components to be launched.
11816 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11817 callerPackage, callingPid, callingUid, requiredPermission,
11818 registeredReceivers, resultTo, resultCode, resultData, map,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070011819 ordered, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011820 if (DEBUG_BROADCAST) Log.v(
11821 TAG, "Enqueueing parallel broadcast " + r
11822 + ": prev had " + mParallelBroadcasts.size());
11823 mParallelBroadcasts.add(r);
11824 scheduleBroadcastsLocked();
11825 registeredReceivers = null;
11826 NR = 0;
11827 }
11828
11829 // Merge into one list.
11830 int ir = 0;
11831 if (receivers != null) {
11832 // A special case for PACKAGE_ADDED: do not allow the package
11833 // being added to see this broadcast. This prevents them from
11834 // using this as a back door to get run as soon as they are
11835 // installed. Maybe in the future we want to have a special install
11836 // broadcast or such for apps, but we'd like to deliberately make
11837 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011838 boolean skip = false;
11839 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011840 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011841 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11842 skip = true;
11843 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11844 skip = true;
11845 }
11846 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011847 ? intent.getData().getSchemeSpecificPart()
11848 : null;
11849 if (skipPackage != null && receivers != null) {
11850 int NT = receivers.size();
11851 for (int it=0; it<NT; it++) {
11852 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11853 if (curt.activityInfo.packageName.equals(skipPackage)) {
11854 receivers.remove(it);
11855 it--;
11856 NT--;
11857 }
11858 }
11859 }
11860
11861 int NT = receivers != null ? receivers.size() : 0;
11862 int it = 0;
11863 ResolveInfo curt = null;
11864 BroadcastFilter curr = null;
11865 while (it < NT && ir < NR) {
11866 if (curt == null) {
11867 curt = (ResolveInfo)receivers.get(it);
11868 }
11869 if (curr == null) {
11870 curr = registeredReceivers.get(ir);
11871 }
11872 if (curr.getPriority() >= curt.priority) {
11873 // Insert this broadcast record into the final list.
11874 receivers.add(it, curr);
11875 ir++;
11876 curr = null;
11877 it++;
11878 NT++;
11879 } else {
11880 // Skip to the next ResolveInfo in the final list.
11881 it++;
11882 curt = null;
11883 }
11884 }
11885 }
11886 while (ir < NR) {
11887 if (receivers == null) {
11888 receivers = new ArrayList();
11889 }
11890 receivers.add(registeredReceivers.get(ir));
11891 ir++;
11892 }
11893
11894 if ((receivers != null && receivers.size() > 0)
11895 || resultTo != null) {
11896 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11897 callerPackage, callingPid, callingUid, requiredPermission,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070011898 receivers, resultTo, resultCode, resultData, map, ordered, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011899 if (DEBUG_BROADCAST) Log.v(
11900 TAG, "Enqueueing ordered broadcast " + r
11901 + ": prev had " + mOrderedBroadcasts.size());
11902 if (DEBUG_BROADCAST) {
11903 int seq = r.intent.getIntExtra("seq", -1);
11904 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11905 }
11906 mOrderedBroadcasts.add(r);
11907 scheduleBroadcastsLocked();
11908 }
11909
11910 return BROADCAST_SUCCESS;
11911 }
11912
11913 public final int broadcastIntent(IApplicationThread caller,
11914 Intent intent, String resolvedType, IIntentReceiver resultTo,
11915 int resultCode, String resultData, Bundle map,
11916 String requiredPermission, boolean serialized, boolean sticky) {
11917 // Refuse possible leaked file descriptors
11918 if (intent != null && intent.hasFileDescriptors() == true) {
11919 throw new IllegalArgumentException("File descriptors passed in Intent");
11920 }
11921
11922 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011923 int flags = intent.getFlags();
11924
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011925 if (!mSystemReady) {
11926 // if the caller really truly claims to know what they're doing, go
11927 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011928 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11929 intent = new Intent(intent);
11930 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11931 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11932 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11933 + " before boot completion");
11934 throw new IllegalStateException("Cannot broadcast before boot completed");
11935 }
11936 }
11937
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011938 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
11939 throw new IllegalArgumentException(
11940 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
11941 }
11942
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011943 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11944 final int callingPid = Binder.getCallingPid();
11945 final int callingUid = Binder.getCallingUid();
11946 final long origId = Binder.clearCallingIdentity();
11947 int res = broadcastIntentLocked(callerApp,
11948 callerApp != null ? callerApp.info.packageName : null,
11949 intent, resolvedType, resultTo,
11950 resultCode, resultData, map, requiredPermission, serialized,
11951 sticky, callingPid, callingUid);
11952 Binder.restoreCallingIdentity(origId);
11953 return res;
11954 }
11955 }
11956
11957 int broadcastIntentInPackage(String packageName, int uid,
11958 Intent intent, String resolvedType, IIntentReceiver resultTo,
11959 int resultCode, String resultData, Bundle map,
11960 String requiredPermission, boolean serialized, boolean sticky) {
11961 synchronized(this) {
11962 final long origId = Binder.clearCallingIdentity();
11963 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11964 resultTo, resultCode, resultData, map, requiredPermission,
11965 serialized, sticky, -1, uid);
11966 Binder.restoreCallingIdentity(origId);
11967 return res;
11968 }
11969 }
11970
11971 public final void unbroadcastIntent(IApplicationThread caller,
11972 Intent intent) {
11973 // Refuse possible leaked file descriptors
11974 if (intent != null && intent.hasFileDescriptors() == true) {
11975 throw new IllegalArgumentException("File descriptors passed in Intent");
11976 }
11977
11978 synchronized(this) {
11979 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11980 != PackageManager.PERMISSION_GRANTED) {
11981 String msg = "Permission Denial: unbroadcastIntent() from pid="
11982 + Binder.getCallingPid()
11983 + ", uid=" + Binder.getCallingUid()
11984 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11985 Log.w(TAG, msg);
11986 throw new SecurityException(msg);
11987 }
11988 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11989 if (list != null) {
11990 int N = list.size();
11991 int i;
11992 for (i=0; i<N; i++) {
11993 if (intent.filterEquals(list.get(i))) {
11994 list.remove(i);
11995 break;
11996 }
11997 }
11998 }
11999 }
12000 }
12001
12002 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
12003 String resultData, Bundle resultExtras, boolean resultAbort,
12004 boolean explicit) {
12005 if (mOrderedBroadcasts.size() == 0) {
12006 if (explicit) {
12007 Log.w(TAG, "finishReceiver called but no pending broadcasts");
12008 }
12009 return false;
12010 }
12011 BroadcastRecord r = mOrderedBroadcasts.get(0);
12012 if (r.receiver == null) {
12013 if (explicit) {
12014 Log.w(TAG, "finishReceiver called but none active");
12015 }
12016 return false;
12017 }
12018 if (r.receiver != receiver) {
12019 Log.w(TAG, "finishReceiver called but active receiver is different");
12020 return false;
12021 }
12022 int state = r.state;
12023 r.state = r.IDLE;
12024 if (state == r.IDLE) {
12025 if (explicit) {
12026 Log.w(TAG, "finishReceiver called but state is IDLE");
12027 }
12028 }
12029 r.receiver = null;
12030 r.intent.setComponent(null);
12031 if (r.curApp != null) {
12032 r.curApp.curReceiver = null;
12033 }
12034 if (r.curFilter != null) {
12035 r.curFilter.receiverList.curBroadcast = null;
12036 }
12037 r.curFilter = null;
12038 r.curApp = null;
12039 r.curComponent = null;
12040 r.curReceiver = null;
12041 mPendingBroadcast = null;
12042
12043 r.resultCode = resultCode;
12044 r.resultData = resultData;
12045 r.resultExtras = resultExtras;
12046 r.resultAbort = resultAbort;
12047
12048 // We will process the next receiver right now if this is finishing
12049 // an app receiver (which is always asynchronous) or after we have
12050 // come back from calling a receiver.
12051 return state == BroadcastRecord.APP_RECEIVE
12052 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12053 }
12054
12055 public void finishReceiver(IBinder who, int resultCode, String resultData,
12056 Bundle resultExtras, boolean resultAbort) {
12057 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12058
12059 // Refuse possible leaked file descriptors
12060 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12061 throw new IllegalArgumentException("File descriptors passed in Bundle");
12062 }
12063
12064 boolean doNext;
12065
12066 final long origId = Binder.clearCallingIdentity();
12067
12068 synchronized(this) {
12069 doNext = finishReceiverLocked(
12070 who, resultCode, resultData, resultExtras, resultAbort, true);
12071 }
12072
12073 if (doNext) {
12074 processNextBroadcast(false);
12075 }
12076 trimApplications();
12077
12078 Binder.restoreCallingIdentity(origId);
12079 }
12080
12081 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12082 if (r.nextReceiver > 0) {
12083 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12084 if (curReceiver instanceof BroadcastFilter) {
12085 BroadcastFilter bf = (BroadcastFilter) curReceiver;
12086 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
12087 System.identityHashCode(r),
12088 r.intent.getAction(),
12089 r.nextReceiver - 1,
12090 System.identityHashCode(bf));
12091 } else {
12092 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12093 System.identityHashCode(r),
12094 r.intent.getAction(),
12095 r.nextReceiver - 1,
12096 ((ResolveInfo)curReceiver).toString());
12097 }
12098 } else {
12099 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12100 + r);
12101 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12102 System.identityHashCode(r),
12103 r.intent.getAction(),
12104 r.nextReceiver,
12105 "NONE");
12106 }
12107 }
12108
12109 private final void broadcastTimeout() {
12110 synchronized (this) {
12111 if (mOrderedBroadcasts.size() == 0) {
12112 return;
12113 }
12114 long now = SystemClock.uptimeMillis();
12115 BroadcastRecord r = mOrderedBroadcasts.get(0);
12116 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
12117 if (DEBUG_BROADCAST) Log.v(TAG,
12118 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
12119 + (r.startTime + BROADCAST_TIMEOUT));
12120 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12121 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12122 return;
12123 }
12124
12125 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
12126 r.startTime = now;
12127 r.anrCount++;
12128
12129 // Current receiver has passed its expiration date.
12130 if (r.nextReceiver <= 0) {
12131 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12132 return;
12133 }
12134
12135 ProcessRecord app = null;
12136
12137 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12138 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12139 logBroadcastReceiverDiscard(r);
12140 if (curReceiver instanceof BroadcastFilter) {
12141 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12142 if (bf.receiverList.pid != 0
12143 && bf.receiverList.pid != MY_PID) {
12144 synchronized (this.mPidsSelfLocked) {
12145 app = this.mPidsSelfLocked.get(
12146 bf.receiverList.pid);
12147 }
12148 }
12149 } else {
12150 app = r.curApp;
12151 }
12152
12153 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070012154 appNotRespondingLocked(app, null, null,
12155 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012156 }
12157
12158 if (mPendingBroadcast == r) {
12159 mPendingBroadcast = null;
12160 }
12161
12162 // Move on to the next receiver.
12163 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12164 r.resultExtras, r.resultAbort, true);
12165 scheduleBroadcastsLocked();
12166 }
12167 }
12168
12169 private final void processCurBroadcastLocked(BroadcastRecord r,
12170 ProcessRecord app) throws RemoteException {
12171 if (app.thread == null) {
12172 throw new RemoteException();
12173 }
12174 r.receiver = app.thread.asBinder();
12175 r.curApp = app;
12176 app.curReceiver = r;
12177 updateLRUListLocked(app, true);
12178
12179 // Tell the application to launch this receiver.
12180 r.intent.setComponent(r.curComponent);
12181
12182 boolean started = false;
12183 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012184 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012185 "Delivering to component " + r.curComponent
12186 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012187 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012188 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12189 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12190 started = true;
12191 } finally {
12192 if (!started) {
12193 r.receiver = null;
12194 r.curApp = null;
12195 app.curReceiver = null;
12196 }
12197 }
12198
12199 }
12200
12201 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012202 Intent intent, int resultCode, String data, Bundle extras,
12203 boolean ordered, boolean sticky) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012204 if (app != null && app.thread != null) {
12205 // If we have an app thread, do the call through that so it is
12206 // correctly ordered with other one-way calls.
12207 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012208 data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012209 } else {
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012210 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012211 }
12212 }
12213
12214 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12215 BroadcastFilter filter, boolean ordered) {
12216 boolean skip = false;
12217 if (filter.requiredPermission != null) {
12218 int perm = checkComponentPermission(filter.requiredPermission,
12219 r.callingPid, r.callingUid, -1);
12220 if (perm != PackageManager.PERMISSION_GRANTED) {
12221 Log.w(TAG, "Permission Denial: broadcasting "
12222 + r.intent.toString()
12223 + " from " + r.callerPackage + " (pid="
12224 + r.callingPid + ", uid=" + r.callingUid + ")"
12225 + " requires " + filter.requiredPermission
12226 + " due to registered receiver " + filter);
12227 skip = true;
12228 }
12229 }
12230 if (r.requiredPermission != null) {
12231 int perm = checkComponentPermission(r.requiredPermission,
12232 filter.receiverList.pid, filter.receiverList.uid, -1);
12233 if (perm != PackageManager.PERMISSION_GRANTED) {
12234 Log.w(TAG, "Permission Denial: receiving "
12235 + r.intent.toString()
12236 + " to " + filter.receiverList.app
12237 + " (pid=" + filter.receiverList.pid
12238 + ", uid=" + filter.receiverList.uid + ")"
12239 + " requires " + r.requiredPermission
12240 + " due to sender " + r.callerPackage
12241 + " (uid " + r.callingUid + ")");
12242 skip = true;
12243 }
12244 }
12245
12246 if (!skip) {
12247 // If this is not being sent as an ordered broadcast, then we
12248 // don't want to touch the fields that keep track of the current
12249 // state of ordered broadcasts.
12250 if (ordered) {
12251 r.receiver = filter.receiverList.receiver.asBinder();
12252 r.curFilter = filter;
12253 filter.receiverList.curBroadcast = r;
12254 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012255 if (filter.receiverList.app != null) {
12256 // Bump hosting application to no longer be in background
12257 // scheduling class. Note that we can't do that if there
12258 // isn't an app... but we can only be in that case for
12259 // things that directly call the IActivityManager API, which
12260 // are already core system stuff so don't matter for this.
12261 r.curApp = filter.receiverList.app;
12262 filter.receiverList.app.curReceiver = r;
12263 updateOomAdjLocked();
12264 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012265 }
12266 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012267 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012268 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012269 Log.i(TAG, "Delivering to " + filter.receiverList.app
12270 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012271 }
12272 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12273 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012274 r.resultData, r.resultExtras, r.ordered, r.sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012275 if (ordered) {
12276 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12277 }
12278 } catch (RemoteException e) {
12279 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12280 if (ordered) {
12281 r.receiver = null;
12282 r.curFilter = null;
12283 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012284 if (filter.receiverList.app != null) {
12285 filter.receiverList.app.curReceiver = null;
12286 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012287 }
12288 }
12289 }
12290 }
12291
12292 private final void processNextBroadcast(boolean fromMsg) {
12293 synchronized(this) {
12294 BroadcastRecord r;
12295
12296 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12297 + mParallelBroadcasts.size() + " broadcasts, "
12298 + mOrderedBroadcasts.size() + " serialized broadcasts");
12299
12300 updateCpuStats();
12301
12302 if (fromMsg) {
12303 mBroadcastsScheduled = false;
12304 }
12305
12306 // First, deliver any non-serialized broadcasts right away.
12307 while (mParallelBroadcasts.size() > 0) {
12308 r = mParallelBroadcasts.remove(0);
12309 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012310 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12311 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012312 for (int i=0; i<N; i++) {
12313 Object target = r.receivers.get(i);
12314 if (DEBUG_BROADCAST) Log.v(TAG,
12315 "Delivering non-serialized to registered "
12316 + target + ": " + r);
12317 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12318 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012319 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12320 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012321 }
12322
12323 // Now take care of the next serialized one...
12324
12325 // If we are waiting for a process to come up to handle the next
12326 // broadcast, then do nothing at this point. Just in case, we
12327 // check that the process we're waiting for still exists.
12328 if (mPendingBroadcast != null) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070012329 if (DEBUG_BROADCAST_LIGHT) {
12330 Log.v(TAG, "processNextBroadcast: waiting for "
12331 + mPendingBroadcast.curApp);
12332 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012333
12334 boolean isDead;
12335 synchronized (mPidsSelfLocked) {
12336 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12337 }
12338 if (!isDead) {
12339 // It's still alive, so keep waiting
12340 return;
12341 } else {
12342 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12343 + " died before responding to broadcast");
12344 mPendingBroadcast = null;
12345 }
12346 }
12347
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012348 boolean looped = false;
12349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012350 do {
12351 if (mOrderedBroadcasts.size() == 0) {
12352 // No more broadcasts pending, so all done!
12353 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012354 if (looped) {
12355 // If we had finished the last ordered broadcast, then
12356 // make sure all processes have correct oom and sched
12357 // adjustments.
12358 updateOomAdjLocked();
12359 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012360 return;
12361 }
12362 r = mOrderedBroadcasts.get(0);
12363 boolean forceReceive = false;
12364
12365 // Ensure that even if something goes awry with the timeout
12366 // detection, we catch "hung" broadcasts here, discard them,
12367 // and continue to make progress.
12368 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12369 long now = SystemClock.uptimeMillis();
12370 if (r.dispatchTime > 0) {
12371 if ((numReceivers > 0) &&
12372 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12373 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12374 + " now=" + now
12375 + " dispatchTime=" + r.dispatchTime
12376 + " startTime=" + r.startTime
12377 + " intent=" + r.intent
12378 + " numReceivers=" + numReceivers
12379 + " nextReceiver=" + r.nextReceiver
12380 + " state=" + r.state);
12381 broadcastTimeout(); // forcibly finish this broadcast
12382 forceReceive = true;
12383 r.state = BroadcastRecord.IDLE;
12384 }
12385 }
12386
12387 if (r.state != BroadcastRecord.IDLE) {
12388 if (DEBUG_BROADCAST) Log.d(TAG,
12389 "processNextBroadcast() called when not idle (state="
12390 + r.state + ")");
12391 return;
12392 }
12393
12394 if (r.receivers == null || r.nextReceiver >= numReceivers
12395 || r.resultAbort || forceReceive) {
12396 // No more receivers for this broadcast! Send the final
12397 // result if requested...
12398 if (r.resultTo != null) {
12399 try {
12400 if (DEBUG_BROADCAST) {
12401 int seq = r.intent.getIntExtra("seq", -1);
12402 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12403 + " seq=" + seq + " app=" + r.callerApp);
12404 }
12405 performReceive(r.callerApp, r.resultTo,
12406 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012407 r.resultData, r.resultExtras, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012408 } catch (RemoteException e) {
12409 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12410 }
12411 }
12412
12413 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12414 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12415
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012416 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12417 + r);
12418
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012419 // ... and on to the next...
12420 mOrderedBroadcasts.remove(0);
12421 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012422 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012423 continue;
12424 }
12425 } while (r == null);
12426
12427 // Get the next receiver...
12428 int recIdx = r.nextReceiver++;
12429
12430 // Keep track of when this receiver started, and make sure there
12431 // is a timeout message pending to kill it if need be.
12432 r.startTime = SystemClock.uptimeMillis();
12433 if (recIdx == 0) {
12434 r.dispatchTime = r.startTime;
12435
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012436 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12437 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012438 if (DEBUG_BROADCAST) Log.v(TAG,
12439 "Submitting BROADCAST_TIMEOUT_MSG for "
12440 + (r.startTime + BROADCAST_TIMEOUT));
12441 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12442 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12443 }
12444
12445 Object nextReceiver = r.receivers.get(recIdx);
12446 if (nextReceiver instanceof BroadcastFilter) {
12447 // Simple case: this is a registered receiver who gets
12448 // a direct call.
12449 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12450 if (DEBUG_BROADCAST) Log.v(TAG,
12451 "Delivering serialized to registered "
12452 + filter + ": " + r);
12453 deliverToRegisteredReceiver(r, filter, r.ordered);
12454 if (r.receiver == null || !r.ordered) {
12455 // The receiver has already finished, so schedule to
12456 // process the next one.
12457 r.state = BroadcastRecord.IDLE;
12458 scheduleBroadcastsLocked();
12459 }
12460 return;
12461 }
12462
12463 // Hard case: need to instantiate the receiver, possibly
12464 // starting its application process to host it.
12465
12466 ResolveInfo info =
12467 (ResolveInfo)nextReceiver;
12468
12469 boolean skip = false;
12470 int perm = checkComponentPermission(info.activityInfo.permission,
12471 r.callingPid, r.callingUid,
12472 info.activityInfo.exported
12473 ? -1 : info.activityInfo.applicationInfo.uid);
12474 if (perm != PackageManager.PERMISSION_GRANTED) {
12475 Log.w(TAG, "Permission Denial: broadcasting "
12476 + r.intent.toString()
12477 + " from " + r.callerPackage + " (pid=" + r.callingPid
12478 + ", uid=" + r.callingUid + ")"
12479 + " requires " + info.activityInfo.permission
12480 + " due to receiver " + info.activityInfo.packageName
12481 + "/" + info.activityInfo.name);
12482 skip = true;
12483 }
12484 if (r.callingUid != Process.SYSTEM_UID &&
12485 r.requiredPermission != null) {
12486 try {
12487 perm = ActivityThread.getPackageManager().
12488 checkPermission(r.requiredPermission,
12489 info.activityInfo.applicationInfo.packageName);
12490 } catch (RemoteException e) {
12491 perm = PackageManager.PERMISSION_DENIED;
12492 }
12493 if (perm != PackageManager.PERMISSION_GRANTED) {
12494 Log.w(TAG, "Permission Denial: receiving "
12495 + r.intent + " to "
12496 + info.activityInfo.applicationInfo.packageName
12497 + " requires " + r.requiredPermission
12498 + " due to sender " + r.callerPackage
12499 + " (uid " + r.callingUid + ")");
12500 skip = true;
12501 }
12502 }
12503 if (r.curApp != null && r.curApp.crashing) {
12504 // If the target process is crashing, just skip it.
12505 skip = true;
12506 }
12507
12508 if (skip) {
12509 r.receiver = null;
12510 r.curFilter = null;
12511 r.state = BroadcastRecord.IDLE;
12512 scheduleBroadcastsLocked();
12513 return;
12514 }
12515
12516 r.state = BroadcastRecord.APP_RECEIVE;
12517 String targetProcess = info.activityInfo.processName;
12518 r.curComponent = new ComponentName(
12519 info.activityInfo.applicationInfo.packageName,
12520 info.activityInfo.name);
12521 r.curReceiver = info.activityInfo;
12522
12523 // Is this receiver's application already running?
12524 ProcessRecord app = getProcessRecordLocked(targetProcess,
12525 info.activityInfo.applicationInfo.uid);
12526 if (app != null && app.thread != null) {
12527 try {
12528 processCurBroadcastLocked(r, app);
12529 return;
12530 } catch (RemoteException e) {
12531 Log.w(TAG, "Exception when sending broadcast to "
12532 + r.curComponent, e);
12533 }
12534
12535 // If a dead object exception was thrown -- fall through to
12536 // restart the application.
12537 }
12538
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012539 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012540 if ((r.curApp=startProcessLocked(targetProcess,
12541 info.activityInfo.applicationInfo, true,
12542 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012543 "broadcast", r.curComponent,
12544 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12545 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012546 // Ah, this recipient is unavailable. Finish it if necessary,
12547 // and mark the broadcast record as ready for the next.
12548 Log.w(TAG, "Unable to launch app "
12549 + info.activityInfo.applicationInfo.packageName + "/"
12550 + info.activityInfo.applicationInfo.uid + " for broadcast "
12551 + r.intent + ": process is bad");
12552 logBroadcastReceiverDiscard(r);
12553 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12554 r.resultExtras, r.resultAbort, true);
12555 scheduleBroadcastsLocked();
12556 r.state = BroadcastRecord.IDLE;
12557 return;
12558 }
12559
12560 mPendingBroadcast = r;
12561 }
12562 }
12563
12564 // =========================================================
12565 // INSTRUMENTATION
12566 // =========================================================
12567
12568 public boolean startInstrumentation(ComponentName className,
12569 String profileFile, int flags, Bundle arguments,
12570 IInstrumentationWatcher watcher) {
12571 // Refuse possible leaked file descriptors
12572 if (arguments != null && arguments.hasFileDescriptors()) {
12573 throw new IllegalArgumentException("File descriptors passed in Bundle");
12574 }
12575
12576 synchronized(this) {
12577 InstrumentationInfo ii = null;
12578 ApplicationInfo ai = null;
12579 try {
12580 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012581 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012582 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012583 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012584 } catch (PackageManager.NameNotFoundException e) {
12585 }
12586 if (ii == null) {
12587 reportStartInstrumentationFailure(watcher, className,
12588 "Unable to find instrumentation info for: " + className);
12589 return false;
12590 }
12591 if (ai == null) {
12592 reportStartInstrumentationFailure(watcher, className,
12593 "Unable to find instrumentation target package: " + ii.targetPackage);
12594 return false;
12595 }
12596
12597 int match = mContext.getPackageManager().checkSignatures(
12598 ii.targetPackage, ii.packageName);
12599 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12600 String msg = "Permission Denial: starting instrumentation "
12601 + className + " from pid="
12602 + Binder.getCallingPid()
12603 + ", uid=" + Binder.getCallingPid()
12604 + " not allowed because package " + ii.packageName
12605 + " does not have a signature matching the target "
12606 + ii.targetPackage;
12607 reportStartInstrumentationFailure(watcher, className, msg);
12608 throw new SecurityException(msg);
12609 }
12610
12611 final long origId = Binder.clearCallingIdentity();
12612 uninstallPackageLocked(ii.targetPackage, -1, true);
12613 ProcessRecord app = addAppLocked(ai);
12614 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012615 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012616 app.instrumentationProfileFile = profileFile;
12617 app.instrumentationArguments = arguments;
12618 app.instrumentationWatcher = watcher;
12619 app.instrumentationResultClass = className;
12620 Binder.restoreCallingIdentity(origId);
12621 }
12622
12623 return true;
12624 }
12625
12626 /**
12627 * Report errors that occur while attempting to start Instrumentation. Always writes the
12628 * error to the logs, but if somebody is watching, send the report there too. This enables
12629 * the "am" command to report errors with more information.
12630 *
12631 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12632 * @param cn The component name of the instrumentation.
12633 * @param report The error report.
12634 */
12635 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12636 ComponentName cn, String report) {
12637 Log.w(TAG, report);
12638 try {
12639 if (watcher != null) {
12640 Bundle results = new Bundle();
12641 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12642 results.putString("Error", report);
12643 watcher.instrumentationStatus(cn, -1, results);
12644 }
12645 } catch (RemoteException e) {
12646 Log.w(TAG, e);
12647 }
12648 }
12649
12650 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12651 if (app.instrumentationWatcher != null) {
12652 try {
12653 // NOTE: IInstrumentationWatcher *must* be oneway here
12654 app.instrumentationWatcher.instrumentationFinished(
12655 app.instrumentationClass,
12656 resultCode,
12657 results);
12658 } catch (RemoteException e) {
12659 }
12660 }
12661 app.instrumentationWatcher = null;
12662 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012663 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012664 app.instrumentationProfileFile = null;
12665 app.instrumentationArguments = null;
12666
12667 uninstallPackageLocked(app.processName, -1, false);
12668 }
12669
12670 public void finishInstrumentation(IApplicationThread target,
12671 int resultCode, Bundle results) {
12672 // Refuse possible leaked file descriptors
12673 if (results != null && results.hasFileDescriptors()) {
12674 throw new IllegalArgumentException("File descriptors passed in Intent");
12675 }
12676
12677 synchronized(this) {
12678 ProcessRecord app = getRecordForAppLocked(target);
12679 if (app == null) {
12680 Log.w(TAG, "finishInstrumentation: no app for " + target);
12681 return;
12682 }
12683 final long origId = Binder.clearCallingIdentity();
12684 finishInstrumentationLocked(app, resultCode, results);
12685 Binder.restoreCallingIdentity(origId);
12686 }
12687 }
12688
12689 // =========================================================
12690 // CONFIGURATION
12691 // =========================================================
12692
12693 public ConfigurationInfo getDeviceConfigurationInfo() {
12694 ConfigurationInfo config = new ConfigurationInfo();
12695 synchronized (this) {
12696 config.reqTouchScreen = mConfiguration.touchscreen;
12697 config.reqKeyboardType = mConfiguration.keyboard;
12698 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012699 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12700 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012701 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12702 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012703 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12704 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012705 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12706 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012707 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012708 }
12709 return config;
12710 }
12711
12712 public Configuration getConfiguration() {
12713 Configuration ci;
12714 synchronized(this) {
12715 ci = new Configuration(mConfiguration);
12716 }
12717 return ci;
12718 }
12719
12720 public void updateConfiguration(Configuration values) {
12721 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12722 "updateConfiguration()");
12723
12724 synchronized(this) {
12725 if (values == null && mWindowManager != null) {
12726 // sentinel: fetch the current configuration from the window manager
12727 values = mWindowManager.computeNewConfiguration();
12728 }
12729
12730 final long origId = Binder.clearCallingIdentity();
12731 updateConfigurationLocked(values, null);
12732 Binder.restoreCallingIdentity(origId);
12733 }
12734 }
12735
12736 /**
12737 * Do either or both things: (1) change the current configuration, and (2)
12738 * make sure the given activity is running with the (now) current
12739 * configuration. Returns true if the activity has been left running, or
12740 * false if <var>starting</var> is being destroyed to match the new
12741 * configuration.
12742 */
12743 public boolean updateConfigurationLocked(Configuration values,
12744 HistoryRecord starting) {
12745 int changes = 0;
12746
12747 boolean kept = true;
12748
12749 if (values != null) {
12750 Configuration newConfig = new Configuration(mConfiguration);
12751 changes = newConfig.updateFrom(values);
12752 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012753 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012754 Log.i(TAG, "Updating configuration to: " + values);
12755 }
12756
12757 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12758
12759 if (values.locale != null) {
12760 saveLocaleLocked(values.locale,
12761 !values.locale.equals(mConfiguration.locale),
12762 values.userSetLocale);
12763 }
12764
12765 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012766 Log.i(TAG, "Config changed: " + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012767
12768 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12769 msg.obj = new Configuration(mConfiguration);
12770 mHandler.sendMessage(msg);
12771
12772 final int N = mLRUProcesses.size();
12773 for (int i=0; i<N; i++) {
12774 ProcessRecord app = mLRUProcesses.get(i);
12775 try {
12776 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012777 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
12778 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012779 app.thread.scheduleConfigurationChanged(mConfiguration);
12780 }
12781 } catch (Exception e) {
12782 }
12783 }
12784 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12785 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12786 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012787
12788 AttributeCache ac = AttributeCache.instance();
12789 if (ac != null) {
12790 ac.updateConfiguration(mConfiguration);
12791 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012792 }
12793 }
12794
12795 if (changes != 0 && starting == null) {
12796 // If the configuration changed, and the caller is not already
12797 // in the process of starting an activity, then find the top
12798 // activity to check if its configuration needs to change.
12799 starting = topRunningActivityLocked(null);
12800 }
12801
12802 if (starting != null) {
12803 kept = ensureActivityConfigurationLocked(starting, changes);
12804 if (kept) {
12805 // If this didn't result in the starting activity being
12806 // destroyed, then we need to make sure at this point that all
12807 // other activities are made visible.
12808 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12809 + ", ensuring others are correct.");
12810 ensureActivitiesVisibleLocked(starting, changes);
12811 }
12812 }
12813
12814 return kept;
12815 }
12816
12817 private final boolean relaunchActivityLocked(HistoryRecord r,
12818 int changes, boolean andResume) {
12819 List<ResultInfo> results = null;
12820 List<Intent> newIntents = null;
12821 if (andResume) {
12822 results = r.results;
12823 newIntents = r.newIntents;
12824 }
12825 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12826 + " with results=" + results + " newIntents=" + newIntents
12827 + " andResume=" + andResume);
12828 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12829 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12830 r.task.taskId, r.shortComponentName);
12831
12832 r.startFreezingScreenLocked(r.app, 0);
12833
12834 try {
12835 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12836 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12837 changes, !andResume);
12838 // Note: don't need to call pauseIfSleepingLocked() here, because
12839 // the caller will only pass in 'andResume' if this activity is
12840 // currently resumed, which implies we aren't sleeping.
12841 } catch (RemoteException e) {
12842 return false;
12843 }
12844
12845 if (andResume) {
12846 r.results = null;
12847 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070012848 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012849 }
12850
12851 return true;
12852 }
12853
12854 /**
12855 * Make sure the given activity matches the current configuration. Returns
12856 * false if the activity had to be destroyed. Returns true if the
12857 * configuration is the same, or the activity will remain running as-is
12858 * for whatever reason. Ensures the HistoryRecord is updated with the
12859 * correct configuration and all other bookkeeping is handled.
12860 */
12861 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12862 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012863 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12864 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012865
12866 // Short circuit: if the two configurations are the exact same
12867 // object (the common case), then there is nothing to do.
12868 Configuration newConfig = mConfiguration;
12869 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012870 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12871 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012872 return true;
12873 }
12874
12875 // We don't worry about activities that are finishing.
12876 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012877 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012878 "Configuration doesn't matter in finishing " + r);
12879 r.stopFreezingScreenLocked(false);
12880 return true;
12881 }
12882
12883 // Okay we now are going to make this activity have the new config.
12884 // But then we need to figure out how it needs to deal with that.
12885 Configuration oldConfig = r.configuration;
12886 r.configuration = newConfig;
12887
12888 // If the activity isn't currently running, just leave the new
12889 // configuration and it will pick that up next time it starts.
12890 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012891 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012892 "Configuration doesn't matter not running " + r);
12893 r.stopFreezingScreenLocked(false);
12894 return true;
12895 }
12896
12897 // If the activity isn't persistent, there is a chance we will
12898 // need to restart it.
12899 if (!r.persistent) {
12900
12901 // Figure out what has changed between the two configurations.
12902 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012903 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
12904 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012905 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012906 + Integer.toHexString(r.info.configChanges)
12907 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012908 }
12909 if ((changes&(~r.info.configChanges)) != 0) {
12910 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12911 r.configChangeFlags |= changes;
12912 r.startFreezingScreenLocked(r.app, globalChanges);
12913 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012914 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12915 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012916 destroyActivityLocked(r, true);
12917 } else if (r.state == ActivityState.PAUSING) {
12918 // A little annoying: we are waiting for this activity to
12919 // finish pausing. Let's not do anything now, but just
12920 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012921 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12922 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012923 r.configDestroy = true;
12924 return true;
12925 } else if (r.state == ActivityState.RESUMED) {
12926 // Try to optimize this case: the configuration is changing
12927 // and we need to restart the top, resumed activity.
12928 // Instead of doing the normal handshaking, just say
12929 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012930 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12931 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012932 relaunchActivityLocked(r, r.configChangeFlags, true);
12933 r.configChangeFlags = 0;
12934 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012935 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12936 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012937 relaunchActivityLocked(r, r.configChangeFlags, false);
12938 r.configChangeFlags = 0;
12939 }
12940
12941 // All done... tell the caller we weren't able to keep this
12942 // activity around.
12943 return false;
12944 }
12945 }
12946
12947 // Default case: the activity can handle this new configuration, so
12948 // hand it over. Note that we don't need to give it the new
12949 // configuration, since we always send configuration changes to all
12950 // process when they happen so it can just use whatever configuration
12951 // it last got.
12952 if (r.app != null && r.app.thread != null) {
12953 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012954 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012955 r.app.thread.scheduleActivityConfigurationChanged(r);
12956 } catch (RemoteException e) {
12957 // If process died, whatever.
12958 }
12959 }
12960 r.stopFreezingScreenLocked(false);
12961
12962 return true;
12963 }
12964
12965 /**
12966 * Save the locale. You must be inside a synchronized (this) block.
12967 */
12968 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12969 if(isDiff) {
12970 SystemProperties.set("user.language", l.getLanguage());
12971 SystemProperties.set("user.region", l.getCountry());
12972 }
12973
12974 if(isPersist) {
12975 SystemProperties.set("persist.sys.language", l.getLanguage());
12976 SystemProperties.set("persist.sys.country", l.getCountry());
12977 SystemProperties.set("persist.sys.localevar", l.getVariant());
12978 }
12979 }
12980
12981 // =========================================================
12982 // LIFETIME MANAGEMENT
12983 // =========================================================
12984
12985 private final int computeOomAdjLocked(
12986 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12987 if (mAdjSeq == app.adjSeq) {
12988 // This adjustment has already been computed.
12989 return app.curAdj;
12990 }
12991
12992 if (app.thread == null) {
12993 app.adjSeq = mAdjSeq;
12994 return (app.curAdj=EMPTY_APP_ADJ);
12995 }
12996
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012997 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
12998 // The max adjustment doesn't allow this app to be anything
12999 // below foreground, so it is not worth doing work for it.
13000 app.adjType = "fixed";
13001 app.adjSeq = mAdjSeq;
13002 app.curRawAdj = app.maxAdj;
13003 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
13004 return (app.curAdj=app.maxAdj);
13005 }
13006
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013007 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013008 app.adjSource = null;
13009 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013010
The Android Open Source Project4df24232009-03-05 14:34:35 -080013011 // Determine the importance of the process, starting with most
13012 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013013 int adj;
13014 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013015 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013016 // The last app on the list is the foreground app.
13017 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013018 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013019 } else if (app.instrumentationClass != null) {
13020 // Don't want to kill running instrumentation.
13021 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013022 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013023 } else if (app.persistentActivities > 0) {
13024 // Special persistent activities... shouldn't be used these days.
13025 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013026 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013027 } else if (app.curReceiver != null ||
13028 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
13029 // An app that is currently receiving a broadcast also
13030 // counts as being in the foreground.
13031 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013032 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013033 } else if (app.executingServices.size() > 0) {
13034 // An app that is currently executing a service callback also
13035 // counts as being in the foreground.
13036 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013037 app.adjType = "exec-service";
13038 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013039 // The user is aware of this app, so make it visible.
13040 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013041 app.adjType = "foreground-service";
13042 } else if (app.forcingToForeground != null) {
13043 // The user is aware of this app, so make it visible.
13044 adj = VISIBLE_APP_ADJ;
13045 app.adjType = "force-foreground";
13046 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013047 } else if (app == mHomeProcess) {
13048 // This process is hosting what we currently consider to be the
13049 // home app, so we don't want to let it go into the background.
13050 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013051 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013052 } else if ((N=app.activities.size()) != 0) {
13053 // This app is in the background with paused activities.
13054 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013055 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013056 for (int j=0; j<N; j++) {
13057 if (((HistoryRecord)app.activities.get(j)).visible) {
13058 // This app has a visible activity!
13059 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013060 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013061 break;
13062 }
13063 }
13064 } else {
13065 // A very not-needed process.
13066 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013067 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013068 }
13069
The Android Open Source Project4df24232009-03-05 14:34:35 -080013070 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013071 // there are applications dependent on our services or providers, but
13072 // this gives us a baseline and makes sure we don't get into an
13073 // infinite recursion.
13074 app.adjSeq = mAdjSeq;
13075 app.curRawAdj = adj;
13076 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
13077
Christopher Tate6fa95972009-06-05 18:43:55 -070013078 if (mBackupTarget != null && app == mBackupTarget.app) {
13079 // If possible we want to avoid killing apps while they're being backed up
13080 if (adj > BACKUP_APP_ADJ) {
13081 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13082 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013083 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070013084 }
13085 }
13086
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013087 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013088 final long now = SystemClock.uptimeMillis();
13089 // This process is more important if the top activity is
13090 // bound to the service.
13091 Iterator jt = app.services.iterator();
13092 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13093 ServiceRecord s = (ServiceRecord)jt.next();
13094 if (s.startRequested) {
13095 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13096 // This service has seen some activity within
13097 // recent memory, so we will keep its process ahead
13098 // of the background processes.
13099 if (adj > SECONDARY_SERVER_ADJ) {
13100 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013101 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013102 }
13103 }
13104 }
13105 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
13106 Iterator<ConnectionRecord> kt
13107 = s.connections.values().iterator();
13108 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13109 // XXX should compute this based on the max of
13110 // all connected clients.
13111 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013112 if (cr.binding.client == app) {
13113 // Binding to ourself is not interesting.
13114 continue;
13115 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013116 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13117 ProcessRecord client = cr.binding.client;
13118 int myHiddenAdj = hiddenAdj;
13119 if (myHiddenAdj > client.hiddenAdj) {
13120 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13121 myHiddenAdj = client.hiddenAdj;
13122 } else {
13123 myHiddenAdj = VISIBLE_APP_ADJ;
13124 }
13125 }
13126 int clientAdj = computeOomAdjLocked(
13127 client, myHiddenAdj, TOP_APP);
13128 if (adj > clientAdj) {
13129 adj = clientAdj > VISIBLE_APP_ADJ
13130 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013131 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013132 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13133 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013134 app.adjSource = cr.binding.client;
13135 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013136 }
13137 }
13138 HistoryRecord a = cr.activity;
13139 //if (a != null) {
13140 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13141 //}
13142 if (a != null && adj > FOREGROUND_APP_ADJ &&
13143 (a.state == ActivityState.RESUMED
13144 || a.state == ActivityState.PAUSING)) {
13145 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013146 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013147 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13148 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013149 app.adjSource = a;
13150 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013151 }
13152 }
13153 }
13154 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013155
13156 // Finally, f this process has active services running in it, we
13157 // would like to avoid killing it unless it would prevent the current
13158 // application from running. By default we put the process in
13159 // with the rest of the background processes; as we scan through
13160 // its services we may bump it up from there.
13161 if (adj > hiddenAdj) {
13162 adj = hiddenAdj;
13163 app.adjType = "bg-services";
13164 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013165 }
13166
13167 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013168 Iterator jt = app.pubProviders.values().iterator();
13169 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13170 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13171 if (cpr.clients.size() != 0) {
13172 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13173 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13174 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013175 if (client == app) {
13176 // Being our own client is not interesting.
13177 continue;
13178 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013179 int myHiddenAdj = hiddenAdj;
13180 if (myHiddenAdj > client.hiddenAdj) {
13181 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13182 myHiddenAdj = client.hiddenAdj;
13183 } else {
13184 myHiddenAdj = FOREGROUND_APP_ADJ;
13185 }
13186 }
13187 int clientAdj = computeOomAdjLocked(
13188 client, myHiddenAdj, TOP_APP);
13189 if (adj > clientAdj) {
13190 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013191 ? clientAdj : FOREGROUND_APP_ADJ;
13192 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013193 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13194 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013195 app.adjSource = client;
13196 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013197 }
13198 }
13199 }
13200 // If the provider has external (non-framework) process
13201 // dependencies, ensure that its adjustment is at least
13202 // FOREGROUND_APP_ADJ.
13203 if (cpr.externals != 0) {
13204 if (adj > FOREGROUND_APP_ADJ) {
13205 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013206 app.adjType = "provider";
13207 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013208 }
13209 }
13210 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013211
13212 // Finally, if this process has published any content providers,
13213 // then its adjustment makes it at least as important as any of the
13214 // processes using those providers, and no less important than
13215 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
13216 if (adj > CONTENT_PROVIDER_ADJ) {
13217 adj = CONTENT_PROVIDER_ADJ;
13218 app.adjType = "pub-providers";
13219 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013220 }
13221
13222 app.curRawAdj = adj;
13223
13224 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13225 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13226 if (adj > app.maxAdj) {
13227 adj = app.maxAdj;
13228 }
13229
13230 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013231 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013232 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
13233 : Process.THREAD_GROUP_DEFAULT;
13234
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013235 return adj;
13236 }
13237
13238 /**
13239 * Ask a given process to GC right now.
13240 */
13241 final void performAppGcLocked(ProcessRecord app) {
13242 try {
13243 app.lastRequestedGc = SystemClock.uptimeMillis();
13244 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013245 if (app.reportLowMemory) {
13246 app.reportLowMemory = false;
13247 app.thread.scheduleLowMemory();
13248 } else {
13249 app.thread.processInBackground();
13250 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013251 }
13252 } catch (Exception e) {
13253 // whatever.
13254 }
13255 }
13256
13257 /**
13258 * Returns true if things are idle enough to perform GCs.
13259 */
13260 private final boolean canGcNow() {
13261 return mParallelBroadcasts.size() == 0
13262 && mOrderedBroadcasts.size() == 0
13263 && (mSleeping || (mResumedActivity != null &&
13264 mResumedActivity.idle));
13265 }
13266
13267 /**
13268 * Perform GCs on all processes that are waiting for it, but only
13269 * if things are idle.
13270 */
13271 final void performAppGcsLocked() {
13272 final int N = mProcessesToGc.size();
13273 if (N <= 0) {
13274 return;
13275 }
13276 if (canGcNow()) {
13277 while (mProcessesToGc.size() > 0) {
13278 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013279 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13280 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13281 <= SystemClock.uptimeMillis()) {
13282 // To avoid spamming the system, we will GC processes one
13283 // at a time, waiting a few seconds between each.
13284 performAppGcLocked(proc);
13285 scheduleAppGcsLocked();
13286 return;
13287 } else {
13288 // It hasn't been long enough since we last GCed this
13289 // process... put it in the list to wait for its time.
13290 addProcessToGcListLocked(proc);
13291 break;
13292 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013293 }
13294 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013295
13296 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013297 }
13298 }
13299
13300 /**
13301 * If all looks good, perform GCs on all processes waiting for them.
13302 */
13303 final void performAppGcsIfAppropriateLocked() {
13304 if (canGcNow()) {
13305 performAppGcsLocked();
13306 return;
13307 }
13308 // Still not idle, wait some more.
13309 scheduleAppGcsLocked();
13310 }
13311
13312 /**
13313 * Schedule the execution of all pending app GCs.
13314 */
13315 final void scheduleAppGcsLocked() {
13316 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013317
13318 if (mProcessesToGc.size() > 0) {
13319 // Schedule a GC for the time to the next process.
13320 ProcessRecord proc = mProcessesToGc.get(0);
13321 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13322
13323 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13324 long now = SystemClock.uptimeMillis();
13325 if (when < (now+GC_TIMEOUT)) {
13326 when = now + GC_TIMEOUT;
13327 }
13328 mHandler.sendMessageAtTime(msg, when);
13329 }
13330 }
13331
13332 /**
13333 * Add a process to the array of processes waiting to be GCed. Keeps the
13334 * list in sorted order by the last GC time. The process can't already be
13335 * on the list.
13336 */
13337 final void addProcessToGcListLocked(ProcessRecord proc) {
13338 boolean added = false;
13339 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13340 if (mProcessesToGc.get(i).lastRequestedGc <
13341 proc.lastRequestedGc) {
13342 added = true;
13343 mProcessesToGc.add(i+1, proc);
13344 break;
13345 }
13346 }
13347 if (!added) {
13348 mProcessesToGc.add(0, proc);
13349 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013350 }
13351
13352 /**
13353 * Set up to ask a process to GC itself. This will either do it
13354 * immediately, or put it on the list of processes to gc the next
13355 * time things are idle.
13356 */
13357 final void scheduleAppGcLocked(ProcessRecord app) {
13358 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013359 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013360 return;
13361 }
13362 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013363 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013364 scheduleAppGcsLocked();
13365 }
13366 }
13367
13368 private final boolean updateOomAdjLocked(
13369 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13370 app.hiddenAdj = hiddenAdj;
13371
13372 if (app.thread == null) {
13373 return true;
13374 }
13375
13376 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
13377
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013378 if (app.pid != 0 && app.pid != MY_PID) {
13379 if (app.curRawAdj != app.setRawAdj) {
13380 if (app.curRawAdj > FOREGROUND_APP_ADJ
13381 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13382 // If this app is transitioning from foreground to
13383 // non-foreground, have it do a gc.
13384 scheduleAppGcLocked(app);
13385 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13386 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13387 // Likewise do a gc when an app is moving in to the
13388 // background (such as a service stopping).
13389 scheduleAppGcLocked(app);
13390 }
13391 app.setRawAdj = app.curRawAdj;
13392 }
13393 if (adj != app.setAdj) {
13394 if (Process.setOomAdj(app.pid, adj)) {
13395 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13396 TAG, "Set app " + app.processName +
13397 " oom adj to " + adj);
13398 app.setAdj = adj;
13399 } else {
13400 return false;
13401 }
13402 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013403 if (app.setSchedGroup != app.curSchedGroup) {
13404 app.setSchedGroup = app.curSchedGroup;
13405 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13406 "Setting process group of " + app.processName
13407 + " to " + app.curSchedGroup);
13408 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013409 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013410 try {
13411 Process.setProcessGroup(app.pid, app.curSchedGroup);
13412 } catch (Exception e) {
13413 Log.w(TAG, "Failed setting process group of " + app.pid
13414 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013415 e.printStackTrace();
13416 } finally {
13417 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013418 }
13419 }
13420 if (false) {
13421 if (app.thread != null) {
13422 try {
13423 app.thread.setSchedulingGroup(app.curSchedGroup);
13424 } catch (RemoteException e) {
13425 }
13426 }
13427 }
13428 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013429 }
13430
13431 return true;
13432 }
13433
13434 private final HistoryRecord resumedAppLocked() {
13435 HistoryRecord resumedActivity = mResumedActivity;
13436 if (resumedActivity == null || resumedActivity.app == null) {
13437 resumedActivity = mPausingActivity;
13438 if (resumedActivity == null || resumedActivity.app == null) {
13439 resumedActivity = topRunningActivityLocked(null);
13440 }
13441 }
13442 return resumedActivity;
13443 }
13444
13445 private final boolean updateOomAdjLocked(ProcessRecord app) {
13446 final HistoryRecord TOP_ACT = resumedAppLocked();
13447 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13448 int curAdj = app.curAdj;
13449 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13450 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13451
13452 mAdjSeq++;
13453
13454 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13455 if (res) {
13456 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13457 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13458 if (nowHidden != wasHidden) {
13459 // Changed to/from hidden state, so apps after it in the LRU
13460 // list may also be changed.
13461 updateOomAdjLocked();
13462 }
13463 }
13464 return res;
13465 }
13466
13467 private final boolean updateOomAdjLocked() {
13468 boolean didOomAdj = true;
13469 final HistoryRecord TOP_ACT = resumedAppLocked();
13470 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13471
13472 if (false) {
13473 RuntimeException e = new RuntimeException();
13474 e.fillInStackTrace();
13475 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13476 }
13477
13478 mAdjSeq++;
13479
13480 // First try updating the OOM adjustment for each of the
13481 // application processes based on their current state.
13482 int i = mLRUProcesses.size();
13483 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13484 while (i > 0) {
13485 i--;
13486 ProcessRecord app = mLRUProcesses.get(i);
13487 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13488 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13489 && app.curAdj == curHiddenAdj) {
13490 curHiddenAdj++;
13491 }
13492 } else {
13493 didOomAdj = false;
13494 }
13495 }
13496
13497 // todo: for now pretend like OOM ADJ didn't work, because things
13498 // aren't behaving as expected on Linux -- it's not killing processes.
13499 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13500 }
13501
13502 private final void trimApplications() {
13503 synchronized (this) {
13504 int i;
13505
13506 // First remove any unused application processes whose package
13507 // has been removed.
13508 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13509 final ProcessRecord app = mRemovedProcesses.get(i);
13510 if (app.activities.size() == 0
13511 && app.curReceiver == null && app.services.size() == 0) {
13512 Log.i(
13513 TAG, "Exiting empty application process "
13514 + app.processName + " ("
13515 + (app.thread != null ? app.thread.asBinder() : null)
13516 + ")\n");
13517 if (app.pid > 0 && app.pid != MY_PID) {
13518 Process.killProcess(app.pid);
13519 } else {
13520 try {
13521 app.thread.scheduleExit();
13522 } catch (Exception e) {
13523 // Ignore exceptions.
13524 }
13525 }
13526 cleanUpApplicationRecordLocked(app, false, -1);
13527 mRemovedProcesses.remove(i);
13528
13529 if (app.persistent) {
13530 if (app.persistent) {
13531 addAppLocked(app.info);
13532 }
13533 }
13534 }
13535 }
13536
13537 // Now try updating the OOM adjustment for each of the
13538 // application processes based on their current state.
13539 // If the setOomAdj() API is not supported, then go with our
13540 // back-up plan...
13541 if (!updateOomAdjLocked()) {
13542
13543 // Count how many processes are running services.
13544 int numServiceProcs = 0;
13545 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13546 final ProcessRecord app = mLRUProcesses.get(i);
13547
13548 if (app.persistent || app.services.size() != 0
13549 || app.curReceiver != null
13550 || app.persistentActivities > 0) {
13551 // Don't count processes holding services against our
13552 // maximum process count.
13553 if (localLOGV) Log.v(
13554 TAG, "Not trimming app " + app + " with services: "
13555 + app.services);
13556 numServiceProcs++;
13557 }
13558 }
13559
13560 int curMaxProcs = mProcessLimit;
13561 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13562 if (mAlwaysFinishActivities) {
13563 curMaxProcs = 1;
13564 }
13565 curMaxProcs += numServiceProcs;
13566
13567 // Quit as many processes as we can to get down to the desired
13568 // process count. First remove any processes that no longer
13569 // have activites running in them.
13570 for ( i=0;
13571 i<mLRUProcesses.size()
13572 && mLRUProcesses.size() > curMaxProcs;
13573 i++) {
13574 final ProcessRecord app = mLRUProcesses.get(i);
13575 // Quit an application only if it is not currently
13576 // running any activities.
13577 if (!app.persistent && app.activities.size() == 0
13578 && app.curReceiver == null && app.services.size() == 0) {
13579 Log.i(
13580 TAG, "Exiting empty application process "
13581 + app.processName + " ("
13582 + (app.thread != null ? app.thread.asBinder() : null)
13583 + ")\n");
13584 if (app.pid > 0 && app.pid != MY_PID) {
13585 Process.killProcess(app.pid);
13586 } else {
13587 try {
13588 app.thread.scheduleExit();
13589 } catch (Exception e) {
13590 // Ignore exceptions.
13591 }
13592 }
13593 // todo: For now we assume the application is not buggy
13594 // or evil, and will quit as a result of our request.
13595 // Eventually we need to drive this off of the death
13596 // notification, and kill the process if it takes too long.
13597 cleanUpApplicationRecordLocked(app, false, i);
13598 i--;
13599 }
13600 }
13601
13602 // If we still have too many processes, now from the least
13603 // recently used process we start finishing activities.
13604 if (Config.LOGV) Log.v(
13605 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13606 " of " + curMaxProcs + " processes");
13607 for ( i=0;
13608 i<mLRUProcesses.size()
13609 && mLRUProcesses.size() > curMaxProcs;
13610 i++) {
13611 final ProcessRecord app = mLRUProcesses.get(i);
13612 // Quit the application only if we have a state saved for
13613 // all of its activities.
13614 boolean canQuit = !app.persistent && app.curReceiver == null
13615 && app.services.size() == 0
13616 && app.persistentActivities == 0;
13617 int NUMA = app.activities.size();
13618 int j;
13619 if (Config.LOGV) Log.v(
13620 TAG, "Looking to quit " + app.processName);
13621 for (j=0; j<NUMA && canQuit; j++) {
13622 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13623 if (Config.LOGV) Log.v(
13624 TAG, " " + r.intent.getComponent().flattenToShortString()
13625 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13626 canQuit = (r.haveState || !r.stateNotNeeded)
13627 && !r.visible && r.stopped;
13628 }
13629 if (canQuit) {
13630 // Finish all of the activities, and then the app itself.
13631 for (j=0; j<NUMA; j++) {
13632 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13633 if (!r.finishing) {
13634 destroyActivityLocked(r, false);
13635 }
13636 r.resultTo = null;
13637 }
13638 Log.i(TAG, "Exiting application process "
13639 + app.processName + " ("
13640 + (app.thread != null ? app.thread.asBinder() : null)
13641 + ")\n");
13642 if (app.pid > 0 && app.pid != MY_PID) {
13643 Process.killProcess(app.pid);
13644 } else {
13645 try {
13646 app.thread.scheduleExit();
13647 } catch (Exception e) {
13648 // Ignore exceptions.
13649 }
13650 }
13651 // todo: For now we assume the application is not buggy
13652 // or evil, and will quit as a result of our request.
13653 // Eventually we need to drive this off of the death
13654 // notification, and kill the process if it takes too long.
13655 cleanUpApplicationRecordLocked(app, false, i);
13656 i--;
13657 //dump();
13658 }
13659 }
13660
13661 }
13662
13663 int curMaxActivities = MAX_ACTIVITIES;
13664 if (mAlwaysFinishActivities) {
13665 curMaxActivities = 1;
13666 }
13667
13668 // Finally, if there are too many activities now running, try to
13669 // finish as many as we can to get back down to the limit.
13670 for ( i=0;
13671 i<mLRUActivities.size()
13672 && mLRUActivities.size() > curMaxActivities;
13673 i++) {
13674 final HistoryRecord r
13675 = (HistoryRecord)mLRUActivities.get(i);
13676
13677 // We can finish this one if we have its icicle saved and
13678 // it is not persistent.
13679 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13680 && r.stopped && !r.persistent && !r.finishing) {
13681 final int origSize = mLRUActivities.size();
13682 destroyActivityLocked(r, true);
13683
13684 // This will remove it from the LRU list, so keep
13685 // our index at the same value. Note that this check to
13686 // see if the size changes is just paranoia -- if
13687 // something unexpected happens, we don't want to end up
13688 // in an infinite loop.
13689 if (origSize > mLRUActivities.size()) {
13690 i--;
13691 }
13692 }
13693 }
13694 }
13695 }
13696
13697 /** This method sends the specified signal to each of the persistent apps */
13698 public void signalPersistentProcesses(int sig) throws RemoteException {
13699 if (sig != Process.SIGNAL_USR1) {
13700 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13701 }
13702
13703 synchronized (this) {
13704 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13705 != PackageManager.PERMISSION_GRANTED) {
13706 throw new SecurityException("Requires permission "
13707 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13708 }
13709
13710 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13711 ProcessRecord r = mLRUProcesses.get(i);
13712 if (r.thread != null && r.persistent) {
13713 Process.sendSignal(r.pid, sig);
13714 }
13715 }
13716 }
13717 }
13718
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013719 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013720 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013721
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013722 try {
13723 synchronized (this) {
13724 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13725 // its own permission.
13726 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13727 != PackageManager.PERMISSION_GRANTED) {
13728 throw new SecurityException("Requires permission "
13729 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013730 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013731
13732 if (start && fd == null) {
13733 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013734 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013735
13736 ProcessRecord proc = null;
13737 try {
13738 int pid = Integer.parseInt(process);
13739 synchronized (mPidsSelfLocked) {
13740 proc = mPidsSelfLocked.get(pid);
13741 }
13742 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013743 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013744
13745 if (proc == null) {
13746 HashMap<String, SparseArray<ProcessRecord>> all
13747 = mProcessNames.getMap();
13748 SparseArray<ProcessRecord> procs = all.get(process);
13749 if (procs != null && procs.size() > 0) {
13750 proc = procs.valueAt(0);
13751 }
13752 }
13753
13754 if (proc == null || proc.thread == null) {
13755 throw new IllegalArgumentException("Unknown process: " + process);
13756 }
13757
13758 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13759 if (isSecure) {
13760 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13761 throw new SecurityException("Process not debuggable: " + proc);
13762 }
13763 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013764
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013765 proc.thread.profilerControl(start, path, fd);
13766 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013767 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013768 }
13769 } catch (RemoteException e) {
13770 throw new IllegalStateException("Process disappeared");
13771 } finally {
13772 if (fd != null) {
13773 try {
13774 fd.close();
13775 } catch (IOException e) {
13776 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013777 }
13778 }
13779 }
13780
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013781 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13782 public void monitor() {
13783 synchronized (this) { }
13784 }
13785}