blob: 6858c75bce2cba1b54fc9b1fad7d26c4c5db66d9 [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 Tate181fafa2009-05-14 11:12:14 -0700143 static final boolean DEBUG_BACKUP = localLOGV || true;
Dianne Hackborndc6b6352009-09-30 14:20:09 -0700144 static final boolean DEBUG_CONFIGURATION = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 static final boolean VALIDATE_TOKENS = false;
146 static final boolean SHOW_ACTIVITY_START_TIME = true;
147
148 // Control over CPU and battery monitoring.
149 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
150 static final boolean MONITOR_CPU_USAGE = true;
151 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
152 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
153 static final boolean MONITOR_THREAD_CPU_USAGE = false;
154
155 // Event log tags
156 static final int LOG_CONFIGURATION_CHANGED = 2719;
157 static final int LOG_CPU = 2721;
158 static final int LOG_AM_FINISH_ACTIVITY = 30001;
159 static final int LOG_TASK_TO_FRONT = 30002;
160 static final int LOG_AM_NEW_INTENT = 30003;
161 static final int LOG_AM_CREATE_TASK = 30004;
162 static final int LOG_AM_CREATE_ACTIVITY = 30005;
163 static final int LOG_AM_RESTART_ACTIVITY = 30006;
164 static final int LOG_AM_RESUME_ACTIVITY = 30007;
165 static final int LOG_ANR = 30008;
166 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
167 static final int LOG_AM_PROCESS_BOUND = 30010;
168 static final int LOG_AM_PROCESS_DIED = 30011;
169 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
170 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
171 static final int LOG_AM_PROCESS_START = 30014;
172 static final int LOG_AM_PROCESS_BAD = 30015;
173 static final int LOG_AM_PROCESS_GOOD = 30016;
174 static final int LOG_AM_LOW_MEMORY = 30017;
175 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
176 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
177 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
178 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
179 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
180 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
181 static final int LOG_AM_CREATE_SERVICE = 30030;
182 static final int LOG_AM_DESTROY_SERVICE = 30031;
183 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
184 static final int LOG_AM_DROP_PROCESS = 30033;
185 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
186 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
187 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
188
189 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
190 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
191
Dianne Hackborn1655be42009-05-08 14:29:01 -0700192 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700193 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 private static final String SYSTEM_SECURE = "ro.secure";
196
197 // This is the maximum number of application processes we would like
198 // to have running. Due to the asynchronous nature of things, we can
199 // temporarily go beyond this limit.
200 static final int MAX_PROCESSES = 2;
201
202 // Set to false to leave processes running indefinitely, relying on
203 // the kernel killing them as resources are required.
204 static final boolean ENFORCE_PROCESS_LIMIT = false;
205
206 // This is the maximum number of activities that we would like to have
207 // running at a given time.
208 static final int MAX_ACTIVITIES = 20;
209
210 // Maximum number of recent tasks that we can remember.
211 static final int MAX_RECENT_TASKS = 20;
212
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700213 // Amount of time after a call to stopAppSwitches() during which we will
214 // prevent further untrusted switches from happening.
215 static final long APP_SWITCH_DELAY_TIME = 5*1000;
216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 // How long until we reset a task when the user returns to it. Currently
218 // 30 minutes.
219 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
220
221 // Set to true to disable the icon that is shown while a new activity
222 // is being started.
223 static final boolean SHOW_APP_STARTING_ICON = true;
224
225 // How long we wait until giving up on the last activity to pause. This
226 // is short because it directly impacts the responsiveness of starting the
227 // next activity.
228 static final int PAUSE_TIMEOUT = 500;
229
230 /**
231 * How long we can hold the launch wake lock before giving up.
232 */
233 static final int LAUNCH_TIMEOUT = 10*1000;
234
235 // How long we wait for a launched process to attach to the activity manager
236 // before we decide it's never going to come up for real.
237 static final int PROC_START_TIMEOUT = 10*1000;
238
239 // How long we wait until giving up on the last activity telling us it
240 // is idle.
241 static final int IDLE_TIMEOUT = 10*1000;
242
243 // How long to wait after going idle before forcing apps to GC.
244 static final int GC_TIMEOUT = 5*1000;
245
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700246 // The minimum amount of time between successive GC requests for a process.
247 static final int GC_MIN_INTERVAL = 60*1000;
248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 // How long we wait until giving up on an activity telling us it has
250 // finished destroying itself.
251 static final int DESTROY_TIMEOUT = 10*1000;
252
253 // How long we allow a receiver to run before giving up on it.
254 static final int BROADCAST_TIMEOUT = 10*1000;
255
256 // How long we wait for a service to finish executing.
257 static final int SERVICE_TIMEOUT = 20*1000;
258
259 // How long a service needs to be running until restarting its process
260 // is no longer considered to be a relaunch of the service.
261 static final int SERVICE_RESTART_DURATION = 5*1000;
262
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700263 // How long a service needs to be running until it will start back at
264 // SERVICE_RESTART_DURATION after being killed.
265 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
266
267 // Multiplying factor to increase restart duration time by, for each time
268 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
269 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
270
271 // The minimum amount of time between restarting services that we allow.
272 // That is, when multiple services are restarting, we won't allow each
273 // to restart less than this amount of time from the last one.
274 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 // Maximum amount of time for there to be no activity on a service before
277 // we consider it non-essential and allow its process to go on the
278 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700279 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280
281 // How long we wait until we timeout on key dispatching.
282 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
283
284 // The minimum time we allow between crashes, for us to consider this
285 // application to be bad and stop and its services and reject broadcasts.
286 static final int MIN_CRASH_INTERVAL = 60*1000;
287
288 // How long we wait until we timeout on key dispatching during instrumentation.
289 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
290
291 // OOM adjustments for processes in various states:
292
293 // This is a process without anything currently running in it. Definitely
294 // the first to go! Value set in system/rootdir/init.rc on startup.
295 // This value is initalized in the constructor, careful when refering to
296 // this static variable externally.
297 static int EMPTY_APP_ADJ;
298
299 // This is a process with a content provider that does not have any clients
300 // attached to it. If it did have any clients, its adjustment would be the
301 // one for the highest-priority of those processes.
302 static int CONTENT_PROVIDER_ADJ;
303
304 // This is a process only hosting activities that are not visible,
305 // so it can be killed without any disruption. Value set in
306 // system/rootdir/init.rc on startup.
307 final int HIDDEN_APP_MAX_ADJ;
308 static int HIDDEN_APP_MIN_ADJ;
309
The Android Open Source Project4df24232009-03-05 14:34:35 -0800310 // This is a process holding the home application -- we want to try
311 // avoiding killing it, even if it would normally be in the background,
312 // because the user interacts with it so much.
313 final int HOME_APP_ADJ;
314
Christopher Tate6fa95972009-06-05 18:43:55 -0700315 // This is a process currently hosting a backup operation. Killing it
316 // is not entirely fatal but is generally a bad idea.
317 final int BACKUP_APP_ADJ;
318
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 // This is a process holding a secondary server -- killing it will not
320 // have much of an impact as far as the user is concerned. Value set in
321 // system/rootdir/init.rc on startup.
322 final int SECONDARY_SERVER_ADJ;
323
324 // This is a process only hosting activities that are visible to the
325 // user, so we'd prefer they don't disappear. Value set in
326 // system/rootdir/init.rc on startup.
327 final int VISIBLE_APP_ADJ;
328
329 // This is the process running the current foreground app. We'd really
330 // rather not kill it! Value set in system/rootdir/init.rc on startup.
331 final int FOREGROUND_APP_ADJ;
332
333 // This is a process running a core server, such as telephony. Definitely
334 // don't want to kill it, but doing so is not completely fatal.
335 static final int CORE_SERVER_ADJ = -12;
336
337 // The system process runs at the default adjustment.
338 static final int SYSTEM_ADJ = -16;
339
340 // Memory pages are 4K.
341 static final int PAGE_SIZE = 4*1024;
342
Jacek Surazski82a73df2009-06-17 14:33:18 +0200343 // System property defining error report receiver for system apps
344 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
345
346 // System property defining default error report receiver
347 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 // Corresponding memory levels for above adjustments.
350 final int EMPTY_APP_MEM;
351 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800352 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700353 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 final int SECONDARY_SERVER_MEM;
355 final int VISIBLE_APP_MEM;
356 final int FOREGROUND_APP_MEM;
357
358 final int MY_PID;
359
360 static final String[] EMPTY_STRING_ARRAY = new String[0];
361
362 enum ActivityState {
363 INITIALIZING,
364 RESUMED,
365 PAUSING,
366 PAUSED,
367 STOPPING,
368 STOPPED,
369 FINISHING,
370 DESTROYING,
371 DESTROYED
372 }
373
374 /**
375 * The back history of all previous (and possibly still
376 * running) activities. It contains HistoryRecord objects.
377 */
378 final ArrayList mHistory = new ArrayList();
379
380 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700381 * Description of a request to start a new activity, which has been held
382 * due to app switches being disabled.
383 */
384 class PendingActivityLaunch {
385 HistoryRecord r;
386 HistoryRecord sourceRecord;
387 Uri[] grantedUriPermissions;
388 int grantedMode;
389 boolean onlyIfNeeded;
390 }
391
392 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
393 = new ArrayList<PendingActivityLaunch>();
394
395 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 * List of all active broadcasts that are to be executed immediately
397 * (without waiting for another broadcast to finish). Currently this only
398 * contains broadcasts to registered receivers, to avoid spinning up
399 * a bunch of processes to execute IntentReceiver components.
400 */
401 final ArrayList<BroadcastRecord> mParallelBroadcasts
402 = new ArrayList<BroadcastRecord>();
403
404 /**
405 * List of all active broadcasts that are to be executed one at a time.
406 * The object at the top of the list is the currently activity broadcasts;
407 * those after it are waiting for the top to finish..
408 */
409 final ArrayList<BroadcastRecord> mOrderedBroadcasts
410 = new ArrayList<BroadcastRecord>();
411
412 /**
413 * Set when we current have a BROADCAST_INTENT_MSG in flight.
414 */
415 boolean mBroadcastsScheduled = false;
416
417 /**
418 * Set to indicate whether to issue an onUserLeaving callback when a
419 * newly launched activity is being brought in front of us.
420 */
421 boolean mUserLeaving = false;
422
423 /**
424 * When we are in the process of pausing an activity, before starting the
425 * next one, this variable holds the activity that is currently being paused.
426 */
427 HistoryRecord mPausingActivity = null;
428
429 /**
430 * Current activity that is resumed, or null if there is none.
431 */
432 HistoryRecord mResumedActivity = null;
433
434 /**
435 * Activity we have told the window manager to have key focus.
436 */
437 HistoryRecord mFocusedActivity = null;
438
439 /**
440 * This is the last activity that we put into the paused state. This is
441 * used to determine if we need to do an activity transition while sleeping,
442 * when we normally hold the top activity paused.
443 */
444 HistoryRecord mLastPausedActivity = null;
445
446 /**
447 * List of activities that are waiting for a new activity
448 * to become visible before completing whatever operation they are
449 * supposed to do.
450 */
451 final ArrayList mWaitingVisibleActivities = new ArrayList();
452
453 /**
454 * List of activities that are ready to be stopped, but waiting
455 * for the next activity to settle down before doing so. It contains
456 * HistoryRecord objects.
457 */
458 final ArrayList<HistoryRecord> mStoppingActivities
459 = new ArrayList<HistoryRecord>();
460
461 /**
Dianne Hackbornbfe319e2009-09-21 00:34:05 -0700462 * Animations that for the current transition have requested not to
463 * be considered for the transition animation.
464 */
465 final ArrayList<HistoryRecord> mNoAnimActivities
466 = new ArrayList<HistoryRecord>();
467
468 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 * List of intents that were used to start the most recent tasks.
470 */
471 final ArrayList<TaskRecord> mRecentTasks
472 = new ArrayList<TaskRecord>();
473
474 /**
475 * List of activities that are ready to be finished, but waiting
476 * for the previous activity to settle down before doing so. It contains
477 * HistoryRecord objects.
478 */
479 final ArrayList mFinishingActivities = new ArrayList();
480
481 /**
482 * All of the applications we currently have running organized by name.
483 * The keys are strings of the application package name (as
484 * returned by the package manager), and the keys are ApplicationRecord
485 * objects.
486 */
487 final ProcessMap<ProcessRecord> mProcessNames
488 = new ProcessMap<ProcessRecord>();
489
490 /**
491 * The last time that various processes have crashed.
492 */
493 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
494
495 /**
496 * Set of applications that we consider to be bad, and will reject
497 * incoming broadcasts from (which the user has no control over).
498 * Processes are added to this set when they have crashed twice within
499 * a minimum amount of time; they are removed from it when they are
500 * later restarted (hopefully due to some user action). The value is the
501 * time it was added to the list.
502 */
503 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
504
505 /**
506 * All of the processes we currently have running organized by pid.
507 * The keys are the pid running the application.
508 *
509 * <p>NOTE: This object is protected by its own lock, NOT the global
510 * activity manager lock!
511 */
512 final SparseArray<ProcessRecord> mPidsSelfLocked
513 = new SparseArray<ProcessRecord>();
514
515 /**
516 * All of the processes that have been forced to be foreground. The key
517 * is the pid of the caller who requested it (we hold a death
518 * link on it).
519 */
520 abstract class ForegroundToken implements IBinder.DeathRecipient {
521 int pid;
522 IBinder token;
523 }
524 final SparseArray<ForegroundToken> mForegroundProcesses
525 = new SparseArray<ForegroundToken>();
526
527 /**
528 * List of records for processes that someone had tried to start before the
529 * system was ready. We don't start them at that point, but ensure they
530 * are started by the time booting is complete.
531 */
532 final ArrayList<ProcessRecord> mProcessesOnHold
533 = new ArrayList<ProcessRecord>();
534
535 /**
536 * List of records for processes that we have started and are waiting
537 * for them to call back. This is really only needed when running in
538 * single processes mode, in which case we do not have a unique pid for
539 * each process.
540 */
541 final ArrayList<ProcessRecord> mStartingProcesses
542 = new ArrayList<ProcessRecord>();
543
544 /**
545 * List of persistent applications that are in the process
546 * of being started.
547 */
548 final ArrayList<ProcessRecord> mPersistentStartingProcesses
549 = new ArrayList<ProcessRecord>();
550
551 /**
552 * Processes that are being forcibly torn down.
553 */
554 final ArrayList<ProcessRecord> mRemovedProcesses
555 = new ArrayList<ProcessRecord>();
556
557 /**
558 * List of running applications, sorted by recent usage.
559 * The first entry in the list is the least recently used.
560 * It contains ApplicationRecord objects. This list does NOT include
561 * any persistent application records (since we never want to exit them).
562 */
563 final ArrayList<ProcessRecord> mLRUProcesses
564 = new ArrayList<ProcessRecord>();
565
566 /**
567 * List of processes that should gc as soon as things are idle.
568 */
569 final ArrayList<ProcessRecord> mProcessesToGc
570 = new ArrayList<ProcessRecord>();
571
572 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800573 * This is the process holding what we currently consider to be
574 * the "home" activity.
575 */
576 private ProcessRecord mHomeProcess;
577
578 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 * List of running activities, sorted by recent usage.
580 * The first entry in the list is the least recently used.
581 * It contains HistoryRecord objects.
582 */
583 private final ArrayList mLRUActivities = new ArrayList();
584
585 /**
586 * Set of PendingResultRecord objects that are currently active.
587 */
588 final HashSet mPendingResultRecords = new HashSet();
589
590 /**
591 * Set of IntentSenderRecord objects that are currently active.
592 */
593 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
594 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
595
596 /**
597 * Intent broadcast that we have tried to start, but are
598 * waiting for its application's process to be created. We only
599 * need one (instead of a list) because we always process broadcasts
600 * one at a time, so no others can be started while waiting for this
601 * one.
602 */
603 BroadcastRecord mPendingBroadcast = null;
604
605 /**
606 * Keeps track of all IIntentReceivers that have been registered for
607 * broadcasts. Hash keys are the receiver IBinder, hash value is
608 * a ReceiverList.
609 */
610 final HashMap mRegisteredReceivers = new HashMap();
611
612 /**
613 * Resolver for broadcast intents to registered receivers.
614 * Holds BroadcastFilter (subclass of IntentFilter).
615 */
616 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
617 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
618 @Override
619 protected boolean allowFilterResult(
620 BroadcastFilter filter, List<BroadcastFilter> dest) {
621 IBinder target = filter.receiverList.receiver.asBinder();
622 for (int i=dest.size()-1; i>=0; i--) {
623 if (dest.get(i).receiverList.receiver.asBinder() == target) {
624 return false;
625 }
626 }
627 return true;
628 }
629 };
630
631 /**
632 * State of all active sticky broadcasts. Keys are the action of the
633 * sticky Intent, values are an ArrayList of all broadcasted intents with
634 * that action (which should usually be one).
635 */
636 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
637 new HashMap<String, ArrayList<Intent>>();
638
639 /**
640 * All currently running services.
641 */
642 final HashMap<ComponentName, ServiceRecord> mServices =
643 new HashMap<ComponentName, ServiceRecord>();
644
645 /**
646 * All currently running services indexed by the Intent used to start them.
647 */
648 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
649 new HashMap<Intent.FilterComparison, ServiceRecord>();
650
651 /**
652 * All currently bound service connections. Keys are the IBinder of
653 * the client's IServiceConnection.
654 */
655 final HashMap<IBinder, ConnectionRecord> mServiceConnections
656 = new HashMap<IBinder, ConnectionRecord>();
657
658 /**
659 * List of services that we have been asked to start,
660 * but haven't yet been able to. It is used to hold start requests
661 * while waiting for their corresponding application thread to get
662 * going.
663 */
664 final ArrayList<ServiceRecord> mPendingServices
665 = new ArrayList<ServiceRecord>();
666
667 /**
668 * List of services that are scheduled to restart following a crash.
669 */
670 final ArrayList<ServiceRecord> mRestartingServices
671 = new ArrayList<ServiceRecord>();
672
673 /**
674 * List of services that are in the process of being stopped.
675 */
676 final ArrayList<ServiceRecord> mStoppingServices
677 = new ArrayList<ServiceRecord>();
678
679 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700680 * Backup/restore process management
681 */
682 String mBackupAppName = null;
683 BackupRecord mBackupTarget = null;
684
685 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 * List of PendingThumbnailsRecord objects of clients who are still
687 * waiting to receive all of the thumbnails for a task.
688 */
689 final ArrayList mPendingThumbnails = new ArrayList();
690
691 /**
692 * List of HistoryRecord objects that have been finished and must
693 * still report back to a pending thumbnail receiver.
694 */
695 final ArrayList mCancelledThumbnails = new ArrayList();
696
697 /**
698 * All of the currently running global content providers. Keys are a
699 * string containing the provider name and values are a
700 * ContentProviderRecord object containing the data about it. Note
701 * that a single provider may be published under multiple names, so
702 * there may be multiple entries here for a single one in mProvidersByClass.
703 */
704 final HashMap mProvidersByName = new HashMap();
705
706 /**
707 * All of the currently running global content providers. Keys are a
708 * string containing the provider's implementation class and values are a
709 * ContentProviderRecord object containing the data about it.
710 */
711 final HashMap mProvidersByClass = new HashMap();
712
713 /**
714 * List of content providers who have clients waiting for them. The
715 * application is currently being launched and the provider will be
716 * removed from this list once it is published.
717 */
718 final ArrayList mLaunchingProviders = new ArrayList();
719
720 /**
721 * Global set of specific Uri permissions that have been granted.
722 */
723 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
724 = new SparseArray<HashMap<Uri, UriPermission>>();
725
726 /**
727 * Thread-local storage used to carry caller permissions over through
728 * indirect content-provider access.
729 * @see #ActivityManagerService.openContentUri()
730 */
731 private class Identity {
732 public int pid;
733 public int uid;
734
735 Identity(int _pid, int _uid) {
736 pid = _pid;
737 uid = _uid;
738 }
739 }
740 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
741
742 /**
743 * All information we have collected about the runtime performance of
744 * any user id that can impact battery performance.
745 */
746 final BatteryStatsService mBatteryStatsService;
747
748 /**
749 * information about component usage
750 */
751 final UsageStatsService mUsageStatsService;
752
753 /**
754 * Current configuration information. HistoryRecord objects are given
755 * a reference to this object to indicate which configuration they are
756 * currently running in, so this object must be kept immutable.
757 */
758 Configuration mConfiguration = new Configuration();
759
760 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700761 * Hardware-reported OpenGLES version.
762 */
763 final int GL_ES_VERSION;
764
765 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 * List of initialization arguments to pass to all processes when binding applications to them.
767 * For example, references to the commonly used services.
768 */
769 HashMap<String, IBinder> mAppBindArgs;
770
771 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700772 * Temporary to avoid allocations. Protected by main lock.
773 */
774 final StringBuilder mStringBuilder = new StringBuilder(256);
775
776 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 * Used to control how we initialize the service.
778 */
779 boolean mStartRunning = false;
780 ComponentName mTopComponent;
781 String mTopAction;
782 String mTopData;
783 boolean mSystemReady = false;
784 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700785 boolean mWaitingUpdate = false;
786 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787
788 Context mContext;
789
790 int mFactoryTest;
791
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700792 boolean mCheckedForSetup;
793
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700795 * The time at which we will allow normal application switches again,
796 * after a call to {@link #stopAppSwitches()}.
797 */
798 long mAppSwitchesAllowedTime;
799
800 /**
801 * This is set to true after the first switch after mAppSwitchesAllowedTime
802 * is set; any switches after that will clear the time.
803 */
804 boolean mDidAppSwitch;
805
806 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 * Set while we are wanting to sleep, to prevent any
808 * activities from being started/resumed.
809 */
810 boolean mSleeping = false;
811
812 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700813 * Set if we are shutting down the system, similar to sleeping.
814 */
815 boolean mShuttingDown = false;
816
817 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 * Set when the system is going to sleep, until we have
819 * successfully paused the current activity and released our wake lock.
820 * At that point the system is allowed to actually sleep.
821 */
822 PowerManager.WakeLock mGoingToSleep;
823
824 /**
825 * We don't want to allow the device to go to sleep while in the process
826 * of launching an activity. This is primarily to allow alarm intent
827 * receivers to launch an activity and get that to run before the device
828 * goes back to sleep.
829 */
830 PowerManager.WakeLock mLaunchingActivity;
831
832 /**
833 * Task identifier that activities are currently being started
834 * in. Incremented each time a new task is created.
835 * todo: Replace this with a TokenSpace class that generates non-repeating
836 * integers that won't wrap.
837 */
838 int mCurTask = 1;
839
840 /**
841 * Current sequence id for oom_adj computation traversal.
842 */
843 int mAdjSeq = 0;
844
845 /**
846 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
847 * is set, indicating the user wants processes started in such a way
848 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
849 * running in each process (thus no pre-initialized process, etc).
850 */
851 boolean mSimpleProcessManagement = false;
852
853 /**
854 * System monitoring: number of processes that died since the last
855 * N procs were started.
856 */
857 int[] mProcDeaths = new int[20];
858
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700859 /**
860 * This is set if we had to do a delayed dexopt of an app before launching
861 * it, to increasing the ANR timeouts in that case.
862 */
863 boolean mDidDexOpt;
864
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800865 String mDebugApp = null;
866 boolean mWaitForDebugger = false;
867 boolean mDebugTransient = false;
868 String mOrigDebugApp = null;
869 boolean mOrigWaitForDebugger = false;
870 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700871 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800872
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700873 final RemoteCallbackList<IActivityWatcher> mWatchers
874 = new RemoteCallbackList<IActivityWatcher>();
875
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 /**
877 * Callback of last caller to {@link #requestPss}.
878 */
879 Runnable mRequestPssCallback;
880
881 /**
882 * Remaining processes for which we are waiting results from the last
883 * call to {@link #requestPss}.
884 */
885 final ArrayList<ProcessRecord> mRequestPssList
886 = new ArrayList<ProcessRecord>();
887
888 /**
889 * Runtime statistics collection thread. This object's lock is used to
890 * protect all related state.
891 */
892 final Thread mProcessStatsThread;
893
894 /**
895 * Used to collect process stats when showing not responding dialog.
896 * Protected by mProcessStatsThread.
897 */
898 final ProcessStats mProcessStats = new ProcessStats(
899 MONITOR_THREAD_CPU_USAGE);
900 long mLastCpuTime = 0;
901 long mLastWriteTime = 0;
902
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700903 long mInitialStartTime = 0;
904
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 /**
906 * Set to true after the system has finished booting.
907 */
908 boolean mBooted = false;
909
910 int mProcessLimit = 0;
911
912 WindowManagerService mWindowManager;
913
914 static ActivityManagerService mSelf;
915 static ActivityThread mSystemThread;
916
917 private final class AppDeathRecipient implements IBinder.DeathRecipient {
918 final ProcessRecord mApp;
919 final int mPid;
920 final IApplicationThread mAppThread;
921
922 AppDeathRecipient(ProcessRecord app, int pid,
923 IApplicationThread thread) {
924 if (localLOGV) Log.v(
925 TAG, "New death recipient " + this
926 + " for thread " + thread.asBinder());
927 mApp = app;
928 mPid = pid;
929 mAppThread = thread;
930 }
931
932 public void binderDied() {
933 if (localLOGV) Log.v(
934 TAG, "Death received in " + this
935 + " for thread " + mAppThread.asBinder());
936 removeRequestedPss(mApp);
937 synchronized(ActivityManagerService.this) {
938 appDiedLocked(mApp, mPid, mAppThread);
939 }
940 }
941 }
942
943 static final int SHOW_ERROR_MSG = 1;
944 static final int SHOW_NOT_RESPONDING_MSG = 2;
945 static final int SHOW_FACTORY_ERROR_MSG = 3;
946 static final int UPDATE_CONFIGURATION_MSG = 4;
947 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
948 static final int WAIT_FOR_DEBUGGER_MSG = 6;
949 static final int BROADCAST_INTENT_MSG = 7;
950 static final int BROADCAST_TIMEOUT_MSG = 8;
951 static final int PAUSE_TIMEOUT_MSG = 9;
952 static final int IDLE_TIMEOUT_MSG = 10;
953 static final int IDLE_NOW_MSG = 11;
954 static final int SERVICE_TIMEOUT_MSG = 12;
955 static final int UPDATE_TIME_ZONE = 13;
956 static final int SHOW_UID_ERROR_MSG = 14;
957 static final int IM_FEELING_LUCKY_MSG = 15;
958 static final int LAUNCH_TIMEOUT_MSG = 16;
959 static final int DESTROY_TIMEOUT_MSG = 17;
960 static final int SERVICE_ERROR_MSG = 18;
961 static final int RESUME_TOP_ACTIVITY_MSG = 19;
962 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700963 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700964 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965
966 AlertDialog mUidAlert;
967
968 final Handler mHandler = new Handler() {
969 //public Handler() {
970 // if (localLOGV) Log.v(TAG, "Handler started!");
971 //}
972
973 public void handleMessage(Message msg) {
974 switch (msg.what) {
975 case SHOW_ERROR_MSG: {
976 HashMap data = (HashMap) msg.obj;
977 byte[] crashData = (byte[])data.get("crashData");
978 if (crashData != null) {
979 // This needs to be *un*synchronized to avoid deadlock.
980 ContentResolver resolver = mContext.getContentResolver();
981 Checkin.reportCrash(resolver, crashData);
982 }
983 synchronized (ActivityManagerService.this) {
984 ProcessRecord proc = (ProcessRecord)data.get("app");
985 if (proc != null && proc.crashDialog != null) {
986 Log.e(TAG, "App already has crash dialog: " + proc);
987 return;
988 }
989 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700990 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991 Dialog d = new AppErrorDialog(
992 mContext, res, proc,
993 (Integer)data.get("flags"),
994 (String)data.get("shortMsg"),
995 (String)data.get("longMsg"));
996 d.show();
997 proc.crashDialog = d;
998 } else {
999 // The device is asleep, so just pretend that the user
1000 // saw a crash dialog and hit "force quit".
1001 res.set(0);
1002 }
1003 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001004
1005 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001006 } break;
1007 case SHOW_NOT_RESPONDING_MSG: {
1008 synchronized (ActivityManagerService.this) {
1009 HashMap data = (HashMap) msg.obj;
1010 ProcessRecord proc = (ProcessRecord)data.get("app");
1011 if (proc != null && proc.anrDialog != null) {
1012 Log.e(TAG, "App already has anr dialog: " + proc);
1013 return;
1014 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001015
1016 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1017 null, null, 0, null, null, null,
1018 false, false, MY_PID, Process.SYSTEM_UID);
1019
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1021 mContext, proc, (HistoryRecord)data.get("activity"));
1022 d.show();
1023 proc.anrDialog = d;
1024 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001025
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001026 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001027 } break;
1028 case SHOW_FACTORY_ERROR_MSG: {
1029 Dialog d = new FactoryErrorDialog(
1030 mContext, msg.getData().getCharSequence("msg"));
1031 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001032 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033 } break;
1034 case UPDATE_CONFIGURATION_MSG: {
1035 final ContentResolver resolver = mContext.getContentResolver();
1036 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1037 } break;
1038 case GC_BACKGROUND_PROCESSES_MSG: {
1039 synchronized (ActivityManagerService.this) {
1040 performAppGcsIfAppropriateLocked();
1041 }
1042 } break;
1043 case WAIT_FOR_DEBUGGER_MSG: {
1044 synchronized (ActivityManagerService.this) {
1045 ProcessRecord app = (ProcessRecord)msg.obj;
1046 if (msg.arg1 != 0) {
1047 if (!app.waitedForDebugger) {
1048 Dialog d = new AppWaitingForDebuggerDialog(
1049 ActivityManagerService.this,
1050 mContext, app);
1051 app.waitDialog = d;
1052 app.waitedForDebugger = true;
1053 d.show();
1054 }
1055 } else {
1056 if (app.waitDialog != null) {
1057 app.waitDialog.dismiss();
1058 app.waitDialog = null;
1059 }
1060 }
1061 }
1062 } break;
1063 case BROADCAST_INTENT_MSG: {
1064 if (DEBUG_BROADCAST) Log.v(
1065 TAG, "Received BROADCAST_INTENT_MSG");
1066 processNextBroadcast(true);
1067 } break;
1068 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001069 if (mDidDexOpt) {
1070 mDidDexOpt = false;
1071 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1072 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1073 return;
1074 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001075 broadcastTimeout();
1076 } break;
1077 case PAUSE_TIMEOUT_MSG: {
1078 IBinder token = (IBinder)msg.obj;
1079 // We don't at this point know if the activity is fullscreen,
1080 // so we need to be conservative and assume it isn't.
1081 Log.w(TAG, "Activity pause timeout for " + token);
1082 activityPaused(token, null, true);
1083 } break;
1084 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001085 if (mDidDexOpt) {
1086 mDidDexOpt = false;
1087 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1088 nmsg.obj = msg.obj;
1089 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1090 return;
1091 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001092 // We don't at this point know if the activity is fullscreen,
1093 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001094 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001095 Log.w(TAG, "Activity idle timeout for " + token);
1096 activityIdleInternal(token, true);
1097 } break;
1098 case DESTROY_TIMEOUT_MSG: {
1099 IBinder token = (IBinder)msg.obj;
1100 // We don't at this point know if the activity is fullscreen,
1101 // so we need to be conservative and assume it isn't.
1102 Log.w(TAG, "Activity destroy timeout for " + token);
1103 activityDestroyed(token);
1104 } break;
1105 case IDLE_NOW_MSG: {
1106 IBinder token = (IBinder)msg.obj;
1107 activityIdle(token);
1108 } break;
1109 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001110 if (mDidDexOpt) {
1111 mDidDexOpt = false;
1112 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1113 nmsg.obj = msg.obj;
1114 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1115 return;
1116 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117 serviceTimeout((ProcessRecord)msg.obj);
1118 } break;
1119 case UPDATE_TIME_ZONE: {
1120 synchronized (ActivityManagerService.this) {
1121 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1122 ProcessRecord r = mLRUProcesses.get(i);
1123 if (r.thread != null) {
1124 try {
1125 r.thread.updateTimeZone();
1126 } catch (RemoteException ex) {
1127 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1128 }
1129 }
1130 }
1131 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001132 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001133 case SHOW_UID_ERROR_MSG: {
1134 // XXX This is a temporary dialog, no need to localize.
1135 AlertDialog d = new BaseErrorDialog(mContext);
1136 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1137 d.setCancelable(false);
1138 d.setTitle("System UIDs Inconsistent");
1139 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1140 d.setButton("I'm Feeling Lucky",
1141 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1142 mUidAlert = d;
1143 d.show();
1144 } break;
1145 case IM_FEELING_LUCKY_MSG: {
1146 if (mUidAlert != null) {
1147 mUidAlert.dismiss();
1148 mUidAlert = null;
1149 }
1150 } break;
1151 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001152 if (mDidDexOpt) {
1153 mDidDexOpt = false;
1154 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1155 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1156 return;
1157 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001158 synchronized (ActivityManagerService.this) {
1159 if (mLaunchingActivity.isHeld()) {
1160 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1161 mLaunchingActivity.release();
1162 }
1163 }
1164 } break;
1165 case SERVICE_ERROR_MSG: {
1166 ServiceRecord srv = (ServiceRecord)msg.obj;
1167 // This needs to be *un*synchronized to avoid deadlock.
1168 Checkin.logEvent(mContext.getContentResolver(),
1169 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1170 srv.name.toShortString());
1171 } break;
1172 case RESUME_TOP_ACTIVITY_MSG: {
1173 synchronized (ActivityManagerService.this) {
1174 resumeTopActivityLocked(null);
1175 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001176 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001178 if (mDidDexOpt) {
1179 mDidDexOpt = false;
1180 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1181 nmsg.obj = msg.obj;
1182 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1183 return;
1184 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001185 ProcessRecord app = (ProcessRecord)msg.obj;
1186 synchronized (ActivityManagerService.this) {
1187 processStartTimedOutLocked(app);
1188 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001189 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001190 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1191 synchronized (ActivityManagerService.this) {
1192 doPendingActivityLaunchesLocked(true);
1193 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001194 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001195 case KILL_APPLICATION_MSG: {
1196 synchronized (ActivityManagerService.this) {
1197 int uid = msg.arg1;
1198 boolean restart = (msg.arg2 == 1);
1199 String pkg = (String) msg.obj;
1200 uninstallPackageLocked(pkg, uid, restart);
1201 }
1202 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001203 }
1204 }
1205 };
1206
1207 public static void setSystemProcess() {
1208 try {
1209 ActivityManagerService m = mSelf;
1210
1211 ServiceManager.addService("activity", m);
1212 ServiceManager.addService("meminfo", new MemBinder(m));
1213 if (MONITOR_CPU_USAGE) {
1214 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1215 }
1216 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1217 ServiceManager.addService("activity.services", new ServicesBinder(m));
1218 ServiceManager.addService("activity.senders", new SendersBinder(m));
1219 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1220 ServiceManager.addService("permission", new PermissionController(m));
1221
1222 ApplicationInfo info =
1223 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001224 "android", STOCK_PM_FLAGS);
Mike Cleron432b7132009-09-24 15:28:29 -07001225 mSystemThread.installSystemApplicationInfo(info);
1226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001227 synchronized (mSelf) {
1228 ProcessRecord app = mSelf.newProcessRecordLocked(
1229 mSystemThread.getApplicationThread(), info,
1230 info.processName);
1231 app.persistent = true;
1232 app.pid = Process.myPid();
1233 app.maxAdj = SYSTEM_ADJ;
1234 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1235 synchronized (mSelf.mPidsSelfLocked) {
1236 mSelf.mPidsSelfLocked.put(app.pid, app);
1237 }
1238 mSelf.updateLRUListLocked(app, true);
1239 }
1240 } catch (PackageManager.NameNotFoundException e) {
1241 throw new RuntimeException(
1242 "Unable to find android system package", e);
1243 }
1244 }
1245
1246 public void setWindowManager(WindowManagerService wm) {
1247 mWindowManager = wm;
1248 }
1249
1250 public static final Context main(int factoryTest) {
1251 AThread thr = new AThread();
1252 thr.start();
1253
1254 synchronized (thr) {
1255 while (thr.mService == null) {
1256 try {
1257 thr.wait();
1258 } catch (InterruptedException e) {
1259 }
1260 }
1261 }
1262
1263 ActivityManagerService m = thr.mService;
1264 mSelf = m;
1265 ActivityThread at = ActivityThread.systemMain();
1266 mSystemThread = at;
1267 Context context = at.getSystemContext();
1268 m.mContext = context;
1269 m.mFactoryTest = factoryTest;
1270 PowerManager pm =
1271 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1272 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1273 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1274 m.mLaunchingActivity.setReferenceCounted(false);
1275
1276 m.mBatteryStatsService.publish(context);
1277 m.mUsageStatsService.publish(context);
1278
1279 synchronized (thr) {
1280 thr.mReady = true;
1281 thr.notifyAll();
1282 }
1283
1284 m.startRunning(null, null, null, null);
1285
1286 return context;
1287 }
1288
1289 public static ActivityManagerService self() {
1290 return mSelf;
1291 }
1292
1293 static class AThread extends Thread {
1294 ActivityManagerService mService;
1295 boolean mReady = false;
1296
1297 public AThread() {
1298 super("ActivityManager");
1299 }
1300
1301 public void run() {
1302 Looper.prepare();
1303
1304 android.os.Process.setThreadPriority(
1305 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1306
1307 ActivityManagerService m = new ActivityManagerService();
1308
1309 synchronized (this) {
1310 mService = m;
1311 notifyAll();
1312 }
1313
1314 synchronized (this) {
1315 while (!mReady) {
1316 try {
1317 wait();
1318 } catch (InterruptedException e) {
1319 }
1320 }
1321 }
1322
1323 Looper.loop();
1324 }
1325 }
1326
1327 static class BroadcastsBinder extends Binder {
1328 ActivityManagerService mActivityManagerService;
1329 BroadcastsBinder(ActivityManagerService activityManagerService) {
1330 mActivityManagerService = activityManagerService;
1331 }
1332
1333 @Override
1334 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1335 mActivityManagerService.dumpBroadcasts(pw);
1336 }
1337 }
1338
1339 static class ServicesBinder extends Binder {
1340 ActivityManagerService mActivityManagerService;
1341 ServicesBinder(ActivityManagerService activityManagerService) {
1342 mActivityManagerService = activityManagerService;
1343 }
1344
1345 @Override
1346 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1347 mActivityManagerService.dumpServices(pw);
1348 }
1349 }
1350
1351 static class SendersBinder extends Binder {
1352 ActivityManagerService mActivityManagerService;
1353 SendersBinder(ActivityManagerService activityManagerService) {
1354 mActivityManagerService = activityManagerService;
1355 }
1356
1357 @Override
1358 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1359 mActivityManagerService.dumpSenders(pw);
1360 }
1361 }
1362
1363 static class ProvidersBinder extends Binder {
1364 ActivityManagerService mActivityManagerService;
1365 ProvidersBinder(ActivityManagerService activityManagerService) {
1366 mActivityManagerService = activityManagerService;
1367 }
1368
1369 @Override
1370 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1371 mActivityManagerService.dumpProviders(pw);
1372 }
1373 }
1374
1375 static class MemBinder extends Binder {
1376 ActivityManagerService mActivityManagerService;
1377 MemBinder(ActivityManagerService activityManagerService) {
1378 mActivityManagerService = activityManagerService;
1379 }
1380
1381 @Override
1382 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1383 ActivityManagerService service = mActivityManagerService;
1384 ArrayList<ProcessRecord> procs;
1385 synchronized (mActivityManagerService) {
1386 if (args != null && args.length > 0
1387 && args[0].charAt(0) != '-') {
1388 procs = new ArrayList<ProcessRecord>();
1389 int pid = -1;
1390 try {
1391 pid = Integer.parseInt(args[0]);
1392 } catch (NumberFormatException e) {
1393
1394 }
1395 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1396 ProcessRecord proc = service.mLRUProcesses.get(i);
1397 if (proc.pid == pid) {
1398 procs.add(proc);
1399 } else if (proc.processName.equals(args[0])) {
1400 procs.add(proc);
1401 }
1402 }
1403 if (procs.size() <= 0) {
1404 pw.println("No process found for: " + args[0]);
1405 return;
1406 }
1407 } else {
1408 procs = service.mLRUProcesses;
1409 }
1410 }
1411 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1412 }
1413 }
1414
1415 static class CpuBinder extends Binder {
1416 ActivityManagerService mActivityManagerService;
1417 CpuBinder(ActivityManagerService activityManagerService) {
1418 mActivityManagerService = activityManagerService;
1419 }
1420
1421 @Override
1422 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1423 synchronized (mActivityManagerService.mProcessStatsThread) {
1424 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1425 }
1426 }
1427 }
1428
1429 private ActivityManagerService() {
1430 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1431 if (v != null && Integer.getInteger(v) != 0) {
1432 mSimpleProcessManagement = true;
1433 }
1434 v = System.getenv("ANDROID_DEBUG_APP");
1435 if (v != null) {
1436 mSimpleProcessManagement = true;
1437 }
1438
1439 MY_PID = Process.myPid();
1440
1441 File dataDir = Environment.getDataDirectory();
1442 File systemDir = new File(dataDir, "system");
1443 systemDir.mkdirs();
1444 mBatteryStatsService = new BatteryStatsService(new File(
1445 systemDir, "batterystats.bin").toString());
1446 mBatteryStatsService.getActiveStatistics().readLocked();
1447 mBatteryStatsService.getActiveStatistics().writeLocked();
1448
1449 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001450 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451
Jack Palevichb90d28c2009-07-22 15:35:24 -07001452 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1453 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1454
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001455 mConfiguration.makeDefault();
1456 mProcessStats.init();
1457
1458 // Add ourself to the Watchdog monitors.
1459 Watchdog.getInstance().addMonitor(this);
1460
1461 // These values are set in system/rootdir/init.rc on startup.
1462 FOREGROUND_APP_ADJ =
1463 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1464 VISIBLE_APP_ADJ =
1465 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1466 SECONDARY_SERVER_ADJ =
1467 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001468 BACKUP_APP_ADJ =
1469 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001470 HOME_APP_ADJ =
1471 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472 HIDDEN_APP_MIN_ADJ =
1473 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1474 CONTENT_PROVIDER_ADJ =
1475 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1476 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1477 EMPTY_APP_ADJ =
1478 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1479 FOREGROUND_APP_MEM =
1480 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1481 VISIBLE_APP_MEM =
1482 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1483 SECONDARY_SERVER_MEM =
1484 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001485 BACKUP_APP_MEM =
1486 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001487 HOME_APP_MEM =
1488 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 HIDDEN_APP_MEM =
1490 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1491 EMPTY_APP_MEM =
1492 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1493
1494 mProcessStatsThread = new Thread("ProcessStats") {
1495 public void run() {
1496 while (true) {
1497 try {
1498 try {
1499 synchronized(this) {
1500 final long now = SystemClock.uptimeMillis();
1501 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1502 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1503 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1504 // + ", write delay=" + nextWriteDelay);
1505 if (nextWriteDelay < nextCpuDelay) {
1506 nextCpuDelay = nextWriteDelay;
1507 }
1508 if (nextCpuDelay > 0) {
1509 this.wait(nextCpuDelay);
1510 }
1511 }
1512 } catch (InterruptedException e) {
1513 }
1514
1515 updateCpuStatsNow();
1516 } catch (Exception e) {
1517 Log.e(TAG, "Unexpected exception collecting process stats", e);
1518 }
1519 }
1520 }
1521 };
1522 mProcessStatsThread.start();
1523 }
1524
1525 @Override
1526 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1527 throws RemoteException {
1528 try {
1529 return super.onTransact(code, data, reply, flags);
1530 } catch (RuntimeException e) {
1531 // The activity manager only throws security exceptions, so let's
1532 // log all others.
1533 if (!(e instanceof SecurityException)) {
1534 Log.e(TAG, "Activity Manager Crash", e);
1535 }
1536 throw e;
1537 }
1538 }
1539
1540 void updateCpuStats() {
1541 synchronized (mProcessStatsThread) {
1542 final long now = SystemClock.uptimeMillis();
1543 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1544 mProcessStatsThread.notify();
1545 }
1546 }
1547 }
1548
1549 void updateCpuStatsNow() {
1550 synchronized (mProcessStatsThread) {
1551 final long now = SystemClock.uptimeMillis();
1552 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 if (MONITOR_CPU_USAGE &&
1555 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1556 mLastCpuTime = now;
1557 haveNewCpuStats = true;
1558 mProcessStats.update();
1559 //Log.i(TAG, mProcessStats.printCurrentState());
1560 //Log.i(TAG, "Total CPU usage: "
1561 // + mProcessStats.getTotalCpuPercent() + "%");
1562
1563 // Log the cpu usage if the property is set.
1564 if ("true".equals(SystemProperties.get("events.cpu"))) {
1565 int user = mProcessStats.getLastUserTime();
1566 int system = mProcessStats.getLastSystemTime();
1567 int iowait = mProcessStats.getLastIoWaitTime();
1568 int irq = mProcessStats.getLastIrqTime();
1569 int softIrq = mProcessStats.getLastSoftIrqTime();
1570 int idle = mProcessStats.getLastIdleTime();
1571
1572 int total = user + system + iowait + irq + softIrq + idle;
1573 if (total == 0) total = 1;
1574
1575 EventLog.writeEvent(LOG_CPU,
1576 ((user+system+iowait+irq+softIrq) * 100) / total,
1577 (user * 100) / total,
1578 (system * 100) / total,
1579 (iowait * 100) / total,
1580 (irq * 100) / total,
1581 (softIrq * 100) / total);
1582 }
1583 }
1584
Amith Yamasanie43530a2009-08-21 13:11:37 -07001585 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001586 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001587 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001588 synchronized(mPidsSelfLocked) {
1589 if (haveNewCpuStats) {
1590 if (mBatteryStatsService.isOnBattery()) {
1591 final int N = mProcessStats.countWorkingStats();
1592 for (int i=0; i<N; i++) {
1593 ProcessStats.Stats st
1594 = mProcessStats.getWorkingStats(i);
1595 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1596 if (pr != null) {
1597 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1598 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001599 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001600 } else {
1601 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001602 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001603 if (ps != null) {
1604 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001605 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001606 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607 }
1608 }
1609 }
1610 }
1611 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001612
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001613 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1614 mLastWriteTime = now;
1615 mBatteryStatsService.getActiveStatistics().writeLocked();
1616 }
1617 }
1618 }
1619 }
1620
1621 /**
1622 * Initialize the application bind args. These are passed to each
1623 * process when the bindApplication() IPC is sent to the process. They're
1624 * lazily setup to make sure the services are running when they're asked for.
1625 */
1626 private HashMap<String, IBinder> getCommonServicesLocked() {
1627 if (mAppBindArgs == null) {
1628 mAppBindArgs = new HashMap<String, IBinder>();
1629
1630 // Setup the application init args
1631 mAppBindArgs.put("package", ServiceManager.getService("package"));
1632 mAppBindArgs.put("window", ServiceManager.getService("window"));
1633 mAppBindArgs.put(Context.ALARM_SERVICE,
1634 ServiceManager.getService(Context.ALARM_SERVICE));
1635 }
1636 return mAppBindArgs;
1637 }
1638
1639 private final void setFocusedActivityLocked(HistoryRecord r) {
1640 if (mFocusedActivity != r) {
1641 mFocusedActivity = r;
1642 mWindowManager.setFocusedApp(r, true);
1643 }
1644 }
1645
1646 private final void updateLRUListLocked(ProcessRecord app,
1647 boolean oomAdj) {
1648 // put it on the LRU to keep track of when it should be exited.
1649 int lrui = mLRUProcesses.indexOf(app);
1650 if (lrui >= 0) mLRUProcesses.remove(lrui);
1651 mLRUProcesses.add(app);
1652 //Log.i(TAG, "Putting proc to front: " + app.processName);
1653 if (oomAdj) {
1654 updateOomAdjLocked();
1655 }
1656 }
1657
1658 private final boolean updateLRUListLocked(HistoryRecord r) {
1659 final boolean hadit = mLRUActivities.remove(r);
1660 mLRUActivities.add(r);
1661 return hadit;
1662 }
1663
1664 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1665 int i = mHistory.size()-1;
1666 while (i >= 0) {
1667 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1668 if (!r.finishing && r != notTop) {
1669 return r;
1670 }
1671 i--;
1672 }
1673 return null;
1674 }
1675
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001676 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1677 int i = mHistory.size()-1;
1678 while (i >= 0) {
1679 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1680 if (!r.finishing && !r.delayedResume && r != notTop) {
1681 return r;
1682 }
1683 i--;
1684 }
1685 return null;
1686 }
1687
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001688 /**
1689 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001690 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 *
1692 * @param token If non-null, any history records matching this token will be skipped.
1693 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1694 *
1695 * @return Returns the HistoryRecord of the next activity on the stack.
1696 */
1697 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1698 int i = mHistory.size()-1;
1699 while (i >= 0) {
1700 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1701 // Note: the taskId check depends on real taskId fields being non-zero
1702 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1703 return r;
1704 }
1705 i--;
1706 }
1707 return null;
1708 }
1709
1710 private final ProcessRecord getProcessRecordLocked(
1711 String processName, int uid) {
1712 if (uid == Process.SYSTEM_UID) {
1713 // The system gets to run in any process. If there are multiple
1714 // processes with the same uid, just pick the first (this
1715 // should never happen).
1716 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1717 processName);
1718 return procs != null ? procs.valueAt(0) : null;
1719 }
1720 ProcessRecord proc = mProcessNames.get(processName, uid);
1721 return proc;
1722 }
1723
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001724 private void ensurePackageDexOpt(String packageName) {
1725 IPackageManager pm = ActivityThread.getPackageManager();
1726 try {
1727 if (pm.performDexOpt(packageName)) {
1728 mDidDexOpt = true;
1729 }
1730 } catch (RemoteException e) {
1731 }
1732 }
1733
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 private boolean isNextTransitionForward() {
1735 int transit = mWindowManager.getPendingAppTransition();
1736 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1737 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1738 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1739 }
1740
1741 private final boolean realStartActivityLocked(HistoryRecord r,
1742 ProcessRecord app, boolean andResume, boolean checkConfig)
1743 throws RemoteException {
1744
1745 r.startFreezingScreenLocked(app, 0);
1746 mWindowManager.setAppVisibility(r, true);
1747
1748 // Have the window manager re-evaluate the orientation of
1749 // the screen based on the new activity order. Note that
1750 // as a result of this, it can call back into the activity
1751 // manager with a new orientation. We don't care about that,
1752 // because the activity is not currently running so we are
1753 // just restarting it anyway.
1754 if (checkConfig) {
1755 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001756 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001757 r.mayFreezeScreenLocked(app) ? r : null);
1758 updateConfigurationLocked(config, r);
1759 }
1760
1761 r.app = app;
1762
1763 if (localLOGV) Log.v(TAG, "Launching: " + r);
1764
1765 int idx = app.activities.indexOf(r);
1766 if (idx < 0) {
1767 app.activities.add(r);
1768 }
1769 updateLRUListLocked(app, true);
1770
1771 try {
1772 if (app.thread == null) {
1773 throw new RemoteException();
1774 }
1775 List<ResultInfo> results = null;
1776 List<Intent> newIntents = null;
1777 if (andResume) {
1778 results = r.results;
1779 newIntents = r.newIntents;
1780 }
1781 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1782 + " icicle=" + r.icicle
1783 + " with results=" + results + " newIntents=" + newIntents
1784 + " andResume=" + andResume);
1785 if (andResume) {
1786 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1787 System.identityHashCode(r),
1788 r.task.taskId, r.shortComponentName);
1789 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001790 if (r.isHomeActivity) {
1791 mHomeProcess = app;
1792 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001793 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001794 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001795 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001796 r.info, r.icicle, results, newIntents, !andResume,
1797 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001798 } catch (RemoteException e) {
1799 if (r.launchFailed) {
1800 // This is the second time we failed -- finish activity
1801 // and give up.
1802 Log.e(TAG, "Second failure launching "
1803 + r.intent.getComponent().flattenToShortString()
1804 + ", giving up", e);
1805 appDiedLocked(app, app.pid, app.thread);
1806 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1807 "2nd-crash");
1808 return false;
1809 }
1810
1811 // This is the first time we failed -- restart process and
1812 // retry.
1813 app.activities.remove(r);
1814 throw e;
1815 }
1816
1817 r.launchFailed = false;
1818 if (updateLRUListLocked(r)) {
1819 Log.w(TAG, "Activity " + r
1820 + " being launched, but already in LRU list");
1821 }
1822
1823 if (andResume) {
1824 // As part of the process of launching, ActivityThread also performs
1825 // a resume.
1826 r.state = ActivityState.RESUMED;
1827 r.icicle = null;
1828 r.haveState = false;
1829 r.stopped = false;
1830 mResumedActivity = r;
1831 r.task.touchActiveTime();
1832 completeResumeLocked(r);
1833 pauseIfSleepingLocked();
1834 } else {
1835 // This activity is not starting in the resumed state... which
1836 // should look like we asked it to pause+stop (but remain visible),
1837 // and it has done so and reported back the current icicle and
1838 // other state.
1839 r.state = ActivityState.STOPPED;
1840 r.stopped = true;
1841 }
1842
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001843 // Launch the new version setup screen if needed. We do this -after-
1844 // launching the initial activity (that is, home), so that it can have
1845 // a chance to initialize itself while in the background, making the
1846 // switch back to it faster and look better.
1847 startSetupActivityLocked();
1848
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001849 return true;
1850 }
1851
1852 private final void startSpecificActivityLocked(HistoryRecord r,
1853 boolean andResume, boolean checkConfig) {
1854 // Is this activity's application already running?
1855 ProcessRecord app = getProcessRecordLocked(r.processName,
1856 r.info.applicationInfo.uid);
1857
1858 if (r.startTime == 0) {
1859 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001860 if (mInitialStartTime == 0) {
1861 mInitialStartTime = r.startTime;
1862 }
1863 } else if (mInitialStartTime == 0) {
1864 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001865 }
1866
1867 if (app != null && app.thread != null) {
1868 try {
1869 realStartActivityLocked(r, app, andResume, checkConfig);
1870 return;
1871 } catch (RemoteException e) {
1872 Log.w(TAG, "Exception when starting activity "
1873 + r.intent.getComponent().flattenToShortString(), e);
1874 }
1875
1876 // If a dead object exception was thrown -- fall through to
1877 // restart the application.
1878 }
1879
1880 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001881 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001882 }
1883
1884 private final ProcessRecord startProcessLocked(String processName,
1885 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001886 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001887 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1888 // We don't have to do anything more if:
1889 // (1) There is an existing application record; and
1890 // (2) The caller doesn't think it is dead, OR there is no thread
1891 // object attached to it so we know it couldn't have crashed; and
1892 // (3) There is a pid assigned to it, so it is either starting or
1893 // already running.
1894 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1895 + " app=" + app + " knownToBeDead=" + knownToBeDead
1896 + " thread=" + (app != null ? app.thread : null)
1897 + " pid=" + (app != null ? app.pid : -1));
1898 if (app != null &&
1899 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1900 return app;
1901 }
1902
1903 String hostingNameStr = hostingName != null
1904 ? hostingName.flattenToShortString() : null;
1905
1906 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1907 // If we are in the background, then check to see if this process
1908 // is bad. If so, we will just silently fail.
1909 if (mBadProcesses.get(info.processName, info.uid) != null) {
1910 return null;
1911 }
1912 } else {
1913 // When the user is explicitly starting a process, then clear its
1914 // crash count so that we won't make it bad until they see at
1915 // least one crash dialog again, and make the process good again
1916 // if it had been bad.
1917 mProcessCrashTimes.remove(info.processName, info.uid);
1918 if (mBadProcesses.get(info.processName, info.uid) != null) {
1919 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1920 info.processName);
1921 mBadProcesses.remove(info.processName, info.uid);
1922 if (app != null) {
1923 app.bad = false;
1924 }
1925 }
1926 }
1927
1928 if (app == null) {
1929 app = newProcessRecordLocked(null, info, processName);
1930 mProcessNames.put(processName, info.uid, app);
1931 } else {
1932 // If this is a new package in the process, add the package to the list
1933 app.addPackage(info.packageName);
1934 }
1935
1936 // If the system is not ready yet, then hold off on starting this
1937 // process until it is.
1938 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001939 && !isAllowedWhileBooting(info)
1940 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001941 if (!mProcessesOnHold.contains(app)) {
1942 mProcessesOnHold.add(app);
1943 }
1944 return app;
1945 }
1946
1947 startProcessLocked(app, hostingType, hostingNameStr);
1948 return (app.pid != 0) ? app : null;
1949 }
1950
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001951 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1952 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1953 }
1954
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001955 private final void startProcessLocked(ProcessRecord app,
1956 String hostingType, String hostingNameStr) {
1957 if (app.pid > 0 && app.pid != MY_PID) {
1958 synchronized (mPidsSelfLocked) {
1959 mPidsSelfLocked.remove(app.pid);
1960 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1961 }
1962 app.pid = 0;
1963 }
1964
1965 mProcessesOnHold.remove(app);
1966
1967 updateCpuStats();
1968
1969 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1970 mProcDeaths[0] = 0;
1971
1972 try {
1973 int uid = app.info.uid;
1974 int[] gids = null;
1975 try {
1976 gids = mContext.getPackageManager().getPackageGids(
1977 app.info.packageName);
1978 } catch (PackageManager.NameNotFoundException e) {
1979 Log.w(TAG, "Unable to retrieve gids", e);
1980 }
1981 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1982 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1983 && mTopComponent != null
1984 && app.processName.equals(mTopComponent.getPackageName())) {
1985 uid = 0;
1986 }
1987 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1988 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1989 uid = 0;
1990 }
1991 }
1992 int debugFlags = 0;
1993 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1994 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1995 }
1996 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1997 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1998 }
1999 if ("1".equals(SystemProperties.get("debug.assert"))) {
2000 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
2001 }
2002 int pid = Process.start("android.app.ActivityThread",
2003 mSimpleProcessManagement ? app.processName : null, uid, uid,
2004 gids, debugFlags, null);
2005 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
2006 synchronized (bs) {
2007 if (bs.isOnBattery()) {
2008 app.batteryStats.incStartsLocked();
2009 }
2010 }
2011
2012 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
2013 app.processName, hostingType,
2014 hostingNameStr != null ? hostingNameStr : "");
2015
2016 if (app.persistent) {
2017 Watchdog.getInstance().processStarted(app, app.processName, pid);
2018 }
2019
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07002020 StringBuilder buf = mStringBuilder;
2021 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002022 buf.append("Start proc ");
2023 buf.append(app.processName);
2024 buf.append(" for ");
2025 buf.append(hostingType);
2026 if (hostingNameStr != null) {
2027 buf.append(" ");
2028 buf.append(hostingNameStr);
2029 }
2030 buf.append(": pid=");
2031 buf.append(pid);
2032 buf.append(" uid=");
2033 buf.append(uid);
2034 buf.append(" gids={");
2035 if (gids != null) {
2036 for (int gi=0; gi<gids.length; gi++) {
2037 if (gi != 0) buf.append(", ");
2038 buf.append(gids[gi]);
2039
2040 }
2041 }
2042 buf.append("}");
2043 Log.i(TAG, buf.toString());
2044 if (pid == 0 || pid == MY_PID) {
2045 // Processes are being emulated with threads.
2046 app.pid = MY_PID;
2047 app.removed = false;
2048 mStartingProcesses.add(app);
2049 } else if (pid > 0) {
2050 app.pid = pid;
2051 app.removed = false;
2052 synchronized (mPidsSelfLocked) {
2053 this.mPidsSelfLocked.put(pid, app);
2054 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2055 msg.obj = app;
2056 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2057 }
2058 } else {
2059 app.pid = 0;
2060 RuntimeException e = new RuntimeException(
2061 "Failure starting process " + app.processName
2062 + ": returned pid=" + pid);
2063 Log.e(TAG, e.getMessage(), e);
2064 }
2065 } catch (RuntimeException e) {
2066 // XXX do better error recovery.
2067 app.pid = 0;
2068 Log.e(TAG, "Failure starting process " + app.processName, e);
2069 }
2070 }
2071
2072 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2073 if (mPausingActivity != null) {
2074 RuntimeException e = new RuntimeException();
2075 Log.e(TAG, "Trying to pause when pause is already pending for "
2076 + mPausingActivity, e);
2077 }
2078 HistoryRecord prev = mResumedActivity;
2079 if (prev == null) {
2080 RuntimeException e = new RuntimeException();
2081 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2082 resumeTopActivityLocked(null);
2083 return;
2084 }
2085 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2086 mResumedActivity = null;
2087 mPausingActivity = prev;
2088 mLastPausedActivity = prev;
2089 prev.state = ActivityState.PAUSING;
2090 prev.task.touchActiveTime();
2091
2092 updateCpuStats();
2093
2094 if (prev.app != null && prev.app.thread != null) {
2095 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2096 try {
2097 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2098 System.identityHashCode(prev),
2099 prev.shortComponentName);
2100 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2101 prev.configChangeFlags);
2102 updateUsageStats(prev, false);
2103 } catch (Exception e) {
2104 // Ignore exception, if process died other code will cleanup.
2105 Log.w(TAG, "Exception thrown during pause", e);
2106 mPausingActivity = null;
2107 mLastPausedActivity = null;
2108 }
2109 } else {
2110 mPausingActivity = null;
2111 mLastPausedActivity = null;
2112 }
2113
2114 // If we are not going to sleep, we want to ensure the device is
2115 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002116 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002117 mLaunchingActivity.acquire();
2118 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2119 // To be safe, don't allow the wake lock to be held for too long.
2120 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2121 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2122 }
2123 }
2124
2125
2126 if (mPausingActivity != null) {
2127 // Have the window manager pause its key dispatching until the new
2128 // activity has started. If we're pausing the activity just because
2129 // the screen is being turned off and the UI is sleeping, don't interrupt
2130 // key dispatch; the same activity will pick it up again on wakeup.
2131 if (!uiSleeping) {
2132 prev.pauseKeyDispatchingLocked();
2133 } else {
2134 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2135 }
2136
2137 // Schedule a pause timeout in case the app doesn't respond.
2138 // We don't give it much time because this directly impacts the
2139 // responsiveness seen by the user.
2140 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2141 msg.obj = prev;
2142 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2143 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2144 } else {
2145 // This activity failed to schedule the
2146 // pause, so just treat it as being paused now.
2147 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2148 resumeTopActivityLocked(null);
2149 }
2150 }
2151
2152 private final void completePauseLocked() {
2153 HistoryRecord prev = mPausingActivity;
2154 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2155
2156 if (prev != null) {
2157 if (prev.finishing) {
2158 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2159 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2160 } else if (prev.app != null) {
2161 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2162 if (prev.waitingVisible) {
2163 prev.waitingVisible = false;
2164 mWaitingVisibleActivities.remove(prev);
2165 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2166 TAG, "Complete pause, no longer waiting: " + prev);
2167 }
2168 if (prev.configDestroy) {
2169 // The previous is being paused because the configuration
2170 // is changing, which means it is actually stopping...
2171 // To juggle the fact that we are also starting a new
2172 // instance right now, we need to first completely stop
2173 // the current instance before starting the new one.
2174 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2175 destroyActivityLocked(prev, true);
2176 } else {
2177 mStoppingActivities.add(prev);
2178 if (mStoppingActivities.size() > 3) {
2179 // If we already have a few activities waiting to stop,
2180 // then give up on things going idle and start clearing
2181 // them out.
2182 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2183 Message msg = Message.obtain();
2184 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2185 mHandler.sendMessage(msg);
2186 }
2187 }
2188 } else {
2189 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2190 prev = null;
2191 }
2192 mPausingActivity = null;
2193 }
2194
Dianne Hackborn55280a92009-05-07 15:53:46 -07002195 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002196 resumeTopActivityLocked(prev);
2197 } else {
2198 if (mGoingToSleep.isHeld()) {
2199 mGoingToSleep.release();
2200 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002201 if (mShuttingDown) {
2202 notifyAll();
2203 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002204 }
2205
2206 if (prev != null) {
2207 prev.resumeKeyDispatchingLocked();
2208 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002209
2210 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2211 long diff = 0;
2212 synchronized (mProcessStatsThread) {
2213 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2214 }
2215 if (diff > 0) {
2216 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2217 synchronized (bsi) {
2218 BatteryStatsImpl.Uid.Proc ps =
2219 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2220 prev.info.packageName);
2221 if (ps != null) {
2222 ps.addForegroundTimeLocked(diff);
2223 }
2224 }
2225 }
2226 }
2227 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002228 }
2229
2230 /**
2231 * Once we know that we have asked an application to put an activity in
2232 * the resumed state (either by launching it or explicitly telling it),
2233 * this function updates the rest of our state to match that fact.
2234 */
2235 private final void completeResumeLocked(HistoryRecord next) {
2236 next.idle = false;
2237 next.results = null;
2238 next.newIntents = null;
2239
2240 // schedule an idle timeout in case the app doesn't do it for us.
2241 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2242 msg.obj = next;
2243 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2244
2245 if (false) {
2246 // The activity was never told to pause, so just keep
2247 // things going as-is. To maintain our own state,
2248 // we need to emulate it coming back and saying it is
2249 // idle.
2250 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2251 msg.obj = next;
2252 mHandler.sendMessage(msg);
2253 }
2254
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002255 reportResumedActivity(next);
2256
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 Hackbornb06ea702009-07-13 13:07:51 -07002528 private void reportResumedActivity(HistoryRecord r) {
2529 //Log.i(TAG, "**** REPORT RESUME: " + r);
2530
2531 final int identHash = System.identityHashCode(r);
2532 updateUsageStats(r, true);
2533
2534 int i = mWatchers.beginBroadcast();
2535 while (i > 0) {
2536 i--;
2537 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2538 if (w != null) {
2539 try {
2540 w.activityResuming(identHash);
2541 } catch (RemoteException e) {
2542 }
2543 }
2544 }
2545 mWatchers.finishBroadcast();
2546 }
2547
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002548 /**
2549 * Ensure that the top activity in the stack is resumed.
2550 *
2551 * @param prev The previously resumed activity, for when in the process
2552 * of pausing; can be null to call from elsewhere.
2553 *
2554 * @return Returns true if something is being resumed, or false if
2555 * nothing happened.
2556 */
2557 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2558 // Find the first activity that is not finishing.
2559 HistoryRecord next = topRunningActivityLocked(null);
2560
2561 // Remember how we'll process this pause/resume situation, and ensure
2562 // that the state is reset however we wind up proceeding.
2563 final boolean userLeaving = mUserLeaving;
2564 mUserLeaving = false;
2565
2566 if (next == null) {
2567 // There are no more activities! Let's just start up the
2568 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002569 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002570 }
2571
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002572 next.delayedResume = false;
2573
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002574 // If the top activity is the resumed one, nothing to do.
2575 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2576 // Make sure we have executed any pending transitions, since there
2577 // should be nothing left to do at this point.
2578 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002579 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002580 return false;
2581 }
2582
2583 // If we are sleeping, and there is no resumed activity, and the top
2584 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002585 if ((mSleeping || mShuttingDown)
2586 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002587 // Make sure we have executed any pending transitions, since there
2588 // should be nothing left to do at this point.
2589 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002590 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002591 return false;
2592 }
2593
2594 // The activity may be waiting for stop, but that is no longer
2595 // appropriate for it.
2596 mStoppingActivities.remove(next);
2597 mWaitingVisibleActivities.remove(next);
2598
2599 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2600
2601 // If we are currently pausing an activity, then don't do anything
2602 // until that is done.
2603 if (mPausingActivity != null) {
2604 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2605 return false;
2606 }
2607
2608 // We need to start pausing the current activity so the top one
2609 // can be resumed...
2610 if (mResumedActivity != null) {
2611 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2612 startPausingLocked(userLeaving, false);
2613 return true;
2614 }
2615
2616 if (prev != null && prev != next) {
2617 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2618 prev.waitingVisible = true;
2619 mWaitingVisibleActivities.add(prev);
2620 if (DEBUG_SWITCH) Log.v(
2621 TAG, "Resuming top, waiting visible to hide: " + prev);
2622 } else {
2623 // The next activity is already visible, so hide the previous
2624 // activity's windows right now so we can show the new one ASAP.
2625 // We only do this if the previous is finishing, which should mean
2626 // it is on top of the one being resumed so hiding it quickly
2627 // is good. Otherwise, we want to do the normal route of allowing
2628 // the resumed activity to be shown so we can decide if the
2629 // previous should actually be hidden depending on whether the
2630 // new one is found to be full-screen or not.
2631 if (prev.finishing) {
2632 mWindowManager.setAppVisibility(prev, false);
2633 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2634 + prev + ", waitingVisible="
2635 + (prev != null ? prev.waitingVisible : null)
2636 + ", nowVisible=" + next.nowVisible);
2637 } else {
2638 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2639 + prev + ", waitingVisible="
2640 + (prev != null ? prev.waitingVisible : null)
2641 + ", nowVisible=" + next.nowVisible);
2642 }
2643 }
2644 }
2645
2646 // We are starting up the next activity, so tell the window manager
2647 // that the previous one will be hidden soon. This way it can know
2648 // to ignore it when computing the desired screen orientation.
2649 if (prev != null) {
2650 if (prev.finishing) {
2651 if (DEBUG_TRANSITION) Log.v(TAG,
2652 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002653 if (mNoAnimActivities.contains(prev)) {
2654 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2655 } else {
2656 mWindowManager.prepareAppTransition(prev.task == next.task
2657 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2658 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2659 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002660 mWindowManager.setAppWillBeHidden(prev);
2661 mWindowManager.setAppVisibility(prev, false);
2662 } else {
2663 if (DEBUG_TRANSITION) Log.v(TAG,
2664 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002665 if (mNoAnimActivities.contains(next)) {
2666 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2667 } else {
2668 mWindowManager.prepareAppTransition(prev.task == next.task
2669 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2670 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2671 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002672 }
2673 if (false) {
2674 mWindowManager.setAppWillBeHidden(prev);
2675 mWindowManager.setAppVisibility(prev, false);
2676 }
2677 } else if (mHistory.size() > 1) {
2678 if (DEBUG_TRANSITION) Log.v(TAG,
2679 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002680 if (mNoAnimActivities.contains(next)) {
2681 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2682 } else {
2683 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2684 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002685 }
2686
2687 if (next.app != null && next.app.thread != null) {
2688 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2689
2690 // This activity is now becoming visible.
2691 mWindowManager.setAppVisibility(next, true);
2692
2693 HistoryRecord lastResumedActivity = mResumedActivity;
2694 ActivityState lastState = next.state;
2695
2696 updateCpuStats();
2697
2698 next.state = ActivityState.RESUMED;
2699 mResumedActivity = next;
2700 next.task.touchActiveTime();
2701 updateLRUListLocked(next.app, true);
2702 updateLRUListLocked(next);
2703
2704 // Have the window manager re-evaluate the orientation of
2705 // the screen based on the new activity order.
2706 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002707 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002708 next.mayFreezeScreenLocked(next.app) ? next : null);
2709 if (config != null) {
2710 next.frozenBeforeDestroy = true;
2711 }
2712 if (!updateConfigurationLocked(config, next)) {
2713 // The configuration update wasn't able to keep the existing
2714 // instance of the activity, and instead started a new one.
2715 // We should be all done, but let's just make sure our activity
2716 // is still at the top and schedule another run if something
2717 // weird happened.
2718 HistoryRecord nextNext = topRunningActivityLocked(null);
2719 if (DEBUG_SWITCH) Log.i(TAG,
2720 "Activity config changed during resume: " + next
2721 + ", new next: " + nextNext);
2722 if (nextNext != next) {
2723 // Do over!
2724 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2725 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002726 setFocusedActivityLocked(next);
2727 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002728 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002729 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002730 return true;
2731 }
2732
2733 try {
2734 // Deliver all pending results.
2735 ArrayList a = next.results;
2736 if (a != null) {
2737 final int N = a.size();
2738 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002739 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002740 TAG, "Delivering results to " + next
2741 + ": " + a);
2742 next.app.thread.scheduleSendResult(next, a);
2743 }
2744 }
2745
2746 if (next.newIntents != null) {
2747 next.app.thread.scheduleNewIntent(next.newIntents, next);
2748 }
2749
2750 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2751 System.identityHashCode(next),
2752 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002753
2754 next.app.thread.scheduleResumeActivity(next,
2755 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002756
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002757 pauseIfSleepingLocked();
2758
2759 } catch (Exception e) {
2760 // Whoops, need to restart this activity!
2761 next.state = lastState;
2762 mResumedActivity = lastResumedActivity;
2763 if (Config.LOGD) Log.d(TAG,
2764 "Restarting because process died: " + next);
2765 if (!next.hasBeenLaunched) {
2766 next.hasBeenLaunched = true;
2767 } else {
2768 if (SHOW_APP_STARTING_ICON) {
2769 mWindowManager.setAppStartingWindow(
2770 next, next.packageName, next.theme,
2771 next.nonLocalizedLabel,
2772 next.labelRes, next.icon, null, true);
2773 }
2774 }
2775 startSpecificActivityLocked(next, true, false);
2776 return true;
2777 }
2778
2779 // From this point on, if something goes wrong there is no way
2780 // to recover the activity.
2781 try {
2782 next.visible = true;
2783 completeResumeLocked(next);
2784 } catch (Exception e) {
2785 // If any exception gets thrown, toss away this
2786 // activity and try the next one.
2787 Log.w(TAG, "Exception thrown during resume of " + next, e);
2788 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2789 "resume-exception");
2790 return true;
2791 }
2792
2793 // Didn't need to use the icicle, and it is now out of date.
2794 next.icicle = null;
2795 next.haveState = false;
2796 next.stopped = false;
2797
2798 } else {
2799 // Whoops, need to restart this activity!
2800 if (!next.hasBeenLaunched) {
2801 next.hasBeenLaunched = true;
2802 } else {
2803 if (SHOW_APP_STARTING_ICON) {
2804 mWindowManager.setAppStartingWindow(
2805 next, next.packageName, next.theme,
2806 next.nonLocalizedLabel,
2807 next.labelRes, next.icon, null, true);
2808 }
2809 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2810 }
2811 startSpecificActivityLocked(next, true, true);
2812 }
2813
2814 return true;
2815 }
2816
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002817 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2818 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002819 final int NH = mHistory.size();
2820
2821 int addPos = -1;
2822
2823 if (!newTask) {
2824 // If starting in an existing task, find where that is...
2825 HistoryRecord next = null;
2826 boolean startIt = true;
2827 for (int i = NH-1; i >= 0; i--) {
2828 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2829 if (p.finishing) {
2830 continue;
2831 }
2832 if (p.task == r.task) {
2833 // Here it is! Now, if this is not yet visible to the
2834 // user, then just add it without starting; it will
2835 // get started when the user navigates back to it.
2836 addPos = i+1;
2837 if (!startIt) {
2838 mHistory.add(addPos, r);
2839 r.inHistory = true;
2840 r.task.numActivities++;
2841 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2842 r.info.screenOrientation, r.fullscreen);
2843 if (VALIDATE_TOKENS) {
2844 mWindowManager.validateAppTokens(mHistory);
2845 }
2846 return;
2847 }
2848 break;
2849 }
2850 if (p.fullscreen) {
2851 startIt = false;
2852 }
2853 next = p;
2854 }
2855 }
2856
2857 // Place a new activity at top of stack, so it is next to interact
2858 // with the user.
2859 if (addPos < 0) {
2860 addPos = mHistory.size();
2861 }
2862
2863 // If we are not placing the new activity frontmost, we do not want
2864 // to deliver the onUserLeaving callback to the actual frontmost
2865 // activity
2866 if (addPos < NH) {
2867 mUserLeaving = false;
2868 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2869 }
2870
2871 // Slot the activity into the history stack and proceed
2872 mHistory.add(addPos, r);
2873 r.inHistory = true;
2874 r.frontOfTask = newTask;
2875 r.task.numActivities++;
2876 if (NH > 0) {
2877 // We want to show the starting preview window if we are
2878 // switching to a new task, or the next activity's process is
2879 // not currently running.
2880 boolean showStartingIcon = newTask;
2881 ProcessRecord proc = r.app;
2882 if (proc == null) {
2883 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2884 }
2885 if (proc == null || proc.thread == null) {
2886 showStartingIcon = true;
2887 }
2888 if (DEBUG_TRANSITION) Log.v(TAG,
2889 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002890 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2891 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2892 mNoAnimActivities.add(r);
2893 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2894 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2895 mNoAnimActivities.remove(r);
2896 } else {
2897 mWindowManager.prepareAppTransition(newTask
2898 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2899 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2900 mNoAnimActivities.remove(r);
2901 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002902 mWindowManager.addAppToken(
2903 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2904 boolean doShow = true;
2905 if (newTask) {
2906 // Even though this activity is starting fresh, we still need
2907 // to reset it to make sure we apply affinities to move any
2908 // existing activities from other tasks in to it.
2909 // If the caller has requested that the target task be
2910 // reset, then do so.
2911 if ((r.intent.getFlags()
2912 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2913 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002914 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002915 }
2916 }
2917 if (SHOW_APP_STARTING_ICON && doShow) {
2918 // Figure out if we are transitioning from another activity that is
2919 // "has the same starting icon" as the next one. This allows the
2920 // window manager to keep the previous window it had previously
2921 // created, if it still had one.
2922 HistoryRecord prev = mResumedActivity;
2923 if (prev != null) {
2924 // We don't want to reuse the previous starting preview if:
2925 // (1) The current activity is in a different task.
2926 if (prev.task != r.task) prev = null;
2927 // (2) The current activity is already displayed.
2928 else if (prev.nowVisible) prev = null;
2929 }
2930 mWindowManager.setAppStartingWindow(
2931 r, r.packageName, r.theme, r.nonLocalizedLabel,
2932 r.labelRes, r.icon, prev, showStartingIcon);
2933 }
2934 } else {
2935 // If this is the first activity, don't do any fancy animations,
2936 // because there is nothing for it to animate on top of.
2937 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2938 r.info.screenOrientation, r.fullscreen);
2939 }
2940 if (VALIDATE_TOKENS) {
2941 mWindowManager.validateAppTokens(mHistory);
2942 }
2943
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002944 if (doResume) {
2945 resumeTopActivityLocked(null);
2946 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002947 }
2948
2949 /**
2950 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002951 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2952 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002953 * an instance of that activity in the stack and, if found, finish all
2954 * activities on top of it and return the instance.
2955 *
2956 * @param newR Description of the new activity being started.
2957 * @return Returns the old activity that should be continue to be used,
2958 * or null if none was found.
2959 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002960 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002961 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002962 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002963
2964 // First find the requested task.
2965 while (i > 0) {
2966 i--;
2967 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2968 if (r.task.taskId == taskId) {
2969 i++;
2970 break;
2971 }
2972 }
2973
2974 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002975 while (i > 0) {
2976 i--;
2977 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2978 if (r.finishing) {
2979 continue;
2980 }
2981 if (r.task.taskId != taskId) {
2982 return null;
2983 }
2984 if (r.realActivity.equals(newR.realActivity)) {
2985 // Here it is! Now finish everything in front...
2986 HistoryRecord ret = r;
2987 if (doClear) {
2988 while (i < (mHistory.size()-1)) {
2989 i++;
2990 r = (HistoryRecord)mHistory.get(i);
2991 if (r.finishing) {
2992 continue;
2993 }
2994 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2995 null, "clear")) {
2996 i--;
2997 }
2998 }
2999 }
3000
3001 // Finally, if this is a normal launch mode (that is, not
3002 // expecting onNewIntent()), then we will finish the current
3003 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003004 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
3005 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003006 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003007 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003008 if (index >= 0) {
3009 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
3010 null, "clear");
3011 }
3012 return null;
3013 }
3014 }
3015
3016 return ret;
3017 }
3018 }
3019
3020 return null;
3021 }
3022
3023 /**
3024 * Find the activity in the history stack within the given task. Returns
3025 * the index within the history at which it's found, or < 0 if not found.
3026 */
3027 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3028 int i = mHistory.size();
3029 while (i > 0) {
3030 i--;
3031 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3032 if (candidate.task.taskId != task) {
3033 break;
3034 }
3035 if (candidate.realActivity.equals(r.realActivity)) {
3036 return i;
3037 }
3038 }
3039
3040 return -1;
3041 }
3042
3043 /**
3044 * Reorder the history stack so that the activity at the given index is
3045 * brought to the front.
3046 */
3047 private final HistoryRecord moveActivityToFrontLocked(int where) {
3048 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3049 int top = mHistory.size();
3050 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3051 mHistory.add(top, newTop);
3052 oldTop.frontOfTask = false;
3053 newTop.frontOfTask = true;
3054 return newTop;
3055 }
3056
3057 /**
3058 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3059 * method will be called at the proper time.
3060 */
3061 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3062 boolean sent = false;
3063 if (r.state == ActivityState.RESUMED
3064 && r.app != null && r.app.thread != null) {
3065 try {
3066 ArrayList<Intent> ar = new ArrayList<Intent>();
3067 ar.add(new Intent(intent));
3068 r.app.thread.scheduleNewIntent(ar, r);
3069 sent = true;
3070 } catch (Exception e) {
3071 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3072 }
3073 }
3074 if (!sent) {
3075 r.addNewIntentLocked(new Intent(intent));
3076 }
3077 }
3078
3079 private final void logStartActivity(int tag, HistoryRecord r,
3080 TaskRecord task) {
3081 EventLog.writeEvent(tag,
3082 System.identityHashCode(r), task.taskId,
3083 r.shortComponentName, r.intent.getAction(),
3084 r.intent.getType(), r.intent.getDataString(),
3085 r.intent.getFlags());
3086 }
3087
3088 private final int startActivityLocked(IApplicationThread caller,
3089 Intent intent, String resolvedType,
3090 Uri[] grantedUriPermissions,
3091 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3092 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003093 int callingPid, int callingUid, boolean onlyIfNeeded,
3094 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003095 Log.i(TAG, "Starting activity: " + intent);
3096
3097 HistoryRecord sourceRecord = null;
3098 HistoryRecord resultRecord = null;
3099 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003100 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003101 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003102 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3103 if (index >= 0) {
3104 sourceRecord = (HistoryRecord)mHistory.get(index);
3105 if (requestCode >= 0 && !sourceRecord.finishing) {
3106 resultRecord = sourceRecord;
3107 }
3108 }
3109 }
3110
3111 int launchFlags = intent.getFlags();
3112
3113 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3114 && sourceRecord != null) {
3115 // Transfer the result target from the source activity to the new
3116 // one being started, including any failures.
3117 if (requestCode >= 0) {
3118 return START_FORWARD_AND_REQUEST_CONFLICT;
3119 }
3120 resultRecord = sourceRecord.resultTo;
3121 resultWho = sourceRecord.resultWho;
3122 requestCode = sourceRecord.requestCode;
3123 sourceRecord.resultTo = null;
3124 if (resultRecord != null) {
3125 resultRecord.removeResultsLocked(
3126 sourceRecord, resultWho, requestCode);
3127 }
3128 }
3129
3130 int err = START_SUCCESS;
3131
3132 if (intent.getComponent() == null) {
3133 // We couldn't find a class that can handle the given Intent.
3134 // That's the end of that!
3135 err = START_INTENT_NOT_RESOLVED;
3136 }
3137
3138 if (err == START_SUCCESS && aInfo == null) {
3139 // We couldn't find the specific class specified in the Intent.
3140 // Also the end of the line.
3141 err = START_CLASS_NOT_FOUND;
3142 }
3143
3144 ProcessRecord callerApp = null;
3145 if (err == START_SUCCESS && caller != null) {
3146 callerApp = getRecordForAppLocked(caller);
3147 if (callerApp != null) {
3148 callingPid = callerApp.pid;
3149 callingUid = callerApp.info.uid;
3150 } else {
3151 Log.w(TAG, "Unable to find app for caller " + caller
3152 + " (pid=" + callingPid + ") when starting: "
3153 + intent.toString());
3154 err = START_PERMISSION_DENIED;
3155 }
3156 }
3157
3158 if (err != START_SUCCESS) {
3159 if (resultRecord != null) {
3160 sendActivityResultLocked(-1,
3161 resultRecord, resultWho, requestCode,
3162 Activity.RESULT_CANCELED, null);
3163 }
3164 return err;
3165 }
3166
3167 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3168 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3169 if (perm != PackageManager.PERMISSION_GRANTED) {
3170 if (resultRecord != null) {
3171 sendActivityResultLocked(-1,
3172 resultRecord, resultWho, requestCode,
3173 Activity.RESULT_CANCELED, null);
3174 }
3175 String msg = "Permission Denial: starting " + intent.toString()
3176 + " from " + callerApp + " (pid=" + callingPid
3177 + ", uid=" + callingUid + ")"
3178 + " requires " + aInfo.permission;
3179 Log.w(TAG, msg);
3180 throw new SecurityException(msg);
3181 }
3182
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003183 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003184 boolean abort = false;
3185 try {
3186 // The Intent we give to the watcher has the extra data
3187 // stripped off, since it can contain private information.
3188 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003189 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003190 aInfo.applicationInfo.packageName);
3191 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003192 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003193 }
3194
3195 if (abort) {
3196 if (resultRecord != null) {
3197 sendActivityResultLocked(-1,
3198 resultRecord, resultWho, requestCode,
3199 Activity.RESULT_CANCELED, null);
3200 }
3201 // We pretend to the caller that it was really started, but
3202 // they will just get a cancel result.
3203 return START_SUCCESS;
3204 }
3205 }
3206
3207 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3208 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003209 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003210
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003211 if (mResumedActivity == null
3212 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3213 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3214 PendingActivityLaunch pal = new PendingActivityLaunch();
3215 pal.r = r;
3216 pal.sourceRecord = sourceRecord;
3217 pal.grantedUriPermissions = grantedUriPermissions;
3218 pal.grantedMode = grantedMode;
3219 pal.onlyIfNeeded = onlyIfNeeded;
3220 mPendingActivityLaunches.add(pal);
3221 return START_SWITCHES_CANCELED;
3222 }
3223 }
3224
3225 if (mDidAppSwitch) {
3226 // This is the second allowed switch since we stopped switches,
3227 // so now just generally allow switches. Use case: user presses
3228 // home (switches disabled, switch to home, mDidAppSwitch now true);
3229 // user taps a home icon (coming from home so allowed, we hit here
3230 // and now allow anyone to switch again).
3231 mAppSwitchesAllowedTime = 0;
3232 } else {
3233 mDidAppSwitch = true;
3234 }
3235
3236 doPendingActivityLaunchesLocked(false);
3237
3238 return startActivityUncheckedLocked(r, sourceRecord,
3239 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3240 }
3241
3242 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3243 final int N = mPendingActivityLaunches.size();
3244 if (N <= 0) {
3245 return;
3246 }
3247 for (int i=0; i<N; i++) {
3248 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3249 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3250 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3251 doResume && i == (N-1));
3252 }
3253 mPendingActivityLaunches.clear();
3254 }
3255
3256 private final int startActivityUncheckedLocked(HistoryRecord r,
3257 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3258 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3259 final Intent intent = r.intent;
3260 final int callingUid = r.launchedFromUid;
3261
3262 int launchFlags = intent.getFlags();
3263
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003264 // We'll invoke onUserLeaving before onPause only if the launching
3265 // activity did not explicitly state that this is an automated launch.
3266 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3267 if (DEBUG_USER_LEAVING) Log.v(TAG,
3268 "startActivity() => mUserLeaving=" + mUserLeaving);
3269
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003270 // If the caller has asked not to resume at this point, we make note
3271 // of this in the record so that we can skip it when trying to find
3272 // the top running activity.
3273 if (!doResume) {
3274 r.delayedResume = true;
3275 }
3276
3277 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3278 != 0 ? r : null;
3279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003280 // If the onlyIfNeeded flag is set, then we can do this if the activity
3281 // being launched is the same as the one making the call... or, as
3282 // a special case, if we do not know the caller then we count the
3283 // current top activity as the caller.
3284 if (onlyIfNeeded) {
3285 HistoryRecord checkedCaller = sourceRecord;
3286 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003287 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003288 }
3289 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3290 // Caller is not the same as launcher, so always needed.
3291 onlyIfNeeded = false;
3292 }
3293 }
3294
3295 if (grantedUriPermissions != null && callingUid > 0) {
3296 for (int i=0; i<grantedUriPermissions.length; i++) {
3297 grantUriPermissionLocked(callingUid, r.packageName,
3298 grantedUriPermissions[i], grantedMode, r);
3299 }
3300 }
3301
3302 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3303 intent, r);
3304
3305 if (sourceRecord == null) {
3306 // This activity is not being started from another... in this
3307 // case we -always- start a new task.
3308 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3309 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3310 + intent);
3311 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3312 }
3313 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3314 // The original activity who is starting us is running as a single
3315 // instance... this new activity it is starting must go on its
3316 // own task.
3317 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3318 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3319 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3320 // The activity being started is a single instance... it always
3321 // gets launched into its own task.
3322 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3323 }
3324
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003325 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003326 // For whatever reason this activity is being launched into a new
3327 // task... yet the caller has requested a result back. Well, that
3328 // is pretty messed up, so instead immediately send back a cancel
3329 // and let the new task continue launched as normal without a
3330 // dependency on its originator.
3331 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3332 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003333 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003334 Activity.RESULT_CANCELED, null);
3335 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003336 }
3337
3338 boolean addingToTask = false;
3339 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3340 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3341 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3342 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3343 // If bring to front is requested, and no result is requested, and
3344 // we can find a task that was started with this same
3345 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003346 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003347 // See if there is a task to bring to the front. If this is
3348 // a SINGLE_INSTANCE activity, there can be one and only one
3349 // instance of it in the history, and it is always in its own
3350 // unique task, so we do a special search.
3351 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3352 ? findTaskLocked(intent, r.info)
3353 : findActivityLocked(intent, r.info);
3354 if (taskTop != null) {
3355 if (taskTop.task.intent == null) {
3356 // This task was started because of movement of
3357 // the activity based on affinity... now that we
3358 // are actually launching it, we can assign the
3359 // base intent.
3360 taskTop.task.setIntent(intent, r.info);
3361 }
3362 // If the target task is not in the front, then we need
3363 // to bring it to the front... except... well, with
3364 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3365 // to have the same behavior as if a new instance was
3366 // being started, which means not bringing it to the front
3367 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003368 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003369 if (curTop.task != taskTop.task) {
3370 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3371 boolean callerAtFront = sourceRecord == null
3372 || curTop.task == sourceRecord.task;
3373 if (callerAtFront) {
3374 // We really do want to push this one into the
3375 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003376 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003377 }
3378 }
3379 // If the caller has requested that the target task be
3380 // reset, then do so.
3381 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3382 taskTop = resetTaskIfNeededLocked(taskTop, r);
3383 }
3384 if (onlyIfNeeded) {
3385 // We don't need to start a new activity, and
3386 // the client said not to do anything if that
3387 // is the case, so this is it! And for paranoia, make
3388 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003389 if (doResume) {
3390 resumeTopActivityLocked(null);
3391 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003392 return START_RETURN_INTENT_TO_CALLER;
3393 }
3394 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3395 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3396 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3397 // In this situation we want to remove all activities
3398 // from the task up to the one being started. In most
3399 // cases this means we are resetting the task to its
3400 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003401 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003402 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003403 if (top != null) {
3404 if (top.frontOfTask) {
3405 // Activity aliases may mean we use different
3406 // intents for the top activity, so make sure
3407 // the task now has the identity of the new
3408 // intent.
3409 top.task.setIntent(r.intent, r.info);
3410 }
3411 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3412 deliverNewIntentLocked(top, r.intent);
3413 } else {
3414 // A special case: we need to
3415 // start the activity because it is not currently
3416 // running, and the caller has asked to clear the
3417 // current task to have this activity at the top.
3418 addingToTask = true;
3419 // Now pretend like this activity is being started
3420 // by the top of its task, so it is put in the
3421 // right place.
3422 sourceRecord = taskTop;
3423 }
3424 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3425 // In this case the top activity on the task is the
3426 // same as the one being launched, so we take that
3427 // as a request to bring the task to the foreground.
3428 // If the top activity in the task is the root
3429 // activity, deliver this new intent to it if it
3430 // desires.
3431 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3432 && taskTop.realActivity.equals(r.realActivity)) {
3433 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3434 if (taskTop.frontOfTask) {
3435 taskTop.task.setIntent(r.intent, r.info);
3436 }
3437 deliverNewIntentLocked(taskTop, r.intent);
3438 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3439 // In this case we are launching the root activity
3440 // of the task, but with a different intent. We
3441 // should start a new instance on top.
3442 addingToTask = true;
3443 sourceRecord = taskTop;
3444 }
3445 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3446 // In this case an activity is being launched in to an
3447 // existing task, without resetting that task. This
3448 // is typically the situation of launching an activity
3449 // from a notification or shortcut. We want to place
3450 // the new activity on top of the current task.
3451 addingToTask = true;
3452 sourceRecord = taskTop;
3453 } else if (!taskTop.task.rootWasReset) {
3454 // In this case we are launching in to an existing task
3455 // that has not yet been started from its front door.
3456 // The current task has been brought to the front.
3457 // Ideally, we'd probably like to place this new task
3458 // at the bottom of its stack, but that's a little hard
3459 // to do with the current organization of the code so
3460 // for now we'll just drop it.
3461 taskTop.task.setIntent(r.intent, r.info);
3462 }
3463 if (!addingToTask) {
3464 // We didn't do anything... but it was needed (a.k.a., client
3465 // don't use that intent!) And for paranoia, make
3466 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003467 if (doResume) {
3468 resumeTopActivityLocked(null);
3469 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003470 return START_TASK_TO_FRONT;
3471 }
3472 }
3473 }
3474 }
3475
3476 //String uri = r.intent.toURI();
3477 //Intent intent2 = new Intent(uri);
3478 //Log.i(TAG, "Given intent: " + r.intent);
3479 //Log.i(TAG, "URI is: " + uri);
3480 //Log.i(TAG, "To intent: " + intent2);
3481
3482 if (r.packageName != null) {
3483 // If the activity being launched is the same as the one currently
3484 // at the top, then we need to check if it should only be launched
3485 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003486 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3487 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003488 if (top.realActivity.equals(r.realActivity)) {
3489 if (top.app != null && top.app.thread != null) {
3490 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3491 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3492 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3493 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3494 // For paranoia, make sure we have correctly
3495 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003496 if (doResume) {
3497 resumeTopActivityLocked(null);
3498 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003499 if (onlyIfNeeded) {
3500 // We don't need to start a new activity, and
3501 // the client said not to do anything if that
3502 // is the case, so this is it!
3503 return START_RETURN_INTENT_TO_CALLER;
3504 }
3505 deliverNewIntentLocked(top, r.intent);
3506 return START_DELIVERED_TO_TOP;
3507 }
3508 }
3509 }
3510 }
3511
3512 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003513 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003514 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003515 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003516 Activity.RESULT_CANCELED, null);
3517 }
3518 return START_CLASS_NOT_FOUND;
3519 }
3520
3521 boolean newTask = false;
3522
3523 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003524 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003525 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3526 // todo: should do better management of integers.
3527 mCurTask++;
3528 if (mCurTask <= 0) {
3529 mCurTask = 1;
3530 }
3531 r.task = new TaskRecord(mCurTask, r.info, intent,
3532 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3533 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3534 + " in new task " + r.task);
3535 newTask = true;
3536 addRecentTask(r.task);
3537
3538 } else if (sourceRecord != null) {
3539 if (!addingToTask &&
3540 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3541 // In this case, we are adding the activity to an existing
3542 // task, but the caller has asked to clear that task if the
3543 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003544 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003545 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003546 if (top != null) {
3547 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3548 deliverNewIntentLocked(top, r.intent);
3549 // For paranoia, make sure we have correctly
3550 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003551 if (doResume) {
3552 resumeTopActivityLocked(null);
3553 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003554 return START_DELIVERED_TO_TOP;
3555 }
3556 } else if (!addingToTask &&
3557 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3558 // In this case, we are launching an activity in our own task
3559 // that may already be running somewhere in the history, and
3560 // we want to shuffle it to the front of the stack if so.
3561 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3562 if (where >= 0) {
3563 HistoryRecord top = moveActivityToFrontLocked(where);
3564 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3565 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003566 if (doResume) {
3567 resumeTopActivityLocked(null);
3568 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003569 return START_DELIVERED_TO_TOP;
3570 }
3571 }
3572 // An existing activity is starting this new activity, so we want
3573 // to keep the new one in the same task as the one that is starting
3574 // it.
3575 r.task = sourceRecord.task;
3576 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3577 + " in existing task " + r.task);
3578
3579 } else {
3580 // This not being started from an existing activity, and not part
3581 // of a new task... just put it in the top task, though these days
3582 // this case should never happen.
3583 final int N = mHistory.size();
3584 HistoryRecord prev =
3585 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3586 r.task = prev != null
3587 ? prev.task
3588 : new TaskRecord(mCurTask, r.info, intent,
3589 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3590 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3591 + " in new guessed " + r.task);
3592 }
3593 if (newTask) {
3594 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3595 }
3596 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003597 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003598 return START_SUCCESS;
3599 }
3600
3601 public final int startActivity(IApplicationThread caller,
3602 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3603 int grantedMode, IBinder resultTo,
3604 String resultWho, int requestCode, boolean onlyIfNeeded,
3605 boolean debug) {
3606 // Refuse possible leaked file descriptors
3607 if (intent != null && intent.hasFileDescriptors()) {
3608 throw new IllegalArgumentException("File descriptors passed in Intent");
3609 }
3610
The Android Open Source Project4df24232009-03-05 14:34:35 -08003611 final boolean componentSpecified = intent.getComponent() != null;
3612
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003613 // Don't modify the client's object!
3614 intent = new Intent(intent);
3615
3616 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003617 ActivityInfo aInfo;
3618 try {
3619 ResolveInfo rInfo =
3620 ActivityThread.getPackageManager().resolveIntent(
3621 intent, resolvedType,
3622 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003623 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003624 aInfo = rInfo != null ? rInfo.activityInfo : null;
3625 } catch (RemoteException e) {
3626 aInfo = null;
3627 }
3628
3629 if (aInfo != null) {
3630 // Store the found target back into the intent, because now that
3631 // we have it we never want to do this again. For example, if the
3632 // user navigates back to this point in the history, we should
3633 // always restart the exact same activity.
3634 intent.setComponent(new ComponentName(
3635 aInfo.applicationInfo.packageName, aInfo.name));
3636
3637 // Don't debug things in the system process
3638 if (debug) {
3639 if (!aInfo.processName.equals("system")) {
3640 setDebugApp(aInfo.processName, true, false);
3641 }
3642 }
3643 }
3644
3645 synchronized(this) {
3646 final long origId = Binder.clearCallingIdentity();
3647 int res = startActivityLocked(caller, intent, resolvedType,
3648 grantedUriPermissions, grantedMode, aInfo,
3649 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003650 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003651 Binder.restoreCallingIdentity(origId);
3652 return res;
3653 }
3654 }
3655
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003656 public int startActivityIntentSender(IApplicationThread caller,
3657 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003658 IBinder resultTo, String resultWho, int requestCode,
3659 int flagsMask, int flagsValues) {
3660 // Refuse possible leaked file descriptors
3661 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3662 throw new IllegalArgumentException("File descriptors passed in Intent");
3663 }
3664
3665 IIntentSender sender = intent.getTarget();
3666 if (!(sender instanceof PendingIntentRecord)) {
3667 throw new IllegalArgumentException("Bad PendingIntent object");
3668 }
3669
3670 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003671
3672 synchronized (this) {
3673 // If this is coming from the currently resumed activity, it is
3674 // effectively saying that app switches are allowed at this point.
3675 if (mResumedActivity != null
3676 && mResumedActivity.info.applicationInfo.uid ==
3677 Binder.getCallingUid()) {
3678 mAppSwitchesAllowedTime = 0;
3679 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003680 }
3681
3682 return pir.sendInner(0, fillInIntent, resolvedType,
3683 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3684 }
3685
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003686 public boolean startNextMatchingActivity(IBinder callingActivity,
3687 Intent intent) {
3688 // Refuse possible leaked file descriptors
3689 if (intent != null && intent.hasFileDescriptors() == true) {
3690 throw new IllegalArgumentException("File descriptors passed in Intent");
3691 }
3692
3693 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003694 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003695 if (index < 0) {
3696 return false;
3697 }
3698 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3699 if (r.app == null || r.app.thread == null) {
3700 // The caller is not running... d'oh!
3701 return false;
3702 }
3703 intent = new Intent(intent);
3704 // The caller is not allowed to change the data.
3705 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3706 // And we are resetting to find the next component...
3707 intent.setComponent(null);
3708
3709 ActivityInfo aInfo = null;
3710 try {
3711 List<ResolveInfo> resolves =
3712 ActivityThread.getPackageManager().queryIntentActivities(
3713 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003714 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003715
3716 // Look for the original activity in the list...
3717 final int N = resolves != null ? resolves.size() : 0;
3718 for (int i=0; i<N; i++) {
3719 ResolveInfo rInfo = resolves.get(i);
3720 if (rInfo.activityInfo.packageName.equals(r.packageName)
3721 && rInfo.activityInfo.name.equals(r.info.name)) {
3722 // We found the current one... the next matching is
3723 // after it.
3724 i++;
3725 if (i<N) {
3726 aInfo = resolves.get(i).activityInfo;
3727 }
3728 break;
3729 }
3730 }
3731 } catch (RemoteException e) {
3732 }
3733
3734 if (aInfo == null) {
3735 // Nobody who is next!
3736 return false;
3737 }
3738
3739 intent.setComponent(new ComponentName(
3740 aInfo.applicationInfo.packageName, aInfo.name));
3741 intent.setFlags(intent.getFlags()&~(
3742 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3743 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3744 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3745 Intent.FLAG_ACTIVITY_NEW_TASK));
3746
3747 // Okay now we need to start the new activity, replacing the
3748 // currently running activity. This is a little tricky because
3749 // we want to start the new one as if the current one is finished,
3750 // but not finish the current one first so that there is no flicker.
3751 // And thus...
3752 final boolean wasFinishing = r.finishing;
3753 r.finishing = true;
3754
3755 // Propagate reply information over to the new activity.
3756 final HistoryRecord resultTo = r.resultTo;
3757 final String resultWho = r.resultWho;
3758 final int requestCode = r.requestCode;
3759 r.resultTo = null;
3760 if (resultTo != null) {
3761 resultTo.removeResultsLocked(r, resultWho, requestCode);
3762 }
3763
3764 final long origId = Binder.clearCallingIdentity();
3765 // XXX we are not dealing with propagating grantedUriPermissions...
3766 // those are not yet exposed to user code, so there is no need.
3767 int res = startActivityLocked(r.app.thread, intent,
3768 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003769 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003770 Binder.restoreCallingIdentity(origId);
3771
3772 r.finishing = wasFinishing;
3773 if (res != START_SUCCESS) {
3774 return false;
3775 }
3776 return true;
3777 }
3778 }
3779
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003780 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003781 Intent intent, String resolvedType, IBinder resultTo,
3782 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003783
3784 // This is so super not safe, that only the system (or okay root)
3785 // can do it.
3786 final int callingUid = Binder.getCallingUid();
3787 if (callingUid != 0 && callingUid != Process.myUid()) {
3788 throw new SecurityException(
3789 "startActivityInPackage only available to the system");
3790 }
3791
The Android Open Source Project4df24232009-03-05 14:34:35 -08003792 final boolean componentSpecified = intent.getComponent() != null;
3793
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003794 // Don't modify the client's object!
3795 intent = new Intent(intent);
3796
3797 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003798 ActivityInfo aInfo;
3799 try {
3800 ResolveInfo rInfo =
3801 ActivityThread.getPackageManager().resolveIntent(
3802 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003803 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003804 aInfo = rInfo != null ? rInfo.activityInfo : null;
3805 } catch (RemoteException e) {
3806 aInfo = null;
3807 }
3808
3809 if (aInfo != null) {
3810 // Store the found target back into the intent, because now that
3811 // we have it we never want to do this again. For example, if the
3812 // user navigates back to this point in the history, we should
3813 // always restart the exact same activity.
3814 intent.setComponent(new ComponentName(
3815 aInfo.applicationInfo.packageName, aInfo.name));
3816 }
3817
3818 synchronized(this) {
3819 return startActivityLocked(null, intent, resolvedType,
3820 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003821 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003822 }
3823 }
3824
3825 private final void addRecentTask(TaskRecord task) {
3826 // Remove any existing entries that are the same kind of task.
3827 int N = mRecentTasks.size();
3828 for (int i=0; i<N; i++) {
3829 TaskRecord tr = mRecentTasks.get(i);
3830 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3831 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3832 mRecentTasks.remove(i);
3833 i--;
3834 N--;
3835 if (task.intent == null) {
3836 // If the new recent task we are adding is not fully
3837 // specified, then replace it with the existing recent task.
3838 task = tr;
3839 }
3840 }
3841 }
3842 if (N >= MAX_RECENT_TASKS) {
3843 mRecentTasks.remove(N-1);
3844 }
3845 mRecentTasks.add(0, task);
3846 }
3847
3848 public void setRequestedOrientation(IBinder token,
3849 int requestedOrientation) {
3850 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003851 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003852 if (index < 0) {
3853 return;
3854 }
3855 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3856 final long origId = Binder.clearCallingIdentity();
3857 mWindowManager.setAppOrientation(r, requestedOrientation);
3858 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003859 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003860 r.mayFreezeScreenLocked(r.app) ? r : null);
3861 if (config != null) {
3862 r.frozenBeforeDestroy = true;
3863 if (!updateConfigurationLocked(config, r)) {
3864 resumeTopActivityLocked(null);
3865 }
3866 }
3867 Binder.restoreCallingIdentity(origId);
3868 }
3869 }
3870
3871 public int getRequestedOrientation(IBinder token) {
3872 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003873 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003874 if (index < 0) {
3875 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3876 }
3877 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3878 return mWindowManager.getAppOrientation(r);
3879 }
3880 }
3881
3882 private final void stopActivityLocked(HistoryRecord r) {
3883 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3884 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3885 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3886 if (!r.finishing) {
3887 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3888 "no-history");
3889 }
3890 } else if (r.app != null && r.app.thread != null) {
3891 if (mFocusedActivity == r) {
3892 setFocusedActivityLocked(topRunningActivityLocked(null));
3893 }
3894 r.resumeKeyDispatchingLocked();
3895 try {
3896 r.stopped = false;
3897 r.state = ActivityState.STOPPING;
3898 if (DEBUG_VISBILITY) Log.v(
3899 TAG, "Stopping visible=" + r.visible + " for " + r);
3900 if (!r.visible) {
3901 mWindowManager.setAppVisibility(r, false);
3902 }
3903 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3904 } catch (Exception e) {
3905 // Maybe just ignore exceptions here... if the process
3906 // has crashed, our death notification will clean things
3907 // up.
3908 Log.w(TAG, "Exception thrown during pause", e);
3909 // Just in case, assume it to be stopped.
3910 r.stopped = true;
3911 r.state = ActivityState.STOPPED;
3912 if (r.configDestroy) {
3913 destroyActivityLocked(r, true);
3914 }
3915 }
3916 }
3917 }
3918
3919 /**
3920 * @return Returns true if the activity is being finished, false if for
3921 * some reason it is being left as-is.
3922 */
3923 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3924 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003925 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003926 TAG, "Finishing activity: token=" + token
3927 + ", result=" + resultCode + ", data=" + resultData);
3928
Dianne Hackborn75b03852009-06-12 15:43:26 -07003929 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003930 if (index < 0) {
3931 return false;
3932 }
3933 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3934
3935 // Is this the last activity left?
3936 boolean lastActivity = true;
3937 for (int i=mHistory.size()-1; i>=0; i--) {
3938 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3939 if (!p.finishing && p != r) {
3940 lastActivity = false;
3941 break;
3942 }
3943 }
3944
3945 // If this is the last activity, but it is the home activity, then
3946 // just don't finish it.
3947 if (lastActivity) {
3948 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3949 return false;
3950 }
3951 }
3952
3953 finishActivityLocked(r, index, resultCode, resultData, reason);
3954 return true;
3955 }
3956
3957 /**
3958 * @return Returns true if this activity has been removed from the history
3959 * list, or false if it is still in the list and will be removed later.
3960 */
3961 private final boolean finishActivityLocked(HistoryRecord r, int index,
3962 int resultCode, Intent resultData, String reason) {
3963 if (r.finishing) {
3964 Log.w(TAG, "Duplicate finish request for " + r);
3965 return false;
3966 }
3967
3968 r.finishing = true;
3969 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3970 System.identityHashCode(r),
3971 r.task.taskId, r.shortComponentName, reason);
3972 r.task.numActivities--;
3973 if (r.frontOfTask && index < (mHistory.size()-1)) {
3974 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3975 if (next.task == r.task) {
3976 next.frontOfTask = true;
3977 }
3978 }
3979
3980 r.pauseKeyDispatchingLocked();
3981 if (mFocusedActivity == r) {
3982 setFocusedActivityLocked(topRunningActivityLocked(null));
3983 }
3984
3985 // send the result
3986 HistoryRecord resultTo = r.resultTo;
3987 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003988 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3989 + " who=" + r.resultWho + " req=" + r.requestCode
3990 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003991 if (r.info.applicationInfo.uid > 0) {
3992 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3993 r.packageName, resultData, r);
3994 }
3995 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3996 resultData);
3997 r.resultTo = null;
3998 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003999 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004000
4001 // Make sure this HistoryRecord is not holding on to other resources,
4002 // because clients have remote IPC references to this object so we
4003 // can't assume that will go away and want to avoid circular IPC refs.
4004 r.results = null;
4005 r.pendingResults = null;
4006 r.newIntents = null;
4007 r.icicle = null;
4008
4009 if (mPendingThumbnails.size() > 0) {
4010 // There are clients waiting to receive thumbnails so, in case
4011 // this is an activity that someone is waiting for, add it
4012 // to the pending list so we can correctly update the clients.
4013 mCancelledThumbnails.add(r);
4014 }
4015
4016 if (mResumedActivity == r) {
4017 boolean endTask = index <= 0
4018 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
4019 if (DEBUG_TRANSITION) Log.v(TAG,
4020 "Prepare close transition: finishing " + r);
4021 mWindowManager.prepareAppTransition(endTask
4022 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
4023 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
4024
4025 // Tell window manager to prepare for this one to be removed.
4026 mWindowManager.setAppVisibility(r, false);
4027
4028 if (mPausingActivity == null) {
4029 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4030 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4031 startPausingLocked(false, false);
4032 }
4033
4034 } else if (r.state != ActivityState.PAUSING) {
4035 // If the activity is PAUSING, we will complete the finish once
4036 // it is done pausing; else we can just directly finish it here.
4037 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4038 return finishCurrentActivityLocked(r, index,
4039 FINISH_AFTER_PAUSE) == null;
4040 } else {
4041 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4042 }
4043
4044 return false;
4045 }
4046
4047 private static final int FINISH_IMMEDIATELY = 0;
4048 private static final int FINISH_AFTER_PAUSE = 1;
4049 private static final int FINISH_AFTER_VISIBLE = 2;
4050
4051 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4052 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004053 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004054 if (index < 0) {
4055 return null;
4056 }
4057
4058 return finishCurrentActivityLocked(r, index, mode);
4059 }
4060
4061 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4062 int index, int mode) {
4063 // First things first: if this activity is currently visible,
4064 // and the resumed activity is not yet visible, then hold off on
4065 // finishing until the resumed one becomes visible.
4066 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4067 if (!mStoppingActivities.contains(r)) {
4068 mStoppingActivities.add(r);
4069 if (mStoppingActivities.size() > 3) {
4070 // If we already have a few activities waiting to stop,
4071 // then give up on things going idle and start clearing
4072 // them out.
4073 Message msg = Message.obtain();
4074 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4075 mHandler.sendMessage(msg);
4076 }
4077 }
4078 r.state = ActivityState.STOPPING;
4079 updateOomAdjLocked();
4080 return r;
4081 }
4082
4083 // make sure the record is cleaned out of other places.
4084 mStoppingActivities.remove(r);
4085 mWaitingVisibleActivities.remove(r);
4086 if (mResumedActivity == r) {
4087 mResumedActivity = null;
4088 }
4089 final ActivityState prevState = r.state;
4090 r.state = ActivityState.FINISHING;
4091
4092 if (mode == FINISH_IMMEDIATELY
4093 || prevState == ActivityState.STOPPED
4094 || prevState == ActivityState.INITIALIZING) {
4095 // If this activity is already stopped, we can just finish
4096 // it right now.
4097 return destroyActivityLocked(r, true) ? null : r;
4098 } else {
4099 // Need to go through the full pause cycle to get this
4100 // activity into the stopped state and then finish it.
4101 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4102 mFinishingActivities.add(r);
4103 resumeTopActivityLocked(null);
4104 }
4105 return r;
4106 }
4107
4108 /**
4109 * This is the internal entry point for handling Activity.finish().
4110 *
4111 * @param token The Binder token referencing the Activity we want to finish.
4112 * @param resultCode Result code, if any, from this Activity.
4113 * @param resultData Result data (Intent), if any, from this Activity.
4114 *
4115 * @result Returns true if the activity successfully finished, or false if it is still running.
4116 */
4117 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4118 // Refuse possible leaked file descriptors
4119 if (resultData != null && resultData.hasFileDescriptors() == true) {
4120 throw new IllegalArgumentException("File descriptors passed in Intent");
4121 }
4122
4123 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004124 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004125 // Find the first activity that is not finishing.
4126 HistoryRecord next = topRunningActivityLocked(token, 0);
4127 if (next != null) {
4128 // ask watcher if this is allowed
4129 boolean resumeOK = true;
4130 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004131 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004132 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004133 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004134 }
4135
4136 if (!resumeOK) {
4137 return false;
4138 }
4139 }
4140 }
4141 final long origId = Binder.clearCallingIdentity();
4142 boolean res = requestFinishActivityLocked(token, resultCode,
4143 resultData, "app-request");
4144 Binder.restoreCallingIdentity(origId);
4145 return res;
4146 }
4147 }
4148
4149 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4150 String resultWho, int requestCode, int resultCode, Intent data) {
4151
4152 if (callingUid > 0) {
4153 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4154 data, r);
4155 }
4156
The Android Open Source Project10592532009-03-18 17:39:46 -07004157 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4158 + " : who=" + resultWho + " req=" + requestCode
4159 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004160 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4161 try {
4162 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4163 list.add(new ResultInfo(resultWho, requestCode,
4164 resultCode, data));
4165 r.app.thread.scheduleSendResult(r, list);
4166 return;
4167 } catch (Exception e) {
4168 Log.w(TAG, "Exception thrown sending result to " + r, e);
4169 }
4170 }
4171
4172 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4173 }
4174
4175 public final void finishSubActivity(IBinder token, String resultWho,
4176 int requestCode) {
4177 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004178 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004179 if (index < 0) {
4180 return;
4181 }
4182 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4183
4184 final long origId = Binder.clearCallingIdentity();
4185
4186 int i;
4187 for (i=mHistory.size()-1; i>=0; i--) {
4188 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4189 if (r.resultTo == self && r.requestCode == requestCode) {
4190 if ((r.resultWho == null && resultWho == null) ||
4191 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4192 finishActivityLocked(r, i,
4193 Activity.RESULT_CANCELED, null, "request-sub");
4194 }
4195 }
4196 }
4197
4198 Binder.restoreCallingIdentity(origId);
4199 }
4200 }
4201
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004202 public void overridePendingTransition(IBinder token, String packageName,
4203 int enterAnim, int exitAnim) {
4204 synchronized(this) {
4205 int index = indexOfTokenLocked(token);
4206 if (index < 0) {
4207 return;
4208 }
4209 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4210
4211 final long origId = Binder.clearCallingIdentity();
4212
4213 if (self.state == ActivityState.RESUMED
4214 || self.state == ActivityState.PAUSING) {
4215 mWindowManager.overridePendingAppTransition(packageName,
4216 enterAnim, exitAnim);
4217 }
4218
4219 Binder.restoreCallingIdentity(origId);
4220 }
4221 }
4222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004223 /**
4224 * Perform clean-up of service connections in an activity record.
4225 */
4226 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4227 // Throw away any services that have been bound by this activity.
4228 if (r.connections != null) {
4229 Iterator<ConnectionRecord> it = r.connections.iterator();
4230 while (it.hasNext()) {
4231 ConnectionRecord c = it.next();
4232 removeConnectionLocked(c, null, r);
4233 }
4234 r.connections = null;
4235 }
4236 }
4237
4238 /**
4239 * Perform the common clean-up of an activity record. This is called both
4240 * as part of destroyActivityLocked() (when destroying the client-side
4241 * representation) and cleaning things up as a result of its hosting
4242 * processing going away, in which case there is no remaining client-side
4243 * state to destroy so only the cleanup here is needed.
4244 */
4245 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4246 if (mResumedActivity == r) {
4247 mResumedActivity = null;
4248 }
4249 if (mFocusedActivity == r) {
4250 mFocusedActivity = null;
4251 }
4252
4253 r.configDestroy = false;
4254 r.frozenBeforeDestroy = false;
4255
4256 // Make sure this record is no longer in the pending finishes list.
4257 // This could happen, for example, if we are trimming activities
4258 // down to the max limit while they are still waiting to finish.
4259 mFinishingActivities.remove(r);
4260 mWaitingVisibleActivities.remove(r);
4261
4262 // Remove any pending results.
4263 if (r.finishing && r.pendingResults != null) {
4264 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4265 PendingIntentRecord rec = apr.get();
4266 if (rec != null) {
4267 cancelIntentSenderLocked(rec, false);
4268 }
4269 }
4270 r.pendingResults = null;
4271 }
4272
4273 if (cleanServices) {
4274 cleanUpActivityServicesLocked(r);
4275 }
4276
4277 if (mPendingThumbnails.size() > 0) {
4278 // There are clients waiting to receive thumbnails so, in case
4279 // this is an activity that someone is waiting for, add it
4280 // to the pending list so we can correctly update the clients.
4281 mCancelledThumbnails.add(r);
4282 }
4283
4284 // Get rid of any pending idle timeouts.
4285 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4286 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4287 }
4288
4289 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4290 if (r.state != ActivityState.DESTROYED) {
4291 mHistory.remove(r);
4292 r.inHistory = false;
4293 r.state = ActivityState.DESTROYED;
4294 mWindowManager.removeAppToken(r);
4295 if (VALIDATE_TOKENS) {
4296 mWindowManager.validateAppTokens(mHistory);
4297 }
4298 cleanUpActivityServicesLocked(r);
4299 removeActivityUriPermissionsLocked(r);
4300 }
4301 }
4302
4303 /**
4304 * Destroy the current CLIENT SIDE instance of an activity. This may be
4305 * called both when actually finishing an activity, or when performing
4306 * a configuration switch where we destroy the current client-side object
4307 * but then create a new client-side object for this same HistoryRecord.
4308 */
4309 private final boolean destroyActivityLocked(HistoryRecord r,
4310 boolean removeFromApp) {
4311 if (DEBUG_SWITCH) Log.v(
4312 TAG, "Removing activity: token=" + r
4313 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4314 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4315 System.identityHashCode(r),
4316 r.task.taskId, r.shortComponentName);
4317
4318 boolean removedFromHistory = false;
4319
4320 cleanUpActivityLocked(r, false);
4321
4322 if (r.app != null) {
4323 if (removeFromApp) {
4324 int idx = r.app.activities.indexOf(r);
4325 if (idx >= 0) {
4326 r.app.activities.remove(idx);
4327 }
4328 if (r.persistent) {
4329 decPersistentCountLocked(r.app);
4330 }
4331 }
4332
4333 boolean skipDestroy = false;
4334
4335 try {
4336 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4337 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4338 r.configChangeFlags);
4339 } catch (Exception e) {
4340 // We can just ignore exceptions here... if the process
4341 // has crashed, our death notification will clean things
4342 // up.
4343 //Log.w(TAG, "Exception thrown during finish", e);
4344 if (r.finishing) {
4345 removeActivityFromHistoryLocked(r);
4346 removedFromHistory = true;
4347 skipDestroy = true;
4348 }
4349 }
4350
4351 r.app = null;
4352 r.nowVisible = false;
4353
4354 if (r.finishing && !skipDestroy) {
4355 r.state = ActivityState.DESTROYING;
4356 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4357 msg.obj = r;
4358 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4359 } else {
4360 r.state = ActivityState.DESTROYED;
4361 }
4362 } else {
4363 // remove this record from the history.
4364 if (r.finishing) {
4365 removeActivityFromHistoryLocked(r);
4366 removedFromHistory = true;
4367 } else {
4368 r.state = ActivityState.DESTROYED;
4369 }
4370 }
4371
4372 r.configChangeFlags = 0;
4373
4374 if (!mLRUActivities.remove(r)) {
4375 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4376 }
4377
4378 return removedFromHistory;
4379 }
4380
4381 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4382 ProcessRecord app)
4383 {
4384 int i = list.size();
4385 if (localLOGV) Log.v(
4386 TAG, "Removing app " + app + " from list " + list
4387 + " with " + i + " entries");
4388 while (i > 0) {
4389 i--;
4390 HistoryRecord r = (HistoryRecord)list.get(i);
4391 if (localLOGV) Log.v(
4392 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4393 if (r.app == app) {
4394 if (localLOGV) Log.v(TAG, "Removing this entry!");
4395 list.remove(i);
4396 }
4397 }
4398 }
4399
4400 /**
4401 * Main function for removing an existing process from the activity manager
4402 * as a result of that process going away. Clears out all connections
4403 * to the process.
4404 */
4405 private final void handleAppDiedLocked(ProcessRecord app,
4406 boolean restarting) {
4407 cleanUpApplicationRecordLocked(app, restarting, -1);
4408 if (!restarting) {
4409 mLRUProcesses.remove(app);
4410 }
4411
4412 // Just in case...
4413 if (mPausingActivity != null && mPausingActivity.app == app) {
4414 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4415 mPausingActivity = null;
4416 }
4417 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4418 mLastPausedActivity = null;
4419 }
4420
4421 // Remove this application's activities from active lists.
4422 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4423 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4424 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4425 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4426
4427 boolean atTop = true;
4428 boolean hasVisibleActivities = false;
4429
4430 // Clean out the history list.
4431 int i = mHistory.size();
4432 if (localLOGV) Log.v(
4433 TAG, "Removing app " + app + " from history with " + i + " entries");
4434 while (i > 0) {
4435 i--;
4436 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4437 if (localLOGV) Log.v(
4438 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4439 if (r.app == app) {
4440 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4441 if (localLOGV) Log.v(
4442 TAG, "Removing this entry! frozen=" + r.haveState
4443 + " finishing=" + r.finishing);
4444 mHistory.remove(i);
4445
4446 r.inHistory = false;
4447 mWindowManager.removeAppToken(r);
4448 if (VALIDATE_TOKENS) {
4449 mWindowManager.validateAppTokens(mHistory);
4450 }
4451 removeActivityUriPermissionsLocked(r);
4452
4453 } else {
4454 // We have the current state for this activity, so
4455 // it can be restarted later when needed.
4456 if (localLOGV) Log.v(
4457 TAG, "Keeping entry, setting app to null");
4458 if (r.visible) {
4459 hasVisibleActivities = true;
4460 }
4461 r.app = null;
4462 r.nowVisible = false;
4463 if (!r.haveState) {
4464 r.icicle = null;
4465 }
4466 }
4467
4468 cleanUpActivityLocked(r, true);
4469 r.state = ActivityState.STOPPED;
4470 }
4471 atTop = false;
4472 }
4473
4474 app.activities.clear();
4475
4476 if (app.instrumentationClass != null) {
4477 Log.w(TAG, "Crash of app " + app.processName
4478 + " running instrumentation " + app.instrumentationClass);
4479 Bundle info = new Bundle();
4480 info.putString("shortMsg", "Process crashed.");
4481 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4482 }
4483
4484 if (!restarting) {
4485 if (!resumeTopActivityLocked(null)) {
4486 // If there was nothing to resume, and we are not already
4487 // restarting this process, but there is a visible activity that
4488 // is hosted by the process... then make sure all visible
4489 // activities are running, taking care of restarting this
4490 // process.
4491 if (hasVisibleActivities) {
4492 ensureActivitiesVisibleLocked(null, 0);
4493 }
4494 }
4495 }
4496 }
4497
4498 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4499 IBinder threadBinder = thread.asBinder();
4500
4501 // Find the application record.
4502 int count = mLRUProcesses.size();
4503 int i;
4504 for (i=0; i<count; i++) {
4505 ProcessRecord rec = mLRUProcesses.get(i);
4506 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4507 return i;
4508 }
4509 }
4510 return -1;
4511 }
4512
4513 private final ProcessRecord getRecordForAppLocked(
4514 IApplicationThread thread) {
4515 if (thread == null) {
4516 return null;
4517 }
4518
4519 int appIndex = getLRURecordIndexForAppLocked(thread);
4520 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4521 }
4522
4523 private final void appDiedLocked(ProcessRecord app, int pid,
4524 IApplicationThread thread) {
4525
4526 mProcDeaths[0]++;
4527
4528 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4529 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4530 + ") has died.");
4531 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4532 if (localLOGV) Log.v(
4533 TAG, "Dying app: " + app + ", pid: " + pid
4534 + ", thread: " + thread.asBinder());
4535 boolean doLowMem = app.instrumentationClass == null;
4536 handleAppDiedLocked(app, false);
4537
4538 if (doLowMem) {
4539 // If there are no longer any background processes running,
4540 // and the app that died was not running instrumentation,
4541 // then tell everyone we are now low on memory.
4542 boolean haveBg = false;
4543 int count = mLRUProcesses.size();
4544 int i;
4545 for (i=0; i<count; i++) {
4546 ProcessRecord rec = mLRUProcesses.get(i);
4547 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4548 haveBg = true;
4549 break;
4550 }
4551 }
4552
4553 if (!haveBg) {
4554 Log.i(TAG, "Low Memory: No more background processes.");
4555 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004556 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004557 for (i=0; i<count; i++) {
4558 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004559 if (rec.thread != null &&
4560 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4561 // The low memory report is overriding any current
4562 // state for a GC request. Make sure to do
4563 // visible/foreground processes first.
4564 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4565 rec.lastRequestedGc = 0;
4566 } else {
4567 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004568 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004569 rec.reportLowMemory = true;
4570 rec.lastLowMemory = now;
4571 mProcessesToGc.remove(rec);
4572 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004573 }
4574 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004575 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004576 }
4577 }
4578 } else if (Config.LOGD) {
4579 Log.d(TAG, "Received spurious death notification for thread "
4580 + thread.asBinder());
4581 }
4582 }
4583
4584 final String readFile(String filename) {
4585 try {
4586 FileInputStream fs = new FileInputStream(filename);
4587 byte[] inp = new byte[8192];
4588 int size = fs.read(inp);
4589 fs.close();
4590 return new String(inp, 0, 0, size);
4591 } catch (java.io.IOException e) {
4592 }
4593 return "";
4594 }
4595
4596 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004597 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004598 if (app.notResponding || app.crashing) {
4599 return;
4600 }
4601
4602 // Log the ANR to the event log.
4603 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4604
4605 // If we are on a secure build and the application is not interesting to the user (it is
4606 // not visible or in the background), just kill it instead of displaying a dialog.
4607 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4608 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4609 Process.killProcess(app.pid);
4610 return;
4611 }
4612
4613 // DeviceMonitor.start();
4614
4615 String processInfo = null;
4616 if (MONITOR_CPU_USAGE) {
4617 updateCpuStatsNow();
4618 synchronized (mProcessStatsThread) {
4619 processInfo = mProcessStats.printCurrentState();
4620 }
4621 }
4622
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004623 StringBuilder info = mStringBuilder;
4624 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004625 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004626 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004627 if (reportedActivity != null && reportedActivity.app != null) {
4628 info.append(" (last in ");
4629 info.append(reportedActivity.app.processName);
4630 info.append(")");
4631 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004632 if (annotation != null) {
4633 info.append("\nAnnotation: ");
4634 info.append(annotation);
4635 }
4636 if (MONITOR_CPU_USAGE) {
4637 info.append("\nCPU usage:\n");
4638 info.append(processInfo);
4639 }
4640 Log.i(TAG, info.toString());
4641
4642 // The application is not responding. Dump as many thread traces as we can.
4643 boolean fileDump = prepareTraceFile(true);
4644 if (!fileDump) {
4645 // Dumping traces to the log, just dump the process that isn't responding so
4646 // we don't overflow the log
4647 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4648 } else {
4649 // Dumping traces to a file so dump all active processes we know about
4650 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004651 // First, these are the most important processes.
4652 final int[] imppids = new int[3];
4653 int i=0;
4654 imppids[0] = app.pid;
4655 i++;
4656 if (reportedActivity != null && reportedActivity.app != null
4657 && reportedActivity.app.thread != null
4658 && reportedActivity.app.pid != app.pid) {
4659 imppids[i] = reportedActivity.app.pid;
4660 i++;
4661 }
4662 imppids[i] = Process.myPid();
4663 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4664 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4665 synchronized (this) {
4666 try {
4667 wait(200);
4668 } catch (InterruptedException e) {
4669 }
4670 }
4671 }
4672 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004673 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004674 boolean done = false;
4675 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4676 if (imppids[j] == r.pid) {
4677 done = true;
4678 break;
4679 }
4680 }
4681 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004682 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004683 synchronized (this) {
4684 try {
4685 wait(200);
4686 } catch (InterruptedException e) {
4687 }
4688 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004689 }
4690 }
4691 }
4692 }
4693
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004694 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004695 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004696 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004697 app.pid, info.toString());
4698 if (res != 0) {
4699 if (res < 0) {
4700 // wait until the SIGQUIT has had a chance to process before killing the
4701 // process.
4702 try {
4703 wait(2000);
4704 } catch (InterruptedException e) {
4705 }
4706
4707 Process.killProcess(app.pid);
4708 return;
4709 }
4710 }
4711 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004712 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004713 }
4714 }
4715
4716 makeAppNotRespondingLocked(app,
4717 activity != null ? activity.shortComponentName : null,
4718 annotation != null ? "ANR " + annotation : "ANR",
4719 info.toString(), null);
4720 Message msg = Message.obtain();
4721 HashMap map = new HashMap();
4722 msg.what = SHOW_NOT_RESPONDING_MSG;
4723 msg.obj = map;
4724 map.put("app", app);
4725 if (activity != null) {
4726 map.put("activity", activity);
4727 }
4728
4729 mHandler.sendMessage(msg);
4730 return;
4731 }
4732
4733 /**
4734 * If a stack trace file has been configured, prepare the filesystem
4735 * by creating the directory if it doesn't exist and optionally
4736 * removing the old trace file.
4737 *
4738 * @param removeExisting If set, the existing trace file will be removed.
4739 * @return Returns true if the trace file preparations succeeded
4740 */
4741 public static boolean prepareTraceFile(boolean removeExisting) {
4742 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4743 boolean fileReady = false;
4744 if (!TextUtils.isEmpty(tracesPath)) {
4745 File f = new File(tracesPath);
4746 if (!f.exists()) {
4747 // Ensure the enclosing directory exists
4748 File dir = f.getParentFile();
4749 if (!dir.exists()) {
4750 fileReady = dir.mkdirs();
4751 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004752 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004753 } else if (dir.isDirectory()) {
4754 fileReady = true;
4755 }
4756 } else if (removeExisting) {
4757 // Remove the previous traces file, so we don't fill the disk.
4758 // The VM will recreate it
4759 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4760 fileReady = f.delete();
4761 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004762
4763 if (removeExisting) {
4764 try {
4765 f.createNewFile();
4766 FileUtils.setPermissions(f.getAbsolutePath(),
4767 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4768 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4769 fileReady = true;
4770 } catch (IOException e) {
4771 Log.w(TAG, "Unable to make ANR traces file", e);
4772 }
4773 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004774 }
4775
4776 return fileReady;
4777 }
4778
4779
4780 private final void decPersistentCountLocked(ProcessRecord app)
4781 {
4782 app.persistentActivities--;
4783 if (app.persistentActivities > 0) {
4784 // Still more of 'em...
4785 return;
4786 }
4787 if (app.persistent) {
4788 // Ah, but the application itself is persistent. Whatever!
4789 return;
4790 }
4791
4792 // App is no longer persistent... make sure it and the ones
4793 // following it in the LRU list have the correc oom_adj.
4794 updateOomAdjLocked();
4795 }
4796
4797 public void setPersistent(IBinder token, boolean isPersistent) {
4798 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4799 != PackageManager.PERMISSION_GRANTED) {
4800 String msg = "Permission Denial: setPersistent() from pid="
4801 + Binder.getCallingPid()
4802 + ", uid=" + Binder.getCallingUid()
4803 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4804 Log.w(TAG, msg);
4805 throw new SecurityException(msg);
4806 }
4807
4808 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004809 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004810 if (index < 0) {
4811 return;
4812 }
4813 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4814 ProcessRecord app = r.app;
4815
4816 if (localLOGV) Log.v(
4817 TAG, "Setting persistence " + isPersistent + ": " + r);
4818
4819 if (isPersistent) {
4820 if (r.persistent) {
4821 // Okay okay, I heard you already!
4822 if (localLOGV) Log.v(TAG, "Already persistent!");
4823 return;
4824 }
4825 r.persistent = true;
4826 app.persistentActivities++;
4827 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4828 if (app.persistentActivities > 1) {
4829 // We aren't the first...
4830 if (localLOGV) Log.v(TAG, "Not the first!");
4831 return;
4832 }
4833 if (app.persistent) {
4834 // This would be redundant.
4835 if (localLOGV) Log.v(TAG, "App is persistent!");
4836 return;
4837 }
4838
4839 // App is now persistent... make sure it and the ones
4840 // following it now have the correct oom_adj.
4841 final long origId = Binder.clearCallingIdentity();
4842 updateOomAdjLocked();
4843 Binder.restoreCallingIdentity(origId);
4844
4845 } else {
4846 if (!r.persistent) {
4847 // Okay okay, I heard you already!
4848 return;
4849 }
4850 r.persistent = false;
4851 final long origId = Binder.clearCallingIdentity();
4852 decPersistentCountLocked(app);
4853 Binder.restoreCallingIdentity(origId);
4854
4855 }
4856 }
4857 }
4858
4859 public boolean clearApplicationUserData(final String packageName,
4860 final IPackageDataObserver observer) {
4861 int uid = Binder.getCallingUid();
4862 int pid = Binder.getCallingPid();
4863 long callingId = Binder.clearCallingIdentity();
4864 try {
4865 IPackageManager pm = ActivityThread.getPackageManager();
4866 int pkgUid = -1;
4867 synchronized(this) {
4868 try {
4869 pkgUid = pm.getPackageUid(packageName);
4870 } catch (RemoteException e) {
4871 }
4872 if (pkgUid == -1) {
4873 Log.w(TAG, "Invalid packageName:" + packageName);
4874 return false;
4875 }
4876 if (uid == pkgUid || checkComponentPermission(
4877 android.Manifest.permission.CLEAR_APP_USER_DATA,
4878 pid, uid, -1)
4879 == PackageManager.PERMISSION_GRANTED) {
4880 restartPackageLocked(packageName, pkgUid);
4881 } else {
4882 throw new SecurityException(pid+" does not have permission:"+
4883 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4884 "for process:"+packageName);
4885 }
4886 }
4887
4888 try {
4889 //clear application user data
4890 pm.clearApplicationUserData(packageName, observer);
4891 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4892 Uri.fromParts("package", packageName, null));
4893 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4894 broadcastIntentLocked(null, null, intent,
4895 null, null, 0, null, null, null,
4896 false, false, MY_PID, Process.SYSTEM_UID);
4897 } catch (RemoteException e) {
4898 }
4899 } finally {
4900 Binder.restoreCallingIdentity(callingId);
4901 }
4902 return true;
4903 }
4904
4905 public void restartPackage(final String packageName) {
4906 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4907 != PackageManager.PERMISSION_GRANTED) {
4908 String msg = "Permission Denial: restartPackage() from pid="
4909 + Binder.getCallingPid()
4910 + ", uid=" + Binder.getCallingUid()
4911 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4912 Log.w(TAG, msg);
4913 throw new SecurityException(msg);
4914 }
4915
4916 long callingId = Binder.clearCallingIdentity();
4917 try {
4918 IPackageManager pm = ActivityThread.getPackageManager();
4919 int pkgUid = -1;
4920 synchronized(this) {
4921 try {
4922 pkgUid = pm.getPackageUid(packageName);
4923 } catch (RemoteException e) {
4924 }
4925 if (pkgUid == -1) {
4926 Log.w(TAG, "Invalid packageName: " + packageName);
4927 return;
4928 }
4929 restartPackageLocked(packageName, pkgUid);
4930 }
4931 } finally {
4932 Binder.restoreCallingIdentity(callingId);
4933 }
4934 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004935
4936 /*
4937 * The pkg name and uid have to be specified.
4938 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4939 */
4940 public void killApplicationWithUid(String pkg, int uid) {
4941 if (pkg == null) {
4942 return;
4943 }
4944 // Make sure the uid is valid.
4945 if (uid < 0) {
4946 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4947 return;
4948 }
4949 int callerUid = Binder.getCallingUid();
4950 // Only the system server can kill an application
4951 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004952 // Post an aysnc message to kill the application
4953 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4954 msg.arg1 = uid;
4955 msg.arg2 = 0;
4956 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004957 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004958 } else {
4959 throw new SecurityException(callerUid + " cannot kill pkg: " +
4960 pkg);
4961 }
4962 }
4963
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004964 public void closeSystemDialogs(String reason) {
4965 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4966 if (reason != null) {
4967 intent.putExtra("reason", reason);
4968 }
4969
4970 final int uid = Binder.getCallingUid();
4971 final long origId = Binder.clearCallingIdentity();
4972 synchronized (this) {
4973 int i = mWatchers.beginBroadcast();
4974 while (i > 0) {
4975 i--;
4976 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4977 if (w != null) {
4978 try {
4979 w.closingSystemDialogs(reason);
4980 } catch (RemoteException e) {
4981 }
4982 }
4983 }
4984 mWatchers.finishBroadcast();
4985
Dianne Hackbornffa42482009-09-23 22:20:11 -07004986 mWindowManager.closeSystemDialogs(reason);
4987
4988 for (i=mHistory.size()-1; i>=0; i--) {
4989 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4990 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
4991 finishActivityLocked(r, i,
4992 Activity.RESULT_CANCELED, null, "close-sys");
4993 }
4994 }
4995
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004996 broadcastIntentLocked(null, null, intent, null,
4997 null, 0, null, null, null, false, false, -1, uid);
4998 }
4999 Binder.restoreCallingIdentity(origId);
5000 }
5001
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005002 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005003 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005004 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
5005 for (int i=pids.length-1; i>=0; i--) {
5006 infos[i] = new Debug.MemoryInfo();
5007 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005008 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005009 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005010 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07005011
5012 public void killApplicationProcess(String processName, int uid) {
5013 if (processName == null) {
5014 return;
5015 }
5016
5017 int callerUid = Binder.getCallingUid();
5018 // Only the system server can kill an application
5019 if (callerUid == Process.SYSTEM_UID) {
5020 synchronized (this) {
5021 ProcessRecord app = getProcessRecordLocked(processName, uid);
5022 if (app != null) {
5023 try {
5024 app.thread.scheduleSuicide();
5025 } catch (RemoteException e) {
5026 // If the other end already died, then our work here is done.
5027 }
5028 } else {
5029 Log.w(TAG, "Process/uid not found attempting kill of "
5030 + processName + " / " + uid);
5031 }
5032 }
5033 } else {
5034 throw new SecurityException(callerUid + " cannot kill app process: " +
5035 processName);
5036 }
5037 }
5038
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005039 private void restartPackageLocked(final String packageName, int uid) {
5040 uninstallPackageLocked(packageName, uid, false);
5041 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5042 Uri.fromParts("package", packageName, null));
5043 intent.putExtra(Intent.EXTRA_UID, uid);
5044 broadcastIntentLocked(null, null, intent,
5045 null, null, 0, null, null, null,
5046 false, false, MY_PID, Process.SYSTEM_UID);
5047 }
5048
5049 private final void uninstallPackageLocked(String name, int uid,
5050 boolean callerWillRestart) {
5051 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
5052
5053 int i, N;
5054
5055 final String procNamePrefix = name + ":";
5056 if (uid < 0) {
5057 try {
5058 uid = ActivityThread.getPackageManager().getPackageUid(name);
5059 } catch (RemoteException e) {
5060 }
5061 }
5062
5063 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5064 while (badApps.hasNext()) {
5065 SparseArray<Long> ba = badApps.next();
5066 if (ba.get(uid) != null) {
5067 badApps.remove();
5068 }
5069 }
5070
5071 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
5072
5073 // Remove all processes this package may have touched: all with the
5074 // same UID (except for the system or root user), and all whose name
5075 // matches the package name.
5076 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5077 final int NA = apps.size();
5078 for (int ia=0; ia<NA; ia++) {
5079 ProcessRecord app = apps.valueAt(ia);
5080 if (app.removed) {
5081 procs.add(app);
5082 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5083 || app.processName.equals(name)
5084 || app.processName.startsWith(procNamePrefix)) {
5085 app.removed = true;
5086 procs.add(app);
5087 }
5088 }
5089 }
5090
5091 N = procs.size();
5092 for (i=0; i<N; i++) {
5093 removeProcessLocked(procs.get(i), callerWillRestart);
5094 }
5095
5096 for (i=mHistory.size()-1; i>=0; i--) {
5097 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5098 if (r.packageName.equals(name)) {
5099 if (Config.LOGD) Log.d(
5100 TAG, " Force finishing activity "
5101 + r.intent.getComponent().flattenToShortString());
5102 if (r.app != null) {
5103 r.app.removed = true;
5104 }
5105 r.app = null;
5106 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5107 }
5108 }
5109
5110 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5111 for (ServiceRecord service : mServices.values()) {
5112 if (service.packageName.equals(name)) {
5113 if (service.app != null) {
5114 service.app.removed = true;
5115 }
5116 service.app = null;
5117 services.add(service);
5118 }
5119 }
5120
5121 N = services.size();
5122 for (i=0; i<N; i++) {
5123 bringDownServiceLocked(services.get(i), true);
5124 }
5125
5126 resumeTopActivityLocked(null);
5127 }
5128
5129 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5130 final String name = app.processName;
5131 final int uid = app.info.uid;
5132 if (Config.LOGD) Log.d(
5133 TAG, "Force removing process " + app + " (" + name
5134 + "/" + uid + ")");
5135
5136 mProcessNames.remove(name, uid);
5137 boolean needRestart = false;
5138 if (app.pid > 0 && app.pid != MY_PID) {
5139 int pid = app.pid;
5140 synchronized (mPidsSelfLocked) {
5141 mPidsSelfLocked.remove(pid);
5142 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5143 }
5144 handleAppDiedLocked(app, true);
5145 mLRUProcesses.remove(app);
5146 Process.killProcess(pid);
5147
5148 if (app.persistent) {
5149 if (!callerWillRestart) {
5150 addAppLocked(app.info);
5151 } else {
5152 needRestart = true;
5153 }
5154 }
5155 } else {
5156 mRemovedProcesses.add(app);
5157 }
5158
5159 return needRestart;
5160 }
5161
5162 private final void processStartTimedOutLocked(ProcessRecord app) {
5163 final int pid = app.pid;
5164 boolean gone = false;
5165 synchronized (mPidsSelfLocked) {
5166 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5167 if (knownApp != null && knownApp.thread == null) {
5168 mPidsSelfLocked.remove(pid);
5169 gone = true;
5170 }
5171 }
5172
5173 if (gone) {
5174 Log.w(TAG, "Process " + app + " failed to attach");
5175 mProcessNames.remove(app.processName, app.info.uid);
5176 Process.killProcess(pid);
5177 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5178 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5179 mPendingBroadcast = null;
5180 scheduleBroadcastsLocked();
5181 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005182 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5183 Log.w(TAG, "Unattached app died before backup, skipping");
5184 try {
5185 IBackupManager bm = IBackupManager.Stub.asInterface(
5186 ServiceManager.getService(Context.BACKUP_SERVICE));
5187 bm.agentDisconnected(app.info.packageName);
5188 } catch (RemoteException e) {
5189 // Can't happen; the backup manager is local
5190 }
5191 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005192 } else {
5193 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5194 }
5195 }
5196
5197 private final boolean attachApplicationLocked(IApplicationThread thread,
5198 int pid) {
5199
5200 // Find the application record that is being attached... either via
5201 // the pid if we are running in multiple processes, or just pull the
5202 // next app record if we are emulating process with anonymous threads.
5203 ProcessRecord app;
5204 if (pid != MY_PID && pid >= 0) {
5205 synchronized (mPidsSelfLocked) {
5206 app = mPidsSelfLocked.get(pid);
5207 }
5208 } else if (mStartingProcesses.size() > 0) {
5209 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005210 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005211 } else {
5212 app = null;
5213 }
5214
5215 if (app == null) {
5216 Log.w(TAG, "No pending application record for pid " + pid
5217 + " (IApplicationThread " + thread + "); dropping process");
5218 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5219 if (pid > 0 && pid != MY_PID) {
5220 Process.killProcess(pid);
5221 } else {
5222 try {
5223 thread.scheduleExit();
5224 } catch (Exception e) {
5225 // Ignore exceptions.
5226 }
5227 }
5228 return false;
5229 }
5230
5231 // If this application record is still attached to a previous
5232 // process, clean it up now.
5233 if (app.thread != null) {
5234 handleAppDiedLocked(app, true);
5235 }
5236
5237 // Tell the process all about itself.
5238
5239 if (localLOGV) Log.v(
5240 TAG, "Binding process pid " + pid + " to record " + app);
5241
5242 String processName = app.processName;
5243 try {
5244 thread.asBinder().linkToDeath(new AppDeathRecipient(
5245 app, pid, thread), 0);
5246 } catch (RemoteException e) {
5247 app.resetPackageList();
5248 startProcessLocked(app, "link fail", processName);
5249 return false;
5250 }
5251
5252 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5253
5254 app.thread = thread;
5255 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005256 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005257 app.forcingToForeground = null;
5258 app.foregroundServices = false;
5259 app.debugging = false;
5260
5261 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5262
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005263 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5264 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005265
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005266 if (!normalMode) {
5267 Log.i(TAG, "Launching preboot mode app: " + app);
5268 }
5269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005270 if (localLOGV) Log.v(
5271 TAG, "New app record " + app
5272 + " thread=" + thread.asBinder() + " pid=" + pid);
5273 try {
5274 int testMode = IApplicationThread.DEBUG_OFF;
5275 if (mDebugApp != null && mDebugApp.equals(processName)) {
5276 testMode = mWaitForDebugger
5277 ? IApplicationThread.DEBUG_WAIT
5278 : IApplicationThread.DEBUG_ON;
5279 app.debugging = true;
5280 if (mDebugTransient) {
5281 mDebugApp = mOrigDebugApp;
5282 mWaitForDebugger = mOrigWaitForDebugger;
5283 }
5284 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005285
Christopher Tate181fafa2009-05-14 11:12:14 -07005286 // If the app is being launched for restore or full backup, set it up specially
5287 boolean isRestrictedBackupMode = false;
5288 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5289 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5290 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5291 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005292
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005293 ensurePackageDexOpt(app.instrumentationInfo != null
5294 ? app.instrumentationInfo.packageName
5295 : app.info.packageName);
5296 if (app.instrumentationClass != null) {
5297 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005298 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005299 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5300 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005301 thread.bindApplication(processName, app.instrumentationInfo != null
5302 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005303 app.instrumentationClass, app.instrumentationProfileFile,
5304 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005305 isRestrictedBackupMode || !normalMode,
5306 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005307 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005308 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005309 } catch (Exception e) {
5310 // todo: Yikes! What should we do? For now we will try to
5311 // start another process, but that could easily get us in
5312 // an infinite loop of restarting processes...
5313 Log.w(TAG, "Exception thrown during bind!", e);
5314
5315 app.resetPackageList();
5316 startProcessLocked(app, "bind fail", processName);
5317 return false;
5318 }
5319
5320 // Remove this record from the list of starting applications.
5321 mPersistentStartingProcesses.remove(app);
5322 mProcessesOnHold.remove(app);
5323
5324 boolean badApp = false;
5325 boolean didSomething = false;
5326
5327 // See if the top visible activity is waiting to run in this process...
5328 HistoryRecord hr = topRunningActivityLocked(null);
5329 if (hr != null) {
5330 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5331 && processName.equals(hr.processName)) {
5332 try {
5333 if (realStartActivityLocked(hr, app, true, true)) {
5334 didSomething = true;
5335 }
5336 } catch (Exception e) {
5337 Log.w(TAG, "Exception in new application when starting activity "
5338 + hr.intent.getComponent().flattenToShortString(), e);
5339 badApp = true;
5340 }
5341 } else {
5342 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5343 }
5344 }
5345
5346 // Find any services that should be running in this process...
5347 if (!badApp && mPendingServices.size() > 0) {
5348 ServiceRecord sr = null;
5349 try {
5350 for (int i=0; i<mPendingServices.size(); i++) {
5351 sr = mPendingServices.get(i);
5352 if (app.info.uid != sr.appInfo.uid
5353 || !processName.equals(sr.processName)) {
5354 continue;
5355 }
5356
5357 mPendingServices.remove(i);
5358 i--;
5359 realStartServiceLocked(sr, app);
5360 didSomething = true;
5361 }
5362 } catch (Exception e) {
5363 Log.w(TAG, "Exception in new application when starting service "
5364 + sr.shortName, e);
5365 badApp = true;
5366 }
5367 }
5368
5369 // Check if the next broadcast receiver is in this process...
5370 BroadcastRecord br = mPendingBroadcast;
5371 if (!badApp && br != null && br.curApp == app) {
5372 try {
5373 mPendingBroadcast = null;
5374 processCurBroadcastLocked(br, app);
5375 didSomething = true;
5376 } catch (Exception e) {
5377 Log.w(TAG, "Exception in new application when starting receiver "
5378 + br.curComponent.flattenToShortString(), e);
5379 badApp = true;
5380 logBroadcastReceiverDiscard(br);
5381 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5382 br.resultExtras, br.resultAbort, true);
5383 scheduleBroadcastsLocked();
5384 }
5385 }
5386
Christopher Tate181fafa2009-05-14 11:12:14 -07005387 // Check whether the next backup agent is in this process...
5388 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5389 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005390 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005391 try {
5392 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5393 } catch (Exception e) {
5394 Log.w(TAG, "Exception scheduling backup agent creation: ");
5395 e.printStackTrace();
5396 }
5397 }
5398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005399 if (badApp) {
5400 // todo: Also need to kill application to deal with all
5401 // kinds of exceptions.
5402 handleAppDiedLocked(app, false);
5403 return false;
5404 }
5405
5406 if (!didSomething) {
5407 updateOomAdjLocked();
5408 }
5409
5410 return true;
5411 }
5412
5413 public final void attachApplication(IApplicationThread thread) {
5414 synchronized (this) {
5415 int callingPid = Binder.getCallingPid();
5416 final long origId = Binder.clearCallingIdentity();
5417 attachApplicationLocked(thread, callingPid);
5418 Binder.restoreCallingIdentity(origId);
5419 }
5420 }
5421
5422 public final void activityIdle(IBinder token) {
5423 final long origId = Binder.clearCallingIdentity();
5424 activityIdleInternal(token, false);
5425 Binder.restoreCallingIdentity(origId);
5426 }
5427
5428 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5429 boolean remove) {
5430 int N = mStoppingActivities.size();
5431 if (N <= 0) return null;
5432
5433 ArrayList<HistoryRecord> stops = null;
5434
5435 final boolean nowVisible = mResumedActivity != null
5436 && mResumedActivity.nowVisible
5437 && !mResumedActivity.waitingVisible;
5438 for (int i=0; i<N; i++) {
5439 HistoryRecord s = mStoppingActivities.get(i);
5440 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5441 + nowVisible + " waitingVisible=" + s.waitingVisible
5442 + " finishing=" + s.finishing);
5443 if (s.waitingVisible && nowVisible) {
5444 mWaitingVisibleActivities.remove(s);
5445 s.waitingVisible = false;
5446 if (s.finishing) {
5447 // If this activity is finishing, it is sitting on top of
5448 // everyone else but we now know it is no longer needed...
5449 // so get rid of it. Otherwise, we need to go through the
5450 // normal flow and hide it once we determine that it is
5451 // hidden by the activities in front of it.
5452 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5453 mWindowManager.setAppVisibility(s, false);
5454 }
5455 }
5456 if (!s.waitingVisible && remove) {
5457 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5458 if (stops == null) {
5459 stops = new ArrayList<HistoryRecord>();
5460 }
5461 stops.add(s);
5462 mStoppingActivities.remove(i);
5463 N--;
5464 i--;
5465 }
5466 }
5467
5468 return stops;
5469 }
5470
5471 void enableScreenAfterBoot() {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005472 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5473 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005474 mWindowManager.enableScreenAfterBoot();
5475 }
5476
5477 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5478 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5479
5480 ArrayList<HistoryRecord> stops = null;
5481 ArrayList<HistoryRecord> finishes = null;
5482 ArrayList<HistoryRecord> thumbnails = null;
5483 int NS = 0;
5484 int NF = 0;
5485 int NT = 0;
5486 IApplicationThread sendThumbnail = null;
5487 boolean booting = false;
5488 boolean enableScreen = false;
5489
5490 synchronized (this) {
5491 if (token != null) {
5492 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5493 }
5494
5495 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005496 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005497 if (index >= 0) {
5498 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5499
5500 // No longer need to keep the device awake.
5501 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5502 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5503 mLaunchingActivity.release();
5504 }
5505
5506 // We are now idle. If someone is waiting for a thumbnail from
5507 // us, we can now deliver.
5508 r.idle = true;
5509 scheduleAppGcsLocked();
5510 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5511 sendThumbnail = r.app.thread;
5512 r.thumbnailNeeded = false;
5513 }
5514
5515 // If this activity is fullscreen, set up to hide those under it.
5516
5517 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5518 ensureActivitiesVisibleLocked(null, 0);
5519
5520 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5521 if (!mBooted && !fromTimeout) {
5522 mBooted = true;
5523 enableScreen = true;
5524 }
5525 }
5526
5527 // Atomically retrieve all of the other things to do.
5528 stops = processStoppingActivitiesLocked(true);
5529 NS = stops != null ? stops.size() : 0;
5530 if ((NF=mFinishingActivities.size()) > 0) {
5531 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5532 mFinishingActivities.clear();
5533 }
5534 if ((NT=mCancelledThumbnails.size()) > 0) {
5535 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5536 mCancelledThumbnails.clear();
5537 }
5538
5539 booting = mBooting;
5540 mBooting = false;
5541 }
5542
5543 int i;
5544
5545 // Send thumbnail if requested.
5546 if (sendThumbnail != null) {
5547 try {
5548 sendThumbnail.requestThumbnail(token);
5549 } catch (Exception e) {
5550 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5551 sendPendingThumbnail(null, token, null, null, true);
5552 }
5553 }
5554
5555 // Stop any activities that are scheduled to do so but have been
5556 // waiting for the next one to start.
5557 for (i=0; i<NS; i++) {
5558 HistoryRecord r = (HistoryRecord)stops.get(i);
5559 synchronized (this) {
5560 if (r.finishing) {
5561 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5562 } else {
5563 stopActivityLocked(r);
5564 }
5565 }
5566 }
5567
5568 // Finish any activities that are scheduled to do so but have been
5569 // waiting for the next one to start.
5570 for (i=0; i<NF; i++) {
5571 HistoryRecord r = (HistoryRecord)finishes.get(i);
5572 synchronized (this) {
5573 destroyActivityLocked(r, true);
5574 }
5575 }
5576
5577 // Report back to any thumbnail receivers.
5578 for (i=0; i<NT; i++) {
5579 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5580 sendPendingThumbnail(r, null, null, null, true);
5581 }
5582
5583 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005584 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005585 }
5586
5587 trimApplications();
5588 //dump();
5589 //mWindowManager.dump();
5590
5591 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005592 enableScreenAfterBoot();
5593 }
5594 }
5595
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005596 final void finishBooting() {
5597 // Ensure that any processes we had put on hold are now started
5598 // up.
5599 final int NP = mProcessesOnHold.size();
5600 if (NP > 0) {
5601 ArrayList<ProcessRecord> procs =
5602 new ArrayList<ProcessRecord>(mProcessesOnHold);
5603 for (int ip=0; ip<NP; ip++) {
5604 this.startProcessLocked(procs.get(ip), "on-hold", null);
5605 }
5606 }
5607 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5608 // Tell anyone interested that we are done booting!
5609 synchronized (this) {
5610 broadcastIntentLocked(null, null,
5611 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5612 null, null, 0, null, null,
5613 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5614 false, false, MY_PID, Process.SYSTEM_UID);
5615 }
5616 }
5617 }
5618
5619 final void ensureBootCompleted() {
5620 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005621 boolean enableScreen;
5622 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005623 booting = mBooting;
5624 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005625 enableScreen = !mBooted;
5626 mBooted = true;
5627 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005628
5629 if (booting) {
5630 finishBooting();
5631 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005632
5633 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005634 enableScreenAfterBoot();
5635 }
5636 }
5637
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005638 public final void activityPaused(IBinder token, Bundle icicle) {
5639 // Refuse possible leaked file descriptors
5640 if (icicle != null && icicle.hasFileDescriptors()) {
5641 throw new IllegalArgumentException("File descriptors passed in Bundle");
5642 }
5643
5644 final long origId = Binder.clearCallingIdentity();
5645 activityPaused(token, icicle, false);
5646 Binder.restoreCallingIdentity(origId);
5647 }
5648
5649 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5650 if (DEBUG_PAUSE) Log.v(
5651 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5652 + ", timeout=" + timeout);
5653
5654 HistoryRecord r = null;
5655
5656 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005657 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005658 if (index >= 0) {
5659 r = (HistoryRecord)mHistory.get(index);
5660 if (!timeout) {
5661 r.icicle = icicle;
5662 r.haveState = true;
5663 }
5664 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5665 if (mPausingActivity == r) {
5666 r.state = ActivityState.PAUSED;
5667 completePauseLocked();
5668 } else {
5669 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5670 System.identityHashCode(r), r.shortComponentName,
5671 mPausingActivity != null
5672 ? mPausingActivity.shortComponentName : "(none)");
5673 }
5674 }
5675 }
5676 }
5677
5678 public final void activityStopped(IBinder token, Bitmap thumbnail,
5679 CharSequence description) {
5680 if (localLOGV) Log.v(
5681 TAG, "Activity stopped: token=" + token);
5682
5683 HistoryRecord r = null;
5684
5685 final long origId = Binder.clearCallingIdentity();
5686
5687 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005688 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005689 if (index >= 0) {
5690 r = (HistoryRecord)mHistory.get(index);
5691 r.thumbnail = thumbnail;
5692 r.description = description;
5693 r.stopped = true;
5694 r.state = ActivityState.STOPPED;
5695 if (!r.finishing) {
5696 if (r.configDestroy) {
5697 destroyActivityLocked(r, true);
5698 resumeTopActivityLocked(null);
5699 }
5700 }
5701 }
5702 }
5703
5704 if (r != null) {
5705 sendPendingThumbnail(r, null, null, null, false);
5706 }
5707
5708 trimApplications();
5709
5710 Binder.restoreCallingIdentity(origId);
5711 }
5712
5713 public final void activityDestroyed(IBinder token) {
5714 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5715 synchronized (this) {
5716 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5717
Dianne Hackborn75b03852009-06-12 15:43:26 -07005718 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005719 if (index >= 0) {
5720 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5721 if (r.state == ActivityState.DESTROYING) {
5722 final long origId = Binder.clearCallingIdentity();
5723 removeActivityFromHistoryLocked(r);
5724 Binder.restoreCallingIdentity(origId);
5725 }
5726 }
5727 }
5728 }
5729
5730 public String getCallingPackage(IBinder token) {
5731 synchronized (this) {
5732 HistoryRecord r = getCallingRecordLocked(token);
5733 return r != null && r.app != null ? r.app.processName : null;
5734 }
5735 }
5736
5737 public ComponentName getCallingActivity(IBinder token) {
5738 synchronized (this) {
5739 HistoryRecord r = getCallingRecordLocked(token);
5740 return r != null ? r.intent.getComponent() : null;
5741 }
5742 }
5743
5744 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005745 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005746 if (index >= 0) {
5747 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5748 if (r != null) {
5749 return r.resultTo;
5750 }
5751 }
5752 return null;
5753 }
5754
5755 public ComponentName getActivityClassForToken(IBinder token) {
5756 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005757 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005758 if (index >= 0) {
5759 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5760 return r.intent.getComponent();
5761 }
5762 return null;
5763 }
5764 }
5765
5766 public String getPackageForToken(IBinder token) {
5767 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005768 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005769 if (index >= 0) {
5770 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5771 return r.packageName;
5772 }
5773 return null;
5774 }
5775 }
5776
5777 public IIntentSender getIntentSender(int type,
5778 String packageName, IBinder token, String resultWho,
5779 int requestCode, Intent intent, String resolvedType, int flags) {
5780 // Refuse possible leaked file descriptors
5781 if (intent != null && intent.hasFileDescriptors() == true) {
5782 throw new IllegalArgumentException("File descriptors passed in Intent");
5783 }
5784
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005785 if (type == INTENT_SENDER_BROADCAST) {
5786 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5787 throw new IllegalArgumentException(
5788 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5789 }
5790 }
5791
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005792 synchronized(this) {
5793 int callingUid = Binder.getCallingUid();
5794 try {
5795 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5796 Process.supportsProcesses()) {
5797 int uid = ActivityThread.getPackageManager()
5798 .getPackageUid(packageName);
5799 if (uid != Binder.getCallingUid()) {
5800 String msg = "Permission Denial: getIntentSender() from pid="
5801 + Binder.getCallingPid()
5802 + ", uid=" + Binder.getCallingUid()
5803 + ", (need uid=" + uid + ")"
5804 + " is not allowed to send as package " + packageName;
5805 Log.w(TAG, msg);
5806 throw new SecurityException(msg);
5807 }
5808 }
5809 } catch (RemoteException e) {
5810 throw new SecurityException(e);
5811 }
5812 HistoryRecord activity = null;
5813 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005814 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005815 if (index < 0) {
5816 return null;
5817 }
5818 activity = (HistoryRecord)mHistory.get(index);
5819 if (activity.finishing) {
5820 return null;
5821 }
5822 }
5823
5824 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5825 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5826 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5827 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5828 |PendingIntent.FLAG_UPDATE_CURRENT);
5829
5830 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5831 type, packageName, activity, resultWho,
5832 requestCode, intent, resolvedType, flags);
5833 WeakReference<PendingIntentRecord> ref;
5834 ref = mIntentSenderRecords.get(key);
5835 PendingIntentRecord rec = ref != null ? ref.get() : null;
5836 if (rec != null) {
5837 if (!cancelCurrent) {
5838 if (updateCurrent) {
5839 rec.key.requestIntent.replaceExtras(intent);
5840 }
5841 return rec;
5842 }
5843 rec.canceled = true;
5844 mIntentSenderRecords.remove(key);
5845 }
5846 if (noCreate) {
5847 return rec;
5848 }
5849 rec = new PendingIntentRecord(this, key, callingUid);
5850 mIntentSenderRecords.put(key, rec.ref);
5851 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5852 if (activity.pendingResults == null) {
5853 activity.pendingResults
5854 = new HashSet<WeakReference<PendingIntentRecord>>();
5855 }
5856 activity.pendingResults.add(rec.ref);
5857 }
5858 return rec;
5859 }
5860 }
5861
5862 public void cancelIntentSender(IIntentSender sender) {
5863 if (!(sender instanceof PendingIntentRecord)) {
5864 return;
5865 }
5866 synchronized(this) {
5867 PendingIntentRecord rec = (PendingIntentRecord)sender;
5868 try {
5869 int uid = ActivityThread.getPackageManager()
5870 .getPackageUid(rec.key.packageName);
5871 if (uid != Binder.getCallingUid()) {
5872 String msg = "Permission Denial: cancelIntentSender() from pid="
5873 + Binder.getCallingPid()
5874 + ", uid=" + Binder.getCallingUid()
5875 + " is not allowed to cancel packges "
5876 + rec.key.packageName;
5877 Log.w(TAG, msg);
5878 throw new SecurityException(msg);
5879 }
5880 } catch (RemoteException e) {
5881 throw new SecurityException(e);
5882 }
5883 cancelIntentSenderLocked(rec, true);
5884 }
5885 }
5886
5887 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5888 rec.canceled = true;
5889 mIntentSenderRecords.remove(rec.key);
5890 if (cleanActivity && rec.key.activity != null) {
5891 rec.key.activity.pendingResults.remove(rec.ref);
5892 }
5893 }
5894
5895 public String getPackageForIntentSender(IIntentSender pendingResult) {
5896 if (!(pendingResult instanceof PendingIntentRecord)) {
5897 return null;
5898 }
5899 synchronized(this) {
5900 try {
5901 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5902 return res.key.packageName;
5903 } catch (ClassCastException e) {
5904 }
5905 }
5906 return null;
5907 }
5908
5909 public void setProcessLimit(int max) {
5910 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5911 "setProcessLimit()");
5912 mProcessLimit = max;
5913 }
5914
5915 public int getProcessLimit() {
5916 return mProcessLimit;
5917 }
5918
5919 void foregroundTokenDied(ForegroundToken token) {
5920 synchronized (ActivityManagerService.this) {
5921 synchronized (mPidsSelfLocked) {
5922 ForegroundToken cur
5923 = mForegroundProcesses.get(token.pid);
5924 if (cur != token) {
5925 return;
5926 }
5927 mForegroundProcesses.remove(token.pid);
5928 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5929 if (pr == null) {
5930 return;
5931 }
5932 pr.forcingToForeground = null;
5933 pr.foregroundServices = false;
5934 }
5935 updateOomAdjLocked();
5936 }
5937 }
5938
5939 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5940 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5941 "setProcessForeground()");
5942 synchronized(this) {
5943 boolean changed = false;
5944
5945 synchronized (mPidsSelfLocked) {
5946 ProcessRecord pr = mPidsSelfLocked.get(pid);
5947 if (pr == null) {
5948 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5949 return;
5950 }
5951 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5952 if (oldToken != null) {
5953 oldToken.token.unlinkToDeath(oldToken, 0);
5954 mForegroundProcesses.remove(pid);
5955 pr.forcingToForeground = null;
5956 changed = true;
5957 }
5958 if (isForeground && token != null) {
5959 ForegroundToken newToken = new ForegroundToken() {
5960 public void binderDied() {
5961 foregroundTokenDied(this);
5962 }
5963 };
5964 newToken.pid = pid;
5965 newToken.token = token;
5966 try {
5967 token.linkToDeath(newToken, 0);
5968 mForegroundProcesses.put(pid, newToken);
5969 pr.forcingToForeground = token;
5970 changed = true;
5971 } catch (RemoteException e) {
5972 // If the process died while doing this, we will later
5973 // do the cleanup with the process death link.
5974 }
5975 }
5976 }
5977
5978 if (changed) {
5979 updateOomAdjLocked();
5980 }
5981 }
5982 }
5983
5984 // =========================================================
5985 // PERMISSIONS
5986 // =========================================================
5987
5988 static class PermissionController extends IPermissionController.Stub {
5989 ActivityManagerService mActivityManagerService;
5990 PermissionController(ActivityManagerService activityManagerService) {
5991 mActivityManagerService = activityManagerService;
5992 }
5993
5994 public boolean checkPermission(String permission, int pid, int uid) {
5995 return mActivityManagerService.checkPermission(permission, pid,
5996 uid) == PackageManager.PERMISSION_GRANTED;
5997 }
5998 }
5999
6000 /**
6001 * This can be called with or without the global lock held.
6002 */
6003 int checkComponentPermission(String permission, int pid, int uid,
6004 int reqUid) {
6005 // We might be performing an operation on behalf of an indirect binder
6006 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
6007 // client identity accordingly before proceeding.
6008 Identity tlsIdentity = sCallerIdentity.get();
6009 if (tlsIdentity != null) {
6010 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6011 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6012 uid = tlsIdentity.uid;
6013 pid = tlsIdentity.pid;
6014 }
6015
6016 // Root, system server and our own process get to do everything.
6017 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6018 !Process.supportsProcesses()) {
6019 return PackageManager.PERMISSION_GRANTED;
6020 }
6021 // If the target requires a specific UID, always fail for others.
6022 if (reqUid >= 0 && uid != reqUid) {
6023 return PackageManager.PERMISSION_DENIED;
6024 }
6025 if (permission == null) {
6026 return PackageManager.PERMISSION_GRANTED;
6027 }
6028 try {
6029 return ActivityThread.getPackageManager()
6030 .checkUidPermission(permission, uid);
6031 } catch (RemoteException e) {
6032 // Should never happen, but if it does... deny!
6033 Log.e(TAG, "PackageManager is dead?!?", e);
6034 }
6035 return PackageManager.PERMISSION_DENIED;
6036 }
6037
6038 /**
6039 * As the only public entry point for permissions checking, this method
6040 * can enforce the semantic that requesting a check on a null global
6041 * permission is automatically denied. (Internally a null permission
6042 * string is used when calling {@link #checkComponentPermission} in cases
6043 * when only uid-based security is needed.)
6044 *
6045 * This can be called with or without the global lock held.
6046 */
6047 public int checkPermission(String permission, int pid, int uid) {
6048 if (permission == null) {
6049 return PackageManager.PERMISSION_DENIED;
6050 }
6051 return checkComponentPermission(permission, pid, uid, -1);
6052 }
6053
6054 /**
6055 * Binder IPC calls go through the public entry point.
6056 * This can be called with or without the global lock held.
6057 */
6058 int checkCallingPermission(String permission) {
6059 return checkPermission(permission,
6060 Binder.getCallingPid(),
6061 Binder.getCallingUid());
6062 }
6063
6064 /**
6065 * This can be called with or without the global lock held.
6066 */
6067 void enforceCallingPermission(String permission, String func) {
6068 if (checkCallingPermission(permission)
6069 == PackageManager.PERMISSION_GRANTED) {
6070 return;
6071 }
6072
6073 String msg = "Permission Denial: " + func + " from pid="
6074 + Binder.getCallingPid()
6075 + ", uid=" + Binder.getCallingUid()
6076 + " requires " + permission;
6077 Log.w(TAG, msg);
6078 throw new SecurityException(msg);
6079 }
6080
6081 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6082 ProviderInfo pi, int uid, int modeFlags) {
6083 try {
6084 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6085 if ((pi.readPermission != null) &&
6086 (pm.checkUidPermission(pi.readPermission, uid)
6087 != PackageManager.PERMISSION_GRANTED)) {
6088 return false;
6089 }
6090 }
6091 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6092 if ((pi.writePermission != null) &&
6093 (pm.checkUidPermission(pi.writePermission, uid)
6094 != PackageManager.PERMISSION_GRANTED)) {
6095 return false;
6096 }
6097 }
6098 return true;
6099 } catch (RemoteException e) {
6100 return false;
6101 }
6102 }
6103
6104 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6105 int modeFlags) {
6106 // Root gets to do everything.
6107 if (uid == 0 || !Process.supportsProcesses()) {
6108 return true;
6109 }
6110 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6111 if (perms == null) return false;
6112 UriPermission perm = perms.get(uri);
6113 if (perm == null) return false;
6114 return (modeFlags&perm.modeFlags) == modeFlags;
6115 }
6116
6117 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6118 // Another redirected-binder-call permissions check as in
6119 // {@link checkComponentPermission}.
6120 Identity tlsIdentity = sCallerIdentity.get();
6121 if (tlsIdentity != null) {
6122 uid = tlsIdentity.uid;
6123 pid = tlsIdentity.pid;
6124 }
6125
6126 // Our own process gets to do everything.
6127 if (pid == MY_PID) {
6128 return PackageManager.PERMISSION_GRANTED;
6129 }
6130 synchronized(this) {
6131 return checkUriPermissionLocked(uri, uid, modeFlags)
6132 ? PackageManager.PERMISSION_GRANTED
6133 : PackageManager.PERMISSION_DENIED;
6134 }
6135 }
6136
6137 private void grantUriPermissionLocked(int callingUid,
6138 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6139 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6140 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6141 if (modeFlags == 0) {
6142 return;
6143 }
6144
6145 final IPackageManager pm = ActivityThread.getPackageManager();
6146
6147 // If this is not a content: uri, we can't do anything with it.
6148 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6149 return;
6150 }
6151
6152 String name = uri.getAuthority();
6153 ProviderInfo pi = null;
6154 ContentProviderRecord cpr
6155 = (ContentProviderRecord)mProvidersByName.get(name);
6156 if (cpr != null) {
6157 pi = cpr.info;
6158 } else {
6159 try {
6160 pi = pm.resolveContentProvider(name,
6161 PackageManager.GET_URI_PERMISSION_PATTERNS);
6162 } catch (RemoteException ex) {
6163 }
6164 }
6165 if (pi == null) {
6166 Log.w(TAG, "No content provider found for: " + name);
6167 return;
6168 }
6169
6170 int targetUid;
6171 try {
6172 targetUid = pm.getPackageUid(targetPkg);
6173 if (targetUid < 0) {
6174 return;
6175 }
6176 } catch (RemoteException ex) {
6177 return;
6178 }
6179
6180 // First... does the target actually need this permission?
6181 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6182 // No need to grant the target this permission.
6183 return;
6184 }
6185
6186 // Second... maybe someone else has already granted the
6187 // permission?
6188 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6189 // No need to grant the target this permission.
6190 return;
6191 }
6192
6193 // Third... is the provider allowing granting of URI permissions?
6194 if (!pi.grantUriPermissions) {
6195 throw new SecurityException("Provider " + pi.packageName
6196 + "/" + pi.name
6197 + " does not allow granting of Uri permissions (uri "
6198 + uri + ")");
6199 }
6200 if (pi.uriPermissionPatterns != null) {
6201 final int N = pi.uriPermissionPatterns.length;
6202 boolean allowed = false;
6203 for (int i=0; i<N; i++) {
6204 if (pi.uriPermissionPatterns[i] != null
6205 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6206 allowed = true;
6207 break;
6208 }
6209 }
6210 if (!allowed) {
6211 throw new SecurityException("Provider " + pi.packageName
6212 + "/" + pi.name
6213 + " does not allow granting of permission to path of Uri "
6214 + uri);
6215 }
6216 }
6217
6218 // Fourth... does the caller itself have permission to access
6219 // this uri?
6220 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6221 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6222 throw new SecurityException("Uid " + callingUid
6223 + " does not have permission to uri " + uri);
6224 }
6225 }
6226
6227 // Okay! So here we are: the caller has the assumed permission
6228 // to the uri, and the target doesn't. Let's now give this to
6229 // the target.
6230
6231 HashMap<Uri, UriPermission> targetUris
6232 = mGrantedUriPermissions.get(targetUid);
6233 if (targetUris == null) {
6234 targetUris = new HashMap<Uri, UriPermission>();
6235 mGrantedUriPermissions.put(targetUid, targetUris);
6236 }
6237
6238 UriPermission perm = targetUris.get(uri);
6239 if (perm == null) {
6240 perm = new UriPermission(targetUid, uri);
6241 targetUris.put(uri, perm);
6242
6243 }
6244 perm.modeFlags |= modeFlags;
6245 if (activity == null) {
6246 perm.globalModeFlags |= modeFlags;
6247 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6248 perm.readActivities.add(activity);
6249 if (activity.readUriPermissions == null) {
6250 activity.readUriPermissions = new HashSet<UriPermission>();
6251 }
6252 activity.readUriPermissions.add(perm);
6253 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6254 perm.writeActivities.add(activity);
6255 if (activity.writeUriPermissions == null) {
6256 activity.writeUriPermissions = new HashSet<UriPermission>();
6257 }
6258 activity.writeUriPermissions.add(perm);
6259 }
6260 }
6261
6262 private void grantUriPermissionFromIntentLocked(int callingUid,
6263 String targetPkg, Intent intent, HistoryRecord activity) {
6264 if (intent == null) {
6265 return;
6266 }
6267 Uri data = intent.getData();
6268 if (data == null) {
6269 return;
6270 }
6271 grantUriPermissionLocked(callingUid, targetPkg, data,
6272 intent.getFlags(), activity);
6273 }
6274
6275 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6276 Uri uri, int modeFlags) {
6277 synchronized(this) {
6278 final ProcessRecord r = getRecordForAppLocked(caller);
6279 if (r == null) {
6280 throw new SecurityException("Unable to find app for caller "
6281 + caller
6282 + " when granting permission to uri " + uri);
6283 }
6284 if (targetPkg == null) {
6285 Log.w(TAG, "grantUriPermission: null target");
6286 return;
6287 }
6288 if (uri == null) {
6289 Log.w(TAG, "grantUriPermission: null uri");
6290 return;
6291 }
6292
6293 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6294 null);
6295 }
6296 }
6297
6298 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6299 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6300 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6301 HashMap<Uri, UriPermission> perms
6302 = mGrantedUriPermissions.get(perm.uid);
6303 if (perms != null) {
6304 perms.remove(perm.uri);
6305 if (perms.size() == 0) {
6306 mGrantedUriPermissions.remove(perm.uid);
6307 }
6308 }
6309 }
6310 }
6311
6312 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6313 if (activity.readUriPermissions != null) {
6314 for (UriPermission perm : activity.readUriPermissions) {
6315 perm.readActivities.remove(activity);
6316 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6317 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6318 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6319 removeUriPermissionIfNeededLocked(perm);
6320 }
6321 }
6322 }
6323 if (activity.writeUriPermissions != null) {
6324 for (UriPermission perm : activity.writeUriPermissions) {
6325 perm.writeActivities.remove(activity);
6326 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6327 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6328 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6329 removeUriPermissionIfNeededLocked(perm);
6330 }
6331 }
6332 }
6333 }
6334
6335 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6336 int modeFlags) {
6337 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6338 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6339 if (modeFlags == 0) {
6340 return;
6341 }
6342
6343 final IPackageManager pm = ActivityThread.getPackageManager();
6344
6345 final String authority = uri.getAuthority();
6346 ProviderInfo pi = null;
6347 ContentProviderRecord cpr
6348 = (ContentProviderRecord)mProvidersByName.get(authority);
6349 if (cpr != null) {
6350 pi = cpr.info;
6351 } else {
6352 try {
6353 pi = pm.resolveContentProvider(authority,
6354 PackageManager.GET_URI_PERMISSION_PATTERNS);
6355 } catch (RemoteException ex) {
6356 }
6357 }
6358 if (pi == null) {
6359 Log.w(TAG, "No content provider found for: " + authority);
6360 return;
6361 }
6362
6363 // Does the caller have this permission on the URI?
6364 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6365 // Right now, if you are not the original owner of the permission,
6366 // you are not allowed to revoke it.
6367 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6368 throw new SecurityException("Uid " + callingUid
6369 + " does not have permission to uri " + uri);
6370 //}
6371 }
6372
6373 // Go through all of the permissions and remove any that match.
6374 final List<String> SEGMENTS = uri.getPathSegments();
6375 if (SEGMENTS != null) {
6376 final int NS = SEGMENTS.size();
6377 int N = mGrantedUriPermissions.size();
6378 for (int i=0; i<N; i++) {
6379 HashMap<Uri, UriPermission> perms
6380 = mGrantedUriPermissions.valueAt(i);
6381 Iterator<UriPermission> it = perms.values().iterator();
6382 toploop:
6383 while (it.hasNext()) {
6384 UriPermission perm = it.next();
6385 Uri targetUri = perm.uri;
6386 if (!authority.equals(targetUri.getAuthority())) {
6387 continue;
6388 }
6389 List<String> targetSegments = targetUri.getPathSegments();
6390 if (targetSegments == null) {
6391 continue;
6392 }
6393 if (targetSegments.size() < NS) {
6394 continue;
6395 }
6396 for (int j=0; j<NS; j++) {
6397 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6398 continue toploop;
6399 }
6400 }
6401 perm.clearModes(modeFlags);
6402 if (perm.modeFlags == 0) {
6403 it.remove();
6404 }
6405 }
6406 if (perms.size() == 0) {
6407 mGrantedUriPermissions.remove(
6408 mGrantedUriPermissions.keyAt(i));
6409 N--;
6410 i--;
6411 }
6412 }
6413 }
6414 }
6415
6416 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6417 int modeFlags) {
6418 synchronized(this) {
6419 final ProcessRecord r = getRecordForAppLocked(caller);
6420 if (r == null) {
6421 throw new SecurityException("Unable to find app for caller "
6422 + caller
6423 + " when revoking permission to uri " + uri);
6424 }
6425 if (uri == null) {
6426 Log.w(TAG, "revokeUriPermission: null uri");
6427 return;
6428 }
6429
6430 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6431 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6432 if (modeFlags == 0) {
6433 return;
6434 }
6435
6436 final IPackageManager pm = ActivityThread.getPackageManager();
6437
6438 final String authority = uri.getAuthority();
6439 ProviderInfo pi = null;
6440 ContentProviderRecord cpr
6441 = (ContentProviderRecord)mProvidersByName.get(authority);
6442 if (cpr != null) {
6443 pi = cpr.info;
6444 } else {
6445 try {
6446 pi = pm.resolveContentProvider(authority,
6447 PackageManager.GET_URI_PERMISSION_PATTERNS);
6448 } catch (RemoteException ex) {
6449 }
6450 }
6451 if (pi == null) {
6452 Log.w(TAG, "No content provider found for: " + authority);
6453 return;
6454 }
6455
6456 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6457 }
6458 }
6459
6460 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6461 synchronized (this) {
6462 ProcessRecord app =
6463 who != null ? getRecordForAppLocked(who) : null;
6464 if (app == null) return;
6465
6466 Message msg = Message.obtain();
6467 msg.what = WAIT_FOR_DEBUGGER_MSG;
6468 msg.obj = app;
6469 msg.arg1 = waiting ? 1 : 0;
6470 mHandler.sendMessage(msg);
6471 }
6472 }
6473
6474 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6475 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006476 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006477 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006478 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006479 }
6480
6481 // =========================================================
6482 // TASK MANAGEMENT
6483 // =========================================================
6484
6485 public List getTasks(int maxNum, int flags,
6486 IThumbnailReceiver receiver) {
6487 ArrayList list = new ArrayList();
6488
6489 PendingThumbnailsRecord pending = null;
6490 IApplicationThread topThumbnail = null;
6491 HistoryRecord topRecord = null;
6492
6493 synchronized(this) {
6494 if (localLOGV) Log.v(
6495 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6496 + ", receiver=" + receiver);
6497
6498 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6499 != PackageManager.PERMISSION_GRANTED) {
6500 if (receiver != null) {
6501 // If the caller wants to wait for pending thumbnails,
6502 // it ain't gonna get them.
6503 try {
6504 receiver.finished();
6505 } catch (RemoteException ex) {
6506 }
6507 }
6508 String msg = "Permission Denial: getTasks() from pid="
6509 + Binder.getCallingPid()
6510 + ", uid=" + Binder.getCallingUid()
6511 + " requires " + android.Manifest.permission.GET_TASKS;
6512 Log.w(TAG, msg);
6513 throw new SecurityException(msg);
6514 }
6515
6516 int pos = mHistory.size()-1;
6517 HistoryRecord next =
6518 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6519 HistoryRecord top = null;
6520 CharSequence topDescription = null;
6521 TaskRecord curTask = null;
6522 int numActivities = 0;
6523 int numRunning = 0;
6524 while (pos >= 0 && maxNum > 0) {
6525 final HistoryRecord r = next;
6526 pos--;
6527 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6528
6529 // Initialize state for next task if needed.
6530 if (top == null ||
6531 (top.state == ActivityState.INITIALIZING
6532 && top.task == r.task)) {
6533 top = r;
6534 topDescription = r.description;
6535 curTask = r.task;
6536 numActivities = numRunning = 0;
6537 }
6538
6539 // Add 'r' into the current task.
6540 numActivities++;
6541 if (r.app != null && r.app.thread != null) {
6542 numRunning++;
6543 }
6544 if (topDescription == null) {
6545 topDescription = r.description;
6546 }
6547
6548 if (localLOGV) Log.v(
6549 TAG, r.intent.getComponent().flattenToShortString()
6550 + ": task=" + r.task);
6551
6552 // If the next one is a different task, generate a new
6553 // TaskInfo entry for what we have.
6554 if (next == null || next.task != curTask) {
6555 ActivityManager.RunningTaskInfo ci
6556 = new ActivityManager.RunningTaskInfo();
6557 ci.id = curTask.taskId;
6558 ci.baseActivity = r.intent.getComponent();
6559 ci.topActivity = top.intent.getComponent();
6560 ci.thumbnail = top.thumbnail;
6561 ci.description = topDescription;
6562 ci.numActivities = numActivities;
6563 ci.numRunning = numRunning;
6564 //System.out.println(
6565 // "#" + maxNum + ": " + " descr=" + ci.description);
6566 if (ci.thumbnail == null && receiver != null) {
6567 if (localLOGV) Log.v(
6568 TAG, "State=" + top.state + "Idle=" + top.idle
6569 + " app=" + top.app
6570 + " thr=" + (top.app != null ? top.app.thread : null));
6571 if (top.state == ActivityState.RESUMED
6572 || top.state == ActivityState.PAUSING) {
6573 if (top.idle && top.app != null
6574 && top.app.thread != null) {
6575 topRecord = top;
6576 topThumbnail = top.app.thread;
6577 } else {
6578 top.thumbnailNeeded = true;
6579 }
6580 }
6581 if (pending == null) {
6582 pending = new PendingThumbnailsRecord(receiver);
6583 }
6584 pending.pendingRecords.add(top);
6585 }
6586 list.add(ci);
6587 maxNum--;
6588 top = null;
6589 }
6590 }
6591
6592 if (pending != null) {
6593 mPendingThumbnails.add(pending);
6594 }
6595 }
6596
6597 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6598
6599 if (topThumbnail != null) {
6600 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6601 try {
6602 topThumbnail.requestThumbnail(topRecord);
6603 } catch (Exception e) {
6604 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6605 sendPendingThumbnail(null, topRecord, null, null, true);
6606 }
6607 }
6608
6609 if (pending == null && receiver != null) {
6610 // In this case all thumbnails were available and the client
6611 // is being asked to be told when the remaining ones come in...
6612 // which is unusually, since the top-most currently running
6613 // activity should never have a canned thumbnail! Oh well.
6614 try {
6615 receiver.finished();
6616 } catch (RemoteException ex) {
6617 }
6618 }
6619
6620 return list;
6621 }
6622
6623 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6624 int flags) {
6625 synchronized (this) {
6626 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6627 "getRecentTasks()");
6628
6629 final int N = mRecentTasks.size();
6630 ArrayList<ActivityManager.RecentTaskInfo> res
6631 = new ArrayList<ActivityManager.RecentTaskInfo>(
6632 maxNum < N ? maxNum : N);
6633 for (int i=0; i<N && maxNum > 0; i++) {
6634 TaskRecord tr = mRecentTasks.get(i);
6635 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6636 || (tr.intent == null)
6637 || ((tr.intent.getFlags()
6638 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6639 ActivityManager.RecentTaskInfo rti
6640 = new ActivityManager.RecentTaskInfo();
6641 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6642 rti.baseIntent = new Intent(
6643 tr.intent != null ? tr.intent : tr.affinityIntent);
6644 rti.origActivity = tr.origActivity;
6645 res.add(rti);
6646 maxNum--;
6647 }
6648 }
6649 return res;
6650 }
6651 }
6652
6653 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6654 int j;
6655 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6656 TaskRecord jt = startTask;
6657
6658 // First look backwards
6659 for (j=startIndex-1; j>=0; j--) {
6660 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6661 if (r.task != jt) {
6662 jt = r.task;
6663 if (affinity.equals(jt.affinity)) {
6664 return j;
6665 }
6666 }
6667 }
6668
6669 // Now look forwards
6670 final int N = mHistory.size();
6671 jt = startTask;
6672 for (j=startIndex+1; j<N; j++) {
6673 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6674 if (r.task != jt) {
6675 if (affinity.equals(jt.affinity)) {
6676 return j;
6677 }
6678 jt = r.task;
6679 }
6680 }
6681
6682 // Might it be at the top?
6683 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6684 return N-1;
6685 }
6686
6687 return -1;
6688 }
6689
6690 /**
6691 * Perform a reset of the given task, if needed as part of launching it.
6692 * Returns the new HistoryRecord at the top of the task.
6693 */
6694 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6695 HistoryRecord newActivity) {
6696 boolean forceReset = (newActivity.info.flags
6697 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6698 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6699 if ((newActivity.info.flags
6700 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6701 forceReset = true;
6702 }
6703 }
6704
6705 final TaskRecord task = taskTop.task;
6706
6707 // We are going to move through the history list so that we can look
6708 // at each activity 'target' with 'below' either the interesting
6709 // activity immediately below it in the stack or null.
6710 HistoryRecord target = null;
6711 int targetI = 0;
6712 int taskTopI = -1;
6713 int replyChainEnd = -1;
6714 int lastReparentPos = -1;
6715 for (int i=mHistory.size()-1; i>=-1; i--) {
6716 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6717
6718 if (below != null && below.finishing) {
6719 continue;
6720 }
6721 if (target == null) {
6722 target = below;
6723 targetI = i;
6724 // If we were in the middle of a reply chain before this
6725 // task, it doesn't appear like the root of the chain wants
6726 // anything interesting, so drop it.
6727 replyChainEnd = -1;
6728 continue;
6729 }
6730
6731 final int flags = target.info.flags;
6732
6733 final boolean finishOnTaskLaunch =
6734 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6735 final boolean allowTaskReparenting =
6736 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6737
6738 if (target.task == task) {
6739 // We are inside of the task being reset... we'll either
6740 // finish this activity, push it out for another task,
6741 // or leave it as-is. We only do this
6742 // for activities that are not the root of the task (since
6743 // if we finish the root, we may no longer have the task!).
6744 if (taskTopI < 0) {
6745 taskTopI = targetI;
6746 }
6747 if (below != null && below.task == task) {
6748 final boolean clearWhenTaskReset =
6749 (target.intent.getFlags()
6750 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006751 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006752 // If this activity is sending a reply to a previous
6753 // activity, we can't do anything with it now until
6754 // we reach the start of the reply chain.
6755 // XXX note that we are assuming the result is always
6756 // to the previous activity, which is almost always
6757 // the case but we really shouldn't count on.
6758 if (replyChainEnd < 0) {
6759 replyChainEnd = targetI;
6760 }
Ed Heyl73798232009-03-24 21:32:21 -07006761 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006762 && target.taskAffinity != null
6763 && !target.taskAffinity.equals(task.affinity)) {
6764 // If this activity has an affinity for another
6765 // task, then we need to move it out of here. We will
6766 // move it as far out of the way as possible, to the
6767 // bottom of the activity stack. This also keeps it
6768 // correctly ordered with any activities we previously
6769 // moved.
6770 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6771 if (target.taskAffinity != null
6772 && target.taskAffinity.equals(p.task.affinity)) {
6773 // If the activity currently at the bottom has the
6774 // same task affinity as the one we are moving,
6775 // then merge it into the same task.
6776 target.task = p.task;
6777 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6778 + " out to bottom task " + p.task);
6779 } else {
6780 mCurTask++;
6781 if (mCurTask <= 0) {
6782 mCurTask = 1;
6783 }
6784 target.task = new TaskRecord(mCurTask, target.info, null,
6785 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6786 target.task.affinityIntent = target.intent;
6787 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6788 + " out to new task " + target.task);
6789 }
6790 mWindowManager.setAppGroupId(target, task.taskId);
6791 if (replyChainEnd < 0) {
6792 replyChainEnd = targetI;
6793 }
6794 int dstPos = 0;
6795 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6796 p = (HistoryRecord)mHistory.get(srcPos);
6797 if (p.finishing) {
6798 continue;
6799 }
6800 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6801 + " out to target's task " + target.task);
6802 task.numActivities--;
6803 p.task = target.task;
6804 target.task.numActivities++;
6805 mHistory.remove(srcPos);
6806 mHistory.add(dstPos, p);
6807 mWindowManager.moveAppToken(dstPos, p);
6808 mWindowManager.setAppGroupId(p, p.task.taskId);
6809 dstPos++;
6810 if (VALIDATE_TOKENS) {
6811 mWindowManager.validateAppTokens(mHistory);
6812 }
6813 i++;
6814 }
6815 if (taskTop == p) {
6816 taskTop = below;
6817 }
6818 if (taskTopI == replyChainEnd) {
6819 taskTopI = -1;
6820 }
6821 replyChainEnd = -1;
6822 addRecentTask(target.task);
6823 } else if (forceReset || finishOnTaskLaunch
6824 || clearWhenTaskReset) {
6825 // If the activity should just be removed -- either
6826 // because it asks for it, or the task should be
6827 // cleared -- then finish it and anything that is
6828 // part of its reply chain.
6829 if (clearWhenTaskReset) {
6830 // In this case, we want to finish this activity
6831 // and everything above it, so be sneaky and pretend
6832 // like these are all in the reply chain.
6833 replyChainEnd = targetI+1;
6834 while (replyChainEnd < mHistory.size() &&
6835 ((HistoryRecord)mHistory.get(
6836 replyChainEnd)).task == task) {
6837 replyChainEnd++;
6838 }
6839 replyChainEnd--;
6840 } else if (replyChainEnd < 0) {
6841 replyChainEnd = targetI;
6842 }
6843 HistoryRecord p = null;
6844 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6845 p = (HistoryRecord)mHistory.get(srcPos);
6846 if (p.finishing) {
6847 continue;
6848 }
6849 if (finishActivityLocked(p, srcPos,
6850 Activity.RESULT_CANCELED, null, "reset")) {
6851 replyChainEnd--;
6852 srcPos--;
6853 }
6854 }
6855 if (taskTop == p) {
6856 taskTop = below;
6857 }
6858 if (taskTopI == replyChainEnd) {
6859 taskTopI = -1;
6860 }
6861 replyChainEnd = -1;
6862 } else {
6863 // If we were in the middle of a chain, well the
6864 // activity that started it all doesn't want anything
6865 // special, so leave it all as-is.
6866 replyChainEnd = -1;
6867 }
6868 } else {
6869 // Reached the bottom of the task -- any reply chain
6870 // should be left as-is.
6871 replyChainEnd = -1;
6872 }
6873
6874 } else if (target.resultTo != null) {
6875 // If this activity is sending a reply to a previous
6876 // activity, we can't do anything with it now until
6877 // we reach the start of the reply chain.
6878 // XXX note that we are assuming the result is always
6879 // to the previous activity, which is almost always
6880 // the case but we really shouldn't count on.
6881 if (replyChainEnd < 0) {
6882 replyChainEnd = targetI;
6883 }
6884
6885 } else if (taskTopI >= 0 && allowTaskReparenting
6886 && task.affinity != null
6887 && task.affinity.equals(target.taskAffinity)) {
6888 // We are inside of another task... if this activity has
6889 // an affinity for our task, then either remove it if we are
6890 // clearing or move it over to our task. Note that
6891 // we currently punt on the case where we are resetting a
6892 // task that is not at the top but who has activities above
6893 // with an affinity to it... this is really not a normal
6894 // case, and we will need to later pull that task to the front
6895 // and usually at that point we will do the reset and pick
6896 // up those remaining activities. (This only happens if
6897 // someone starts an activity in a new task from an activity
6898 // in a task that is not currently on top.)
6899 if (forceReset || finishOnTaskLaunch) {
6900 if (replyChainEnd < 0) {
6901 replyChainEnd = targetI;
6902 }
6903 HistoryRecord p = null;
6904 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6905 p = (HistoryRecord)mHistory.get(srcPos);
6906 if (p.finishing) {
6907 continue;
6908 }
6909 if (finishActivityLocked(p, srcPos,
6910 Activity.RESULT_CANCELED, null, "reset")) {
6911 taskTopI--;
6912 lastReparentPos--;
6913 replyChainEnd--;
6914 srcPos--;
6915 }
6916 }
6917 replyChainEnd = -1;
6918 } else {
6919 if (replyChainEnd < 0) {
6920 replyChainEnd = targetI;
6921 }
6922 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6923 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6924 if (p.finishing) {
6925 continue;
6926 }
6927 if (lastReparentPos < 0) {
6928 lastReparentPos = taskTopI;
6929 taskTop = p;
6930 } else {
6931 lastReparentPos--;
6932 }
6933 mHistory.remove(srcPos);
6934 p.task.numActivities--;
6935 p.task = task;
6936 mHistory.add(lastReparentPos, p);
6937 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6938 + " in to resetting task " + task);
6939 task.numActivities++;
6940 mWindowManager.moveAppToken(lastReparentPos, p);
6941 mWindowManager.setAppGroupId(p, p.task.taskId);
6942 if (VALIDATE_TOKENS) {
6943 mWindowManager.validateAppTokens(mHistory);
6944 }
6945 }
6946 replyChainEnd = -1;
6947
6948 // Now we've moved it in to place... but what if this is
6949 // a singleTop activity and we have put it on top of another
6950 // instance of the same activity? Then we drop the instance
6951 // below so it remains singleTop.
6952 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6953 for (int j=lastReparentPos-1; j>=0; j--) {
6954 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6955 if (p.finishing) {
6956 continue;
6957 }
6958 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6959 if (finishActivityLocked(p, j,
6960 Activity.RESULT_CANCELED, null, "replace")) {
6961 taskTopI--;
6962 lastReparentPos--;
6963 }
6964 }
6965 }
6966 }
6967 }
6968 }
6969
6970 target = below;
6971 targetI = i;
6972 }
6973
6974 return taskTop;
6975 }
6976
6977 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006978 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006979 */
6980 public void moveTaskToFront(int task) {
6981 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6982 "moveTaskToFront()");
6983
6984 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006985 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6986 Binder.getCallingUid(), "Task to front")) {
6987 return;
6988 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006989 final long origId = Binder.clearCallingIdentity();
6990 try {
6991 int N = mRecentTasks.size();
6992 for (int i=0; i<N; i++) {
6993 TaskRecord tr = mRecentTasks.get(i);
6994 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07006995 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006996 return;
6997 }
6998 }
6999 for (int i=mHistory.size()-1; i>=0; i--) {
7000 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
7001 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007002 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007003 return;
7004 }
7005 }
7006 } finally {
7007 Binder.restoreCallingIdentity(origId);
7008 }
7009 }
7010 }
7011
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007012 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007013 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7014
7015 final int task = tr.taskId;
7016 int top = mHistory.size()-1;
7017
7018 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7019 // nothing to do!
7020 return;
7021 }
7022
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007023 ArrayList moved = new ArrayList();
7024
7025 // Applying the affinities may have removed entries from the history,
7026 // so get the size again.
7027 top = mHistory.size()-1;
7028 int pos = top;
7029
7030 // Shift all activities with this task up to the top
7031 // of the stack, keeping them in the same internal order.
7032 while (pos >= 0) {
7033 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7034 if (localLOGV) Log.v(
7035 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7036 boolean first = true;
7037 if (r.task.taskId == task) {
7038 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7039 mHistory.remove(pos);
7040 mHistory.add(top, r);
7041 moved.add(0, r);
7042 top--;
7043 if (first) {
7044 addRecentTask(r.task);
7045 first = false;
7046 }
7047 }
7048 pos--;
7049 }
7050
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007051 if (DEBUG_TRANSITION) Log.v(TAG,
7052 "Prepare to front transition: task=" + tr);
7053 if (reason != null &&
7054 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7055 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7056 HistoryRecord r = topRunningActivityLocked(null);
7057 if (r != null) {
7058 mNoAnimActivities.add(r);
7059 }
7060 } else {
7061 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7062 }
7063
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007064 mWindowManager.moveAppTokensToTop(moved);
7065 if (VALIDATE_TOKENS) {
7066 mWindowManager.validateAppTokens(mHistory);
7067 }
7068
7069 finishTaskMove(task);
7070 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
7071 }
7072
7073 private final void finishTaskMove(int task) {
7074 resumeTopActivityLocked(null);
7075 }
7076
7077 public void moveTaskToBack(int task) {
7078 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7079 "moveTaskToBack()");
7080
7081 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007082 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7083 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7084 Binder.getCallingUid(), "Task to back")) {
7085 return;
7086 }
7087 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007088 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007089 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007090 Binder.restoreCallingIdentity(origId);
7091 }
7092 }
7093
7094 /**
7095 * Moves an activity, and all of the other activities within the same task, to the bottom
7096 * of the history stack. The activity's order within the task is unchanged.
7097 *
7098 * @param token A reference to the activity we wish to move
7099 * @param nonRoot If false then this only works if the activity is the root
7100 * of a task; if true it will work for any activity in a task.
7101 * @return Returns true if the move completed, false if not.
7102 */
7103 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7104 synchronized(this) {
7105 final long origId = Binder.clearCallingIdentity();
7106 int taskId = getTaskForActivityLocked(token, !nonRoot);
7107 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007108 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007109 }
7110 Binder.restoreCallingIdentity(origId);
7111 }
7112 return false;
7113 }
7114
7115 /**
7116 * Worker method for rearranging history stack. Implements the function of moving all
7117 * activities for a specific task (gathering them if disjoint) into a single group at the
7118 * bottom of the stack.
7119 *
7120 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7121 * to premeptively cancel the move.
7122 *
7123 * @param task The taskId to collect and move to the bottom.
7124 * @return Returns true if the move completed, false if not.
7125 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007126 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007127 Log.i(TAG, "moveTaskToBack: " + task);
7128
7129 // If we have a watcher, preflight the move before committing to it. First check
7130 // for *other* available tasks, but if none are available, then try again allowing the
7131 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007132 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007133 HistoryRecord next = topRunningActivityLocked(null, task);
7134 if (next == null) {
7135 next = topRunningActivityLocked(null, 0);
7136 }
7137 if (next != null) {
7138 // ask watcher if this is allowed
7139 boolean moveOK = true;
7140 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007141 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007142 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007143 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007144 }
7145 if (!moveOK) {
7146 return false;
7147 }
7148 }
7149 }
7150
7151 ArrayList moved = new ArrayList();
7152
7153 if (DEBUG_TRANSITION) Log.v(TAG,
7154 "Prepare to back transition: task=" + task);
7155 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
7156
7157 final int N = mHistory.size();
7158 int bottom = 0;
7159 int pos = 0;
7160
7161 // Shift all activities with this task down to the bottom
7162 // of the stack, keeping them in the same internal order.
7163 while (pos < N) {
7164 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7165 if (localLOGV) Log.v(
7166 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7167 if (r.task.taskId == task) {
7168 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7169 mHistory.remove(pos);
7170 mHistory.add(bottom, r);
7171 moved.add(r);
7172 bottom++;
7173 }
7174 pos++;
7175 }
7176
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007177 if (reason != null &&
7178 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7179 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7180 HistoryRecord r = topRunningActivityLocked(null);
7181 if (r != null) {
7182 mNoAnimActivities.add(r);
7183 }
7184 } else {
7185 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7186 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007187 mWindowManager.moveAppTokensToBottom(moved);
7188 if (VALIDATE_TOKENS) {
7189 mWindowManager.validateAppTokens(mHistory);
7190 }
7191
7192 finishTaskMove(task);
7193 return true;
7194 }
7195
7196 public void moveTaskBackwards(int task) {
7197 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7198 "moveTaskBackwards()");
7199
7200 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007201 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7202 Binder.getCallingUid(), "Task backwards")) {
7203 return;
7204 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007205 final long origId = Binder.clearCallingIdentity();
7206 moveTaskBackwardsLocked(task);
7207 Binder.restoreCallingIdentity(origId);
7208 }
7209 }
7210
7211 private final void moveTaskBackwardsLocked(int task) {
7212 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7213 }
7214
7215 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7216 synchronized(this) {
7217 return getTaskForActivityLocked(token, onlyRoot);
7218 }
7219 }
7220
7221 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7222 final int N = mHistory.size();
7223 TaskRecord lastTask = null;
7224 for (int i=0; i<N; i++) {
7225 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7226 if (r == token) {
7227 if (!onlyRoot || lastTask != r.task) {
7228 return r.task.taskId;
7229 }
7230 return -1;
7231 }
7232 lastTask = r.task;
7233 }
7234
7235 return -1;
7236 }
7237
7238 /**
7239 * Returns the top activity in any existing task matching the given
7240 * Intent. Returns null if no such task is found.
7241 */
7242 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7243 ComponentName cls = intent.getComponent();
7244 if (info.targetActivity != null) {
7245 cls = new ComponentName(info.packageName, info.targetActivity);
7246 }
7247
7248 TaskRecord cp = null;
7249
7250 final int N = mHistory.size();
7251 for (int i=(N-1); i>=0; i--) {
7252 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7253 if (!r.finishing && r.task != cp
7254 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7255 cp = r.task;
7256 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7257 // + "/aff=" + r.task.affinity + " to new cls="
7258 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7259 if (r.task.affinity != null) {
7260 if (r.task.affinity.equals(info.taskAffinity)) {
7261 //Log.i(TAG, "Found matching affinity!");
7262 return r;
7263 }
7264 } else if (r.task.intent != null
7265 && r.task.intent.getComponent().equals(cls)) {
7266 //Log.i(TAG, "Found matching class!");
7267 //dump();
7268 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7269 return r;
7270 } else if (r.task.affinityIntent != null
7271 && r.task.affinityIntent.getComponent().equals(cls)) {
7272 //Log.i(TAG, "Found matching class!");
7273 //dump();
7274 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7275 return r;
7276 }
7277 }
7278 }
7279
7280 return null;
7281 }
7282
7283 /**
7284 * Returns the first activity (starting from the top of the stack) that
7285 * is the same as the given activity. Returns null if no such activity
7286 * is found.
7287 */
7288 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7289 ComponentName cls = intent.getComponent();
7290 if (info.targetActivity != null) {
7291 cls = new ComponentName(info.packageName, info.targetActivity);
7292 }
7293
7294 final int N = mHistory.size();
7295 for (int i=(N-1); i>=0; i--) {
7296 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7297 if (!r.finishing) {
7298 if (r.intent.getComponent().equals(cls)) {
7299 //Log.i(TAG, "Found matching class!");
7300 //dump();
7301 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7302 return r;
7303 }
7304 }
7305 }
7306
7307 return null;
7308 }
7309
7310 public void finishOtherInstances(IBinder token, ComponentName className) {
7311 synchronized(this) {
7312 final long origId = Binder.clearCallingIdentity();
7313
7314 int N = mHistory.size();
7315 TaskRecord lastTask = null;
7316 for (int i=0; i<N; i++) {
7317 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7318 if (r.realActivity.equals(className)
7319 && r != token && lastTask != r.task) {
7320 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7321 null, "others")) {
7322 i--;
7323 N--;
7324 }
7325 }
7326 lastTask = r.task;
7327 }
7328
7329 Binder.restoreCallingIdentity(origId);
7330 }
7331 }
7332
7333 // =========================================================
7334 // THUMBNAILS
7335 // =========================================================
7336
7337 public void reportThumbnail(IBinder token,
7338 Bitmap thumbnail, CharSequence description) {
7339 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7340 final long origId = Binder.clearCallingIdentity();
7341 sendPendingThumbnail(null, token, thumbnail, description, true);
7342 Binder.restoreCallingIdentity(origId);
7343 }
7344
7345 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7346 Bitmap thumbnail, CharSequence description, boolean always) {
7347 TaskRecord task = null;
7348 ArrayList receivers = null;
7349
7350 //System.out.println("Send pending thumbnail: " + r);
7351
7352 synchronized(this) {
7353 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007354 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007355 if (index < 0) {
7356 return;
7357 }
7358 r = (HistoryRecord)mHistory.get(index);
7359 }
7360 if (thumbnail == null) {
7361 thumbnail = r.thumbnail;
7362 description = r.description;
7363 }
7364 if (thumbnail == null && !always) {
7365 // If there is no thumbnail, and this entry is not actually
7366 // going away, then abort for now and pick up the next
7367 // thumbnail we get.
7368 return;
7369 }
7370 task = r.task;
7371
7372 int N = mPendingThumbnails.size();
7373 int i=0;
7374 while (i<N) {
7375 PendingThumbnailsRecord pr =
7376 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7377 //System.out.println("Looking in " + pr.pendingRecords);
7378 if (pr.pendingRecords.remove(r)) {
7379 if (receivers == null) {
7380 receivers = new ArrayList();
7381 }
7382 receivers.add(pr);
7383 if (pr.pendingRecords.size() == 0) {
7384 pr.finished = true;
7385 mPendingThumbnails.remove(i);
7386 N--;
7387 continue;
7388 }
7389 }
7390 i++;
7391 }
7392 }
7393
7394 if (receivers != null) {
7395 final int N = receivers.size();
7396 for (int i=0; i<N; i++) {
7397 try {
7398 PendingThumbnailsRecord pr =
7399 (PendingThumbnailsRecord)receivers.get(i);
7400 pr.receiver.newThumbnail(
7401 task != null ? task.taskId : -1, thumbnail, description);
7402 if (pr.finished) {
7403 pr.receiver.finished();
7404 }
7405 } catch (Exception e) {
7406 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7407 }
7408 }
7409 }
7410 }
7411
7412 // =========================================================
7413 // CONTENT PROVIDERS
7414 // =========================================================
7415
7416 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7417 List providers = null;
7418 try {
7419 providers = ActivityThread.getPackageManager().
7420 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007421 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007422 } catch (RemoteException ex) {
7423 }
7424 if (providers != null) {
7425 final int N = providers.size();
7426 for (int i=0; i<N; i++) {
7427 ProviderInfo cpi =
7428 (ProviderInfo)providers.get(i);
7429 ContentProviderRecord cpr =
7430 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7431 if (cpr == null) {
7432 cpr = new ContentProviderRecord(cpi, app.info);
7433 mProvidersByClass.put(cpi.name, cpr);
7434 }
7435 app.pubProviders.put(cpi.name, cpr);
7436 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007437 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007438 }
7439 }
7440 return providers;
7441 }
7442
7443 private final String checkContentProviderPermissionLocked(
7444 ProviderInfo cpi, ProcessRecord r, int mode) {
7445 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7446 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7447 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7448 cpi.exported ? -1 : cpi.applicationInfo.uid)
7449 == PackageManager.PERMISSION_GRANTED
7450 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7451 return null;
7452 }
7453 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7454 cpi.exported ? -1 : cpi.applicationInfo.uid)
7455 == PackageManager.PERMISSION_GRANTED) {
7456 return null;
7457 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007458
7459 PathPermission[] pps = cpi.pathPermissions;
7460 if (pps != null) {
7461 int i = pps.length;
7462 while (i > 0) {
7463 i--;
7464 PathPermission pp = pps[i];
7465 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7466 cpi.exported ? -1 : cpi.applicationInfo.uid)
7467 == PackageManager.PERMISSION_GRANTED
7468 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7469 return null;
7470 }
7471 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7472 cpi.exported ? -1 : cpi.applicationInfo.uid)
7473 == PackageManager.PERMISSION_GRANTED) {
7474 return null;
7475 }
7476 }
7477 }
7478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007479 String msg = "Permission Denial: opening provider " + cpi.name
7480 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7481 + ", uid=" + callingUid + ") requires "
7482 + cpi.readPermission + " or " + cpi.writePermission;
7483 Log.w(TAG, msg);
7484 return msg;
7485 }
7486
7487 private final ContentProviderHolder getContentProviderImpl(
7488 IApplicationThread caller, String name) {
7489 ContentProviderRecord cpr;
7490 ProviderInfo cpi = null;
7491
7492 synchronized(this) {
7493 ProcessRecord r = null;
7494 if (caller != null) {
7495 r = getRecordForAppLocked(caller);
7496 if (r == null) {
7497 throw new SecurityException(
7498 "Unable to find app for caller " + caller
7499 + " (pid=" + Binder.getCallingPid()
7500 + ") when getting content provider " + name);
7501 }
7502 }
7503
7504 // First check if this content provider has been published...
7505 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7506 if (cpr != null) {
7507 cpi = cpr.info;
7508 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7509 return new ContentProviderHolder(cpi,
7510 cpi.readPermission != null
7511 ? cpi.readPermission : cpi.writePermission);
7512 }
7513
7514 if (r != null && cpr.canRunHere(r)) {
7515 // This provider has been published or is in the process
7516 // of being published... but it is also allowed to run
7517 // in the caller's process, so don't make a connection
7518 // and just let the caller instantiate its own instance.
7519 if (cpr.provider != null) {
7520 // don't give caller the provider object, it needs
7521 // to make its own.
7522 cpr = new ContentProviderRecord(cpr);
7523 }
7524 return cpr;
7525 }
7526
7527 final long origId = Binder.clearCallingIdentity();
7528
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007529 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007530 // return it right away.
7531 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007532 if (DEBUG_PROVIDER) Log.v(TAG,
7533 "Adding provider requested by "
7534 + r.processName + " from process "
7535 + cpr.info.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007536 r.conProviders.add(cpr);
7537 cpr.clients.add(r);
7538 } else {
7539 cpr.externals++;
7540 }
7541
7542 if (cpr.app != null) {
7543 updateOomAdjLocked(cpr.app);
7544 }
7545
7546 Binder.restoreCallingIdentity(origId);
7547
7548 } else {
7549 try {
7550 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007551 resolveContentProvider(name,
7552 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007553 } catch (RemoteException ex) {
7554 }
7555 if (cpi == null) {
7556 return null;
7557 }
7558
7559 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7560 return new ContentProviderHolder(cpi,
7561 cpi.readPermission != null
7562 ? cpi.readPermission : cpi.writePermission);
7563 }
7564
7565 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7566 final boolean firstClass = cpr == null;
7567 if (firstClass) {
7568 try {
7569 ApplicationInfo ai =
7570 ActivityThread.getPackageManager().
7571 getApplicationInfo(
7572 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007573 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007574 if (ai == null) {
7575 Log.w(TAG, "No package info for content provider "
7576 + cpi.name);
7577 return null;
7578 }
7579 cpr = new ContentProviderRecord(cpi, ai);
7580 } catch (RemoteException ex) {
7581 // pm is in same process, this will never happen.
7582 }
7583 }
7584
7585 if (r != null && cpr.canRunHere(r)) {
7586 // If this is a multiprocess provider, then just return its
7587 // info and allow the caller to instantiate it. Only do
7588 // this if the provider is the same user as the caller's
7589 // process, or can run as root (so can be in any process).
7590 return cpr;
7591 }
7592
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007593 if (DEBUG_PROVIDER) {
7594 RuntimeException e = new RuntimeException("here");
7595 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7596 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007597 }
7598
7599 // This is single process, and our app is now connecting to it.
7600 // See if we are already in the process of launching this
7601 // provider.
7602 final int N = mLaunchingProviders.size();
7603 int i;
7604 for (i=0; i<N; i++) {
7605 if (mLaunchingProviders.get(i) == cpr) {
7606 break;
7607 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007608 }
7609
7610 // If the provider is not already being launched, then get it
7611 // started.
7612 if (i >= N) {
7613 final long origId = Binder.clearCallingIdentity();
7614 ProcessRecord proc = startProcessLocked(cpi.processName,
7615 cpr.appInfo, false, 0, "content provider",
7616 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007617 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007618 if (proc == null) {
7619 Log.w(TAG, "Unable to launch app "
7620 + cpi.applicationInfo.packageName + "/"
7621 + cpi.applicationInfo.uid + " for provider "
7622 + name + ": process is bad");
7623 return null;
7624 }
7625 cpr.launchingApp = proc;
7626 mLaunchingProviders.add(cpr);
7627 Binder.restoreCallingIdentity(origId);
7628 }
7629
7630 // Make sure the provider is published (the same provider class
7631 // may be published under multiple names).
7632 if (firstClass) {
7633 mProvidersByClass.put(cpi.name, cpr);
7634 }
7635 mProvidersByName.put(name, cpr);
7636
7637 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007638 if (DEBUG_PROVIDER) Log.v(TAG,
7639 "Adding provider requested by "
7640 + r.processName + " from process "
7641 + cpr.info.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007642 r.conProviders.add(cpr);
7643 cpr.clients.add(r);
7644 } else {
7645 cpr.externals++;
7646 }
7647 }
7648 }
7649
7650 // Wait for the provider to be published...
7651 synchronized (cpr) {
7652 while (cpr.provider == null) {
7653 if (cpr.launchingApp == null) {
7654 Log.w(TAG, "Unable to launch app "
7655 + cpi.applicationInfo.packageName + "/"
7656 + cpi.applicationInfo.uid + " for provider "
7657 + name + ": launching app became null");
7658 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7659 cpi.applicationInfo.packageName,
7660 cpi.applicationInfo.uid, name);
7661 return null;
7662 }
7663 try {
7664 cpr.wait();
7665 } catch (InterruptedException ex) {
7666 }
7667 }
7668 }
7669 return cpr;
7670 }
7671
7672 public final ContentProviderHolder getContentProvider(
7673 IApplicationThread caller, String name) {
7674 if (caller == null) {
7675 String msg = "null IApplicationThread when getting content provider "
7676 + name;
7677 Log.w(TAG, msg);
7678 throw new SecurityException(msg);
7679 }
7680
7681 return getContentProviderImpl(caller, name);
7682 }
7683
7684 private ContentProviderHolder getContentProviderExternal(String name) {
7685 return getContentProviderImpl(null, name);
7686 }
7687
7688 /**
7689 * Drop a content provider from a ProcessRecord's bookkeeping
7690 * @param cpr
7691 */
7692 public void removeContentProvider(IApplicationThread caller, String name) {
7693 synchronized (this) {
7694 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7695 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007696 // remove from mProvidersByClass
7697 if (DEBUG_PROVIDER) Log.v(TAG, name +
7698 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007699 return;
7700 }
7701 final ProcessRecord r = getRecordForAppLocked(caller);
7702 if (r == null) {
7703 throw new SecurityException(
7704 "Unable to find app for caller " + caller +
7705 " when removing content provider " + name);
7706 }
7707 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007708 ContentProviderRecord localCpr = (ContentProviderRecord)
7709 mProvidersByClass.get(cpr.info.name);
7710 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7711 + r.info.processName + " from process "
7712 + localCpr.appInfo.processName);
7713 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007714 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007715 Log.w(TAG, "removeContentProvider called on local provider: "
7716 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007717 return;
7718 } else {
7719 localCpr.clients.remove(r);
7720 r.conProviders.remove(localCpr);
7721 }
7722 updateOomAdjLocked();
7723 }
7724 }
7725
7726 private void removeContentProviderExternal(String name) {
7727 synchronized (this) {
7728 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7729 if(cpr == null) {
7730 //remove from mProvidersByClass
7731 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7732 return;
7733 }
7734
7735 //update content provider record entry info
7736 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7737 localCpr.externals--;
7738 if (localCpr.externals < 0) {
7739 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7740 }
7741 updateOomAdjLocked();
7742 }
7743 }
7744
7745 public final void publishContentProviders(IApplicationThread caller,
7746 List<ContentProviderHolder> providers) {
7747 if (providers == null) {
7748 return;
7749 }
7750
7751 synchronized(this) {
7752 final ProcessRecord r = getRecordForAppLocked(caller);
7753 if (r == null) {
7754 throw new SecurityException(
7755 "Unable to find app for caller " + caller
7756 + " (pid=" + Binder.getCallingPid()
7757 + ") when publishing content providers");
7758 }
7759
7760 final long origId = Binder.clearCallingIdentity();
7761
7762 final int N = providers.size();
7763 for (int i=0; i<N; i++) {
7764 ContentProviderHolder src = providers.get(i);
7765 if (src == null || src.info == null || src.provider == null) {
7766 continue;
7767 }
7768 ContentProviderRecord dst =
7769 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7770 if (dst != null) {
7771 mProvidersByClass.put(dst.info.name, dst);
7772 String names[] = dst.info.authority.split(";");
7773 for (int j = 0; j < names.length; j++) {
7774 mProvidersByName.put(names[j], dst);
7775 }
7776
7777 int NL = mLaunchingProviders.size();
7778 int j;
7779 for (j=0; j<NL; j++) {
7780 if (mLaunchingProviders.get(j) == dst) {
7781 mLaunchingProviders.remove(j);
7782 j--;
7783 NL--;
7784 }
7785 }
7786 synchronized (dst) {
7787 dst.provider = src.provider;
7788 dst.app = r;
7789 dst.notifyAll();
7790 }
7791 updateOomAdjLocked(r);
7792 }
7793 }
7794
7795 Binder.restoreCallingIdentity(origId);
7796 }
7797 }
7798
7799 public static final void installSystemProviders() {
7800 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7801 List providers = mSelf.generateApplicationProvidersLocked(app);
7802 mSystemThread.installSystemProviders(providers);
7803 }
7804
7805 // =========================================================
7806 // GLOBAL MANAGEMENT
7807 // =========================================================
7808
7809 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7810 ApplicationInfo info, String customProcess) {
7811 String proc = customProcess != null ? customProcess : info.processName;
7812 BatteryStatsImpl.Uid.Proc ps = null;
7813 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7814 synchronized (stats) {
7815 ps = stats.getProcessStatsLocked(info.uid, proc);
7816 }
7817 return new ProcessRecord(ps, thread, info, proc);
7818 }
7819
7820 final ProcessRecord addAppLocked(ApplicationInfo info) {
7821 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7822
7823 if (app == null) {
7824 app = newProcessRecordLocked(null, info, null);
7825 mProcessNames.put(info.processName, info.uid, app);
7826 updateLRUListLocked(app, true);
7827 }
7828
7829 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7830 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7831 app.persistent = true;
7832 app.maxAdj = CORE_SERVER_ADJ;
7833 }
7834 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7835 mPersistentStartingProcesses.add(app);
7836 startProcessLocked(app, "added application", app.processName);
7837 }
7838
7839 return app;
7840 }
7841
7842 public void unhandledBack() {
7843 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7844 "unhandledBack()");
7845
7846 synchronized(this) {
7847 int count = mHistory.size();
7848 if (Config.LOGD) Log.d(
7849 TAG, "Performing unhandledBack(): stack size = " + count);
7850 if (count > 1) {
7851 final long origId = Binder.clearCallingIdentity();
7852 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7853 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7854 Binder.restoreCallingIdentity(origId);
7855 }
7856 }
7857 }
7858
7859 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7860 String name = uri.getAuthority();
7861 ContentProviderHolder cph = getContentProviderExternal(name);
7862 ParcelFileDescriptor pfd = null;
7863 if (cph != null) {
7864 // We record the binder invoker's uid in thread-local storage before
7865 // going to the content provider to open the file. Later, in the code
7866 // that handles all permissions checks, we look for this uid and use
7867 // that rather than the Activity Manager's own uid. The effect is that
7868 // we do the check against the caller's permissions even though it looks
7869 // to the content provider like the Activity Manager itself is making
7870 // the request.
7871 sCallerIdentity.set(new Identity(
7872 Binder.getCallingPid(), Binder.getCallingUid()));
7873 try {
7874 pfd = cph.provider.openFile(uri, "r");
7875 } catch (FileNotFoundException e) {
7876 // do nothing; pfd will be returned null
7877 } finally {
7878 // Ensure that whatever happens, we clean up the identity state
7879 sCallerIdentity.remove();
7880 }
7881
7882 // We've got the fd now, so we're done with the provider.
7883 removeContentProviderExternal(name);
7884 } else {
7885 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7886 }
7887 return pfd;
7888 }
7889
7890 public void goingToSleep() {
7891 synchronized(this) {
7892 mSleeping = true;
7893 mWindowManager.setEventDispatching(false);
7894
7895 if (mResumedActivity != null) {
7896 pauseIfSleepingLocked();
7897 } else {
7898 Log.w(TAG, "goingToSleep with no resumed activity!");
7899 }
7900 }
7901 }
7902
Dianne Hackborn55280a92009-05-07 15:53:46 -07007903 public boolean shutdown(int timeout) {
7904 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7905 != PackageManager.PERMISSION_GRANTED) {
7906 throw new SecurityException("Requires permission "
7907 + android.Manifest.permission.SHUTDOWN);
7908 }
7909
7910 boolean timedout = false;
7911
7912 synchronized(this) {
7913 mShuttingDown = true;
7914 mWindowManager.setEventDispatching(false);
7915
7916 if (mResumedActivity != null) {
7917 pauseIfSleepingLocked();
7918 final long endTime = System.currentTimeMillis() + timeout;
7919 while (mResumedActivity != null || mPausingActivity != null) {
7920 long delay = endTime - System.currentTimeMillis();
7921 if (delay <= 0) {
7922 Log.w(TAG, "Activity manager shutdown timed out");
7923 timedout = true;
7924 break;
7925 }
7926 try {
7927 this.wait();
7928 } catch (InterruptedException e) {
7929 }
7930 }
7931 }
7932 }
7933
7934 mUsageStatsService.shutdown();
7935 mBatteryStatsService.shutdown();
7936
7937 return timedout;
7938 }
7939
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007940 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007941 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007942 if (!mGoingToSleep.isHeld()) {
7943 mGoingToSleep.acquire();
7944 if (mLaunchingActivity.isHeld()) {
7945 mLaunchingActivity.release();
7946 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7947 }
7948 }
7949
7950 // If we are not currently pausing an activity, get the current
7951 // one to pause. If we are pausing one, we will just let that stuff
7952 // run and release the wake lock when all done.
7953 if (mPausingActivity == null) {
7954 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7955 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7956 startPausingLocked(false, true);
7957 }
7958 }
7959 }
7960
7961 public void wakingUp() {
7962 synchronized(this) {
7963 if (mGoingToSleep.isHeld()) {
7964 mGoingToSleep.release();
7965 }
7966 mWindowManager.setEventDispatching(true);
7967 mSleeping = false;
7968 resumeTopActivityLocked(null);
7969 }
7970 }
7971
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007972 public void stopAppSwitches() {
7973 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7974 != PackageManager.PERMISSION_GRANTED) {
7975 throw new SecurityException("Requires permission "
7976 + android.Manifest.permission.STOP_APP_SWITCHES);
7977 }
7978
7979 synchronized(this) {
7980 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7981 + APP_SWITCH_DELAY_TIME;
7982 mDidAppSwitch = false;
7983 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7984 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7985 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7986 }
7987 }
7988
7989 public void resumeAppSwitches() {
7990 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7991 != PackageManager.PERMISSION_GRANTED) {
7992 throw new SecurityException("Requires permission "
7993 + android.Manifest.permission.STOP_APP_SWITCHES);
7994 }
7995
7996 synchronized(this) {
7997 // Note that we don't execute any pending app switches... we will
7998 // let those wait until either the timeout, or the next start
7999 // activity request.
8000 mAppSwitchesAllowedTime = 0;
8001 }
8002 }
8003
8004 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8005 String name) {
8006 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8007 return true;
8008 }
8009
8010 final int perm = checkComponentPermission(
8011 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8012 callingUid, -1);
8013 if (perm == PackageManager.PERMISSION_GRANTED) {
8014 return true;
8015 }
8016
8017 Log.w(TAG, name + " request from " + callingUid + " stopped");
8018 return false;
8019 }
8020
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008021 public void setDebugApp(String packageName, boolean waitForDebugger,
8022 boolean persistent) {
8023 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8024 "setDebugApp()");
8025
8026 // Note that this is not really thread safe if there are multiple
8027 // callers into it at the same time, but that's not a situation we
8028 // care about.
8029 if (persistent) {
8030 final ContentResolver resolver = mContext.getContentResolver();
8031 Settings.System.putString(
8032 resolver, Settings.System.DEBUG_APP,
8033 packageName);
8034 Settings.System.putInt(
8035 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8036 waitForDebugger ? 1 : 0);
8037 }
8038
8039 synchronized (this) {
8040 if (!persistent) {
8041 mOrigDebugApp = mDebugApp;
8042 mOrigWaitForDebugger = mWaitForDebugger;
8043 }
8044 mDebugApp = packageName;
8045 mWaitForDebugger = waitForDebugger;
8046 mDebugTransient = !persistent;
8047 if (packageName != null) {
8048 final long origId = Binder.clearCallingIdentity();
8049 uninstallPackageLocked(packageName, -1, false);
8050 Binder.restoreCallingIdentity(origId);
8051 }
8052 }
8053 }
8054
8055 public void setAlwaysFinish(boolean enabled) {
8056 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8057 "setAlwaysFinish()");
8058
8059 Settings.System.putInt(
8060 mContext.getContentResolver(),
8061 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8062
8063 synchronized (this) {
8064 mAlwaysFinishActivities = enabled;
8065 }
8066 }
8067
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008068 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008069 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008070 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008071 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008072 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008073 }
8074 }
8075
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008076 public void registerActivityWatcher(IActivityWatcher watcher) {
8077 mWatchers.register(watcher);
8078 }
8079
8080 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8081 mWatchers.unregister(watcher);
8082 }
8083
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008084 public final void enterSafeMode() {
8085 synchronized(this) {
8086 // It only makes sense to do this before the system is ready
8087 // and started launching other packages.
8088 if (!mSystemReady) {
8089 try {
8090 ActivityThread.getPackageManager().enterSafeMode();
8091 } catch (RemoteException e) {
8092 }
8093
8094 View v = LayoutInflater.from(mContext).inflate(
8095 com.android.internal.R.layout.safe_mode, null);
8096 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8097 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8098 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8099 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8100 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8101 lp.format = v.getBackground().getOpacity();
8102 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8103 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8104 ((WindowManager)mContext.getSystemService(
8105 Context.WINDOW_SERVICE)).addView(v, lp);
8106 }
8107 }
8108 }
8109
8110 public void noteWakeupAlarm(IIntentSender sender) {
8111 if (!(sender instanceof PendingIntentRecord)) {
8112 return;
8113 }
8114 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8115 synchronized (stats) {
8116 if (mBatteryStatsService.isOnBattery()) {
8117 mBatteryStatsService.enforceCallingPermission();
8118 PendingIntentRecord rec = (PendingIntentRecord)sender;
8119 int MY_UID = Binder.getCallingUid();
8120 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8121 BatteryStatsImpl.Uid.Pkg pkg =
8122 stats.getPackageStatsLocked(uid, rec.key.packageName);
8123 pkg.incWakeupsLocked();
8124 }
8125 }
8126 }
8127
8128 public boolean killPidsForMemory(int[] pids) {
8129 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8130 throw new SecurityException("killPidsForMemory only available to the system");
8131 }
8132
8133 // XXX Note: don't acquire main activity lock here, because the window
8134 // manager calls in with its locks held.
8135
8136 boolean killed = false;
8137 synchronized (mPidsSelfLocked) {
8138 int[] types = new int[pids.length];
8139 int worstType = 0;
8140 for (int i=0; i<pids.length; i++) {
8141 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8142 if (proc != null) {
8143 int type = proc.setAdj;
8144 types[i] = type;
8145 if (type > worstType) {
8146 worstType = type;
8147 }
8148 }
8149 }
8150
8151 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8152 // then constrain it so we will kill all hidden procs.
8153 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8154 worstType = HIDDEN_APP_MIN_ADJ;
8155 }
8156 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8157 for (int i=0; i<pids.length; i++) {
8158 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8159 if (proc == null) {
8160 continue;
8161 }
8162 int adj = proc.setAdj;
8163 if (adj >= worstType) {
8164 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8165 + adj + ")");
8166 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
8167 proc.processName, adj);
8168 killed = true;
8169 Process.killProcess(pids[i]);
8170 }
8171 }
8172 }
8173 return killed;
8174 }
8175
8176 public void reportPss(IApplicationThread caller, int pss) {
8177 Watchdog.PssRequestor req;
8178 String name;
8179 ProcessRecord callerApp;
8180 synchronized (this) {
8181 if (caller == null) {
8182 return;
8183 }
8184 callerApp = getRecordForAppLocked(caller);
8185 if (callerApp == null) {
8186 return;
8187 }
8188 callerApp.lastPss = pss;
8189 req = callerApp;
8190 name = callerApp.processName;
8191 }
8192 Watchdog.getInstance().reportPss(req, name, pss);
8193 if (!callerApp.persistent) {
8194 removeRequestedPss(callerApp);
8195 }
8196 }
8197
8198 public void requestPss(Runnable completeCallback) {
8199 ArrayList<ProcessRecord> procs;
8200 synchronized (this) {
8201 mRequestPssCallback = completeCallback;
8202 mRequestPssList.clear();
8203 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8204 ProcessRecord proc = mLRUProcesses.get(i);
8205 if (!proc.persistent) {
8206 mRequestPssList.add(proc);
8207 }
8208 }
8209 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8210 }
8211
8212 int oldPri = Process.getThreadPriority(Process.myTid());
8213 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8214 for (int i=procs.size()-1; i>=0; i--) {
8215 ProcessRecord proc = procs.get(i);
8216 proc.lastPss = 0;
8217 proc.requestPss();
8218 }
8219 Process.setThreadPriority(oldPri);
8220 }
8221
8222 void removeRequestedPss(ProcessRecord proc) {
8223 Runnable callback = null;
8224 synchronized (this) {
8225 if (mRequestPssList.remove(proc)) {
8226 if (mRequestPssList.size() == 0) {
8227 callback = mRequestPssCallback;
8228 mRequestPssCallback = null;
8229 }
8230 }
8231 }
8232
8233 if (callback != null) {
8234 callback.run();
8235 }
8236 }
8237
8238 public void collectPss(Watchdog.PssStats stats) {
8239 stats.mEmptyPss = 0;
8240 stats.mEmptyCount = 0;
8241 stats.mBackgroundPss = 0;
8242 stats.mBackgroundCount = 0;
8243 stats.mServicePss = 0;
8244 stats.mServiceCount = 0;
8245 stats.mVisiblePss = 0;
8246 stats.mVisibleCount = 0;
8247 stats.mForegroundPss = 0;
8248 stats.mForegroundCount = 0;
8249 stats.mNoPssCount = 0;
8250 synchronized (this) {
8251 int i;
8252 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8253 ? mProcDeaths.length : stats.mProcDeaths.length;
8254 int aggr = 0;
8255 for (i=0; i<NPD; i++) {
8256 aggr += mProcDeaths[i];
8257 stats.mProcDeaths[i] = aggr;
8258 }
8259 while (i<stats.mProcDeaths.length) {
8260 stats.mProcDeaths[i] = 0;
8261 i++;
8262 }
8263
8264 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8265 ProcessRecord proc = mLRUProcesses.get(i);
8266 if (proc.persistent) {
8267 continue;
8268 }
8269 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8270 if (proc.lastPss == 0) {
8271 stats.mNoPssCount++;
8272 continue;
8273 }
8274 if (proc.setAdj == EMPTY_APP_ADJ) {
8275 stats.mEmptyPss += proc.lastPss;
8276 stats.mEmptyCount++;
8277 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8278 stats.mEmptyPss += proc.lastPss;
8279 stats.mEmptyCount++;
8280 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8281 stats.mBackgroundPss += proc.lastPss;
8282 stats.mBackgroundCount++;
8283 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8284 stats.mVisiblePss += proc.lastPss;
8285 stats.mVisibleCount++;
8286 } else {
8287 stats.mForegroundPss += proc.lastPss;
8288 stats.mForegroundCount++;
8289 }
8290 }
8291 }
8292 }
8293
8294 public final void startRunning(String pkg, String cls, String action,
8295 String data) {
8296 synchronized(this) {
8297 if (mStartRunning) {
8298 return;
8299 }
8300 mStartRunning = true;
8301 mTopComponent = pkg != null && cls != null
8302 ? new ComponentName(pkg, cls) : null;
8303 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8304 mTopData = data;
8305 if (!mSystemReady) {
8306 return;
8307 }
8308 }
8309
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008310 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008311 }
8312
8313 private void retrieveSettings() {
8314 final ContentResolver resolver = mContext.getContentResolver();
8315 String debugApp = Settings.System.getString(
8316 resolver, Settings.System.DEBUG_APP);
8317 boolean waitForDebugger = Settings.System.getInt(
8318 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8319 boolean alwaysFinishActivities = Settings.System.getInt(
8320 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8321
8322 Configuration configuration = new Configuration();
8323 Settings.System.getConfiguration(resolver, configuration);
8324
8325 synchronized (this) {
8326 mDebugApp = mOrigDebugApp = debugApp;
8327 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8328 mAlwaysFinishActivities = alwaysFinishActivities;
8329 // This happens before any activities are started, so we can
8330 // change mConfiguration in-place.
8331 mConfiguration.updateFrom(configuration);
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008332 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008333 }
8334 }
8335
8336 public boolean testIsSystemReady() {
8337 // no need to synchronize(this) just to read & return the value
8338 return mSystemReady;
8339 }
8340
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008341 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008342 // In the simulator, startRunning will never have been called, which
8343 // normally sets a few crucial variables. Do it here instead.
8344 if (!Process.supportsProcesses()) {
8345 mStartRunning = true;
8346 mTopAction = Intent.ACTION_MAIN;
8347 }
8348
8349 synchronized(this) {
8350 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008351 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008352 return;
8353 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008354
8355 // Check to see if there are any update receivers to run.
8356 if (!mDidUpdate) {
8357 if (mWaitingUpdate) {
8358 return;
8359 }
8360 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8361 List<ResolveInfo> ris = null;
8362 try {
8363 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8364 intent, null, 0);
8365 } catch (RemoteException e) {
8366 }
8367 if (ris != null) {
8368 for (int i=ris.size()-1; i>=0; i--) {
8369 if ((ris.get(i).activityInfo.applicationInfo.flags
8370 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8371 ris.remove(i);
8372 }
8373 }
8374 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8375 for (int i=0; i<ris.size(); i++) {
8376 ActivityInfo ai = ris.get(i).activityInfo;
8377 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8378 IIntentReceiver finisher = null;
8379 if (i == 0) {
8380 finisher = new IIntentReceiver.Stub() {
8381 public void performReceive(Intent intent, int resultCode,
8382 String data, Bundle extras, boolean ordered)
8383 throws RemoteException {
8384 synchronized (ActivityManagerService.this) {
8385 mDidUpdate = true;
8386 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008387 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008388 }
8389 };
8390 }
8391 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8392 broadcastIntentLocked(null, null, intent, null, finisher,
8393 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8394 if (i == 0) {
8395 mWaitingUpdate = true;
8396 }
8397 }
8398 }
8399 if (mWaitingUpdate) {
8400 return;
8401 }
8402 mDidUpdate = true;
8403 }
8404
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008405 mSystemReady = true;
8406 if (!mStartRunning) {
8407 return;
8408 }
8409 }
8410
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008411 ArrayList<ProcessRecord> procsToKill = null;
8412 synchronized(mPidsSelfLocked) {
8413 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8414 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8415 if (!isAllowedWhileBooting(proc.info)){
8416 if (procsToKill == null) {
8417 procsToKill = new ArrayList<ProcessRecord>();
8418 }
8419 procsToKill.add(proc);
8420 }
8421 }
8422 }
8423
8424 if (procsToKill != null) {
8425 synchronized(this) {
8426 for (int i=procsToKill.size()-1; i>=0; i--) {
8427 ProcessRecord proc = procsToKill.get(i);
8428 Log.i(TAG, "Removing system update proc: " + proc);
8429 removeProcessLocked(proc, true);
8430 }
8431 }
8432 }
8433
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008434 Log.i(TAG, "System now ready");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008435 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8436 SystemClock.uptimeMillis());
8437
8438 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008439 // Make sure we have no pre-ready processes sitting around.
8440
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008441 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8442 ResolveInfo ri = mContext.getPackageManager()
8443 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008444 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008445 CharSequence errorMsg = null;
8446 if (ri != null) {
8447 ActivityInfo ai = ri.activityInfo;
8448 ApplicationInfo app = ai.applicationInfo;
8449 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8450 mTopAction = Intent.ACTION_FACTORY_TEST;
8451 mTopData = null;
8452 mTopComponent = new ComponentName(app.packageName,
8453 ai.name);
8454 } else {
8455 errorMsg = mContext.getResources().getText(
8456 com.android.internal.R.string.factorytest_not_system);
8457 }
8458 } else {
8459 errorMsg = mContext.getResources().getText(
8460 com.android.internal.R.string.factorytest_no_action);
8461 }
8462 if (errorMsg != null) {
8463 mTopAction = null;
8464 mTopData = null;
8465 mTopComponent = null;
8466 Message msg = Message.obtain();
8467 msg.what = SHOW_FACTORY_ERROR_MSG;
8468 msg.getData().putCharSequence("msg", errorMsg);
8469 mHandler.sendMessage(msg);
8470 }
8471 }
8472 }
8473
8474 retrieveSettings();
8475
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008476 if (goingCallback != null) goingCallback.run();
8477
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008478 synchronized (this) {
8479 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8480 try {
8481 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008482 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008483 if (apps != null) {
8484 int N = apps.size();
8485 int i;
8486 for (i=0; i<N; i++) {
8487 ApplicationInfo info
8488 = (ApplicationInfo)apps.get(i);
8489 if (info != null &&
8490 !info.packageName.equals("android")) {
8491 addAppLocked(info);
8492 }
8493 }
8494 }
8495 } catch (RemoteException ex) {
8496 // pm is in same process, this will never happen.
8497 }
8498 }
8499
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008500 // Start up initial activity.
8501 mBooting = true;
8502
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008503 try {
8504 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8505 Message msg = Message.obtain();
8506 msg.what = SHOW_UID_ERROR_MSG;
8507 mHandler.sendMessage(msg);
8508 }
8509 } catch (RemoteException e) {
8510 }
8511
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008512 resumeTopActivityLocked(null);
8513 }
8514 }
8515
8516 boolean makeAppCrashingLocked(ProcessRecord app,
8517 String tag, String shortMsg, String longMsg, byte[] crashData) {
8518 app.crashing = true;
8519 app.crashingReport = generateProcessError(app,
8520 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8521 startAppProblemLocked(app);
8522 app.stopFreezingAllLocked();
8523 return handleAppCrashLocked(app);
8524 }
8525
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008526 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Jacek Surazskia2339432009-09-18 15:01:26 +02008527 // check if error reporting is enabled in Gservices
8528 int enabled = Settings.Gservices.getInt(mContext.getContentResolver(),
8529 Settings.Gservices.SEND_ACTION_APP_ERROR, 0);
8530 if (enabled == 0) {
8531 return null;
8532 }
8533
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008534 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008535
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008536 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008537 // look for receiver in the installer package
8538 String candidate = pm.getInstallerPackageName(app.info.packageName);
8539 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8540 if (result != null) {
8541 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008542 }
8543
Jacek Surazski82a73df2009-06-17 14:33:18 +02008544 // if the error app is on the system image, look for system apps
8545 // error receiver
8546 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8547 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8548 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8549 if (result != null) {
8550 return result;
8551 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008552 }
8553
Jacek Surazski82a73df2009-06-17 14:33:18 +02008554 // if there is a default receiver, try that
8555 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8556 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008557 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008558 // should not happen
8559 Log.e(TAG, "error talking to PackageManager", e);
8560 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008561 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008562 }
8563
8564 /**
8565 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8566 *
8567 * @param pm PackageManager isntance
8568 * @param errorPackage package which caused the error
8569 * @param receiverPackage candidate package to receive the error
8570 * @return activity component within receiverPackage which handles
8571 * ACTION_APP_ERROR, or null if not found
8572 */
8573 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8574 String receiverPackage) throws RemoteException {
8575 if (receiverPackage == null || receiverPackage.length() == 0) {
8576 return null;
8577 }
8578
8579 // break the loop if it's the error report receiver package that crashed
8580 if (receiverPackage.equals(errorPackage)) {
8581 return null;
8582 }
8583
8584 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8585 intent.setPackage(receiverPackage);
8586 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8587 if (info == null || info.activityInfo == null) {
8588 return null;
8589 }
8590 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008591 }
8592
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008593 void makeAppNotRespondingLocked(ProcessRecord app,
8594 String tag, String shortMsg, String longMsg, byte[] crashData) {
8595 app.notResponding = true;
8596 app.notRespondingReport = generateProcessError(app,
8597 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8598 crashData);
8599 startAppProblemLocked(app);
8600 app.stopFreezingAllLocked();
8601 }
8602
8603 /**
8604 * Generate a process error record, suitable for attachment to a ProcessRecord.
8605 *
8606 * @param app The ProcessRecord in which the error occurred.
8607 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8608 * ActivityManager.AppErrorStateInfo
8609 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8610 * @param shortMsg Short message describing the crash.
8611 * @param longMsg Long message describing the crash.
8612 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8613 *
8614 * @return Returns a fully-formed AppErrorStateInfo record.
8615 */
8616 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8617 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8618 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8619
8620 report.condition = condition;
8621 report.processName = app.processName;
8622 report.pid = app.pid;
8623 report.uid = app.info.uid;
8624 report.tag = tag;
8625 report.shortMsg = shortMsg;
8626 report.longMsg = longMsg;
8627 report.crashData = crashData;
8628
8629 return report;
8630 }
8631
8632 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8633 boolean crashed) {
8634 synchronized (this) {
8635 app.crashing = false;
8636 app.crashingReport = null;
8637 app.notResponding = false;
8638 app.notRespondingReport = null;
8639 if (app.anrDialog == fromDialog) {
8640 app.anrDialog = null;
8641 }
8642 if (app.waitDialog == fromDialog) {
8643 app.waitDialog = null;
8644 }
8645 if (app.pid > 0 && app.pid != MY_PID) {
8646 if (crashed) {
8647 handleAppCrashLocked(app);
8648 }
8649 Log.i(ActivityManagerService.TAG, "Killing process "
8650 + app.processName
8651 + " (pid=" + app.pid + ") at user's request");
8652 Process.killProcess(app.pid);
8653 }
8654
8655 }
8656 }
8657
8658 boolean handleAppCrashLocked(ProcessRecord app) {
8659 long now = SystemClock.uptimeMillis();
8660
8661 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8662 app.info.uid);
8663 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8664 // This process loses!
8665 Log.w(TAG, "Process " + app.info.processName
8666 + " has crashed too many times: killing!");
8667 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8668 app.info.processName, app.info.uid);
8669 killServicesLocked(app, false);
8670 for (int i=mHistory.size()-1; i>=0; i--) {
8671 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8672 if (r.app == app) {
8673 if (Config.LOGD) Log.d(
8674 TAG, " Force finishing activity "
8675 + r.intent.getComponent().flattenToShortString());
8676 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8677 }
8678 }
8679 if (!app.persistent) {
8680 // We don't want to start this process again until the user
8681 // explicitly does so... but for persistent process, we really
8682 // need to keep it running. If a persistent process is actually
8683 // repeatedly crashing, then badness for everyone.
8684 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8685 app.info.processName);
8686 mBadProcesses.put(app.info.processName, app.info.uid, now);
8687 app.bad = true;
8688 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8689 app.removed = true;
8690 removeProcessLocked(app, false);
8691 return false;
8692 }
8693 }
8694
8695 // Bump up the crash count of any services currently running in the proc.
8696 if (app.services.size() != 0) {
8697 // Any services running in the application need to be placed
8698 // back in the pending list.
8699 Iterator it = app.services.iterator();
8700 while (it.hasNext()) {
8701 ServiceRecord sr = (ServiceRecord)it.next();
8702 sr.crashCount++;
8703 }
8704 }
8705
8706 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8707 return true;
8708 }
8709
8710 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008711 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008712 skipCurrentReceiverLocked(app);
8713 }
8714
8715 void skipCurrentReceiverLocked(ProcessRecord app) {
8716 boolean reschedule = false;
8717 BroadcastRecord r = app.curReceiver;
8718 if (r != null) {
8719 // The current broadcast is waiting for this app's receiver
8720 // to be finished. Looks like that's not going to happen, so
8721 // let the broadcast continue.
8722 logBroadcastReceiverDiscard(r);
8723 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8724 r.resultExtras, r.resultAbort, true);
8725 reschedule = true;
8726 }
8727 r = mPendingBroadcast;
8728 if (r != null && r.curApp == app) {
8729 if (DEBUG_BROADCAST) Log.v(TAG,
8730 "skip & discard pending app " + r);
8731 logBroadcastReceiverDiscard(r);
8732 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8733 r.resultExtras, r.resultAbort, true);
8734 reschedule = true;
8735 }
8736 if (reschedule) {
8737 scheduleBroadcastsLocked();
8738 }
8739 }
8740
8741 public int handleApplicationError(IBinder app, int flags,
8742 String tag, String shortMsg, String longMsg, byte[] crashData) {
8743 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008744 ProcessRecord r = null;
8745 synchronized (this) {
8746 if (app != null) {
8747 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8748 final int NA = apps.size();
8749 for (int ia=0; ia<NA; ia++) {
8750 ProcessRecord p = apps.valueAt(ia);
8751 if (p.thread != null && p.thread.asBinder() == app) {
8752 r = p;
8753 break;
8754 }
8755 }
8756 }
8757 }
8758
8759 if (r != null) {
8760 // The application has crashed. Send the SIGQUIT to the process so
8761 // that it can dump its state.
8762 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8763 //Log.i(TAG, "Current system threads:");
8764 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8765 }
8766
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008767 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008768 try {
8769 String name = r != null ? r.processName : null;
8770 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008771 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008772 shortMsg, longMsg, crashData)) {
8773 Log.w(TAG, "Force-killing crashed app " + name
8774 + " at watcher's request");
8775 Process.killProcess(pid);
8776 return 0;
8777 }
8778 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008779 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008780 }
8781 }
8782
8783 final long origId = Binder.clearCallingIdentity();
8784
8785 // If this process is running instrumentation, finish it.
8786 if (r != null && r.instrumentationClass != null) {
8787 Log.w(TAG, "Error in app " + r.processName
8788 + " running instrumentation " + r.instrumentationClass + ":");
8789 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8790 if (longMsg != null) Log.w(TAG, " " + longMsg);
8791 Bundle info = new Bundle();
8792 info.putString("shortMsg", shortMsg);
8793 info.putString("longMsg", longMsg);
8794 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8795 Binder.restoreCallingIdentity(origId);
8796 return 0;
8797 }
8798
8799 if (r != null) {
8800 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8801 return 0;
8802 }
8803 } else {
8804 Log.w(TAG, "Some application object " + app + " tag " + tag
8805 + " has crashed, but I don't know who it is.");
8806 Log.w(TAG, "ShortMsg:" + shortMsg);
8807 Log.w(TAG, "LongMsg:" + longMsg);
8808 Binder.restoreCallingIdentity(origId);
8809 return 0;
8810 }
8811
8812 Message msg = Message.obtain();
8813 msg.what = SHOW_ERROR_MSG;
8814 HashMap data = new HashMap();
8815 data.put("result", result);
8816 data.put("app", r);
8817 data.put("flags", flags);
8818 data.put("shortMsg", shortMsg);
8819 data.put("longMsg", longMsg);
8820 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8821 // For system processes, submit crash data to the server.
8822 data.put("crashData", crashData);
8823 }
8824 msg.obj = data;
8825 mHandler.sendMessage(msg);
8826
8827 Binder.restoreCallingIdentity(origId);
8828 }
8829
8830 int res = result.get();
8831
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008832 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008833 synchronized (this) {
8834 if (r != null) {
8835 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8836 SystemClock.uptimeMillis());
8837 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008838 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8839 appErrorIntent = createAppErrorIntentLocked(r);
8840 res = AppErrorDialog.FORCE_QUIT;
8841 }
8842 }
8843
8844 if (appErrorIntent != null) {
8845 try {
8846 mContext.startActivity(appErrorIntent);
8847 } catch (ActivityNotFoundException e) {
8848 Log.w(TAG, "bug report receiver dissappeared", e);
8849 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008850 }
8851
8852 return res;
8853 }
8854
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008855 Intent createAppErrorIntentLocked(ProcessRecord r) {
8856 ApplicationErrorReport report = createAppErrorReportLocked(r);
8857 if (report == null) {
8858 return null;
8859 }
8860 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8861 result.setComponent(r.errorReportReceiver);
8862 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8863 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8864 return result;
8865 }
8866
8867 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8868 if (r.errorReportReceiver == null) {
8869 return null;
8870 }
8871
8872 if (!r.crashing && !r.notResponding) {
8873 return null;
8874 }
8875
8876 try {
8877 ApplicationErrorReport report = new ApplicationErrorReport();
8878 report.packageName = r.info.packageName;
8879 report.installerPackageName = r.errorReportReceiver.getPackageName();
8880 report.processName = r.processName;
8881
8882 if (r.crashing) {
8883 report.type = ApplicationErrorReport.TYPE_CRASH;
8884 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8885
8886 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8887 r.crashingReport.crashData);
8888 DataInputStream dataStream = new DataInputStream(byteStream);
8889 CrashData crashData = new CrashData(dataStream);
8890 ThrowableData throwData = crashData.getThrowableData();
8891
8892 report.time = crashData.getTime();
8893 report.crashInfo.stackTrace = throwData.toString();
8894
Jacek Surazskif829a782009-06-11 22:47:02 +02008895 // Extract the source of the exception, useful for report
8896 // clustering. Also extract the "deepest" non-null exception
8897 // message.
8898 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008899 while (throwData.getCause() != null) {
8900 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008901 String msg = throwData.getMessage();
8902 if (msg != null && msg.length() > 0) {
8903 exceptionMessage = msg;
8904 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008905 }
8906 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008907 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008908 report.crashInfo.exceptionClassName = throwData.getType();
8909 report.crashInfo.throwFileName = trace.getFileName();
8910 report.crashInfo.throwClassName = trace.getClassName();
8911 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008912 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008913 } else if (r.notResponding) {
8914 report.type = ApplicationErrorReport.TYPE_ANR;
8915 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8916
8917 report.anrInfo.activity = r.notRespondingReport.tag;
8918 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8919 report.anrInfo.info = r.notRespondingReport.longMsg;
8920 }
8921
8922 return report;
8923 } catch (IOException e) {
8924 // we don't send it
8925 }
8926
8927 return null;
8928 }
8929
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008930 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8931 // assume our apps are happy - lazy create the list
8932 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8933
8934 synchronized (this) {
8935
8936 // iterate across all processes
8937 final int N = mLRUProcesses.size();
8938 for (int i = 0; i < N; i++) {
8939 ProcessRecord app = mLRUProcesses.get(i);
8940 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8941 // This one's in trouble, so we'll generate a report for it
8942 // crashes are higher priority (in case there's a crash *and* an anr)
8943 ActivityManager.ProcessErrorStateInfo report = null;
8944 if (app.crashing) {
8945 report = app.crashingReport;
8946 } else if (app.notResponding) {
8947 report = app.notRespondingReport;
8948 }
8949
8950 if (report != null) {
8951 if (errList == null) {
8952 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8953 }
8954 errList.add(report);
8955 } else {
8956 Log.w(TAG, "Missing app error report, app = " + app.processName +
8957 " crashing = " + app.crashing +
8958 " notResponding = " + app.notResponding);
8959 }
8960 }
8961 }
8962 }
8963
8964 return errList;
8965 }
8966
8967 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8968 // Lazy instantiation of list
8969 List<ActivityManager.RunningAppProcessInfo> runList = null;
8970 synchronized (this) {
8971 // Iterate across all processes
8972 final int N = mLRUProcesses.size();
8973 for (int i = 0; i < N; i++) {
8974 ProcessRecord app = mLRUProcesses.get(i);
8975 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8976 // Generate process state info for running application
8977 ActivityManager.RunningAppProcessInfo currApp =
8978 new ActivityManager.RunningAppProcessInfo(app.processName,
8979 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07008980 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008981 int adj = app.curAdj;
8982 if (adj >= CONTENT_PROVIDER_ADJ) {
8983 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8984 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8985 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008986 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8987 } else if (adj >= HOME_APP_ADJ) {
8988 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8989 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008990 } else if (adj >= SECONDARY_SERVER_ADJ) {
8991 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8992 } else if (adj >= VISIBLE_APP_ADJ) {
8993 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8994 } else {
8995 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8996 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07008997 currApp.importanceReasonCode = app.adjTypeCode;
8998 if (app.adjSource instanceof ProcessRecord) {
8999 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9000 } else if (app.adjSource instanceof HistoryRecord) {
9001 HistoryRecord r = (HistoryRecord)app.adjSource;
9002 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9003 }
9004 if (app.adjTarget instanceof ComponentName) {
9005 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9006 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009007 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9008 // + " lru=" + currApp.lru);
9009 if (runList == null) {
9010 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9011 }
9012 runList.add(currApp);
9013 }
9014 }
9015 }
9016 return runList;
9017 }
9018
9019 @Override
9020 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9021 synchronized (this) {
9022 if (checkCallingPermission(android.Manifest.permission.DUMP)
9023 != PackageManager.PERMISSION_GRANTED) {
9024 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9025 + Binder.getCallingPid()
9026 + ", uid=" + Binder.getCallingUid()
9027 + " without permission "
9028 + android.Manifest.permission.DUMP);
9029 return;
9030 }
9031 if (args.length != 0 && "service".equals(args[0])) {
9032 dumpService(fd, pw, args);
9033 return;
9034 }
9035 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009036 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009037 pw.println(" ");
9038 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009039 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009040 if (mWaitingVisibleActivities.size() > 0) {
9041 pw.println(" ");
9042 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009043 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009044 }
9045 if (mStoppingActivities.size() > 0) {
9046 pw.println(" ");
9047 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009048 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009049 }
9050 if (mFinishingActivities.size() > 0) {
9051 pw.println(" ");
9052 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009053 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009054 }
9055
9056 pw.println(" ");
9057 pw.println(" mPausingActivity: " + mPausingActivity);
9058 pw.println(" mResumedActivity: " + mResumedActivity);
9059 pw.println(" mFocusedActivity: " + mFocusedActivity);
9060 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
9061
9062 if (mRecentTasks.size() > 0) {
9063 pw.println(" ");
9064 pw.println("Recent tasks in Current Activity Manager State:");
9065
9066 final int N = mRecentTasks.size();
9067 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009068 TaskRecord tr = mRecentTasks.get(i);
9069 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9070 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009071 mRecentTasks.get(i).dump(pw, " ");
9072 }
9073 }
9074
9075 pw.println(" ");
9076 pw.println(" mCurTask: " + mCurTask);
9077
9078 pw.println(" ");
9079 pw.println("Processes in Current Activity Manager State:");
9080
9081 boolean needSep = false;
9082 int numPers = 0;
9083
9084 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9085 final int NA = procs.size();
9086 for (int ia=0; ia<NA; ia++) {
9087 if (!needSep) {
9088 pw.println(" All known processes:");
9089 needSep = true;
9090 }
9091 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009092 pw.print(r.persistent ? " *PERS*" : " *APP*");
9093 pw.print(" UID "); pw.print(procs.keyAt(ia));
9094 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009095 r.dump(pw, " ");
9096 if (r.persistent) {
9097 numPers++;
9098 }
9099 }
9100 }
9101
9102 if (mLRUProcesses.size() > 0) {
9103 if (needSep) pw.println(" ");
9104 needSep = true;
9105 pw.println(" Running processes (most recent first):");
9106 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009107 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009108 needSep = true;
9109 }
9110
9111 synchronized (mPidsSelfLocked) {
9112 if (mPidsSelfLocked.size() > 0) {
9113 if (needSep) pw.println(" ");
9114 needSep = true;
9115 pw.println(" PID mappings:");
9116 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009117 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9118 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009119 }
9120 }
9121 }
9122
9123 if (mForegroundProcesses.size() > 0) {
9124 if (needSep) pw.println(" ");
9125 needSep = true;
9126 pw.println(" Foreground Processes:");
9127 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009128 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9129 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009130 }
9131 }
9132
9133 if (mPersistentStartingProcesses.size() > 0) {
9134 if (needSep) pw.println(" ");
9135 needSep = true;
9136 pw.println(" Persisent processes that are starting:");
9137 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009138 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009139 }
9140
9141 if (mStartingProcesses.size() > 0) {
9142 if (needSep) pw.println(" ");
9143 needSep = true;
9144 pw.println(" Processes that are starting:");
9145 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009146 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009147 }
9148
9149 if (mRemovedProcesses.size() > 0) {
9150 if (needSep) pw.println(" ");
9151 needSep = true;
9152 pw.println(" Processes that are being removed:");
9153 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009154 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009155 }
9156
9157 if (mProcessesOnHold.size() > 0) {
9158 if (needSep) pw.println(" ");
9159 needSep = true;
9160 pw.println(" Processes that are on old until the system is ready:");
9161 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009162 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009163 }
9164
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009165 if (mProcessesToGc.size() > 0) {
9166 if (needSep) pw.println(" ");
9167 needSep = true;
9168 pw.println(" Processes that are waiting to GC:");
9169 long now = SystemClock.uptimeMillis();
9170 for (int i=0; i<mProcessesToGc.size(); i++) {
9171 ProcessRecord proc = mProcessesToGc.get(i);
9172 pw.print(" Process "); pw.println(proc);
9173 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9174 pw.print(", last gced=");
9175 pw.print(now-proc.lastRequestedGc);
9176 pw.print(" ms ago, last lowMwm=");
9177 pw.print(now-proc.lastLowMemory);
9178 pw.println(" ms ago");
9179
9180 }
9181 }
9182
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009183 if (mProcessCrashTimes.getMap().size() > 0) {
9184 if (needSep) pw.println(" ");
9185 needSep = true;
9186 pw.println(" Time since processes crashed:");
9187 long now = SystemClock.uptimeMillis();
9188 for (Map.Entry<String, SparseArray<Long>> procs
9189 : mProcessCrashTimes.getMap().entrySet()) {
9190 SparseArray<Long> uids = procs.getValue();
9191 final int N = uids.size();
9192 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009193 pw.print(" Process "); pw.print(procs.getKey());
9194 pw.print(" uid "); pw.print(uids.keyAt(i));
9195 pw.print(": last crashed ");
9196 pw.print((now-uids.valueAt(i)));
9197 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009198 }
9199 }
9200 }
9201
9202 if (mBadProcesses.getMap().size() > 0) {
9203 if (needSep) pw.println(" ");
9204 needSep = true;
9205 pw.println(" Bad processes:");
9206 for (Map.Entry<String, SparseArray<Long>> procs
9207 : mBadProcesses.getMap().entrySet()) {
9208 SparseArray<Long> uids = procs.getValue();
9209 final int N = uids.size();
9210 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009211 pw.print(" Bad process "); pw.print(procs.getKey());
9212 pw.print(" uid "); pw.print(uids.keyAt(i));
9213 pw.print(": crashed at time ");
9214 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009215 }
9216 }
9217 }
9218
9219 pw.println(" ");
9220 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009221 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009222 pw.println(" mConfiguration: " + mConfiguration);
9223 pw.println(" mStartRunning=" + mStartRunning
9224 + " mSystemReady=" + mSystemReady
9225 + " mBooting=" + mBooting
9226 + " mBooted=" + mBooted
9227 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009228 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009229 pw.println(" mGoingToSleep=" + mGoingToSleep);
9230 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9231 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9232 + " mDebugTransient=" + mDebugTransient
9233 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9234 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009235 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009236 }
9237 }
9238
9239 /**
9240 * There are three ways to call this:
9241 * - no service specified: dump all the services
9242 * - a flattened component name that matched an existing service was specified as the
9243 * first arg: dump that one service
9244 * - the first arg isn't the flattened component name of an existing service:
9245 * dump all services whose component contains the first arg as a substring
9246 */
9247 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9248 String[] newArgs;
9249 String componentNameString;
9250 ServiceRecord r;
9251 if (args.length == 1) {
9252 componentNameString = null;
9253 newArgs = EMPTY_STRING_ARRAY;
9254 r = null;
9255 } else {
9256 componentNameString = args[1];
9257 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9258 r = componentName != null ? mServices.get(componentName) : null;
9259 newArgs = new String[args.length - 2];
9260 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9261 }
9262
9263 if (r != null) {
9264 dumpService(fd, pw, r, newArgs);
9265 } else {
9266 for (ServiceRecord r1 : mServices.values()) {
9267 if (componentNameString == null
9268 || r1.name.flattenToString().contains(componentNameString)) {
9269 dumpService(fd, pw, r1, newArgs);
9270 }
9271 }
9272 }
9273 }
9274
9275 /**
9276 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9277 * there is a thread associated with the service.
9278 */
9279 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9280 pw.println(" Service " + r.name.flattenToString());
9281 if (r.app != null && r.app.thread != null) {
9282 try {
9283 // flush anything that is already in the PrintWriter since the thread is going
9284 // to write to the file descriptor directly
9285 pw.flush();
9286 r.app.thread.dumpService(fd, r, args);
9287 pw.print("\n");
9288 } catch (RemoteException e) {
9289 pw.println("got a RemoteException while dumping the service");
9290 }
9291 }
9292 }
9293
9294 void dumpBroadcasts(PrintWriter pw) {
9295 synchronized (this) {
9296 if (checkCallingPermission(android.Manifest.permission.DUMP)
9297 != PackageManager.PERMISSION_GRANTED) {
9298 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9299 + Binder.getCallingPid()
9300 + ", uid=" + Binder.getCallingUid()
9301 + " without permission "
9302 + android.Manifest.permission.DUMP);
9303 return;
9304 }
9305 pw.println("Broadcasts in Current Activity Manager State:");
9306
9307 if (mRegisteredReceivers.size() > 0) {
9308 pw.println(" ");
9309 pw.println(" Registered Receivers:");
9310 Iterator it = mRegisteredReceivers.values().iterator();
9311 while (it.hasNext()) {
9312 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009313 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009314 r.dump(pw, " ");
9315 }
9316 }
9317
9318 pw.println(" ");
9319 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009320 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009321
9322 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9323 || mPendingBroadcast != null) {
9324 if (mParallelBroadcasts.size() > 0) {
9325 pw.println(" ");
9326 pw.println(" Active broadcasts:");
9327 }
9328 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9329 pw.println(" Broadcast #" + i + ":");
9330 mParallelBroadcasts.get(i).dump(pw, " ");
9331 }
9332 if (mOrderedBroadcasts.size() > 0) {
9333 pw.println(" ");
9334 pw.println(" Active serialized broadcasts:");
9335 }
9336 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9337 pw.println(" Serialized Broadcast #" + i + ":");
9338 mOrderedBroadcasts.get(i).dump(pw, " ");
9339 }
9340 pw.println(" ");
9341 pw.println(" Pending broadcast:");
9342 if (mPendingBroadcast != null) {
9343 mPendingBroadcast.dump(pw, " ");
9344 } else {
9345 pw.println(" (null)");
9346 }
9347 }
9348
9349 pw.println(" ");
9350 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9351 if (mStickyBroadcasts != null) {
9352 pw.println(" ");
9353 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009354 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009355 for (Map.Entry<String, ArrayList<Intent>> ent
9356 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009357 pw.print(" * Sticky action "); pw.print(ent.getKey());
9358 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009359 ArrayList<Intent> intents = ent.getValue();
9360 final int N = intents.size();
9361 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009362 sb.setLength(0);
9363 sb.append(" Intent: ");
9364 intents.get(i).toShortString(sb, true, false);
9365 pw.println(sb.toString());
9366 Bundle bundle = intents.get(i).getExtras();
9367 if (bundle != null) {
9368 pw.print(" ");
9369 pw.println(bundle.toString());
9370 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009371 }
9372 }
9373 }
9374
9375 pw.println(" ");
9376 pw.println(" mHandler:");
9377 mHandler.dump(new PrintWriterPrinter(pw), " ");
9378 }
9379 }
9380
9381 void dumpServices(PrintWriter pw) {
9382 synchronized (this) {
9383 if (checkCallingPermission(android.Manifest.permission.DUMP)
9384 != PackageManager.PERMISSION_GRANTED) {
9385 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9386 + Binder.getCallingPid()
9387 + ", uid=" + Binder.getCallingUid()
9388 + " without permission "
9389 + android.Manifest.permission.DUMP);
9390 return;
9391 }
9392 pw.println("Services in Current Activity Manager State:");
9393
9394 boolean needSep = false;
9395
9396 if (mServices.size() > 0) {
9397 pw.println(" Active services:");
9398 Iterator<ServiceRecord> it = mServices.values().iterator();
9399 while (it.hasNext()) {
9400 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009401 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009402 r.dump(pw, " ");
9403 }
9404 needSep = true;
9405 }
9406
9407 if (mPendingServices.size() > 0) {
9408 if (needSep) pw.println(" ");
9409 pw.println(" Pending services:");
9410 for (int i=0; i<mPendingServices.size(); i++) {
9411 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009412 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009413 r.dump(pw, " ");
9414 }
9415 needSep = true;
9416 }
9417
9418 if (mRestartingServices.size() > 0) {
9419 if (needSep) pw.println(" ");
9420 pw.println(" Restarting services:");
9421 for (int i=0; i<mRestartingServices.size(); i++) {
9422 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009423 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009424 r.dump(pw, " ");
9425 }
9426 needSep = true;
9427 }
9428
9429 if (mStoppingServices.size() > 0) {
9430 if (needSep) pw.println(" ");
9431 pw.println(" Stopping services:");
9432 for (int i=0; i<mStoppingServices.size(); i++) {
9433 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009434 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009435 r.dump(pw, " ");
9436 }
9437 needSep = true;
9438 }
9439
9440 if (mServiceConnections.size() > 0) {
9441 if (needSep) pw.println(" ");
9442 pw.println(" Connection bindings to services:");
9443 Iterator<ConnectionRecord> it
9444 = mServiceConnections.values().iterator();
9445 while (it.hasNext()) {
9446 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009447 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009448 r.dump(pw, " ");
9449 }
9450 }
9451 }
9452 }
9453
9454 void dumpProviders(PrintWriter pw) {
9455 synchronized (this) {
9456 if (checkCallingPermission(android.Manifest.permission.DUMP)
9457 != PackageManager.PERMISSION_GRANTED) {
9458 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9459 + Binder.getCallingPid()
9460 + ", uid=" + Binder.getCallingUid()
9461 + " without permission "
9462 + android.Manifest.permission.DUMP);
9463 return;
9464 }
9465
9466 pw.println("Content Providers in Current Activity Manager State:");
9467
9468 boolean needSep = false;
9469
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009470 if (mProvidersByClass.size() > 0) {
9471 if (needSep) pw.println(" ");
9472 pw.println(" Published content providers (by class):");
9473 Iterator it = mProvidersByClass.entrySet().iterator();
9474 while (it.hasNext()) {
9475 Map.Entry e = (Map.Entry)it.next();
9476 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009477 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009478 r.dump(pw, " ");
9479 }
9480 needSep = true;
9481 }
9482
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009483 if (mProvidersByName.size() > 0) {
9484 pw.println(" ");
9485 pw.println(" Authority to provider mappings:");
9486 Iterator it = mProvidersByName.entrySet().iterator();
9487 while (it.hasNext()) {
9488 Map.Entry e = (Map.Entry)it.next();
9489 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9490 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9491 pw.println(r);
9492 }
9493 needSep = true;
9494 }
9495
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009496 if (mLaunchingProviders.size() > 0) {
9497 if (needSep) pw.println(" ");
9498 pw.println(" Launching content providers:");
9499 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009500 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9501 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009502 }
9503 needSep = true;
9504 }
9505
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009506 if (mGrantedUriPermissions.size() > 0) {
9507 pw.println();
9508 pw.println("Granted Uri Permissions:");
9509 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9510 int uid = mGrantedUriPermissions.keyAt(i);
9511 HashMap<Uri, UriPermission> perms
9512 = mGrantedUriPermissions.valueAt(i);
9513 pw.print(" * UID "); pw.print(uid);
9514 pw.println(" holds:");
9515 for (UriPermission perm : perms.values()) {
9516 pw.print(" "); pw.println(perm);
9517 perm.dump(pw, " ");
9518 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009519 }
9520 }
9521 }
9522 }
9523
9524 void dumpSenders(PrintWriter pw) {
9525 synchronized (this) {
9526 if (checkCallingPermission(android.Manifest.permission.DUMP)
9527 != PackageManager.PERMISSION_GRANTED) {
9528 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9529 + Binder.getCallingPid()
9530 + ", uid=" + Binder.getCallingUid()
9531 + " without permission "
9532 + android.Manifest.permission.DUMP);
9533 return;
9534 }
9535
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009536 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009537
9538 if (this.mIntentSenderRecords.size() > 0) {
9539 Iterator<WeakReference<PendingIntentRecord>> it
9540 = mIntentSenderRecords.values().iterator();
9541 while (it.hasNext()) {
9542 WeakReference<PendingIntentRecord> ref = it.next();
9543 PendingIntentRecord rec = ref != null ? ref.get(): null;
9544 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009545 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009546 rec.dump(pw, " ");
9547 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009548 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009549 }
9550 }
9551 }
9552 }
9553 }
9554
9555 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009556 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009557 TaskRecord lastTask = null;
9558 for (int i=list.size()-1; i>=0; i--) {
9559 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009560 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009561 if (lastTask != r.task) {
9562 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009563 pw.print(prefix);
9564 pw.print(full ? "* " : " ");
9565 pw.println(lastTask);
9566 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009567 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009568 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009569 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009570 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9571 pw.print(" #"); pw.print(i); pw.print(": ");
9572 pw.println(r);
9573 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009574 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009575 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009576 }
9577 }
9578
9579 private static final int dumpProcessList(PrintWriter pw, List list,
9580 String prefix, String normalLabel, String persistentLabel,
9581 boolean inclOomAdj) {
9582 int numPers = 0;
9583 for (int i=list.size()-1; i>=0; i--) {
9584 ProcessRecord r = (ProcessRecord)list.get(i);
9585 if (false) {
9586 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9587 + " #" + i + ":");
9588 r.dump(pw, prefix + " ");
9589 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009590 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009591 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009592 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9593 if (r.adjSource != null || r.adjTarget != null) {
9594 pw.println(prefix + " " + r.adjTarget
9595 + " used by " + r.adjSource);
9596 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009597 } else {
9598 pw.println(String.format("%s%s #%2d: %s",
9599 prefix, (r.persistent ? persistentLabel : normalLabel),
9600 i, r.toString()));
9601 }
9602 if (r.persistent) {
9603 numPers++;
9604 }
9605 }
9606 return numPers;
9607 }
9608
9609 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9610 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009611 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009612 long uptime = SystemClock.uptimeMillis();
9613 long realtime = SystemClock.elapsedRealtime();
9614
9615 if (isCheckinRequest) {
9616 // short checkin version
9617 pw.println(uptime + "," + realtime);
9618 pw.flush();
9619 } else {
9620 pw.println("Applications Memory Usage (kB):");
9621 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9622 }
9623 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9624 ProcessRecord r = (ProcessRecord)list.get(i);
9625 if (r.thread != null) {
9626 if (!isCheckinRequest) {
9627 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9628 pw.flush();
9629 }
9630 try {
9631 r.thread.asBinder().dump(fd, args);
9632 } catch (RemoteException e) {
9633 if (!isCheckinRequest) {
9634 pw.println("Got RemoteException!");
9635 pw.flush();
9636 }
9637 }
9638 }
9639 }
9640 }
9641
9642 /**
9643 * Searches array of arguments for the specified string
9644 * @param args array of argument strings
9645 * @param value value to search for
9646 * @return true if the value is contained in the array
9647 */
9648 private static boolean scanArgs(String[] args, String value) {
9649 if (args != null) {
9650 for (String arg : args) {
9651 if (value.equals(arg)) {
9652 return true;
9653 }
9654 }
9655 }
9656 return false;
9657 }
9658
Dianne Hackborn75b03852009-06-12 15:43:26 -07009659 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009660 int count = mHistory.size();
9661
9662 // convert the token to an entry in the history.
9663 HistoryRecord r = null;
9664 int index = -1;
9665 for (int i=count-1; i>=0; i--) {
9666 Object o = mHistory.get(i);
9667 if (o == token) {
9668 r = (HistoryRecord)o;
9669 index = i;
9670 break;
9671 }
9672 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009673
9674 return index;
9675 }
9676
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009677 private final void killServicesLocked(ProcessRecord app,
9678 boolean allowRestart) {
9679 // Report disconnected services.
9680 if (false) {
9681 // XXX we are letting the client link to the service for
9682 // death notifications.
9683 if (app.services.size() > 0) {
9684 Iterator it = app.services.iterator();
9685 while (it.hasNext()) {
9686 ServiceRecord r = (ServiceRecord)it.next();
9687 if (r.connections.size() > 0) {
9688 Iterator<ConnectionRecord> jt
9689 = r.connections.values().iterator();
9690 while (jt.hasNext()) {
9691 ConnectionRecord c = jt.next();
9692 if (c.binding.client != app) {
9693 try {
9694 //c.conn.connected(r.className, null);
9695 } catch (Exception e) {
9696 // todo: this should be asynchronous!
9697 Log.w(TAG, "Exception thrown disconnected servce "
9698 + r.shortName
9699 + " from app " + app.processName, e);
9700 }
9701 }
9702 }
9703 }
9704 }
9705 }
9706 }
9707
9708 // Clean up any connections this application has to other services.
9709 if (app.connections.size() > 0) {
9710 Iterator<ConnectionRecord> it = app.connections.iterator();
9711 while (it.hasNext()) {
9712 ConnectionRecord r = it.next();
9713 removeConnectionLocked(r, app, null);
9714 }
9715 }
9716 app.connections.clear();
9717
9718 if (app.services.size() != 0) {
9719 // Any services running in the application need to be placed
9720 // back in the pending list.
9721 Iterator it = app.services.iterator();
9722 while (it.hasNext()) {
9723 ServiceRecord sr = (ServiceRecord)it.next();
9724 synchronized (sr.stats.getBatteryStats()) {
9725 sr.stats.stopLaunchedLocked();
9726 }
9727 sr.app = null;
9728 sr.executeNesting = 0;
9729 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009730
9731 boolean hasClients = sr.bindings.size() > 0;
9732 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009733 Iterator<IntentBindRecord> bindings
9734 = sr.bindings.values().iterator();
9735 while (bindings.hasNext()) {
9736 IntentBindRecord b = bindings.next();
9737 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9738 + ": shouldUnbind=" + b.hasBound);
9739 b.binder = null;
9740 b.requested = b.received = b.hasBound = false;
9741 }
9742 }
9743
9744 if (sr.crashCount >= 2) {
9745 Log.w(TAG, "Service crashed " + sr.crashCount
9746 + " times, stopping: " + sr);
9747 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9748 sr.crashCount, sr.shortName, app.pid);
9749 bringDownServiceLocked(sr, true);
9750 } else if (!allowRestart) {
9751 bringDownServiceLocked(sr, true);
9752 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009753 boolean canceled = scheduleServiceRestartLocked(sr, true);
9754
9755 // Should the service remain running? Note that in the
9756 // extreme case of so many attempts to deliver a command
9757 // that it failed, that we also will stop it here.
9758 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9759 if (sr.pendingStarts.size() == 0) {
9760 sr.startRequested = false;
9761 if (!hasClients) {
9762 // Whoops, no reason to restart!
9763 bringDownServiceLocked(sr, true);
9764 }
9765 }
9766 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009767 }
9768 }
9769
9770 if (!allowRestart) {
9771 app.services.clear();
9772 }
9773 }
9774
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009775 // Make sure we have no more records on the stopping list.
9776 int i = mStoppingServices.size();
9777 while (i > 0) {
9778 i--;
9779 ServiceRecord sr = mStoppingServices.get(i);
9780 if (sr.app == app) {
9781 mStoppingServices.remove(i);
9782 }
9783 }
9784
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009785 app.executingServices.clear();
9786 }
9787
9788 private final void removeDyingProviderLocked(ProcessRecord proc,
9789 ContentProviderRecord cpr) {
9790 synchronized (cpr) {
9791 cpr.launchingApp = null;
9792 cpr.notifyAll();
9793 }
9794
9795 mProvidersByClass.remove(cpr.info.name);
9796 String names[] = cpr.info.authority.split(";");
9797 for (int j = 0; j < names.length; j++) {
9798 mProvidersByName.remove(names[j]);
9799 }
9800
9801 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9802 while (cit.hasNext()) {
9803 ProcessRecord capp = cit.next();
9804 if (!capp.persistent && capp.thread != null
9805 && capp.pid != 0
9806 && capp.pid != MY_PID) {
9807 Log.i(TAG, "Killing app " + capp.processName
9808 + " (pid " + capp.pid
9809 + ") because provider " + cpr.info.name
9810 + " is in dying process " + proc.processName);
9811 Process.killProcess(capp.pid);
9812 }
9813 }
9814
9815 mLaunchingProviders.remove(cpr);
9816 }
9817
9818 /**
9819 * Main code for cleaning up a process when it has gone away. This is
9820 * called both as a result of the process dying, or directly when stopping
9821 * a process when running in single process mode.
9822 */
9823 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9824 boolean restarting, int index) {
9825 if (index >= 0) {
9826 mLRUProcesses.remove(index);
9827 }
9828
9829 // Dismiss any open dialogs.
9830 if (app.crashDialog != null) {
9831 app.crashDialog.dismiss();
9832 app.crashDialog = null;
9833 }
9834 if (app.anrDialog != null) {
9835 app.anrDialog.dismiss();
9836 app.anrDialog = null;
9837 }
9838 if (app.waitDialog != null) {
9839 app.waitDialog.dismiss();
9840 app.waitDialog = null;
9841 }
9842
9843 app.crashing = false;
9844 app.notResponding = false;
9845
9846 app.resetPackageList();
9847 app.thread = null;
9848 app.forcingToForeground = null;
9849 app.foregroundServices = false;
9850
9851 killServicesLocked(app, true);
9852
9853 boolean restart = false;
9854
9855 int NL = mLaunchingProviders.size();
9856
9857 // Remove published content providers.
9858 if (!app.pubProviders.isEmpty()) {
9859 Iterator it = app.pubProviders.values().iterator();
9860 while (it.hasNext()) {
9861 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9862 cpr.provider = null;
9863 cpr.app = null;
9864
9865 // See if someone is waiting for this provider... in which
9866 // case we don't remove it, but just let it restart.
9867 int i = 0;
9868 if (!app.bad) {
9869 for (; i<NL; i++) {
9870 if (mLaunchingProviders.get(i) == cpr) {
9871 restart = true;
9872 break;
9873 }
9874 }
9875 } else {
9876 i = NL;
9877 }
9878
9879 if (i >= NL) {
9880 removeDyingProviderLocked(app, cpr);
9881 NL = mLaunchingProviders.size();
9882 }
9883 }
9884 app.pubProviders.clear();
9885 }
9886
9887 // Look through the content providers we are waiting to have launched,
9888 // and if any run in this process then either schedule a restart of
9889 // the process or kill the client waiting for it if this process has
9890 // gone bad.
9891 for (int i=0; i<NL; i++) {
9892 ContentProviderRecord cpr = (ContentProviderRecord)
9893 mLaunchingProviders.get(i);
9894 if (cpr.launchingApp == app) {
9895 if (!app.bad) {
9896 restart = true;
9897 } else {
9898 removeDyingProviderLocked(app, cpr);
9899 NL = mLaunchingProviders.size();
9900 }
9901 }
9902 }
9903
9904 // Unregister from connected content providers.
9905 if (!app.conProviders.isEmpty()) {
9906 Iterator it = app.conProviders.iterator();
9907 while (it.hasNext()) {
9908 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9909 cpr.clients.remove(app);
9910 }
9911 app.conProviders.clear();
9912 }
9913
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009914 // At this point there may be remaining entries in mLaunchingProviders
9915 // where we were the only one waiting, so they are no longer of use.
9916 // Look for these and clean up if found.
9917 // XXX Commented out for now. Trying to figure out a way to reproduce
9918 // the actual situation to identify what is actually going on.
9919 if (false) {
9920 for (int i=0; i<NL; i++) {
9921 ContentProviderRecord cpr = (ContentProviderRecord)
9922 mLaunchingProviders.get(i);
9923 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9924 synchronized (cpr) {
9925 cpr.launchingApp = null;
9926 cpr.notifyAll();
9927 }
9928 }
9929 }
9930 }
9931
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009932 skipCurrentReceiverLocked(app);
9933
9934 // Unregister any receivers.
9935 if (app.receivers.size() > 0) {
9936 Iterator<ReceiverList> it = app.receivers.iterator();
9937 while (it.hasNext()) {
9938 removeReceiverLocked(it.next());
9939 }
9940 app.receivers.clear();
9941 }
9942
Christopher Tate181fafa2009-05-14 11:12:14 -07009943 // If the app is undergoing backup, tell the backup manager about it
9944 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9945 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9946 try {
9947 IBackupManager bm = IBackupManager.Stub.asInterface(
9948 ServiceManager.getService(Context.BACKUP_SERVICE));
9949 bm.agentDisconnected(app.info.packageName);
9950 } catch (RemoteException e) {
9951 // can't happen; backup manager is local
9952 }
9953 }
9954
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009955 // If the caller is restarting this app, then leave it in its
9956 // current lists and let the caller take care of it.
9957 if (restarting) {
9958 return;
9959 }
9960
9961 if (!app.persistent) {
9962 if (DEBUG_PROCESSES) Log.v(TAG,
9963 "Removing non-persistent process during cleanup: " + app);
9964 mProcessNames.remove(app.processName, app.info.uid);
9965 } else if (!app.removed) {
9966 // This app is persistent, so we need to keep its record around.
9967 // If it is not already on the pending app list, add it there
9968 // and start a new process for it.
9969 app.thread = null;
9970 app.forcingToForeground = null;
9971 app.foregroundServices = false;
9972 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9973 mPersistentStartingProcesses.add(app);
9974 restart = true;
9975 }
9976 }
9977 mProcessesOnHold.remove(app);
9978
The Android Open Source Project4df24232009-03-05 14:34:35 -08009979 if (app == mHomeProcess) {
9980 mHomeProcess = null;
9981 }
9982
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009983 if (restart) {
9984 // We have components that still need to be running in the
9985 // process, so re-launch it.
9986 mProcessNames.put(app.processName, app.info.uid, app);
9987 startProcessLocked(app, "restart", app.processName);
9988 } else if (app.pid > 0 && app.pid != MY_PID) {
9989 // Goodbye!
9990 synchronized (mPidsSelfLocked) {
9991 mPidsSelfLocked.remove(app.pid);
9992 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9993 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009994 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009995 }
9996 }
9997
9998 // =========================================================
9999 // SERVICES
10000 // =========================================================
10001
10002 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10003 ActivityManager.RunningServiceInfo info =
10004 new ActivityManager.RunningServiceInfo();
10005 info.service = r.name;
10006 if (r.app != null) {
10007 info.pid = r.app.pid;
10008 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010009 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010010 info.process = r.processName;
10011 info.foreground = r.isForeground;
10012 info.activeSince = r.createTime;
10013 info.started = r.startRequested;
10014 info.clientCount = r.connections.size();
10015 info.crashCount = r.crashCount;
10016 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010017 if (r.isForeground) {
10018 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10019 }
10020 if (r.startRequested) {
10021 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10022 }
10023 if (r.app != null && r.app.pid == Process.myPid()) {
10024 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10025 }
10026 if (r.app != null && r.app.persistent) {
10027 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10028 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010029 for (ConnectionRecord conn : r.connections.values()) {
10030 if (conn.clientLabel != 0) {
10031 info.clientPackage = conn.binding.client.info.packageName;
10032 info.clientLabel = conn.clientLabel;
10033 break;
10034 }
10035 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010036 return info;
10037 }
10038
10039 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10040 int flags) {
10041 synchronized (this) {
10042 ArrayList<ActivityManager.RunningServiceInfo> res
10043 = new ArrayList<ActivityManager.RunningServiceInfo>();
10044
10045 if (mServices.size() > 0) {
10046 Iterator<ServiceRecord> it = mServices.values().iterator();
10047 while (it.hasNext() && res.size() < maxNum) {
10048 res.add(makeRunningServiceInfoLocked(it.next()));
10049 }
10050 }
10051
10052 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10053 ServiceRecord r = mRestartingServices.get(i);
10054 ActivityManager.RunningServiceInfo info =
10055 makeRunningServiceInfoLocked(r);
10056 info.restarting = r.nextRestartTime;
10057 res.add(info);
10058 }
10059
10060 return res;
10061 }
10062 }
10063
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010064 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10065 synchronized (this) {
10066 ServiceRecord r = mServices.get(name);
10067 if (r != null) {
10068 for (ConnectionRecord conn : r.connections.values()) {
10069 if (conn.clientIntent != null) {
10070 return conn.clientIntent;
10071 }
10072 }
10073 }
10074 }
10075 return null;
10076 }
10077
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010078 private final ServiceRecord findServiceLocked(ComponentName name,
10079 IBinder token) {
10080 ServiceRecord r = mServices.get(name);
10081 return r == token ? r : null;
10082 }
10083
10084 private final class ServiceLookupResult {
10085 final ServiceRecord record;
10086 final String permission;
10087
10088 ServiceLookupResult(ServiceRecord _record, String _permission) {
10089 record = _record;
10090 permission = _permission;
10091 }
10092 };
10093
10094 private ServiceLookupResult findServiceLocked(Intent service,
10095 String resolvedType) {
10096 ServiceRecord r = null;
10097 if (service.getComponent() != null) {
10098 r = mServices.get(service.getComponent());
10099 }
10100 if (r == null) {
10101 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10102 r = mServicesByIntent.get(filter);
10103 }
10104
10105 if (r == null) {
10106 try {
10107 ResolveInfo rInfo =
10108 ActivityThread.getPackageManager().resolveService(
10109 service, resolvedType, 0);
10110 ServiceInfo sInfo =
10111 rInfo != null ? rInfo.serviceInfo : null;
10112 if (sInfo == null) {
10113 return null;
10114 }
10115
10116 ComponentName name = new ComponentName(
10117 sInfo.applicationInfo.packageName, sInfo.name);
10118 r = mServices.get(name);
10119 } catch (RemoteException ex) {
10120 // pm is in same process, this will never happen.
10121 }
10122 }
10123 if (r != null) {
10124 int callingPid = Binder.getCallingPid();
10125 int callingUid = Binder.getCallingUid();
10126 if (checkComponentPermission(r.permission,
10127 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10128 != PackageManager.PERMISSION_GRANTED) {
10129 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10130 + " from pid=" + callingPid
10131 + ", uid=" + callingUid
10132 + " requires " + r.permission);
10133 return new ServiceLookupResult(null, r.permission);
10134 }
10135 return new ServiceLookupResult(r, null);
10136 }
10137 return null;
10138 }
10139
10140 private class ServiceRestarter implements Runnable {
10141 private ServiceRecord mService;
10142
10143 void setService(ServiceRecord service) {
10144 mService = service;
10145 }
10146
10147 public void run() {
10148 synchronized(ActivityManagerService.this) {
10149 performServiceRestartLocked(mService);
10150 }
10151 }
10152 }
10153
10154 private ServiceLookupResult retrieveServiceLocked(Intent service,
10155 String resolvedType, int callingPid, int callingUid) {
10156 ServiceRecord r = null;
10157 if (service.getComponent() != null) {
10158 r = mServices.get(service.getComponent());
10159 }
10160 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10161 r = mServicesByIntent.get(filter);
10162 if (r == null) {
10163 try {
10164 ResolveInfo rInfo =
10165 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010166 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010167 ServiceInfo sInfo =
10168 rInfo != null ? rInfo.serviceInfo : null;
10169 if (sInfo == null) {
10170 Log.w(TAG, "Unable to start service " + service +
10171 ": not found");
10172 return null;
10173 }
10174
10175 ComponentName name = new ComponentName(
10176 sInfo.applicationInfo.packageName, sInfo.name);
10177 r = mServices.get(name);
10178 if (r == null) {
10179 filter = new Intent.FilterComparison(service.cloneFilter());
10180 ServiceRestarter res = new ServiceRestarter();
10181 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10182 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10183 synchronized (stats) {
10184 ss = stats.getServiceStatsLocked(
10185 sInfo.applicationInfo.uid, sInfo.packageName,
10186 sInfo.name);
10187 }
10188 r = new ServiceRecord(ss, name, filter, sInfo, res);
10189 res.setService(r);
10190 mServices.put(name, r);
10191 mServicesByIntent.put(filter, r);
10192
10193 // Make sure this component isn't in the pending list.
10194 int N = mPendingServices.size();
10195 for (int i=0; i<N; i++) {
10196 ServiceRecord pr = mPendingServices.get(i);
10197 if (pr.name.equals(name)) {
10198 mPendingServices.remove(i);
10199 i--;
10200 N--;
10201 }
10202 }
10203 }
10204 } catch (RemoteException ex) {
10205 // pm is in same process, this will never happen.
10206 }
10207 }
10208 if (r != null) {
10209 if (checkComponentPermission(r.permission,
10210 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10211 != PackageManager.PERMISSION_GRANTED) {
10212 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10213 + " from pid=" + Binder.getCallingPid()
10214 + ", uid=" + Binder.getCallingUid()
10215 + " requires " + r.permission);
10216 return new ServiceLookupResult(null, r.permission);
10217 }
10218 return new ServiceLookupResult(r, null);
10219 }
10220 return null;
10221 }
10222
10223 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10224 long now = SystemClock.uptimeMillis();
10225 if (r.executeNesting == 0 && r.app != null) {
10226 if (r.app.executingServices.size() == 0) {
10227 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10228 msg.obj = r.app;
10229 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10230 }
10231 r.app.executingServices.add(r);
10232 }
10233 r.executeNesting++;
10234 r.executingStart = now;
10235 }
10236
10237 private final void sendServiceArgsLocked(ServiceRecord r,
10238 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010239 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010240 if (N == 0) {
10241 return;
10242 }
10243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010244 int i = 0;
10245 while (i < N) {
10246 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010247 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010248 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010249 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010250 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010251 // If somehow we got a dummy start at the front, then
10252 // just drop it here.
10253 i++;
10254 continue;
10255 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010256 bumpServiceExecutingLocked(r);
10257 if (!oomAdjusted) {
10258 oomAdjusted = true;
10259 updateOomAdjLocked(r.app);
10260 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010261 int flags = 0;
10262 if (si.deliveryCount > 0) {
10263 flags |= Service.START_FLAG_RETRY;
10264 }
10265 if (si.doneExecutingCount > 0) {
10266 flags |= Service.START_FLAG_REDELIVERY;
10267 }
10268 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10269 si.deliveredTime = SystemClock.uptimeMillis();
10270 r.deliveredStarts.add(si);
10271 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010272 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010273 } catch (RemoteException e) {
10274 // Remote process gone... we'll let the normal cleanup take
10275 // care of this.
10276 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010277 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010278 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010279 break;
10280 }
10281 }
10282 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010283 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010284 } else {
10285 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010286 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010287 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010288 }
10289 }
10290 }
10291
10292 private final boolean requestServiceBindingLocked(ServiceRecord r,
10293 IntentBindRecord i, boolean rebind) {
10294 if (r.app == null || r.app.thread == null) {
10295 // If service is not currently running, can't yet bind.
10296 return false;
10297 }
10298 if ((!i.requested || rebind) && i.apps.size() > 0) {
10299 try {
10300 bumpServiceExecutingLocked(r);
10301 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10302 + ": shouldUnbind=" + i.hasBound);
10303 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10304 if (!rebind) {
10305 i.requested = true;
10306 }
10307 i.hasBound = true;
10308 i.doRebind = false;
10309 } catch (RemoteException e) {
10310 return false;
10311 }
10312 }
10313 return true;
10314 }
10315
10316 private final void requestServiceBindingsLocked(ServiceRecord r) {
10317 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10318 while (bindings.hasNext()) {
10319 IntentBindRecord i = bindings.next();
10320 if (!requestServiceBindingLocked(r, i, false)) {
10321 break;
10322 }
10323 }
10324 }
10325
10326 private final void realStartServiceLocked(ServiceRecord r,
10327 ProcessRecord app) throws RemoteException {
10328 if (app.thread == null) {
10329 throw new RemoteException();
10330 }
10331
10332 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010333 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010334
10335 app.services.add(r);
10336 bumpServiceExecutingLocked(r);
10337 updateLRUListLocked(app, true);
10338
10339 boolean created = false;
10340 try {
10341 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10342 + r.name + " " + r.intent);
10343 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
10344 System.identityHashCode(r), r.shortName,
10345 r.intent.getIntent().toString(), r.app.pid);
10346 synchronized (r.stats.getBatteryStats()) {
10347 r.stats.startLaunchedLocked();
10348 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010349 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010350 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010351 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010352 created = true;
10353 } finally {
10354 if (!created) {
10355 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010356 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010357 }
10358 }
10359
10360 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010361
10362 // If the service is in the started state, and there are no
10363 // pending arguments, then fake up one so its onStartCommand() will
10364 // be called.
10365 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10366 r.lastStartId++;
10367 if (r.lastStartId < 1) {
10368 r.lastStartId = 1;
10369 }
10370 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10371 }
10372
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010373 sendServiceArgsLocked(r, true);
10374 }
10375
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010376 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10377 boolean allowCancel) {
10378 boolean canceled = false;
10379
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010380 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010381 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010382 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010383
10384 // Any delivered but not yet finished starts should be put back
10385 // on the pending list.
10386 final int N = r.deliveredStarts.size();
10387 if (N > 0) {
10388 for (int i=N-1; i>=0; i--) {
10389 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10390 if (si.intent == null) {
10391 // We'll generate this again if needed.
10392 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10393 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10394 r.pendingStarts.add(0, si);
10395 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10396 dur *= 2;
10397 if (minDuration < dur) minDuration = dur;
10398 if (resetTime < dur) resetTime = dur;
10399 } else {
10400 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10401 + r.name);
10402 canceled = true;
10403 }
10404 }
10405 r.deliveredStarts.clear();
10406 }
10407
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010408 r.totalRestartCount++;
10409 if (r.restartDelay == 0) {
10410 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010411 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010412 } else {
10413 // If it has been a "reasonably long time" since the service
10414 // was started, then reset our restart duration back to
10415 // the beginning, so we don't infinitely increase the duration
10416 // on a service that just occasionally gets killed (which is
10417 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010418 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010419 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010420 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010421 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010422 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010423 if (r.restartDelay < minDuration) {
10424 r.restartDelay = minDuration;
10425 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010426 }
10427 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010428
10429 r.nextRestartTime = now + r.restartDelay;
10430
10431 // Make sure that we don't end up restarting a bunch of services
10432 // all at the same time.
10433 boolean repeat;
10434 do {
10435 repeat = false;
10436 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10437 ServiceRecord r2 = mRestartingServices.get(i);
10438 if (r2 != r && r.nextRestartTime
10439 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10440 && r.nextRestartTime
10441 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10442 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10443 r.restartDelay = r.nextRestartTime - now;
10444 repeat = true;
10445 break;
10446 }
10447 }
10448 } while (repeat);
10449
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010450 if (!mRestartingServices.contains(r)) {
10451 mRestartingServices.add(r);
10452 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010453
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010454 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010455
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010456 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010457 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010458 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10459 Log.w(TAG, "Scheduling restart of crashed service "
10460 + r.shortName + " in " + r.restartDelay + "ms");
10461 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10462 r.shortName, r.restartDelay);
10463
10464 Message msg = Message.obtain();
10465 msg.what = SERVICE_ERROR_MSG;
10466 msg.obj = r;
10467 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010468
10469 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010470 }
10471
10472 final void performServiceRestartLocked(ServiceRecord r) {
10473 if (!mRestartingServices.contains(r)) {
10474 return;
10475 }
10476 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10477 }
10478
10479 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10480 if (r.restartDelay == 0) {
10481 return false;
10482 }
10483 r.resetRestartCounter();
10484 mRestartingServices.remove(r);
10485 mHandler.removeCallbacks(r.restarter);
10486 return true;
10487 }
10488
10489 private final boolean bringUpServiceLocked(ServiceRecord r,
10490 int intentFlags, boolean whileRestarting) {
10491 //Log.i(TAG, "Bring up service:");
10492 //r.dump(" ");
10493
10494 if (r.app != null) {
10495 sendServiceArgsLocked(r, false);
10496 return true;
10497 }
10498
10499 if (!whileRestarting && r.restartDelay > 0) {
10500 // If waiting for a restart, then do nothing.
10501 return true;
10502 }
10503
10504 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10505 + " " + r.intent);
10506
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010507 // We are now bringing the service up, so no longer in the
10508 // restarting state.
10509 mRestartingServices.remove(r);
10510
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010511 final String appName = r.processName;
10512 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10513 if (app != null && app.thread != null) {
10514 try {
10515 realStartServiceLocked(r, app);
10516 return true;
10517 } catch (RemoteException e) {
10518 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10519 }
10520
10521 // If a dead object exception was thrown -- fall through to
10522 // restart the application.
10523 }
10524
10525 if (!mPendingServices.contains(r)) {
10526 // Not running -- get it started, and enqueue this service record
10527 // to be executed when the app comes up.
10528 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070010529 "service", r.name, false) == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010530 Log.w(TAG, "Unable to launch app "
10531 + r.appInfo.packageName + "/"
10532 + r.appInfo.uid + " for service "
10533 + r.intent.getIntent() + ": process is bad");
10534 bringDownServiceLocked(r, true);
10535 return false;
10536 }
10537 mPendingServices.add(r);
10538 }
10539 return true;
10540 }
10541
10542 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10543 //Log.i(TAG, "Bring down service:");
10544 //r.dump(" ");
10545
10546 // Does it still need to run?
10547 if (!force && r.startRequested) {
10548 return;
10549 }
10550 if (r.connections.size() > 0) {
10551 if (!force) {
10552 // XXX should probably keep a count of the number of auto-create
10553 // connections directly in the service.
10554 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10555 while (it.hasNext()) {
10556 ConnectionRecord cr = it.next();
10557 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10558 return;
10559 }
10560 }
10561 }
10562
10563 // Report to all of the connections that the service is no longer
10564 // available.
10565 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10566 while (it.hasNext()) {
10567 ConnectionRecord c = it.next();
10568 try {
10569 // todo: shouldn't be a synchronous call!
10570 c.conn.connected(r.name, null);
10571 } catch (Exception e) {
10572 Log.w(TAG, "Failure disconnecting service " + r.name +
10573 " to connection " + c.conn.asBinder() +
10574 " (in " + c.binding.client.processName + ")", e);
10575 }
10576 }
10577 }
10578
10579 // Tell the service that it has been unbound.
10580 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10581 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10582 while (it.hasNext()) {
10583 IntentBindRecord ibr = it.next();
10584 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10585 + ": hasBound=" + ibr.hasBound);
10586 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10587 try {
10588 bumpServiceExecutingLocked(r);
10589 updateOomAdjLocked(r.app);
10590 ibr.hasBound = false;
10591 r.app.thread.scheduleUnbindService(r,
10592 ibr.intent.getIntent());
10593 } catch (Exception e) {
10594 Log.w(TAG, "Exception when unbinding service "
10595 + r.shortName, e);
10596 serviceDoneExecutingLocked(r, true);
10597 }
10598 }
10599 }
10600 }
10601
10602 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10603 + " " + r.intent);
10604 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10605 System.identityHashCode(r), r.shortName,
10606 (r.app != null) ? r.app.pid : -1);
10607
10608 mServices.remove(r.name);
10609 mServicesByIntent.remove(r.intent);
10610 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10611 r.totalRestartCount = 0;
10612 unscheduleServiceRestartLocked(r);
10613
10614 // Also make sure it is not on the pending list.
10615 int N = mPendingServices.size();
10616 for (int i=0; i<N; i++) {
10617 if (mPendingServices.get(i) == r) {
10618 mPendingServices.remove(i);
10619 if (DEBUG_SERVICE) Log.v(
10620 TAG, "Removed pending service: " + r.shortName);
10621 i--;
10622 N--;
10623 }
10624 }
10625
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010626 r.cancelNotification();
10627 r.isForeground = false;
10628 r.foregroundId = 0;
10629 r.foregroundNoti = null;
10630
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010631 // Clear start entries.
10632 r.deliveredStarts.clear();
10633 r.pendingStarts.clear();
10634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010635 if (r.app != null) {
10636 synchronized (r.stats.getBatteryStats()) {
10637 r.stats.stopLaunchedLocked();
10638 }
10639 r.app.services.remove(r);
10640 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010641 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010642 if (DEBUG_SERVICE) Log.v(TAG,
10643 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010644 bumpServiceExecutingLocked(r);
10645 mStoppingServices.add(r);
10646 updateOomAdjLocked(r.app);
10647 r.app.thread.scheduleStopService(r);
10648 } catch (Exception e) {
10649 Log.w(TAG, "Exception when stopping service "
10650 + r.shortName, e);
10651 serviceDoneExecutingLocked(r, true);
10652 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010653 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010654 } else {
10655 if (DEBUG_SERVICE) Log.v(
10656 TAG, "Removed service that has no process: " + r.shortName);
10657 }
10658 } else {
10659 if (DEBUG_SERVICE) Log.v(
10660 TAG, "Removed service that is not running: " + r.shortName);
10661 }
10662 }
10663
10664 ComponentName startServiceLocked(IApplicationThread caller,
10665 Intent service, String resolvedType,
10666 int callingPid, int callingUid) {
10667 synchronized(this) {
10668 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10669 + " type=" + resolvedType + " args=" + service.getExtras());
10670
10671 if (caller != null) {
10672 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10673 if (callerApp == null) {
10674 throw new SecurityException(
10675 "Unable to find app for caller " + caller
10676 + " (pid=" + Binder.getCallingPid()
10677 + ") when starting service " + service);
10678 }
10679 }
10680
10681 ServiceLookupResult res =
10682 retrieveServiceLocked(service, resolvedType,
10683 callingPid, callingUid);
10684 if (res == null) {
10685 return null;
10686 }
10687 if (res.record == null) {
10688 return new ComponentName("!", res.permission != null
10689 ? res.permission : "private to package");
10690 }
10691 ServiceRecord r = res.record;
10692 if (unscheduleServiceRestartLocked(r)) {
10693 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10694 + r.shortName);
10695 }
10696 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010697 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010698 r.lastStartId++;
10699 if (r.lastStartId < 1) {
10700 r.lastStartId = 1;
10701 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010702 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010703 r.lastActivity = SystemClock.uptimeMillis();
10704 synchronized (r.stats.getBatteryStats()) {
10705 r.stats.startRunningLocked();
10706 }
10707 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10708 return new ComponentName("!", "Service process is bad");
10709 }
10710 return r.name;
10711 }
10712 }
10713
10714 public ComponentName startService(IApplicationThread caller, Intent service,
10715 String resolvedType) {
10716 // Refuse possible leaked file descriptors
10717 if (service != null && service.hasFileDescriptors() == true) {
10718 throw new IllegalArgumentException("File descriptors passed in Intent");
10719 }
10720
10721 synchronized(this) {
10722 final int callingPid = Binder.getCallingPid();
10723 final int callingUid = Binder.getCallingUid();
10724 final long origId = Binder.clearCallingIdentity();
10725 ComponentName res = startServiceLocked(caller, service,
10726 resolvedType, callingPid, callingUid);
10727 Binder.restoreCallingIdentity(origId);
10728 return res;
10729 }
10730 }
10731
10732 ComponentName startServiceInPackage(int uid,
10733 Intent service, String resolvedType) {
10734 synchronized(this) {
10735 final long origId = Binder.clearCallingIdentity();
10736 ComponentName res = startServiceLocked(null, service,
10737 resolvedType, -1, uid);
10738 Binder.restoreCallingIdentity(origId);
10739 return res;
10740 }
10741 }
10742
10743 public int stopService(IApplicationThread caller, Intent service,
10744 String resolvedType) {
10745 // Refuse possible leaked file descriptors
10746 if (service != null && service.hasFileDescriptors() == true) {
10747 throw new IllegalArgumentException("File descriptors passed in Intent");
10748 }
10749
10750 synchronized(this) {
10751 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10752 + " type=" + resolvedType);
10753
10754 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10755 if (caller != null && callerApp == null) {
10756 throw new SecurityException(
10757 "Unable to find app for caller " + caller
10758 + " (pid=" + Binder.getCallingPid()
10759 + ") when stopping service " + service);
10760 }
10761
10762 // If this service is active, make sure it is stopped.
10763 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10764 if (r != null) {
10765 if (r.record != null) {
10766 synchronized (r.record.stats.getBatteryStats()) {
10767 r.record.stats.stopRunningLocked();
10768 }
10769 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010770 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010771 final long origId = Binder.clearCallingIdentity();
10772 bringDownServiceLocked(r.record, false);
10773 Binder.restoreCallingIdentity(origId);
10774 return 1;
10775 }
10776 return -1;
10777 }
10778 }
10779
10780 return 0;
10781 }
10782
10783 public IBinder peekService(Intent service, String resolvedType) {
10784 // Refuse possible leaked file descriptors
10785 if (service != null && service.hasFileDescriptors() == true) {
10786 throw new IllegalArgumentException("File descriptors passed in Intent");
10787 }
10788
10789 IBinder ret = null;
10790
10791 synchronized(this) {
10792 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10793
10794 if (r != null) {
10795 // r.record is null if findServiceLocked() failed the caller permission check
10796 if (r.record == null) {
10797 throw new SecurityException(
10798 "Permission Denial: Accessing service " + r.record.name
10799 + " from pid=" + Binder.getCallingPid()
10800 + ", uid=" + Binder.getCallingUid()
10801 + " requires " + r.permission);
10802 }
10803 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10804 if (ib != null) {
10805 ret = ib.binder;
10806 }
10807 }
10808 }
10809
10810 return ret;
10811 }
10812
10813 public boolean stopServiceToken(ComponentName className, IBinder token,
10814 int startId) {
10815 synchronized(this) {
10816 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10817 + " " + token + " startId=" + startId);
10818 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010819 if (r != null) {
10820 if (startId >= 0) {
10821 // Asked to only stop if done with all work. Note that
10822 // to avoid leaks, we will take this as dropping all
10823 // start items up to and including this one.
10824 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10825 if (si != null) {
10826 while (r.deliveredStarts.size() > 0) {
10827 if (r.deliveredStarts.remove(0) == si) {
10828 break;
10829 }
10830 }
10831 }
10832
10833 if (r.lastStartId != startId) {
10834 return false;
10835 }
10836
10837 if (r.deliveredStarts.size() > 0) {
10838 Log.w(TAG, "stopServiceToken startId " + startId
10839 + " is last, but have " + r.deliveredStarts.size()
10840 + " remaining args");
10841 }
10842 }
10843
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010844 synchronized (r.stats.getBatteryStats()) {
10845 r.stats.stopRunningLocked();
10846 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010847 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010848 }
10849 final long origId = Binder.clearCallingIdentity();
10850 bringDownServiceLocked(r, false);
10851 Binder.restoreCallingIdentity(origId);
10852 return true;
10853 }
10854 }
10855 return false;
10856 }
10857
10858 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010859 int id, Notification notification, boolean removeNotification) {
10860 final long origId = Binder.clearCallingIdentity();
10861 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010862 synchronized(this) {
10863 ServiceRecord r = findServiceLocked(className, token);
10864 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010865 if (id != 0) {
10866 if (notification == null) {
10867 throw new IllegalArgumentException("null notification");
10868 }
10869 if (r.foregroundId != id) {
10870 r.cancelNotification();
10871 r.foregroundId = id;
10872 }
10873 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10874 r.foregroundNoti = notification;
10875 r.isForeground = true;
10876 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010877 if (r.app != null) {
10878 updateServiceForegroundLocked(r.app, true);
10879 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010880 } else {
10881 if (r.isForeground) {
10882 r.isForeground = false;
10883 if (r.app != null) {
10884 updateServiceForegroundLocked(r.app, true);
10885 }
10886 }
10887 if (removeNotification) {
10888 r.cancelNotification();
10889 r.foregroundId = 0;
10890 r.foregroundNoti = null;
10891 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010892 }
10893 }
10894 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010895 } finally {
10896 Binder.restoreCallingIdentity(origId);
10897 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010898 }
10899
10900 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10901 boolean anyForeground = false;
10902 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10903 if (sr.isForeground) {
10904 anyForeground = true;
10905 break;
10906 }
10907 }
10908 if (anyForeground != proc.foregroundServices) {
10909 proc.foregroundServices = anyForeground;
10910 if (oomAdj) {
10911 updateOomAdjLocked();
10912 }
10913 }
10914 }
10915
10916 public int bindService(IApplicationThread caller, IBinder token,
10917 Intent service, String resolvedType,
10918 IServiceConnection connection, int flags) {
10919 // Refuse possible leaked file descriptors
10920 if (service != null && service.hasFileDescriptors() == true) {
10921 throw new IllegalArgumentException("File descriptors passed in Intent");
10922 }
10923
10924 synchronized(this) {
10925 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10926 + " type=" + resolvedType + " conn=" + connection.asBinder()
10927 + " flags=0x" + Integer.toHexString(flags));
10928 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10929 if (callerApp == null) {
10930 throw new SecurityException(
10931 "Unable to find app for caller " + caller
10932 + " (pid=" + Binder.getCallingPid()
10933 + ") when binding service " + service);
10934 }
10935
10936 HistoryRecord activity = null;
10937 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010938 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010939 if (aindex < 0) {
10940 Log.w(TAG, "Binding with unknown activity: " + token);
10941 return 0;
10942 }
10943 activity = (HistoryRecord)mHistory.get(aindex);
10944 }
10945
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010946 int clientLabel = 0;
10947 PendingIntent clientIntent = null;
10948
10949 if (callerApp.info.uid == Process.SYSTEM_UID) {
10950 // Hacky kind of thing -- allow system stuff to tell us
10951 // what they are, so we can report this elsewhere for
10952 // others to know why certain services are running.
10953 try {
10954 clientIntent = (PendingIntent)service.getParcelableExtra(
10955 Intent.EXTRA_CLIENT_INTENT);
10956 } catch (RuntimeException e) {
10957 }
10958 if (clientIntent != null) {
10959 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
10960 if (clientLabel != 0) {
10961 // There are no useful extras in the intent, trash them.
10962 // System code calling with this stuff just needs to know
10963 // this will happen.
10964 service = service.cloneFilter();
10965 }
10966 }
10967 }
10968
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010969 ServiceLookupResult res =
10970 retrieveServiceLocked(service, resolvedType,
10971 Binder.getCallingPid(), Binder.getCallingUid());
10972 if (res == null) {
10973 return 0;
10974 }
10975 if (res.record == null) {
10976 return -1;
10977 }
10978 ServiceRecord s = res.record;
10979
10980 final long origId = Binder.clearCallingIdentity();
10981
10982 if (unscheduleServiceRestartLocked(s)) {
10983 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10984 + s.shortName);
10985 }
10986
10987 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10988 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010989 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010990
10991 IBinder binder = connection.asBinder();
10992 s.connections.put(binder, c);
10993 b.connections.add(c);
10994 if (activity != null) {
10995 if (activity.connections == null) {
10996 activity.connections = new HashSet<ConnectionRecord>();
10997 }
10998 activity.connections.add(c);
10999 }
11000 b.client.connections.add(c);
11001 mServiceConnections.put(binder, c);
11002
11003 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11004 s.lastActivity = SystemClock.uptimeMillis();
11005 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11006 return 0;
11007 }
11008 }
11009
11010 if (s.app != null) {
11011 // This could have made the service more important.
11012 updateOomAdjLocked(s.app);
11013 }
11014
11015 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11016 + ": received=" + b.intent.received
11017 + " apps=" + b.intent.apps.size()
11018 + " doRebind=" + b.intent.doRebind);
11019
11020 if (s.app != null && b.intent.received) {
11021 // Service is already running, so we can immediately
11022 // publish the connection.
11023 try {
11024 c.conn.connected(s.name, b.intent.binder);
11025 } catch (Exception e) {
11026 Log.w(TAG, "Failure sending service " + s.shortName
11027 + " to connection " + c.conn.asBinder()
11028 + " (in " + c.binding.client.processName + ")", e);
11029 }
11030
11031 // If this is the first app connected back to this binding,
11032 // and the service had previously asked to be told when
11033 // rebound, then do so.
11034 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11035 requestServiceBindingLocked(s, b.intent, true);
11036 }
11037 } else if (!b.intent.requested) {
11038 requestServiceBindingLocked(s, b.intent, false);
11039 }
11040
11041 Binder.restoreCallingIdentity(origId);
11042 }
11043
11044 return 1;
11045 }
11046
11047 private void removeConnectionLocked(
11048 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11049 IBinder binder = c.conn.asBinder();
11050 AppBindRecord b = c.binding;
11051 ServiceRecord s = b.service;
11052 s.connections.remove(binder);
11053 b.connections.remove(c);
11054 if (c.activity != null && c.activity != skipAct) {
11055 if (c.activity.connections != null) {
11056 c.activity.connections.remove(c);
11057 }
11058 }
11059 if (b.client != skipApp) {
11060 b.client.connections.remove(c);
11061 }
11062 mServiceConnections.remove(binder);
11063
11064 if (b.connections.size() == 0) {
11065 b.intent.apps.remove(b.client);
11066 }
11067
11068 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11069 + ": shouldUnbind=" + b.intent.hasBound);
11070 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11071 && b.intent.hasBound) {
11072 try {
11073 bumpServiceExecutingLocked(s);
11074 updateOomAdjLocked(s.app);
11075 b.intent.hasBound = false;
11076 // Assume the client doesn't want to know about a rebind;
11077 // we will deal with that later if it asks for one.
11078 b.intent.doRebind = false;
11079 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11080 } catch (Exception e) {
11081 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11082 serviceDoneExecutingLocked(s, true);
11083 }
11084 }
11085
11086 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11087 bringDownServiceLocked(s, false);
11088 }
11089 }
11090
11091 public boolean unbindService(IServiceConnection connection) {
11092 synchronized (this) {
11093 IBinder binder = connection.asBinder();
11094 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11095 ConnectionRecord r = mServiceConnections.get(binder);
11096 if (r == null) {
11097 Log.w(TAG, "Unbind failed: could not find connection for "
11098 + connection.asBinder());
11099 return false;
11100 }
11101
11102 final long origId = Binder.clearCallingIdentity();
11103
11104 removeConnectionLocked(r, null, null);
11105
11106 if (r.binding.service.app != null) {
11107 // This could have made the service less important.
11108 updateOomAdjLocked(r.binding.service.app);
11109 }
11110
11111 Binder.restoreCallingIdentity(origId);
11112 }
11113
11114 return true;
11115 }
11116
11117 public void publishService(IBinder token, Intent intent, IBinder service) {
11118 // Refuse possible leaked file descriptors
11119 if (intent != null && intent.hasFileDescriptors() == true) {
11120 throw new IllegalArgumentException("File descriptors passed in Intent");
11121 }
11122
11123 synchronized(this) {
11124 if (!(token instanceof ServiceRecord)) {
11125 throw new IllegalArgumentException("Invalid service token");
11126 }
11127 ServiceRecord r = (ServiceRecord)token;
11128
11129 final long origId = Binder.clearCallingIdentity();
11130
11131 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11132 + " " + intent + ": " + service);
11133 if (r != null) {
11134 Intent.FilterComparison filter
11135 = new Intent.FilterComparison(intent);
11136 IntentBindRecord b = r.bindings.get(filter);
11137 if (b != null && !b.received) {
11138 b.binder = service;
11139 b.requested = true;
11140 b.received = true;
11141 if (r.connections.size() > 0) {
11142 Iterator<ConnectionRecord> it
11143 = r.connections.values().iterator();
11144 while (it.hasNext()) {
11145 ConnectionRecord c = it.next();
11146 if (!filter.equals(c.binding.intent.intent)) {
11147 if (DEBUG_SERVICE) Log.v(
11148 TAG, "Not publishing to: " + c);
11149 if (DEBUG_SERVICE) Log.v(
11150 TAG, "Bound intent: " + c.binding.intent.intent);
11151 if (DEBUG_SERVICE) Log.v(
11152 TAG, "Published intent: " + intent);
11153 continue;
11154 }
11155 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11156 try {
11157 c.conn.connected(r.name, service);
11158 } catch (Exception e) {
11159 Log.w(TAG, "Failure sending service " + r.name +
11160 " to connection " + c.conn.asBinder() +
11161 " (in " + c.binding.client.processName + ")", e);
11162 }
11163 }
11164 }
11165 }
11166
11167 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11168
11169 Binder.restoreCallingIdentity(origId);
11170 }
11171 }
11172 }
11173
11174 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11175 // Refuse possible leaked file descriptors
11176 if (intent != null && intent.hasFileDescriptors() == true) {
11177 throw new IllegalArgumentException("File descriptors passed in Intent");
11178 }
11179
11180 synchronized(this) {
11181 if (!(token instanceof ServiceRecord)) {
11182 throw new IllegalArgumentException("Invalid service token");
11183 }
11184 ServiceRecord r = (ServiceRecord)token;
11185
11186 final long origId = Binder.clearCallingIdentity();
11187
11188 if (r != null) {
11189 Intent.FilterComparison filter
11190 = new Intent.FilterComparison(intent);
11191 IntentBindRecord b = r.bindings.get(filter);
11192 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11193 + " at " + b + ": apps="
11194 + (b != null ? b.apps.size() : 0));
11195 if (b != null) {
11196 if (b.apps.size() > 0) {
11197 // Applications have already bound since the last
11198 // unbind, so just rebind right here.
11199 requestServiceBindingLocked(r, b, true);
11200 } else {
11201 // Note to tell the service the next time there is
11202 // a new client.
11203 b.doRebind = true;
11204 }
11205 }
11206
11207 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11208
11209 Binder.restoreCallingIdentity(origId);
11210 }
11211 }
11212 }
11213
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011214 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011215 synchronized(this) {
11216 if (!(token instanceof ServiceRecord)) {
11217 throw new IllegalArgumentException("Invalid service token");
11218 }
11219 ServiceRecord r = (ServiceRecord)token;
11220 boolean inStopping = mStoppingServices.contains(token);
11221 if (r != null) {
11222 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11223 + ": nesting=" + r.executeNesting
11224 + ", inStopping=" + inStopping);
11225 if (r != token) {
11226 Log.w(TAG, "Done executing service " + r.name
11227 + " with incorrect token: given " + token
11228 + ", expected " + r);
11229 return;
11230 }
11231
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011232 if (type == 1) {
11233 // This is a call from a service start... take care of
11234 // book-keeping.
11235 r.callStart = true;
11236 switch (res) {
11237 case Service.START_STICKY_COMPATIBILITY:
11238 case Service.START_STICKY: {
11239 // We are done with the associated start arguments.
11240 r.findDeliveredStart(startId, true);
11241 // Don't stop if killed.
11242 r.stopIfKilled = false;
11243 break;
11244 }
11245 case Service.START_NOT_STICKY: {
11246 // We are done with the associated start arguments.
11247 r.findDeliveredStart(startId, true);
11248 if (r.lastStartId == startId) {
11249 // There is no more work, and this service
11250 // doesn't want to hang around if killed.
11251 r.stopIfKilled = true;
11252 }
11253 break;
11254 }
11255 case Service.START_REDELIVER_INTENT: {
11256 // We'll keep this item until they explicitly
11257 // call stop for it, but keep track of the fact
11258 // that it was delivered.
11259 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11260 if (si != null) {
11261 si.deliveryCount = 0;
11262 si.doneExecutingCount++;
11263 // Don't stop if killed.
11264 r.stopIfKilled = true;
11265 }
11266 break;
11267 }
11268 default:
11269 throw new IllegalArgumentException(
11270 "Unknown service start result: " + res);
11271 }
11272 if (res == Service.START_STICKY_COMPATIBILITY) {
11273 r.callStart = false;
11274 }
11275 }
11276
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011277 final long origId = Binder.clearCallingIdentity();
11278 serviceDoneExecutingLocked(r, inStopping);
11279 Binder.restoreCallingIdentity(origId);
11280 } else {
11281 Log.w(TAG, "Done executing unknown service " + r.name
11282 + " with token " + token);
11283 }
11284 }
11285 }
11286
11287 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11288 r.executeNesting--;
11289 if (r.executeNesting <= 0 && r.app != null) {
11290 r.app.executingServices.remove(r);
11291 if (r.app.executingServices.size() == 0) {
11292 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11293 }
11294 if (inStopping) {
11295 mStoppingServices.remove(r);
11296 }
11297 updateOomAdjLocked(r.app);
11298 }
11299 }
11300
11301 void serviceTimeout(ProcessRecord proc) {
11302 synchronized(this) {
11303 if (proc.executingServices.size() == 0 || proc.thread == null) {
11304 return;
11305 }
11306 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11307 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11308 ServiceRecord timeout = null;
11309 long nextTime = 0;
11310 while (it.hasNext()) {
11311 ServiceRecord sr = it.next();
11312 if (sr.executingStart < maxTime) {
11313 timeout = sr;
11314 break;
11315 }
11316 if (sr.executingStart > nextTime) {
11317 nextTime = sr.executingStart;
11318 }
11319 }
11320 if (timeout != null && mLRUProcesses.contains(proc)) {
11321 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011322 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011323 + timeout.name);
11324 } else {
11325 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11326 msg.obj = proc;
11327 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11328 }
11329 }
11330 }
11331
11332 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011333 // BACKUP AND RESTORE
11334 // =========================================================
11335
11336 // Cause the target app to be launched if necessary and its backup agent
11337 // instantiated. The backup agent will invoke backupAgentCreated() on the
11338 // activity manager to announce its creation.
11339 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11340 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11341 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11342
11343 synchronized(this) {
11344 // !!! TODO: currently no check here that we're already bound
11345 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11346 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11347 synchronized (stats) {
11348 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11349 }
11350
11351 BackupRecord r = new BackupRecord(ss, app, backupMode);
11352 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11353 // startProcessLocked() returns existing proc's record if it's already running
11354 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011355 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011356 if (proc == null) {
11357 Log.e(TAG, "Unable to start backup agent process " + r);
11358 return false;
11359 }
11360
11361 r.app = proc;
11362 mBackupTarget = r;
11363 mBackupAppName = app.packageName;
11364
Christopher Tate6fa95972009-06-05 18:43:55 -070011365 // Try not to kill the process during backup
11366 updateOomAdjLocked(proc);
11367
Christopher Tate181fafa2009-05-14 11:12:14 -070011368 // If the process is already attached, schedule the creation of the backup agent now.
11369 // If it is not yet live, this will be done when it attaches to the framework.
11370 if (proc.thread != null) {
11371 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11372 try {
11373 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11374 } catch (RemoteException e) {
11375 // !!! TODO: notify the backup manager that we crashed, or rely on
11376 // death notices, or...?
11377 }
11378 } else {
11379 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11380 }
11381 // Invariants: at this point, the target app process exists and the application
11382 // is either already running or in the process of coming up. mBackupTarget and
11383 // mBackupAppName describe the app, so that when it binds back to the AM we
11384 // know that it's scheduled for a backup-agent operation.
11385 }
11386
11387 return true;
11388 }
11389
11390 // A backup agent has just come up
11391 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11392 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11393 + " = " + agent);
11394
11395 synchronized(this) {
11396 if (!agentPackageName.equals(mBackupAppName)) {
11397 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11398 return;
11399 }
11400
Christopher Tate043dadc2009-06-02 16:11:00 -070011401 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011402 try {
11403 IBackupManager bm = IBackupManager.Stub.asInterface(
11404 ServiceManager.getService(Context.BACKUP_SERVICE));
11405 bm.agentConnected(agentPackageName, agent);
11406 } catch (RemoteException e) {
11407 // can't happen; the backup manager service is local
11408 } catch (Exception e) {
11409 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11410 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011411 } finally {
11412 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011413 }
11414 }
11415 }
11416
11417 // done with this agent
11418 public void unbindBackupAgent(ApplicationInfo appInfo) {
11419 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011420 if (appInfo == null) {
11421 Log.w(TAG, "unbind backup agent for null app");
11422 return;
11423 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011424
11425 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011426 if (mBackupAppName == null) {
11427 Log.w(TAG, "Unbinding backup agent with no active backup");
11428 return;
11429 }
11430
Christopher Tate181fafa2009-05-14 11:12:14 -070011431 if (!mBackupAppName.equals(appInfo.packageName)) {
11432 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11433 return;
11434 }
11435
Christopher Tate6fa95972009-06-05 18:43:55 -070011436 ProcessRecord proc = mBackupTarget.app;
11437 mBackupTarget = null;
11438 mBackupAppName = null;
11439
11440 // Not backing this app up any more; reset its OOM adjustment
11441 updateOomAdjLocked(proc);
11442
Christopher Tatec7b31e32009-06-10 15:49:30 -070011443 // If the app crashed during backup, 'thread' will be null here
11444 if (proc.thread != null) {
11445 try {
11446 proc.thread.scheduleDestroyBackupAgent(appInfo);
11447 } catch (Exception e) {
11448 Log.e(TAG, "Exception when unbinding backup agent:");
11449 e.printStackTrace();
11450 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011451 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011452 }
11453 }
11454 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011455 // BROADCASTS
11456 // =========================================================
11457
11458 private final List getStickies(String action, IntentFilter filter,
11459 List cur) {
11460 final ContentResolver resolver = mContext.getContentResolver();
11461 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11462 if (list == null) {
11463 return cur;
11464 }
11465 int N = list.size();
11466 for (int i=0; i<N; i++) {
11467 Intent intent = list.get(i);
11468 if (filter.match(resolver, intent, true, TAG) >= 0) {
11469 if (cur == null) {
11470 cur = new ArrayList<Intent>();
11471 }
11472 cur.add(intent);
11473 }
11474 }
11475 return cur;
11476 }
11477
11478 private final void scheduleBroadcastsLocked() {
11479 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11480 + mBroadcastsScheduled);
11481
11482 if (mBroadcastsScheduled) {
11483 return;
11484 }
11485 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11486 mBroadcastsScheduled = true;
11487 }
11488
11489 public Intent registerReceiver(IApplicationThread caller,
11490 IIntentReceiver receiver, IntentFilter filter, String permission) {
11491 synchronized(this) {
11492 ProcessRecord callerApp = null;
11493 if (caller != null) {
11494 callerApp = getRecordForAppLocked(caller);
11495 if (callerApp == null) {
11496 throw new SecurityException(
11497 "Unable to find app for caller " + caller
11498 + " (pid=" + Binder.getCallingPid()
11499 + ") when registering receiver " + receiver);
11500 }
11501 }
11502
11503 List allSticky = null;
11504
11505 // Look for any matching sticky broadcasts...
11506 Iterator actions = filter.actionsIterator();
11507 if (actions != null) {
11508 while (actions.hasNext()) {
11509 String action = (String)actions.next();
11510 allSticky = getStickies(action, filter, allSticky);
11511 }
11512 } else {
11513 allSticky = getStickies(null, filter, allSticky);
11514 }
11515
11516 // The first sticky in the list is returned directly back to
11517 // the client.
11518 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11519
11520 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11521 + ": " + sticky);
11522
11523 if (receiver == null) {
11524 return sticky;
11525 }
11526
11527 ReceiverList rl
11528 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11529 if (rl == null) {
11530 rl = new ReceiverList(this, callerApp,
11531 Binder.getCallingPid(),
11532 Binder.getCallingUid(), receiver);
11533 if (rl.app != null) {
11534 rl.app.receivers.add(rl);
11535 } else {
11536 try {
11537 receiver.asBinder().linkToDeath(rl, 0);
11538 } catch (RemoteException e) {
11539 return sticky;
11540 }
11541 rl.linkedToDeath = true;
11542 }
11543 mRegisteredReceivers.put(receiver.asBinder(), rl);
11544 }
11545 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11546 rl.add(bf);
11547 if (!bf.debugCheck()) {
11548 Log.w(TAG, "==> For Dynamic broadast");
11549 }
11550 mReceiverResolver.addFilter(bf);
11551
11552 // Enqueue broadcasts for all existing stickies that match
11553 // this filter.
11554 if (allSticky != null) {
11555 ArrayList receivers = new ArrayList();
11556 receivers.add(bf);
11557
11558 int N = allSticky.size();
11559 for (int i=0; i<N; i++) {
11560 Intent intent = (Intent)allSticky.get(i);
11561 BroadcastRecord r = new BroadcastRecord(intent, null,
11562 null, -1, -1, null, receivers, null, 0, null, null,
11563 false);
11564 if (mParallelBroadcasts.size() == 0) {
11565 scheduleBroadcastsLocked();
11566 }
11567 mParallelBroadcasts.add(r);
11568 }
11569 }
11570
11571 return sticky;
11572 }
11573 }
11574
11575 public void unregisterReceiver(IIntentReceiver receiver) {
11576 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11577
11578 boolean doNext = false;
11579
11580 synchronized(this) {
11581 ReceiverList rl
11582 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11583 if (rl != null) {
11584 if (rl.curBroadcast != null) {
11585 BroadcastRecord r = rl.curBroadcast;
11586 doNext = finishReceiverLocked(
11587 receiver.asBinder(), r.resultCode, r.resultData,
11588 r.resultExtras, r.resultAbort, true);
11589 }
11590
11591 if (rl.app != null) {
11592 rl.app.receivers.remove(rl);
11593 }
11594 removeReceiverLocked(rl);
11595 if (rl.linkedToDeath) {
11596 rl.linkedToDeath = false;
11597 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11598 }
11599 }
11600 }
11601
11602 if (!doNext) {
11603 return;
11604 }
11605
11606 final long origId = Binder.clearCallingIdentity();
11607 processNextBroadcast(false);
11608 trimApplications();
11609 Binder.restoreCallingIdentity(origId);
11610 }
11611
11612 void removeReceiverLocked(ReceiverList rl) {
11613 mRegisteredReceivers.remove(rl.receiver.asBinder());
11614 int N = rl.size();
11615 for (int i=0; i<N; i++) {
11616 mReceiverResolver.removeFilter(rl.get(i));
11617 }
11618 }
11619
11620 private final int broadcastIntentLocked(ProcessRecord callerApp,
11621 String callerPackage, Intent intent, String resolvedType,
11622 IIntentReceiver resultTo, int resultCode, String resultData,
11623 Bundle map, String requiredPermission,
11624 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11625 intent = new Intent(intent);
11626
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011627 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011628 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11629 + " ordered=" + ordered);
11630 if ((resultTo != null) && !ordered) {
11631 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11632 }
11633
11634 // Handle special intents: if this broadcast is from the package
11635 // manager about a package being removed, we need to remove all of
11636 // its activities from the history stack.
11637 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11638 intent.getAction());
11639 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11640 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11641 || uidRemoved) {
11642 if (checkComponentPermission(
11643 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11644 callingPid, callingUid, -1)
11645 == PackageManager.PERMISSION_GRANTED) {
11646 if (uidRemoved) {
11647 final Bundle intentExtras = intent.getExtras();
11648 final int uid = intentExtras != null
11649 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11650 if (uid >= 0) {
11651 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11652 synchronized (bs) {
11653 bs.removeUidStatsLocked(uid);
11654 }
11655 }
11656 } else {
11657 Uri data = intent.getData();
11658 String ssp;
11659 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11660 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11661 uninstallPackageLocked(ssp,
11662 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011663 AttributeCache ac = AttributeCache.instance();
11664 if (ac != null) {
11665 ac.removePackage(ssp);
11666 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011667 }
11668 }
11669 }
11670 } else {
11671 String msg = "Permission Denial: " + intent.getAction()
11672 + " broadcast from " + callerPackage + " (pid=" + callingPid
11673 + ", uid=" + callingUid + ")"
11674 + " requires "
11675 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11676 Log.w(TAG, msg);
11677 throw new SecurityException(msg);
11678 }
11679 }
11680
11681 /*
11682 * If this is the time zone changed action, queue up a message that will reset the timezone
11683 * of all currently running processes. This message will get queued up before the broadcast
11684 * happens.
11685 */
11686 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11687 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11688 }
11689
Dianne Hackborn854060af2009-07-09 18:14:31 -070011690 /*
11691 * Prevent non-system code (defined here to be non-persistent
11692 * processes) from sending protected broadcasts.
11693 */
11694 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11695 || callingUid == Process.SHELL_UID || callingUid == 0) {
11696 // Always okay.
11697 } else if (callerApp == null || !callerApp.persistent) {
11698 try {
11699 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11700 intent.getAction())) {
11701 String msg = "Permission Denial: not allowed to send broadcast "
11702 + intent.getAction() + " from pid="
11703 + callingPid + ", uid=" + callingUid;
11704 Log.w(TAG, msg);
11705 throw new SecurityException(msg);
11706 }
11707 } catch (RemoteException e) {
11708 Log.w(TAG, "Remote exception", e);
11709 return BROADCAST_SUCCESS;
11710 }
11711 }
11712
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011713 // Add to the sticky list if requested.
11714 if (sticky) {
11715 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11716 callingPid, callingUid)
11717 != PackageManager.PERMISSION_GRANTED) {
11718 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11719 + callingPid + ", uid=" + callingUid
11720 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11721 Log.w(TAG, msg);
11722 throw new SecurityException(msg);
11723 }
11724 if (requiredPermission != null) {
11725 Log.w(TAG, "Can't broadcast sticky intent " + intent
11726 + " and enforce permission " + requiredPermission);
11727 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11728 }
11729 if (intent.getComponent() != null) {
11730 throw new SecurityException(
11731 "Sticky broadcasts can't target a specific component");
11732 }
11733 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11734 if (list == null) {
11735 list = new ArrayList<Intent>();
11736 mStickyBroadcasts.put(intent.getAction(), list);
11737 }
11738 int N = list.size();
11739 int i;
11740 for (i=0; i<N; i++) {
11741 if (intent.filterEquals(list.get(i))) {
11742 // This sticky already exists, replace it.
11743 list.set(i, new Intent(intent));
11744 break;
11745 }
11746 }
11747 if (i >= N) {
11748 list.add(new Intent(intent));
11749 }
11750 }
11751
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011752 // Figure out who all will receive this broadcast.
11753 List receivers = null;
11754 List<BroadcastFilter> registeredReceivers = null;
11755 try {
11756 if (intent.getComponent() != null) {
11757 // Broadcast is going to one specific receiver class...
11758 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011759 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011760 if (ai != null) {
11761 receivers = new ArrayList();
11762 ResolveInfo ri = new ResolveInfo();
11763 ri.activityInfo = ai;
11764 receivers.add(ri);
11765 }
11766 } else {
11767 // Need to resolve the intent to interested receivers...
11768 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11769 == 0) {
11770 receivers =
11771 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011772 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011773 }
Mihai Preda074edef2009-05-18 17:13:31 +020011774 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011775 }
11776 } catch (RemoteException ex) {
11777 // pm is in same process, this will never happen.
11778 }
11779
11780 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11781 if (!ordered && NR > 0) {
11782 // If we are not serializing this broadcast, then send the
11783 // registered receivers separately so they don't wait for the
11784 // components to be launched.
11785 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11786 callerPackage, callingPid, callingUid, requiredPermission,
11787 registeredReceivers, resultTo, resultCode, resultData, map,
11788 ordered);
11789 if (DEBUG_BROADCAST) Log.v(
11790 TAG, "Enqueueing parallel broadcast " + r
11791 + ": prev had " + mParallelBroadcasts.size());
11792 mParallelBroadcasts.add(r);
11793 scheduleBroadcastsLocked();
11794 registeredReceivers = null;
11795 NR = 0;
11796 }
11797
11798 // Merge into one list.
11799 int ir = 0;
11800 if (receivers != null) {
11801 // A special case for PACKAGE_ADDED: do not allow the package
11802 // being added to see this broadcast. This prevents them from
11803 // using this as a back door to get run as soon as they are
11804 // installed. Maybe in the future we want to have a special install
11805 // broadcast or such for apps, but we'd like to deliberately make
11806 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011807 boolean skip = false;
11808 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011809 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011810 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11811 skip = true;
11812 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11813 skip = true;
11814 }
11815 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011816 ? intent.getData().getSchemeSpecificPart()
11817 : null;
11818 if (skipPackage != null && receivers != null) {
11819 int NT = receivers.size();
11820 for (int it=0; it<NT; it++) {
11821 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11822 if (curt.activityInfo.packageName.equals(skipPackage)) {
11823 receivers.remove(it);
11824 it--;
11825 NT--;
11826 }
11827 }
11828 }
11829
11830 int NT = receivers != null ? receivers.size() : 0;
11831 int it = 0;
11832 ResolveInfo curt = null;
11833 BroadcastFilter curr = null;
11834 while (it < NT && ir < NR) {
11835 if (curt == null) {
11836 curt = (ResolveInfo)receivers.get(it);
11837 }
11838 if (curr == null) {
11839 curr = registeredReceivers.get(ir);
11840 }
11841 if (curr.getPriority() >= curt.priority) {
11842 // Insert this broadcast record into the final list.
11843 receivers.add(it, curr);
11844 ir++;
11845 curr = null;
11846 it++;
11847 NT++;
11848 } else {
11849 // Skip to the next ResolveInfo in the final list.
11850 it++;
11851 curt = null;
11852 }
11853 }
11854 }
11855 while (ir < NR) {
11856 if (receivers == null) {
11857 receivers = new ArrayList();
11858 }
11859 receivers.add(registeredReceivers.get(ir));
11860 ir++;
11861 }
11862
11863 if ((receivers != null && receivers.size() > 0)
11864 || resultTo != null) {
11865 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11866 callerPackage, callingPid, callingUid, requiredPermission,
11867 receivers, resultTo, resultCode, resultData, map, ordered);
11868 if (DEBUG_BROADCAST) Log.v(
11869 TAG, "Enqueueing ordered broadcast " + r
11870 + ": prev had " + mOrderedBroadcasts.size());
11871 if (DEBUG_BROADCAST) {
11872 int seq = r.intent.getIntExtra("seq", -1);
11873 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11874 }
11875 mOrderedBroadcasts.add(r);
11876 scheduleBroadcastsLocked();
11877 }
11878
11879 return BROADCAST_SUCCESS;
11880 }
11881
11882 public final int broadcastIntent(IApplicationThread caller,
11883 Intent intent, String resolvedType, IIntentReceiver resultTo,
11884 int resultCode, String resultData, Bundle map,
11885 String requiredPermission, boolean serialized, boolean sticky) {
11886 // Refuse possible leaked file descriptors
11887 if (intent != null && intent.hasFileDescriptors() == true) {
11888 throw new IllegalArgumentException("File descriptors passed in Intent");
11889 }
11890
11891 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011892 int flags = intent.getFlags();
11893
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011894 if (!mSystemReady) {
11895 // if the caller really truly claims to know what they're doing, go
11896 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011897 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11898 intent = new Intent(intent);
11899 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11900 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11901 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11902 + " before boot completion");
11903 throw new IllegalStateException("Cannot broadcast before boot completed");
11904 }
11905 }
11906
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011907 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
11908 throw new IllegalArgumentException(
11909 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
11910 }
11911
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011912 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11913 final int callingPid = Binder.getCallingPid();
11914 final int callingUid = Binder.getCallingUid();
11915 final long origId = Binder.clearCallingIdentity();
11916 int res = broadcastIntentLocked(callerApp,
11917 callerApp != null ? callerApp.info.packageName : null,
11918 intent, resolvedType, resultTo,
11919 resultCode, resultData, map, requiredPermission, serialized,
11920 sticky, callingPid, callingUid);
11921 Binder.restoreCallingIdentity(origId);
11922 return res;
11923 }
11924 }
11925
11926 int broadcastIntentInPackage(String packageName, int uid,
11927 Intent intent, String resolvedType, IIntentReceiver resultTo,
11928 int resultCode, String resultData, Bundle map,
11929 String requiredPermission, boolean serialized, boolean sticky) {
11930 synchronized(this) {
11931 final long origId = Binder.clearCallingIdentity();
11932 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11933 resultTo, resultCode, resultData, map, requiredPermission,
11934 serialized, sticky, -1, uid);
11935 Binder.restoreCallingIdentity(origId);
11936 return res;
11937 }
11938 }
11939
11940 public final void unbroadcastIntent(IApplicationThread caller,
11941 Intent intent) {
11942 // Refuse possible leaked file descriptors
11943 if (intent != null && intent.hasFileDescriptors() == true) {
11944 throw new IllegalArgumentException("File descriptors passed in Intent");
11945 }
11946
11947 synchronized(this) {
11948 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11949 != PackageManager.PERMISSION_GRANTED) {
11950 String msg = "Permission Denial: unbroadcastIntent() from pid="
11951 + Binder.getCallingPid()
11952 + ", uid=" + Binder.getCallingUid()
11953 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11954 Log.w(TAG, msg);
11955 throw new SecurityException(msg);
11956 }
11957 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11958 if (list != null) {
11959 int N = list.size();
11960 int i;
11961 for (i=0; i<N; i++) {
11962 if (intent.filterEquals(list.get(i))) {
11963 list.remove(i);
11964 break;
11965 }
11966 }
11967 }
11968 }
11969 }
11970
11971 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11972 String resultData, Bundle resultExtras, boolean resultAbort,
11973 boolean explicit) {
11974 if (mOrderedBroadcasts.size() == 0) {
11975 if (explicit) {
11976 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11977 }
11978 return false;
11979 }
11980 BroadcastRecord r = mOrderedBroadcasts.get(0);
11981 if (r.receiver == null) {
11982 if (explicit) {
11983 Log.w(TAG, "finishReceiver called but none active");
11984 }
11985 return false;
11986 }
11987 if (r.receiver != receiver) {
11988 Log.w(TAG, "finishReceiver called but active receiver is different");
11989 return false;
11990 }
11991 int state = r.state;
11992 r.state = r.IDLE;
11993 if (state == r.IDLE) {
11994 if (explicit) {
11995 Log.w(TAG, "finishReceiver called but state is IDLE");
11996 }
11997 }
11998 r.receiver = null;
11999 r.intent.setComponent(null);
12000 if (r.curApp != null) {
12001 r.curApp.curReceiver = null;
12002 }
12003 if (r.curFilter != null) {
12004 r.curFilter.receiverList.curBroadcast = null;
12005 }
12006 r.curFilter = null;
12007 r.curApp = null;
12008 r.curComponent = null;
12009 r.curReceiver = null;
12010 mPendingBroadcast = null;
12011
12012 r.resultCode = resultCode;
12013 r.resultData = resultData;
12014 r.resultExtras = resultExtras;
12015 r.resultAbort = resultAbort;
12016
12017 // We will process the next receiver right now if this is finishing
12018 // an app receiver (which is always asynchronous) or after we have
12019 // come back from calling a receiver.
12020 return state == BroadcastRecord.APP_RECEIVE
12021 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12022 }
12023
12024 public void finishReceiver(IBinder who, int resultCode, String resultData,
12025 Bundle resultExtras, boolean resultAbort) {
12026 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12027
12028 // Refuse possible leaked file descriptors
12029 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12030 throw new IllegalArgumentException("File descriptors passed in Bundle");
12031 }
12032
12033 boolean doNext;
12034
12035 final long origId = Binder.clearCallingIdentity();
12036
12037 synchronized(this) {
12038 doNext = finishReceiverLocked(
12039 who, resultCode, resultData, resultExtras, resultAbort, true);
12040 }
12041
12042 if (doNext) {
12043 processNextBroadcast(false);
12044 }
12045 trimApplications();
12046
12047 Binder.restoreCallingIdentity(origId);
12048 }
12049
12050 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12051 if (r.nextReceiver > 0) {
12052 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12053 if (curReceiver instanceof BroadcastFilter) {
12054 BroadcastFilter bf = (BroadcastFilter) curReceiver;
12055 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
12056 System.identityHashCode(r),
12057 r.intent.getAction(),
12058 r.nextReceiver - 1,
12059 System.identityHashCode(bf));
12060 } else {
12061 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12062 System.identityHashCode(r),
12063 r.intent.getAction(),
12064 r.nextReceiver - 1,
12065 ((ResolveInfo)curReceiver).toString());
12066 }
12067 } else {
12068 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12069 + r);
12070 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
12071 System.identityHashCode(r),
12072 r.intent.getAction(),
12073 r.nextReceiver,
12074 "NONE");
12075 }
12076 }
12077
12078 private final void broadcastTimeout() {
12079 synchronized (this) {
12080 if (mOrderedBroadcasts.size() == 0) {
12081 return;
12082 }
12083 long now = SystemClock.uptimeMillis();
12084 BroadcastRecord r = mOrderedBroadcasts.get(0);
12085 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
12086 if (DEBUG_BROADCAST) Log.v(TAG,
12087 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
12088 + (r.startTime + BROADCAST_TIMEOUT));
12089 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12090 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12091 return;
12092 }
12093
12094 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
12095 r.startTime = now;
12096 r.anrCount++;
12097
12098 // Current receiver has passed its expiration date.
12099 if (r.nextReceiver <= 0) {
12100 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12101 return;
12102 }
12103
12104 ProcessRecord app = null;
12105
12106 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12107 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12108 logBroadcastReceiverDiscard(r);
12109 if (curReceiver instanceof BroadcastFilter) {
12110 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12111 if (bf.receiverList.pid != 0
12112 && bf.receiverList.pid != MY_PID) {
12113 synchronized (this.mPidsSelfLocked) {
12114 app = this.mPidsSelfLocked.get(
12115 bf.receiverList.pid);
12116 }
12117 }
12118 } else {
12119 app = r.curApp;
12120 }
12121
12122 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070012123 appNotRespondingLocked(app, null, null,
12124 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012125 }
12126
12127 if (mPendingBroadcast == r) {
12128 mPendingBroadcast = null;
12129 }
12130
12131 // Move on to the next receiver.
12132 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12133 r.resultExtras, r.resultAbort, true);
12134 scheduleBroadcastsLocked();
12135 }
12136 }
12137
12138 private final void processCurBroadcastLocked(BroadcastRecord r,
12139 ProcessRecord app) throws RemoteException {
12140 if (app.thread == null) {
12141 throw new RemoteException();
12142 }
12143 r.receiver = app.thread.asBinder();
12144 r.curApp = app;
12145 app.curReceiver = r;
12146 updateLRUListLocked(app, true);
12147
12148 // Tell the application to launch this receiver.
12149 r.intent.setComponent(r.curComponent);
12150
12151 boolean started = false;
12152 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012153 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012154 "Delivering to component " + r.curComponent
12155 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012156 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012157 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12158 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12159 started = true;
12160 } finally {
12161 if (!started) {
12162 r.receiver = null;
12163 r.curApp = null;
12164 app.curReceiver = null;
12165 }
12166 }
12167
12168 }
12169
12170 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
12171 Intent intent, int resultCode, String data,
12172 Bundle extras, boolean ordered) throws RemoteException {
12173 if (app != null && app.thread != null) {
12174 // If we have an app thread, do the call through that so it is
12175 // correctly ordered with other one-way calls.
12176 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
12177 data, extras, ordered);
12178 } else {
12179 receiver.performReceive(intent, resultCode, data, extras, ordered);
12180 }
12181 }
12182
12183 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12184 BroadcastFilter filter, boolean ordered) {
12185 boolean skip = false;
12186 if (filter.requiredPermission != null) {
12187 int perm = checkComponentPermission(filter.requiredPermission,
12188 r.callingPid, r.callingUid, -1);
12189 if (perm != PackageManager.PERMISSION_GRANTED) {
12190 Log.w(TAG, "Permission Denial: broadcasting "
12191 + r.intent.toString()
12192 + " from " + r.callerPackage + " (pid="
12193 + r.callingPid + ", uid=" + r.callingUid + ")"
12194 + " requires " + filter.requiredPermission
12195 + " due to registered receiver " + filter);
12196 skip = true;
12197 }
12198 }
12199 if (r.requiredPermission != null) {
12200 int perm = checkComponentPermission(r.requiredPermission,
12201 filter.receiverList.pid, filter.receiverList.uid, -1);
12202 if (perm != PackageManager.PERMISSION_GRANTED) {
12203 Log.w(TAG, "Permission Denial: receiving "
12204 + r.intent.toString()
12205 + " to " + filter.receiverList.app
12206 + " (pid=" + filter.receiverList.pid
12207 + ", uid=" + filter.receiverList.uid + ")"
12208 + " requires " + r.requiredPermission
12209 + " due to sender " + r.callerPackage
12210 + " (uid " + r.callingUid + ")");
12211 skip = true;
12212 }
12213 }
12214
12215 if (!skip) {
12216 // If this is not being sent as an ordered broadcast, then we
12217 // don't want to touch the fields that keep track of the current
12218 // state of ordered broadcasts.
12219 if (ordered) {
12220 r.receiver = filter.receiverList.receiver.asBinder();
12221 r.curFilter = filter;
12222 filter.receiverList.curBroadcast = r;
12223 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012224 if (filter.receiverList.app != null) {
12225 // Bump hosting application to no longer be in background
12226 // scheduling class. Note that we can't do that if there
12227 // isn't an app... but we can only be in that case for
12228 // things that directly call the IActivityManager API, which
12229 // are already core system stuff so don't matter for this.
12230 r.curApp = filter.receiverList.app;
12231 filter.receiverList.app.curReceiver = r;
12232 updateOomAdjLocked();
12233 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012234 }
12235 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012236 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012237 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012238 Log.i(TAG, "Delivering to " + filter.receiverList.app
12239 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012240 }
12241 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12242 new Intent(r.intent), r.resultCode,
12243 r.resultData, r.resultExtras, r.ordered);
12244 if (ordered) {
12245 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12246 }
12247 } catch (RemoteException e) {
12248 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12249 if (ordered) {
12250 r.receiver = null;
12251 r.curFilter = null;
12252 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012253 if (filter.receiverList.app != null) {
12254 filter.receiverList.app.curReceiver = null;
12255 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012256 }
12257 }
12258 }
12259 }
12260
12261 private final void processNextBroadcast(boolean fromMsg) {
12262 synchronized(this) {
12263 BroadcastRecord r;
12264
12265 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12266 + mParallelBroadcasts.size() + " broadcasts, "
12267 + mOrderedBroadcasts.size() + " serialized broadcasts");
12268
12269 updateCpuStats();
12270
12271 if (fromMsg) {
12272 mBroadcastsScheduled = false;
12273 }
12274
12275 // First, deliver any non-serialized broadcasts right away.
12276 while (mParallelBroadcasts.size() > 0) {
12277 r = mParallelBroadcasts.remove(0);
12278 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012279 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12280 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012281 for (int i=0; i<N; i++) {
12282 Object target = r.receivers.get(i);
12283 if (DEBUG_BROADCAST) Log.v(TAG,
12284 "Delivering non-serialized to registered "
12285 + target + ": " + r);
12286 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12287 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012288 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12289 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012290 }
12291
12292 // Now take care of the next serialized one...
12293
12294 // If we are waiting for a process to come up to handle the next
12295 // broadcast, then do nothing at this point. Just in case, we
12296 // check that the process we're waiting for still exists.
12297 if (mPendingBroadcast != null) {
12298 Log.i(TAG, "processNextBroadcast: waiting for "
12299 + mPendingBroadcast.curApp);
12300
12301 boolean isDead;
12302 synchronized (mPidsSelfLocked) {
12303 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12304 }
12305 if (!isDead) {
12306 // It's still alive, so keep waiting
12307 return;
12308 } else {
12309 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12310 + " died before responding to broadcast");
12311 mPendingBroadcast = null;
12312 }
12313 }
12314
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012315 boolean looped = false;
12316
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012317 do {
12318 if (mOrderedBroadcasts.size() == 0) {
12319 // No more broadcasts pending, so all done!
12320 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012321 if (looped) {
12322 // If we had finished the last ordered broadcast, then
12323 // make sure all processes have correct oom and sched
12324 // adjustments.
12325 updateOomAdjLocked();
12326 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012327 return;
12328 }
12329 r = mOrderedBroadcasts.get(0);
12330 boolean forceReceive = false;
12331
12332 // Ensure that even if something goes awry with the timeout
12333 // detection, we catch "hung" broadcasts here, discard them,
12334 // and continue to make progress.
12335 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12336 long now = SystemClock.uptimeMillis();
12337 if (r.dispatchTime > 0) {
12338 if ((numReceivers > 0) &&
12339 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12340 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12341 + " now=" + now
12342 + " dispatchTime=" + r.dispatchTime
12343 + " startTime=" + r.startTime
12344 + " intent=" + r.intent
12345 + " numReceivers=" + numReceivers
12346 + " nextReceiver=" + r.nextReceiver
12347 + " state=" + r.state);
12348 broadcastTimeout(); // forcibly finish this broadcast
12349 forceReceive = true;
12350 r.state = BroadcastRecord.IDLE;
12351 }
12352 }
12353
12354 if (r.state != BroadcastRecord.IDLE) {
12355 if (DEBUG_BROADCAST) Log.d(TAG,
12356 "processNextBroadcast() called when not idle (state="
12357 + r.state + ")");
12358 return;
12359 }
12360
12361 if (r.receivers == null || r.nextReceiver >= numReceivers
12362 || r.resultAbort || forceReceive) {
12363 // No more receivers for this broadcast! Send the final
12364 // result if requested...
12365 if (r.resultTo != null) {
12366 try {
12367 if (DEBUG_BROADCAST) {
12368 int seq = r.intent.getIntExtra("seq", -1);
12369 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12370 + " seq=" + seq + " app=" + r.callerApp);
12371 }
12372 performReceive(r.callerApp, r.resultTo,
12373 new Intent(r.intent), r.resultCode,
12374 r.resultData, r.resultExtras, false);
12375 } catch (RemoteException e) {
12376 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12377 }
12378 }
12379
12380 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12381 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12382
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012383 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12384 + r);
12385
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012386 // ... and on to the next...
12387 mOrderedBroadcasts.remove(0);
12388 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012389 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012390 continue;
12391 }
12392 } while (r == null);
12393
12394 // Get the next receiver...
12395 int recIdx = r.nextReceiver++;
12396
12397 // Keep track of when this receiver started, and make sure there
12398 // is a timeout message pending to kill it if need be.
12399 r.startTime = SystemClock.uptimeMillis();
12400 if (recIdx == 0) {
12401 r.dispatchTime = r.startTime;
12402
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012403 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12404 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012405 if (DEBUG_BROADCAST) Log.v(TAG,
12406 "Submitting BROADCAST_TIMEOUT_MSG for "
12407 + (r.startTime + BROADCAST_TIMEOUT));
12408 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12409 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12410 }
12411
12412 Object nextReceiver = r.receivers.get(recIdx);
12413 if (nextReceiver instanceof BroadcastFilter) {
12414 // Simple case: this is a registered receiver who gets
12415 // a direct call.
12416 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12417 if (DEBUG_BROADCAST) Log.v(TAG,
12418 "Delivering serialized to registered "
12419 + filter + ": " + r);
12420 deliverToRegisteredReceiver(r, filter, r.ordered);
12421 if (r.receiver == null || !r.ordered) {
12422 // The receiver has already finished, so schedule to
12423 // process the next one.
12424 r.state = BroadcastRecord.IDLE;
12425 scheduleBroadcastsLocked();
12426 }
12427 return;
12428 }
12429
12430 // Hard case: need to instantiate the receiver, possibly
12431 // starting its application process to host it.
12432
12433 ResolveInfo info =
12434 (ResolveInfo)nextReceiver;
12435
12436 boolean skip = false;
12437 int perm = checkComponentPermission(info.activityInfo.permission,
12438 r.callingPid, r.callingUid,
12439 info.activityInfo.exported
12440 ? -1 : info.activityInfo.applicationInfo.uid);
12441 if (perm != PackageManager.PERMISSION_GRANTED) {
12442 Log.w(TAG, "Permission Denial: broadcasting "
12443 + r.intent.toString()
12444 + " from " + r.callerPackage + " (pid=" + r.callingPid
12445 + ", uid=" + r.callingUid + ")"
12446 + " requires " + info.activityInfo.permission
12447 + " due to receiver " + info.activityInfo.packageName
12448 + "/" + info.activityInfo.name);
12449 skip = true;
12450 }
12451 if (r.callingUid != Process.SYSTEM_UID &&
12452 r.requiredPermission != null) {
12453 try {
12454 perm = ActivityThread.getPackageManager().
12455 checkPermission(r.requiredPermission,
12456 info.activityInfo.applicationInfo.packageName);
12457 } catch (RemoteException e) {
12458 perm = PackageManager.PERMISSION_DENIED;
12459 }
12460 if (perm != PackageManager.PERMISSION_GRANTED) {
12461 Log.w(TAG, "Permission Denial: receiving "
12462 + r.intent + " to "
12463 + info.activityInfo.applicationInfo.packageName
12464 + " requires " + r.requiredPermission
12465 + " due to sender " + r.callerPackage
12466 + " (uid " + r.callingUid + ")");
12467 skip = true;
12468 }
12469 }
12470 if (r.curApp != null && r.curApp.crashing) {
12471 // If the target process is crashing, just skip it.
12472 skip = true;
12473 }
12474
12475 if (skip) {
12476 r.receiver = null;
12477 r.curFilter = null;
12478 r.state = BroadcastRecord.IDLE;
12479 scheduleBroadcastsLocked();
12480 return;
12481 }
12482
12483 r.state = BroadcastRecord.APP_RECEIVE;
12484 String targetProcess = info.activityInfo.processName;
12485 r.curComponent = new ComponentName(
12486 info.activityInfo.applicationInfo.packageName,
12487 info.activityInfo.name);
12488 r.curReceiver = info.activityInfo;
12489
12490 // Is this receiver's application already running?
12491 ProcessRecord app = getProcessRecordLocked(targetProcess,
12492 info.activityInfo.applicationInfo.uid);
12493 if (app != null && app.thread != null) {
12494 try {
12495 processCurBroadcastLocked(r, app);
12496 return;
12497 } catch (RemoteException e) {
12498 Log.w(TAG, "Exception when sending broadcast to "
12499 + r.curComponent, e);
12500 }
12501
12502 // If a dead object exception was thrown -- fall through to
12503 // restart the application.
12504 }
12505
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012506 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012507 if ((r.curApp=startProcessLocked(targetProcess,
12508 info.activityInfo.applicationInfo, true,
12509 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012510 "broadcast", r.curComponent,
12511 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12512 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012513 // Ah, this recipient is unavailable. Finish it if necessary,
12514 // and mark the broadcast record as ready for the next.
12515 Log.w(TAG, "Unable to launch app "
12516 + info.activityInfo.applicationInfo.packageName + "/"
12517 + info.activityInfo.applicationInfo.uid + " for broadcast "
12518 + r.intent + ": process is bad");
12519 logBroadcastReceiverDiscard(r);
12520 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12521 r.resultExtras, r.resultAbort, true);
12522 scheduleBroadcastsLocked();
12523 r.state = BroadcastRecord.IDLE;
12524 return;
12525 }
12526
12527 mPendingBroadcast = r;
12528 }
12529 }
12530
12531 // =========================================================
12532 // INSTRUMENTATION
12533 // =========================================================
12534
12535 public boolean startInstrumentation(ComponentName className,
12536 String profileFile, int flags, Bundle arguments,
12537 IInstrumentationWatcher watcher) {
12538 // Refuse possible leaked file descriptors
12539 if (arguments != null && arguments.hasFileDescriptors()) {
12540 throw new IllegalArgumentException("File descriptors passed in Bundle");
12541 }
12542
12543 synchronized(this) {
12544 InstrumentationInfo ii = null;
12545 ApplicationInfo ai = null;
12546 try {
12547 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012548 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012549 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012550 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012551 } catch (PackageManager.NameNotFoundException e) {
12552 }
12553 if (ii == null) {
12554 reportStartInstrumentationFailure(watcher, className,
12555 "Unable to find instrumentation info for: " + className);
12556 return false;
12557 }
12558 if (ai == null) {
12559 reportStartInstrumentationFailure(watcher, className,
12560 "Unable to find instrumentation target package: " + ii.targetPackage);
12561 return false;
12562 }
12563
12564 int match = mContext.getPackageManager().checkSignatures(
12565 ii.targetPackage, ii.packageName);
12566 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12567 String msg = "Permission Denial: starting instrumentation "
12568 + className + " from pid="
12569 + Binder.getCallingPid()
12570 + ", uid=" + Binder.getCallingPid()
12571 + " not allowed because package " + ii.packageName
12572 + " does not have a signature matching the target "
12573 + ii.targetPackage;
12574 reportStartInstrumentationFailure(watcher, className, msg);
12575 throw new SecurityException(msg);
12576 }
12577
12578 final long origId = Binder.clearCallingIdentity();
12579 uninstallPackageLocked(ii.targetPackage, -1, true);
12580 ProcessRecord app = addAppLocked(ai);
12581 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012582 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012583 app.instrumentationProfileFile = profileFile;
12584 app.instrumentationArguments = arguments;
12585 app.instrumentationWatcher = watcher;
12586 app.instrumentationResultClass = className;
12587 Binder.restoreCallingIdentity(origId);
12588 }
12589
12590 return true;
12591 }
12592
12593 /**
12594 * Report errors that occur while attempting to start Instrumentation. Always writes the
12595 * error to the logs, but if somebody is watching, send the report there too. This enables
12596 * the "am" command to report errors with more information.
12597 *
12598 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12599 * @param cn The component name of the instrumentation.
12600 * @param report The error report.
12601 */
12602 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12603 ComponentName cn, String report) {
12604 Log.w(TAG, report);
12605 try {
12606 if (watcher != null) {
12607 Bundle results = new Bundle();
12608 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12609 results.putString("Error", report);
12610 watcher.instrumentationStatus(cn, -1, results);
12611 }
12612 } catch (RemoteException e) {
12613 Log.w(TAG, e);
12614 }
12615 }
12616
12617 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12618 if (app.instrumentationWatcher != null) {
12619 try {
12620 // NOTE: IInstrumentationWatcher *must* be oneway here
12621 app.instrumentationWatcher.instrumentationFinished(
12622 app.instrumentationClass,
12623 resultCode,
12624 results);
12625 } catch (RemoteException e) {
12626 }
12627 }
12628 app.instrumentationWatcher = null;
12629 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012630 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012631 app.instrumentationProfileFile = null;
12632 app.instrumentationArguments = null;
12633
12634 uninstallPackageLocked(app.processName, -1, false);
12635 }
12636
12637 public void finishInstrumentation(IApplicationThread target,
12638 int resultCode, Bundle results) {
12639 // Refuse possible leaked file descriptors
12640 if (results != null && results.hasFileDescriptors()) {
12641 throw new IllegalArgumentException("File descriptors passed in Intent");
12642 }
12643
12644 synchronized(this) {
12645 ProcessRecord app = getRecordForAppLocked(target);
12646 if (app == null) {
12647 Log.w(TAG, "finishInstrumentation: no app for " + target);
12648 return;
12649 }
12650 final long origId = Binder.clearCallingIdentity();
12651 finishInstrumentationLocked(app, resultCode, results);
12652 Binder.restoreCallingIdentity(origId);
12653 }
12654 }
12655
12656 // =========================================================
12657 // CONFIGURATION
12658 // =========================================================
12659
12660 public ConfigurationInfo getDeviceConfigurationInfo() {
12661 ConfigurationInfo config = new ConfigurationInfo();
12662 synchronized (this) {
12663 config.reqTouchScreen = mConfiguration.touchscreen;
12664 config.reqKeyboardType = mConfiguration.keyboard;
12665 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012666 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12667 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012668 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12669 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012670 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12671 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012672 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12673 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012674 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012675 }
12676 return config;
12677 }
12678
12679 public Configuration getConfiguration() {
12680 Configuration ci;
12681 synchronized(this) {
12682 ci = new Configuration(mConfiguration);
12683 }
12684 return ci;
12685 }
12686
12687 public void updateConfiguration(Configuration values) {
12688 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12689 "updateConfiguration()");
12690
12691 synchronized(this) {
12692 if (values == null && mWindowManager != null) {
12693 // sentinel: fetch the current configuration from the window manager
12694 values = mWindowManager.computeNewConfiguration();
12695 }
12696
12697 final long origId = Binder.clearCallingIdentity();
12698 updateConfigurationLocked(values, null);
12699 Binder.restoreCallingIdentity(origId);
12700 }
12701 }
12702
12703 /**
12704 * Do either or both things: (1) change the current configuration, and (2)
12705 * make sure the given activity is running with the (now) current
12706 * configuration. Returns true if the activity has been left running, or
12707 * false if <var>starting</var> is being destroyed to match the new
12708 * configuration.
12709 */
12710 public boolean updateConfigurationLocked(Configuration values,
12711 HistoryRecord starting) {
12712 int changes = 0;
12713
12714 boolean kept = true;
12715
12716 if (values != null) {
12717 Configuration newConfig = new Configuration(mConfiguration);
12718 changes = newConfig.updateFrom(values);
12719 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012720 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012721 Log.i(TAG, "Updating configuration to: " + values);
12722 }
12723
12724 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12725
12726 if (values.locale != null) {
12727 saveLocaleLocked(values.locale,
12728 !values.locale.equals(mConfiguration.locale),
12729 values.userSetLocale);
12730 }
12731
12732 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012733 Log.i(TAG, "Config changed: " + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012734
12735 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12736 msg.obj = new Configuration(mConfiguration);
12737 mHandler.sendMessage(msg);
12738
12739 final int N = mLRUProcesses.size();
12740 for (int i=0; i<N; i++) {
12741 ProcessRecord app = mLRUProcesses.get(i);
12742 try {
12743 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012744 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
12745 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012746 app.thread.scheduleConfigurationChanged(mConfiguration);
12747 }
12748 } catch (Exception e) {
12749 }
12750 }
12751 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12752 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12753 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012754
12755 AttributeCache ac = AttributeCache.instance();
12756 if (ac != null) {
12757 ac.updateConfiguration(mConfiguration);
12758 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012759 }
12760 }
12761
12762 if (changes != 0 && starting == null) {
12763 // If the configuration changed, and the caller is not already
12764 // in the process of starting an activity, then find the top
12765 // activity to check if its configuration needs to change.
12766 starting = topRunningActivityLocked(null);
12767 }
12768
12769 if (starting != null) {
12770 kept = ensureActivityConfigurationLocked(starting, changes);
12771 if (kept) {
12772 // If this didn't result in the starting activity being
12773 // destroyed, then we need to make sure at this point that all
12774 // other activities are made visible.
12775 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12776 + ", ensuring others are correct.");
12777 ensureActivitiesVisibleLocked(starting, changes);
12778 }
12779 }
12780
12781 return kept;
12782 }
12783
12784 private final boolean relaunchActivityLocked(HistoryRecord r,
12785 int changes, boolean andResume) {
12786 List<ResultInfo> results = null;
12787 List<Intent> newIntents = null;
12788 if (andResume) {
12789 results = r.results;
12790 newIntents = r.newIntents;
12791 }
12792 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12793 + " with results=" + results + " newIntents=" + newIntents
12794 + " andResume=" + andResume);
12795 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12796 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12797 r.task.taskId, r.shortComponentName);
12798
12799 r.startFreezingScreenLocked(r.app, 0);
12800
12801 try {
12802 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12803 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12804 changes, !andResume);
12805 // Note: don't need to call pauseIfSleepingLocked() here, because
12806 // the caller will only pass in 'andResume' if this activity is
12807 // currently resumed, which implies we aren't sleeping.
12808 } catch (RemoteException e) {
12809 return false;
12810 }
12811
12812 if (andResume) {
12813 r.results = null;
12814 r.newIntents = null;
12815 }
12816
12817 return true;
12818 }
12819
12820 /**
12821 * Make sure the given activity matches the current configuration. Returns
12822 * false if the activity had to be destroyed. Returns true if the
12823 * configuration is the same, or the activity will remain running as-is
12824 * for whatever reason. Ensures the HistoryRecord is updated with the
12825 * correct configuration and all other bookkeeping is handled.
12826 */
12827 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12828 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012829 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12830 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012831
12832 // Short circuit: if the two configurations are the exact same
12833 // object (the common case), then there is nothing to do.
12834 Configuration newConfig = mConfiguration;
12835 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012836 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12837 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012838 return true;
12839 }
12840
12841 // We don't worry about activities that are finishing.
12842 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012843 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012844 "Configuration doesn't matter in finishing " + r);
12845 r.stopFreezingScreenLocked(false);
12846 return true;
12847 }
12848
12849 // Okay we now are going to make this activity have the new config.
12850 // But then we need to figure out how it needs to deal with that.
12851 Configuration oldConfig = r.configuration;
12852 r.configuration = newConfig;
12853
12854 // If the activity isn't currently running, just leave the new
12855 // configuration and it will pick that up next time it starts.
12856 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012857 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012858 "Configuration doesn't matter not running " + r);
12859 r.stopFreezingScreenLocked(false);
12860 return true;
12861 }
12862
12863 // If the activity isn't persistent, there is a chance we will
12864 // need to restart it.
12865 if (!r.persistent) {
12866
12867 // Figure out what has changed between the two configurations.
12868 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012869 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
12870 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012871 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012872 + Integer.toHexString(r.info.configChanges)
12873 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012874 }
12875 if ((changes&(~r.info.configChanges)) != 0) {
12876 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12877 r.configChangeFlags |= changes;
12878 r.startFreezingScreenLocked(r.app, globalChanges);
12879 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012880 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12881 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012882 destroyActivityLocked(r, true);
12883 } else if (r.state == ActivityState.PAUSING) {
12884 // A little annoying: we are waiting for this activity to
12885 // finish pausing. Let's not do anything now, but just
12886 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012887 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12888 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012889 r.configDestroy = true;
12890 return true;
12891 } else if (r.state == ActivityState.RESUMED) {
12892 // Try to optimize this case: the configuration is changing
12893 // and we need to restart the top, resumed activity.
12894 // Instead of doing the normal handshaking, just say
12895 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012896 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12897 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012898 relaunchActivityLocked(r, r.configChangeFlags, true);
12899 r.configChangeFlags = 0;
12900 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012901 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12902 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012903 relaunchActivityLocked(r, r.configChangeFlags, false);
12904 r.configChangeFlags = 0;
12905 }
12906
12907 // All done... tell the caller we weren't able to keep this
12908 // activity around.
12909 return false;
12910 }
12911 }
12912
12913 // Default case: the activity can handle this new configuration, so
12914 // hand it over. Note that we don't need to give it the new
12915 // configuration, since we always send configuration changes to all
12916 // process when they happen so it can just use whatever configuration
12917 // it last got.
12918 if (r.app != null && r.app.thread != null) {
12919 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012920 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012921 r.app.thread.scheduleActivityConfigurationChanged(r);
12922 } catch (RemoteException e) {
12923 // If process died, whatever.
12924 }
12925 }
12926 r.stopFreezingScreenLocked(false);
12927
12928 return true;
12929 }
12930
12931 /**
12932 * Save the locale. You must be inside a synchronized (this) block.
12933 */
12934 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12935 if(isDiff) {
12936 SystemProperties.set("user.language", l.getLanguage());
12937 SystemProperties.set("user.region", l.getCountry());
12938 }
12939
12940 if(isPersist) {
12941 SystemProperties.set("persist.sys.language", l.getLanguage());
12942 SystemProperties.set("persist.sys.country", l.getCountry());
12943 SystemProperties.set("persist.sys.localevar", l.getVariant());
12944 }
12945 }
12946
12947 // =========================================================
12948 // LIFETIME MANAGEMENT
12949 // =========================================================
12950
12951 private final int computeOomAdjLocked(
12952 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12953 if (mAdjSeq == app.adjSeq) {
12954 // This adjustment has already been computed.
12955 return app.curAdj;
12956 }
12957
12958 if (app.thread == null) {
12959 app.adjSeq = mAdjSeq;
12960 return (app.curAdj=EMPTY_APP_ADJ);
12961 }
12962
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012963 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
12964 // The max adjustment doesn't allow this app to be anything
12965 // below foreground, so it is not worth doing work for it.
12966 app.adjType = "fixed";
12967 app.adjSeq = mAdjSeq;
12968 app.curRawAdj = app.maxAdj;
12969 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
12970 return (app.curAdj=app.maxAdj);
12971 }
12972
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070012973 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012974 app.adjSource = null;
12975 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012976
The Android Open Source Project4df24232009-03-05 14:34:35 -080012977 // Determine the importance of the process, starting with most
12978 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012979 int adj;
12980 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012981 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012982 // The last app on the list is the foreground app.
12983 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012984 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012985 } else if (app.instrumentationClass != null) {
12986 // Don't want to kill running instrumentation.
12987 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012988 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012989 } else if (app.persistentActivities > 0) {
12990 // Special persistent activities... shouldn't be used these days.
12991 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012992 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012993 } else if (app.curReceiver != null ||
12994 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12995 // An app that is currently receiving a broadcast also
12996 // counts as being in the foreground.
12997 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012998 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012999 } else if (app.executingServices.size() > 0) {
13000 // An app that is currently executing a service callback also
13001 // counts as being in the foreground.
13002 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013003 app.adjType = "exec-service";
13004 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013005 // The user is aware of this app, so make it visible.
13006 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013007 app.adjType = "foreground-service";
13008 } else if (app.forcingToForeground != null) {
13009 // The user is aware of this app, so make it visible.
13010 adj = VISIBLE_APP_ADJ;
13011 app.adjType = "force-foreground";
13012 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013013 } else if (app == mHomeProcess) {
13014 // This process is hosting what we currently consider to be the
13015 // home app, so we don't want to let it go into the background.
13016 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013017 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013018 } else if ((N=app.activities.size()) != 0) {
13019 // This app is in the background with paused activities.
13020 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013021 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013022 for (int j=0; j<N; j++) {
13023 if (((HistoryRecord)app.activities.get(j)).visible) {
13024 // This app has a visible activity!
13025 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013026 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013027 break;
13028 }
13029 }
13030 } else {
13031 // A very not-needed process.
13032 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013033 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013034 }
13035
The Android Open Source Project4df24232009-03-05 14:34:35 -080013036 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013037 // there are applications dependent on our services or providers, but
13038 // this gives us a baseline and makes sure we don't get into an
13039 // infinite recursion.
13040 app.adjSeq = mAdjSeq;
13041 app.curRawAdj = adj;
13042 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
13043
Christopher Tate6fa95972009-06-05 18:43:55 -070013044 if (mBackupTarget != null && app == mBackupTarget.app) {
13045 // If possible we want to avoid killing apps while they're being backed up
13046 if (adj > BACKUP_APP_ADJ) {
13047 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13048 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013049 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070013050 }
13051 }
13052
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013053 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013054 final long now = SystemClock.uptimeMillis();
13055 // This process is more important if the top activity is
13056 // bound to the service.
13057 Iterator jt = app.services.iterator();
13058 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13059 ServiceRecord s = (ServiceRecord)jt.next();
13060 if (s.startRequested) {
13061 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13062 // This service has seen some activity within
13063 // recent memory, so we will keep its process ahead
13064 // of the background processes.
13065 if (adj > SECONDARY_SERVER_ADJ) {
13066 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013067 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013068 }
13069 }
13070 }
13071 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
13072 Iterator<ConnectionRecord> kt
13073 = s.connections.values().iterator();
13074 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13075 // XXX should compute this based on the max of
13076 // all connected clients.
13077 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013078 if (cr.binding.client == app) {
13079 // Binding to ourself is not interesting.
13080 continue;
13081 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013082 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13083 ProcessRecord client = cr.binding.client;
13084 int myHiddenAdj = hiddenAdj;
13085 if (myHiddenAdj > client.hiddenAdj) {
13086 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13087 myHiddenAdj = client.hiddenAdj;
13088 } else {
13089 myHiddenAdj = VISIBLE_APP_ADJ;
13090 }
13091 }
13092 int clientAdj = computeOomAdjLocked(
13093 client, myHiddenAdj, TOP_APP);
13094 if (adj > clientAdj) {
13095 adj = clientAdj > VISIBLE_APP_ADJ
13096 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013097 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013098 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13099 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013100 app.adjSource = cr.binding.client;
13101 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013102 }
13103 }
13104 HistoryRecord a = cr.activity;
13105 //if (a != null) {
13106 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13107 //}
13108 if (a != null && adj > FOREGROUND_APP_ADJ &&
13109 (a.state == ActivityState.RESUMED
13110 || a.state == ActivityState.PAUSING)) {
13111 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013112 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013113 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13114 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013115 app.adjSource = a;
13116 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013117 }
13118 }
13119 }
13120 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013121
13122 // Finally, f this process has active services running in it, we
13123 // would like to avoid killing it unless it would prevent the current
13124 // application from running. By default we put the process in
13125 // with the rest of the background processes; as we scan through
13126 // its services we may bump it up from there.
13127 if (adj > hiddenAdj) {
13128 adj = hiddenAdj;
13129 app.adjType = "bg-services";
13130 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013131 }
13132
13133 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013134 Iterator jt = app.pubProviders.values().iterator();
13135 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13136 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13137 if (cpr.clients.size() != 0) {
13138 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13139 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13140 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013141 if (client == app) {
13142 // Being our own client is not interesting.
13143 continue;
13144 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013145 int myHiddenAdj = hiddenAdj;
13146 if (myHiddenAdj > client.hiddenAdj) {
13147 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13148 myHiddenAdj = client.hiddenAdj;
13149 } else {
13150 myHiddenAdj = FOREGROUND_APP_ADJ;
13151 }
13152 }
13153 int clientAdj = computeOomAdjLocked(
13154 client, myHiddenAdj, TOP_APP);
13155 if (adj > clientAdj) {
13156 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013157 ? clientAdj : FOREGROUND_APP_ADJ;
13158 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013159 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13160 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013161 app.adjSource = client;
13162 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013163 }
13164 }
13165 }
13166 // If the provider has external (non-framework) process
13167 // dependencies, ensure that its adjustment is at least
13168 // FOREGROUND_APP_ADJ.
13169 if (cpr.externals != 0) {
13170 if (adj > FOREGROUND_APP_ADJ) {
13171 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013172 app.adjType = "provider";
13173 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013174 }
13175 }
13176 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013177
13178 // Finally, if this process has published any content providers,
13179 // then its adjustment makes it at least as important as any of the
13180 // processes using those providers, and no less important than
13181 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
13182 if (adj > CONTENT_PROVIDER_ADJ) {
13183 adj = CONTENT_PROVIDER_ADJ;
13184 app.adjType = "pub-providers";
13185 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013186 }
13187
13188 app.curRawAdj = adj;
13189
13190 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13191 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13192 if (adj > app.maxAdj) {
13193 adj = app.maxAdj;
13194 }
13195
13196 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013197 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013198 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
13199 : Process.THREAD_GROUP_DEFAULT;
13200
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013201 return adj;
13202 }
13203
13204 /**
13205 * Ask a given process to GC right now.
13206 */
13207 final void performAppGcLocked(ProcessRecord app) {
13208 try {
13209 app.lastRequestedGc = SystemClock.uptimeMillis();
13210 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013211 if (app.reportLowMemory) {
13212 app.reportLowMemory = false;
13213 app.thread.scheduleLowMemory();
13214 } else {
13215 app.thread.processInBackground();
13216 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013217 }
13218 } catch (Exception e) {
13219 // whatever.
13220 }
13221 }
13222
13223 /**
13224 * Returns true if things are idle enough to perform GCs.
13225 */
13226 private final boolean canGcNow() {
13227 return mParallelBroadcasts.size() == 0
13228 && mOrderedBroadcasts.size() == 0
13229 && (mSleeping || (mResumedActivity != null &&
13230 mResumedActivity.idle));
13231 }
13232
13233 /**
13234 * Perform GCs on all processes that are waiting for it, but only
13235 * if things are idle.
13236 */
13237 final void performAppGcsLocked() {
13238 final int N = mProcessesToGc.size();
13239 if (N <= 0) {
13240 return;
13241 }
13242 if (canGcNow()) {
13243 while (mProcessesToGc.size() > 0) {
13244 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013245 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13246 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13247 <= SystemClock.uptimeMillis()) {
13248 // To avoid spamming the system, we will GC processes one
13249 // at a time, waiting a few seconds between each.
13250 performAppGcLocked(proc);
13251 scheduleAppGcsLocked();
13252 return;
13253 } else {
13254 // It hasn't been long enough since we last GCed this
13255 // process... put it in the list to wait for its time.
13256 addProcessToGcListLocked(proc);
13257 break;
13258 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013259 }
13260 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013261
13262 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013263 }
13264 }
13265
13266 /**
13267 * If all looks good, perform GCs on all processes waiting for them.
13268 */
13269 final void performAppGcsIfAppropriateLocked() {
13270 if (canGcNow()) {
13271 performAppGcsLocked();
13272 return;
13273 }
13274 // Still not idle, wait some more.
13275 scheduleAppGcsLocked();
13276 }
13277
13278 /**
13279 * Schedule the execution of all pending app GCs.
13280 */
13281 final void scheduleAppGcsLocked() {
13282 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013283
13284 if (mProcessesToGc.size() > 0) {
13285 // Schedule a GC for the time to the next process.
13286 ProcessRecord proc = mProcessesToGc.get(0);
13287 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13288
13289 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13290 long now = SystemClock.uptimeMillis();
13291 if (when < (now+GC_TIMEOUT)) {
13292 when = now + GC_TIMEOUT;
13293 }
13294 mHandler.sendMessageAtTime(msg, when);
13295 }
13296 }
13297
13298 /**
13299 * Add a process to the array of processes waiting to be GCed. Keeps the
13300 * list in sorted order by the last GC time. The process can't already be
13301 * on the list.
13302 */
13303 final void addProcessToGcListLocked(ProcessRecord proc) {
13304 boolean added = false;
13305 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13306 if (mProcessesToGc.get(i).lastRequestedGc <
13307 proc.lastRequestedGc) {
13308 added = true;
13309 mProcessesToGc.add(i+1, proc);
13310 break;
13311 }
13312 }
13313 if (!added) {
13314 mProcessesToGc.add(0, proc);
13315 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013316 }
13317
13318 /**
13319 * Set up to ask a process to GC itself. This will either do it
13320 * immediately, or put it on the list of processes to gc the next
13321 * time things are idle.
13322 */
13323 final void scheduleAppGcLocked(ProcessRecord app) {
13324 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013325 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013326 return;
13327 }
13328 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013329 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013330 scheduleAppGcsLocked();
13331 }
13332 }
13333
13334 private final boolean updateOomAdjLocked(
13335 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13336 app.hiddenAdj = hiddenAdj;
13337
13338 if (app.thread == null) {
13339 return true;
13340 }
13341
13342 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
13343
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013344 if (app.pid != 0 && app.pid != MY_PID) {
13345 if (app.curRawAdj != app.setRawAdj) {
13346 if (app.curRawAdj > FOREGROUND_APP_ADJ
13347 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13348 // If this app is transitioning from foreground to
13349 // non-foreground, have it do a gc.
13350 scheduleAppGcLocked(app);
13351 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13352 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13353 // Likewise do a gc when an app is moving in to the
13354 // background (such as a service stopping).
13355 scheduleAppGcLocked(app);
13356 }
13357 app.setRawAdj = app.curRawAdj;
13358 }
13359 if (adj != app.setAdj) {
13360 if (Process.setOomAdj(app.pid, adj)) {
13361 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13362 TAG, "Set app " + app.processName +
13363 " oom adj to " + adj);
13364 app.setAdj = adj;
13365 } else {
13366 return false;
13367 }
13368 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013369 if (app.setSchedGroup != app.curSchedGroup) {
13370 app.setSchedGroup = app.curSchedGroup;
13371 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13372 "Setting process group of " + app.processName
13373 + " to " + app.curSchedGroup);
13374 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013375 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013376 try {
13377 Process.setProcessGroup(app.pid, app.curSchedGroup);
13378 } catch (Exception e) {
13379 Log.w(TAG, "Failed setting process group of " + app.pid
13380 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013381 e.printStackTrace();
13382 } finally {
13383 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013384 }
13385 }
13386 if (false) {
13387 if (app.thread != null) {
13388 try {
13389 app.thread.setSchedulingGroup(app.curSchedGroup);
13390 } catch (RemoteException e) {
13391 }
13392 }
13393 }
13394 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013395 }
13396
13397 return true;
13398 }
13399
13400 private final HistoryRecord resumedAppLocked() {
13401 HistoryRecord resumedActivity = mResumedActivity;
13402 if (resumedActivity == null || resumedActivity.app == null) {
13403 resumedActivity = mPausingActivity;
13404 if (resumedActivity == null || resumedActivity.app == null) {
13405 resumedActivity = topRunningActivityLocked(null);
13406 }
13407 }
13408 return resumedActivity;
13409 }
13410
13411 private final boolean updateOomAdjLocked(ProcessRecord app) {
13412 final HistoryRecord TOP_ACT = resumedAppLocked();
13413 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13414 int curAdj = app.curAdj;
13415 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13416 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13417
13418 mAdjSeq++;
13419
13420 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13421 if (res) {
13422 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13423 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13424 if (nowHidden != wasHidden) {
13425 // Changed to/from hidden state, so apps after it in the LRU
13426 // list may also be changed.
13427 updateOomAdjLocked();
13428 }
13429 }
13430 return res;
13431 }
13432
13433 private final boolean updateOomAdjLocked() {
13434 boolean didOomAdj = true;
13435 final HistoryRecord TOP_ACT = resumedAppLocked();
13436 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13437
13438 if (false) {
13439 RuntimeException e = new RuntimeException();
13440 e.fillInStackTrace();
13441 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13442 }
13443
13444 mAdjSeq++;
13445
13446 // First try updating the OOM adjustment for each of the
13447 // application processes based on their current state.
13448 int i = mLRUProcesses.size();
13449 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13450 while (i > 0) {
13451 i--;
13452 ProcessRecord app = mLRUProcesses.get(i);
13453 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13454 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13455 && app.curAdj == curHiddenAdj) {
13456 curHiddenAdj++;
13457 }
13458 } else {
13459 didOomAdj = false;
13460 }
13461 }
13462
13463 // todo: for now pretend like OOM ADJ didn't work, because things
13464 // aren't behaving as expected on Linux -- it's not killing processes.
13465 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13466 }
13467
13468 private final void trimApplications() {
13469 synchronized (this) {
13470 int i;
13471
13472 // First remove any unused application processes whose package
13473 // has been removed.
13474 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13475 final ProcessRecord app = mRemovedProcesses.get(i);
13476 if (app.activities.size() == 0
13477 && app.curReceiver == null && app.services.size() == 0) {
13478 Log.i(
13479 TAG, "Exiting empty application process "
13480 + app.processName + " ("
13481 + (app.thread != null ? app.thread.asBinder() : null)
13482 + ")\n");
13483 if (app.pid > 0 && app.pid != MY_PID) {
13484 Process.killProcess(app.pid);
13485 } else {
13486 try {
13487 app.thread.scheduleExit();
13488 } catch (Exception e) {
13489 // Ignore exceptions.
13490 }
13491 }
13492 cleanUpApplicationRecordLocked(app, false, -1);
13493 mRemovedProcesses.remove(i);
13494
13495 if (app.persistent) {
13496 if (app.persistent) {
13497 addAppLocked(app.info);
13498 }
13499 }
13500 }
13501 }
13502
13503 // Now try updating the OOM adjustment for each of the
13504 // application processes based on their current state.
13505 // If the setOomAdj() API is not supported, then go with our
13506 // back-up plan...
13507 if (!updateOomAdjLocked()) {
13508
13509 // Count how many processes are running services.
13510 int numServiceProcs = 0;
13511 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13512 final ProcessRecord app = mLRUProcesses.get(i);
13513
13514 if (app.persistent || app.services.size() != 0
13515 || app.curReceiver != null
13516 || app.persistentActivities > 0) {
13517 // Don't count processes holding services against our
13518 // maximum process count.
13519 if (localLOGV) Log.v(
13520 TAG, "Not trimming app " + app + " with services: "
13521 + app.services);
13522 numServiceProcs++;
13523 }
13524 }
13525
13526 int curMaxProcs = mProcessLimit;
13527 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13528 if (mAlwaysFinishActivities) {
13529 curMaxProcs = 1;
13530 }
13531 curMaxProcs += numServiceProcs;
13532
13533 // Quit as many processes as we can to get down to the desired
13534 // process count. First remove any processes that no longer
13535 // have activites running in them.
13536 for ( i=0;
13537 i<mLRUProcesses.size()
13538 && mLRUProcesses.size() > curMaxProcs;
13539 i++) {
13540 final ProcessRecord app = mLRUProcesses.get(i);
13541 // Quit an application only if it is not currently
13542 // running any activities.
13543 if (!app.persistent && app.activities.size() == 0
13544 && app.curReceiver == null && app.services.size() == 0) {
13545 Log.i(
13546 TAG, "Exiting empty application process "
13547 + app.processName + " ("
13548 + (app.thread != null ? app.thread.asBinder() : null)
13549 + ")\n");
13550 if (app.pid > 0 && app.pid != MY_PID) {
13551 Process.killProcess(app.pid);
13552 } else {
13553 try {
13554 app.thread.scheduleExit();
13555 } catch (Exception e) {
13556 // Ignore exceptions.
13557 }
13558 }
13559 // todo: For now we assume the application is not buggy
13560 // or evil, and will quit as a result of our request.
13561 // Eventually we need to drive this off of the death
13562 // notification, and kill the process if it takes too long.
13563 cleanUpApplicationRecordLocked(app, false, i);
13564 i--;
13565 }
13566 }
13567
13568 // If we still have too many processes, now from the least
13569 // recently used process we start finishing activities.
13570 if (Config.LOGV) Log.v(
13571 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13572 " of " + curMaxProcs + " processes");
13573 for ( i=0;
13574 i<mLRUProcesses.size()
13575 && mLRUProcesses.size() > curMaxProcs;
13576 i++) {
13577 final ProcessRecord app = mLRUProcesses.get(i);
13578 // Quit the application only if we have a state saved for
13579 // all of its activities.
13580 boolean canQuit = !app.persistent && app.curReceiver == null
13581 && app.services.size() == 0
13582 && app.persistentActivities == 0;
13583 int NUMA = app.activities.size();
13584 int j;
13585 if (Config.LOGV) Log.v(
13586 TAG, "Looking to quit " + app.processName);
13587 for (j=0; j<NUMA && canQuit; j++) {
13588 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13589 if (Config.LOGV) Log.v(
13590 TAG, " " + r.intent.getComponent().flattenToShortString()
13591 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13592 canQuit = (r.haveState || !r.stateNotNeeded)
13593 && !r.visible && r.stopped;
13594 }
13595 if (canQuit) {
13596 // Finish all of the activities, and then the app itself.
13597 for (j=0; j<NUMA; j++) {
13598 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13599 if (!r.finishing) {
13600 destroyActivityLocked(r, false);
13601 }
13602 r.resultTo = null;
13603 }
13604 Log.i(TAG, "Exiting application process "
13605 + app.processName + " ("
13606 + (app.thread != null ? app.thread.asBinder() : null)
13607 + ")\n");
13608 if (app.pid > 0 && app.pid != MY_PID) {
13609 Process.killProcess(app.pid);
13610 } else {
13611 try {
13612 app.thread.scheduleExit();
13613 } catch (Exception e) {
13614 // Ignore exceptions.
13615 }
13616 }
13617 // todo: For now we assume the application is not buggy
13618 // or evil, and will quit as a result of our request.
13619 // Eventually we need to drive this off of the death
13620 // notification, and kill the process if it takes too long.
13621 cleanUpApplicationRecordLocked(app, false, i);
13622 i--;
13623 //dump();
13624 }
13625 }
13626
13627 }
13628
13629 int curMaxActivities = MAX_ACTIVITIES;
13630 if (mAlwaysFinishActivities) {
13631 curMaxActivities = 1;
13632 }
13633
13634 // Finally, if there are too many activities now running, try to
13635 // finish as many as we can to get back down to the limit.
13636 for ( i=0;
13637 i<mLRUActivities.size()
13638 && mLRUActivities.size() > curMaxActivities;
13639 i++) {
13640 final HistoryRecord r
13641 = (HistoryRecord)mLRUActivities.get(i);
13642
13643 // We can finish this one if we have its icicle saved and
13644 // it is not persistent.
13645 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13646 && r.stopped && !r.persistent && !r.finishing) {
13647 final int origSize = mLRUActivities.size();
13648 destroyActivityLocked(r, true);
13649
13650 // This will remove it from the LRU list, so keep
13651 // our index at the same value. Note that this check to
13652 // see if the size changes is just paranoia -- if
13653 // something unexpected happens, we don't want to end up
13654 // in an infinite loop.
13655 if (origSize > mLRUActivities.size()) {
13656 i--;
13657 }
13658 }
13659 }
13660 }
13661 }
13662
13663 /** This method sends the specified signal to each of the persistent apps */
13664 public void signalPersistentProcesses(int sig) throws RemoteException {
13665 if (sig != Process.SIGNAL_USR1) {
13666 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13667 }
13668
13669 synchronized (this) {
13670 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13671 != PackageManager.PERMISSION_GRANTED) {
13672 throw new SecurityException("Requires permission "
13673 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13674 }
13675
13676 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13677 ProcessRecord r = mLRUProcesses.get(i);
13678 if (r.thread != null && r.persistent) {
13679 Process.sendSignal(r.pid, sig);
13680 }
13681 }
13682 }
13683 }
13684
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013685 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013686 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013687
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013688 try {
13689 synchronized (this) {
13690 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13691 // its own permission.
13692 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13693 != PackageManager.PERMISSION_GRANTED) {
13694 throw new SecurityException("Requires permission "
13695 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013696 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013697
13698 if (start && fd == null) {
13699 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013700 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013701
13702 ProcessRecord proc = null;
13703 try {
13704 int pid = Integer.parseInt(process);
13705 synchronized (mPidsSelfLocked) {
13706 proc = mPidsSelfLocked.get(pid);
13707 }
13708 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013709 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013710
13711 if (proc == null) {
13712 HashMap<String, SparseArray<ProcessRecord>> all
13713 = mProcessNames.getMap();
13714 SparseArray<ProcessRecord> procs = all.get(process);
13715 if (procs != null && procs.size() > 0) {
13716 proc = procs.valueAt(0);
13717 }
13718 }
13719
13720 if (proc == null || proc.thread == null) {
13721 throw new IllegalArgumentException("Unknown process: " + process);
13722 }
13723
13724 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13725 if (isSecure) {
13726 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13727 throw new SecurityException("Process not debuggable: " + proc);
13728 }
13729 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013730
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013731 proc.thread.profilerControl(start, path, fd);
13732 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013733 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013734 }
13735 } catch (RemoteException e) {
13736 throw new IllegalStateException("Process disappeared");
13737 } finally {
13738 if (fd != null) {
13739 try {
13740 fd.close();
13741 } catch (IOException e) {
13742 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013743 }
13744 }
13745 }
13746
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013747 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13748 public void monitor() {
13749 synchronized (this) { }
13750 }
13751}