blob: 9554a22a2ae871531843c7da894b919b61e583ba [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
19import com.android.internal.os.BatteryStatsImpl;
Dianne Hackbornde7faf62009-06-30 13:27:30 -070020import com.android.server.AttributeCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import com.android.server.IntentResolver;
22import com.android.server.ProcessMap;
23import com.android.server.ProcessStats;
24import com.android.server.SystemServer;
25import com.android.server.Watchdog;
26import com.android.server.WindowManagerService;
27
28import android.app.Activity;
29import android.app.ActivityManager;
30import android.app.ActivityManagerNative;
31import android.app.ActivityThread;
32import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020033import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.app.Dialog;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070035import android.app.IActivityController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.app.IActivityWatcher;
37import android.app.IApplicationThread;
38import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.app.IServiceConnection;
40import android.app.IThumbnailReceiver;
41import android.app.Instrumentation;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070042import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.app.PendingIntent;
44import android.app.ResultInfo;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070045import android.app.Service;
Christopher Tate181fafa2009-05-14 11:12:14 -070046import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020047import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.ComponentName;
49import android.content.ContentResolver;
50import android.content.Context;
51import android.content.Intent;
52import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070053import android.content.IIntentReceiver;
54import android.content.IIntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.content.pm.ActivityInfo;
56import android.content.pm.ApplicationInfo;
57import android.content.pm.ConfigurationInfo;
58import android.content.pm.IPackageDataObserver;
59import android.content.pm.IPackageManager;
60import android.content.pm.InstrumentationInfo;
61import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070062import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.content.pm.ProviderInfo;
64import android.content.pm.ResolveInfo;
65import android.content.pm.ServiceInfo;
66import android.content.res.Configuration;
67import android.graphics.Bitmap;
68import android.net.Uri;
69import android.os.Binder;
70import android.os.Bundle;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070071import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.os.Environment;
73import android.os.FileUtils;
74import android.os.Handler;
75import android.os.IBinder;
76import android.os.IPermissionController;
77import android.os.Looper;
78import android.os.Message;
79import android.os.Parcel;
80import android.os.ParcelFileDescriptor;
81import android.os.PowerManager;
82import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070083import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084import android.os.RemoteException;
85import android.os.ServiceManager;
86import android.os.SystemClock;
87import android.os.SystemProperties;
88import android.provider.Checkin;
89import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020090import android.server.data.CrashData;
91import android.server.data.StackTraceElementData;
92import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093import android.text.TextUtils;
94import android.util.Config;
95import android.util.EventLog;
96import android.util.Log;
97import android.util.PrintWriterPrinter;
98import android.util.SparseArray;
99import android.view.Gravity;
100import android.view.LayoutInflater;
101import android.view.View;
102import android.view.WindowManager;
103import android.view.WindowManagerPolicy;
104
105import dalvik.system.Zygote;
106
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200107import java.io.ByteArrayInputStream;
108import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109import java.io.File;
110import java.io.FileDescriptor;
111import java.io.FileInputStream;
112import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200113import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114import java.io.PrintWriter;
115import java.lang.IllegalStateException;
116import java.lang.ref.WeakReference;
117import java.util.ArrayList;
118import java.util.HashMap;
119import java.util.HashSet;
120import java.util.Iterator;
121import java.util.List;
122import java.util.Locale;
123import java.util.Map;
124
125public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
126 static final String TAG = "ActivityManager";
127 static final boolean DEBUG = false;
128 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
129 static final boolean DEBUG_SWITCH = localLOGV || false;
130 static final boolean DEBUG_TASKS = localLOGV || false;
131 static final boolean DEBUG_PAUSE = localLOGV || false;
132 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
133 static final boolean DEBUG_TRANSITION = localLOGV || false;
134 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700135 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 static final boolean DEBUG_SERVICE = localLOGV || false;
137 static final boolean DEBUG_VISBILITY = localLOGV || false;
138 static final boolean DEBUG_PROCESSES = localLOGV || false;
139 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700140 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700141 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 static final boolean VALIDATE_TOKENS = false;
143 static final boolean SHOW_ACTIVITY_START_TIME = true;
144
145 // Control over CPU and battery monitoring.
146 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
147 static final boolean MONITOR_CPU_USAGE = true;
148 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
149 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
150 static final boolean MONITOR_THREAD_CPU_USAGE = false;
151
152 // Event log tags
153 static final int LOG_CONFIGURATION_CHANGED = 2719;
154 static final int LOG_CPU = 2721;
155 static final int LOG_AM_FINISH_ACTIVITY = 30001;
156 static final int LOG_TASK_TO_FRONT = 30002;
157 static final int LOG_AM_NEW_INTENT = 30003;
158 static final int LOG_AM_CREATE_TASK = 30004;
159 static final int LOG_AM_CREATE_ACTIVITY = 30005;
160 static final int LOG_AM_RESTART_ACTIVITY = 30006;
161 static final int LOG_AM_RESUME_ACTIVITY = 30007;
162 static final int LOG_ANR = 30008;
163 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
164 static final int LOG_AM_PROCESS_BOUND = 30010;
165 static final int LOG_AM_PROCESS_DIED = 30011;
166 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
167 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
168 static final int LOG_AM_PROCESS_START = 30014;
169 static final int LOG_AM_PROCESS_BAD = 30015;
170 static final int LOG_AM_PROCESS_GOOD = 30016;
171 static final int LOG_AM_LOW_MEMORY = 30017;
172 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
173 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
174 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
175 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
176 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
177 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
178 static final int LOG_AM_CREATE_SERVICE = 30030;
179 static final int LOG_AM_DESTROY_SERVICE = 30031;
180 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
181 static final int LOG_AM_DROP_PROCESS = 30033;
182 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
183 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
184 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
185
186 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
187 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
188
Dianne Hackborn1655be42009-05-08 14:29:01 -0700189 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700190 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700191
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 private static final String SYSTEM_SECURE = "ro.secure";
193
194 // This is the maximum number of application processes we would like
195 // to have running. Due to the asynchronous nature of things, we can
196 // temporarily go beyond this limit.
197 static final int MAX_PROCESSES = 2;
198
199 // Set to false to leave processes running indefinitely, relying on
200 // the kernel killing them as resources are required.
201 static final boolean ENFORCE_PROCESS_LIMIT = false;
202
203 // This is the maximum number of activities that we would like to have
204 // running at a given time.
205 static final int MAX_ACTIVITIES = 20;
206
207 // Maximum number of recent tasks that we can remember.
208 static final int MAX_RECENT_TASKS = 20;
209
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700210 // Amount of time after a call to stopAppSwitches() during which we will
211 // prevent further untrusted switches from happening.
212 static final long APP_SWITCH_DELAY_TIME = 5*1000;
213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 // How long until we reset a task when the user returns to it. Currently
215 // 30 minutes.
216 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
217
218 // Set to true to disable the icon that is shown while a new activity
219 // is being started.
220 static final boolean SHOW_APP_STARTING_ICON = true;
221
222 // How long we wait until giving up on the last activity to pause. This
223 // is short because it directly impacts the responsiveness of starting the
224 // next activity.
225 static final int PAUSE_TIMEOUT = 500;
226
227 /**
228 * How long we can hold the launch wake lock before giving up.
229 */
230 static final int LAUNCH_TIMEOUT = 10*1000;
231
232 // How long we wait for a launched process to attach to the activity manager
233 // before we decide it's never going to come up for real.
234 static final int PROC_START_TIMEOUT = 10*1000;
235
236 // How long we wait until giving up on the last activity telling us it
237 // is idle.
238 static final int IDLE_TIMEOUT = 10*1000;
239
240 // How long to wait after going idle before forcing apps to GC.
241 static final int GC_TIMEOUT = 5*1000;
242
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700243 // The minimum amount of time between successive GC requests for a process.
244 static final int GC_MIN_INTERVAL = 60*1000;
245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246 // How long we wait until giving up on an activity telling us it has
247 // finished destroying itself.
248 static final int DESTROY_TIMEOUT = 10*1000;
249
250 // How long we allow a receiver to run before giving up on it.
251 static final int BROADCAST_TIMEOUT = 10*1000;
252
253 // How long we wait for a service to finish executing.
254 static final int SERVICE_TIMEOUT = 20*1000;
255
256 // How long a service needs to be running until restarting its process
257 // is no longer considered to be a relaunch of the service.
258 static final int SERVICE_RESTART_DURATION = 5*1000;
259
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700260 // How long a service needs to be running until it will start back at
261 // SERVICE_RESTART_DURATION after being killed.
262 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
263
264 // Multiplying factor to increase restart duration time by, for each time
265 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
266 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
267
268 // The minimum amount of time between restarting services that we allow.
269 // That is, when multiple services are restarting, we won't allow each
270 // to restart less than this amount of time from the last one.
271 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
272
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 // Maximum amount of time for there to be no activity on a service before
274 // we consider it non-essential and allow its process to go on the
275 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700276 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277
278 // How long we wait until we timeout on key dispatching.
279 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
280
281 // The minimum time we allow between crashes, for us to consider this
282 // application to be bad and stop and its services and reject broadcasts.
283 static final int MIN_CRASH_INTERVAL = 60*1000;
284
285 // How long we wait until we timeout on key dispatching during instrumentation.
286 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
287
288 // OOM adjustments for processes in various states:
289
290 // This is a process without anything currently running in it. Definitely
291 // the first to go! Value set in system/rootdir/init.rc on startup.
292 // This value is initalized in the constructor, careful when refering to
293 // this static variable externally.
294 static int EMPTY_APP_ADJ;
295
296 // This is a process with a content provider that does not have any clients
297 // attached to it. If it did have any clients, its adjustment would be the
298 // one for the highest-priority of those processes.
299 static int CONTENT_PROVIDER_ADJ;
300
301 // This is a process only hosting activities that are not visible,
302 // so it can be killed without any disruption. Value set in
303 // system/rootdir/init.rc on startup.
304 final int HIDDEN_APP_MAX_ADJ;
305 static int HIDDEN_APP_MIN_ADJ;
306
The Android Open Source Project4df24232009-03-05 14:34:35 -0800307 // This is a process holding the home application -- we want to try
308 // avoiding killing it, even if it would normally be in the background,
309 // because the user interacts with it so much.
310 final int HOME_APP_ADJ;
311
Christopher Tate6fa95972009-06-05 18:43:55 -0700312 // This is a process currently hosting a backup operation. Killing it
313 // is not entirely fatal but is generally a bad idea.
314 final int BACKUP_APP_ADJ;
315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 // This is a process holding a secondary server -- killing it will not
317 // have much of an impact as far as the user is concerned. Value set in
318 // system/rootdir/init.rc on startup.
319 final int SECONDARY_SERVER_ADJ;
320
321 // This is a process only hosting activities that are visible to the
322 // user, so we'd prefer they don't disappear. Value set in
323 // system/rootdir/init.rc on startup.
324 final int VISIBLE_APP_ADJ;
325
326 // This is the process running the current foreground app. We'd really
327 // rather not kill it! Value set in system/rootdir/init.rc on startup.
328 final int FOREGROUND_APP_ADJ;
329
330 // This is a process running a core server, such as telephony. Definitely
331 // don't want to kill it, but doing so is not completely fatal.
332 static final int CORE_SERVER_ADJ = -12;
333
334 // The system process runs at the default adjustment.
335 static final int SYSTEM_ADJ = -16;
336
337 // Memory pages are 4K.
338 static final int PAGE_SIZE = 4*1024;
339
Jacek Surazski82a73df2009-06-17 14:33:18 +0200340 // System property defining error report receiver for system apps
341 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
342
343 // System property defining default error report receiver
344 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
345
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 // Corresponding memory levels for above adjustments.
347 final int EMPTY_APP_MEM;
348 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800349 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700350 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 final int SECONDARY_SERVER_MEM;
352 final int VISIBLE_APP_MEM;
353 final int FOREGROUND_APP_MEM;
354
355 final int MY_PID;
356
357 static final String[] EMPTY_STRING_ARRAY = new String[0];
358
359 enum ActivityState {
360 INITIALIZING,
361 RESUMED,
362 PAUSING,
363 PAUSED,
364 STOPPING,
365 STOPPED,
366 FINISHING,
367 DESTROYING,
368 DESTROYED
369 }
370
371 /**
372 * The back history of all previous (and possibly still
373 * running) activities. It contains HistoryRecord objects.
374 */
375 final ArrayList mHistory = new ArrayList();
376
377 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700378 * Description of a request to start a new activity, which has been held
379 * due to app switches being disabled.
380 */
381 class PendingActivityLaunch {
382 HistoryRecord r;
383 HistoryRecord sourceRecord;
384 Uri[] grantedUriPermissions;
385 int grantedMode;
386 boolean onlyIfNeeded;
387 }
388
389 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
390 = new ArrayList<PendingActivityLaunch>();
391
392 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 * List of all active broadcasts that are to be executed immediately
394 * (without waiting for another broadcast to finish). Currently this only
395 * contains broadcasts to registered receivers, to avoid spinning up
396 * a bunch of processes to execute IntentReceiver components.
397 */
398 final ArrayList<BroadcastRecord> mParallelBroadcasts
399 = new ArrayList<BroadcastRecord>();
400
401 /**
402 * List of all active broadcasts that are to be executed one at a time.
403 * The object at the top of the list is the currently activity broadcasts;
404 * those after it are waiting for the top to finish..
405 */
406 final ArrayList<BroadcastRecord> mOrderedBroadcasts
407 = new ArrayList<BroadcastRecord>();
408
409 /**
410 * Set when we current have a BROADCAST_INTENT_MSG in flight.
411 */
412 boolean mBroadcastsScheduled = false;
413
414 /**
415 * Set to indicate whether to issue an onUserLeaving callback when a
416 * newly launched activity is being brought in front of us.
417 */
418 boolean mUserLeaving = false;
419
420 /**
421 * When we are in the process of pausing an activity, before starting the
422 * next one, this variable holds the activity that is currently being paused.
423 */
424 HistoryRecord mPausingActivity = null;
425
426 /**
427 * Current activity that is resumed, or null if there is none.
428 */
429 HistoryRecord mResumedActivity = null;
430
431 /**
432 * Activity we have told the window manager to have key focus.
433 */
434 HistoryRecord mFocusedActivity = null;
435
436 /**
437 * This is the last activity that we put into the paused state. This is
438 * used to determine if we need to do an activity transition while sleeping,
439 * when we normally hold the top activity paused.
440 */
441 HistoryRecord mLastPausedActivity = null;
442
443 /**
444 * List of activities that are waiting for a new activity
445 * to become visible before completing whatever operation they are
446 * supposed to do.
447 */
448 final ArrayList mWaitingVisibleActivities = new ArrayList();
449
450 /**
451 * List of activities that are ready to be stopped, but waiting
452 * for the next activity to settle down before doing so. It contains
453 * HistoryRecord objects.
454 */
455 final ArrayList<HistoryRecord> mStoppingActivities
456 = new ArrayList<HistoryRecord>();
457
458 /**
459 * List of intents that were used to start the most recent tasks.
460 */
461 final ArrayList<TaskRecord> mRecentTasks
462 = new ArrayList<TaskRecord>();
463
464 /**
465 * List of activities that are ready to be finished, but waiting
466 * for the previous activity to settle down before doing so. It contains
467 * HistoryRecord objects.
468 */
469 final ArrayList mFinishingActivities = new ArrayList();
470
471 /**
472 * All of the applications we currently have running organized by name.
473 * The keys are strings of the application package name (as
474 * returned by the package manager), and the keys are ApplicationRecord
475 * objects.
476 */
477 final ProcessMap<ProcessRecord> mProcessNames
478 = new ProcessMap<ProcessRecord>();
479
480 /**
481 * The last time that various processes have crashed.
482 */
483 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
484
485 /**
486 * Set of applications that we consider to be bad, and will reject
487 * incoming broadcasts from (which the user has no control over).
488 * Processes are added to this set when they have crashed twice within
489 * a minimum amount of time; they are removed from it when they are
490 * later restarted (hopefully due to some user action). The value is the
491 * time it was added to the list.
492 */
493 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
494
495 /**
496 * All of the processes we currently have running organized by pid.
497 * The keys are the pid running the application.
498 *
499 * <p>NOTE: This object is protected by its own lock, NOT the global
500 * activity manager lock!
501 */
502 final SparseArray<ProcessRecord> mPidsSelfLocked
503 = new SparseArray<ProcessRecord>();
504
505 /**
506 * All of the processes that have been forced to be foreground. The key
507 * is the pid of the caller who requested it (we hold a death
508 * link on it).
509 */
510 abstract class ForegroundToken implements IBinder.DeathRecipient {
511 int pid;
512 IBinder token;
513 }
514 final SparseArray<ForegroundToken> mForegroundProcesses
515 = new SparseArray<ForegroundToken>();
516
517 /**
518 * List of records for processes that someone had tried to start before the
519 * system was ready. We don't start them at that point, but ensure they
520 * are started by the time booting is complete.
521 */
522 final ArrayList<ProcessRecord> mProcessesOnHold
523 = new ArrayList<ProcessRecord>();
524
525 /**
526 * List of records for processes that we have started and are waiting
527 * for them to call back. This is really only needed when running in
528 * single processes mode, in which case we do not have a unique pid for
529 * each process.
530 */
531 final ArrayList<ProcessRecord> mStartingProcesses
532 = new ArrayList<ProcessRecord>();
533
534 /**
535 * List of persistent applications that are in the process
536 * of being started.
537 */
538 final ArrayList<ProcessRecord> mPersistentStartingProcesses
539 = new ArrayList<ProcessRecord>();
540
541 /**
542 * Processes that are being forcibly torn down.
543 */
544 final ArrayList<ProcessRecord> mRemovedProcesses
545 = new ArrayList<ProcessRecord>();
546
547 /**
548 * List of running applications, sorted by recent usage.
549 * The first entry in the list is the least recently used.
550 * It contains ApplicationRecord objects. This list does NOT include
551 * any persistent application records (since we never want to exit them).
552 */
553 final ArrayList<ProcessRecord> mLRUProcesses
554 = new ArrayList<ProcessRecord>();
555
556 /**
557 * List of processes that should gc as soon as things are idle.
558 */
559 final ArrayList<ProcessRecord> mProcessesToGc
560 = new ArrayList<ProcessRecord>();
561
562 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800563 * This is the process holding what we currently consider to be
564 * the "home" activity.
565 */
566 private ProcessRecord mHomeProcess;
567
568 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 * List of running activities, sorted by recent usage.
570 * The first entry in the list is the least recently used.
571 * It contains HistoryRecord objects.
572 */
573 private final ArrayList mLRUActivities = new ArrayList();
574
575 /**
576 * Set of PendingResultRecord objects that are currently active.
577 */
578 final HashSet mPendingResultRecords = new HashSet();
579
580 /**
581 * Set of IntentSenderRecord objects that are currently active.
582 */
583 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
584 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
585
586 /**
587 * Intent broadcast that we have tried to start, but are
588 * waiting for its application's process to be created. We only
589 * need one (instead of a list) because we always process broadcasts
590 * one at a time, so no others can be started while waiting for this
591 * one.
592 */
593 BroadcastRecord mPendingBroadcast = null;
594
595 /**
596 * Keeps track of all IIntentReceivers that have been registered for
597 * broadcasts. Hash keys are the receiver IBinder, hash value is
598 * a ReceiverList.
599 */
600 final HashMap mRegisteredReceivers = new HashMap();
601
602 /**
603 * Resolver for broadcast intents to registered receivers.
604 * Holds BroadcastFilter (subclass of IntentFilter).
605 */
606 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
607 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
608 @Override
609 protected boolean allowFilterResult(
610 BroadcastFilter filter, List<BroadcastFilter> dest) {
611 IBinder target = filter.receiverList.receiver.asBinder();
612 for (int i=dest.size()-1; i>=0; i--) {
613 if (dest.get(i).receiverList.receiver.asBinder() == target) {
614 return false;
615 }
616 }
617 return true;
618 }
619 };
620
621 /**
622 * State of all active sticky broadcasts. Keys are the action of the
623 * sticky Intent, values are an ArrayList of all broadcasted intents with
624 * that action (which should usually be one).
625 */
626 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
627 new HashMap<String, ArrayList<Intent>>();
628
629 /**
630 * All currently running services.
631 */
632 final HashMap<ComponentName, ServiceRecord> mServices =
633 new HashMap<ComponentName, ServiceRecord>();
634
635 /**
636 * All currently running services indexed by the Intent used to start them.
637 */
638 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
639 new HashMap<Intent.FilterComparison, ServiceRecord>();
640
641 /**
642 * All currently bound service connections. Keys are the IBinder of
643 * the client's IServiceConnection.
644 */
645 final HashMap<IBinder, ConnectionRecord> mServiceConnections
646 = new HashMap<IBinder, ConnectionRecord>();
647
648 /**
649 * List of services that we have been asked to start,
650 * but haven't yet been able to. It is used to hold start requests
651 * while waiting for their corresponding application thread to get
652 * going.
653 */
654 final ArrayList<ServiceRecord> mPendingServices
655 = new ArrayList<ServiceRecord>();
656
657 /**
658 * List of services that are scheduled to restart following a crash.
659 */
660 final ArrayList<ServiceRecord> mRestartingServices
661 = new ArrayList<ServiceRecord>();
662
663 /**
664 * List of services that are in the process of being stopped.
665 */
666 final ArrayList<ServiceRecord> mStoppingServices
667 = new ArrayList<ServiceRecord>();
668
669 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700670 * Backup/restore process management
671 */
672 String mBackupAppName = null;
673 BackupRecord mBackupTarget = null;
674
675 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 * List of PendingThumbnailsRecord objects of clients who are still
677 * waiting to receive all of the thumbnails for a task.
678 */
679 final ArrayList mPendingThumbnails = new ArrayList();
680
681 /**
682 * List of HistoryRecord objects that have been finished and must
683 * still report back to a pending thumbnail receiver.
684 */
685 final ArrayList mCancelledThumbnails = new ArrayList();
686
687 /**
688 * All of the currently running global content providers. Keys are a
689 * string containing the provider name and values are a
690 * ContentProviderRecord object containing the data about it. Note
691 * that a single provider may be published under multiple names, so
692 * there may be multiple entries here for a single one in mProvidersByClass.
693 */
694 final HashMap mProvidersByName = new HashMap();
695
696 /**
697 * All of the currently running global content providers. Keys are a
698 * string containing the provider's implementation class and values are a
699 * ContentProviderRecord object containing the data about it.
700 */
701 final HashMap mProvidersByClass = new HashMap();
702
703 /**
704 * List of content providers who have clients waiting for them. The
705 * application is currently being launched and the provider will be
706 * removed from this list once it is published.
707 */
708 final ArrayList mLaunchingProviders = new ArrayList();
709
710 /**
711 * Global set of specific Uri permissions that have been granted.
712 */
713 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
714 = new SparseArray<HashMap<Uri, UriPermission>>();
715
716 /**
717 * Thread-local storage used to carry caller permissions over through
718 * indirect content-provider access.
719 * @see #ActivityManagerService.openContentUri()
720 */
721 private class Identity {
722 public int pid;
723 public int uid;
724
725 Identity(int _pid, int _uid) {
726 pid = _pid;
727 uid = _uid;
728 }
729 }
730 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
731
732 /**
733 * All information we have collected about the runtime performance of
734 * any user id that can impact battery performance.
735 */
736 final BatteryStatsService mBatteryStatsService;
737
738 /**
739 * information about component usage
740 */
741 final UsageStatsService mUsageStatsService;
742
743 /**
744 * Current configuration information. HistoryRecord objects are given
745 * a reference to this object to indicate which configuration they are
746 * currently running in, so this object must be kept immutable.
747 */
748 Configuration mConfiguration = new Configuration();
749
750 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700751 * Hardware-reported OpenGLES version.
752 */
753 final int GL_ES_VERSION;
754
755 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 * List of initialization arguments to pass to all processes when binding applications to them.
757 * For example, references to the commonly used services.
758 */
759 HashMap<String, IBinder> mAppBindArgs;
760
761 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700762 * Temporary to avoid allocations. Protected by main lock.
763 */
764 final StringBuilder mStringBuilder = new StringBuilder(256);
765
766 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 * Used to control how we initialize the service.
768 */
769 boolean mStartRunning = false;
770 ComponentName mTopComponent;
771 String mTopAction;
772 String mTopData;
773 boolean mSystemReady = false;
774 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700775 boolean mWaitingUpdate = false;
776 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777
778 Context mContext;
779
780 int mFactoryTest;
781
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700782 boolean mCheckedForSetup;
783
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700785 * The time at which we will allow normal application switches again,
786 * after a call to {@link #stopAppSwitches()}.
787 */
788 long mAppSwitchesAllowedTime;
789
790 /**
791 * This is set to true after the first switch after mAppSwitchesAllowedTime
792 * is set; any switches after that will clear the time.
793 */
794 boolean mDidAppSwitch;
795
796 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 * Set while we are wanting to sleep, to prevent any
798 * activities from being started/resumed.
799 */
800 boolean mSleeping = false;
801
802 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700803 * Set if we are shutting down the system, similar to sleeping.
804 */
805 boolean mShuttingDown = false;
806
807 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800808 * Set when the system is going to sleep, until we have
809 * successfully paused the current activity and released our wake lock.
810 * At that point the system is allowed to actually sleep.
811 */
812 PowerManager.WakeLock mGoingToSleep;
813
814 /**
815 * We don't want to allow the device to go to sleep while in the process
816 * of launching an activity. This is primarily to allow alarm intent
817 * receivers to launch an activity and get that to run before the device
818 * goes back to sleep.
819 */
820 PowerManager.WakeLock mLaunchingActivity;
821
822 /**
823 * Task identifier that activities are currently being started
824 * in. Incremented each time a new task is created.
825 * todo: Replace this with a TokenSpace class that generates non-repeating
826 * integers that won't wrap.
827 */
828 int mCurTask = 1;
829
830 /**
831 * Current sequence id for oom_adj computation traversal.
832 */
833 int mAdjSeq = 0;
834
835 /**
836 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
837 * is set, indicating the user wants processes started in such a way
838 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
839 * running in each process (thus no pre-initialized process, etc).
840 */
841 boolean mSimpleProcessManagement = false;
842
843 /**
844 * System monitoring: number of processes that died since the last
845 * N procs were started.
846 */
847 int[] mProcDeaths = new int[20];
848
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700849 /**
850 * This is set if we had to do a delayed dexopt of an app before launching
851 * it, to increasing the ANR timeouts in that case.
852 */
853 boolean mDidDexOpt;
854
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 String mDebugApp = null;
856 boolean mWaitForDebugger = false;
857 boolean mDebugTransient = false;
858 String mOrigDebugApp = null;
859 boolean mOrigWaitForDebugger = false;
860 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700861 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800862
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700863 final RemoteCallbackList<IActivityWatcher> mWatchers
864 = new RemoteCallbackList<IActivityWatcher>();
865
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 /**
867 * Callback of last caller to {@link #requestPss}.
868 */
869 Runnable mRequestPssCallback;
870
871 /**
872 * Remaining processes for which we are waiting results from the last
873 * call to {@link #requestPss}.
874 */
875 final ArrayList<ProcessRecord> mRequestPssList
876 = new ArrayList<ProcessRecord>();
877
878 /**
879 * Runtime statistics collection thread. This object's lock is used to
880 * protect all related state.
881 */
882 final Thread mProcessStatsThread;
883
884 /**
885 * Used to collect process stats when showing not responding dialog.
886 * Protected by mProcessStatsThread.
887 */
888 final ProcessStats mProcessStats = new ProcessStats(
889 MONITOR_THREAD_CPU_USAGE);
890 long mLastCpuTime = 0;
891 long mLastWriteTime = 0;
892
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700893 long mInitialStartTime = 0;
894
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800895 /**
896 * Set to true after the system has finished booting.
897 */
898 boolean mBooted = false;
899
900 int mProcessLimit = 0;
901
902 WindowManagerService mWindowManager;
903
904 static ActivityManagerService mSelf;
905 static ActivityThread mSystemThread;
906
907 private final class AppDeathRecipient implements IBinder.DeathRecipient {
908 final ProcessRecord mApp;
909 final int mPid;
910 final IApplicationThread mAppThread;
911
912 AppDeathRecipient(ProcessRecord app, int pid,
913 IApplicationThread thread) {
914 if (localLOGV) Log.v(
915 TAG, "New death recipient " + this
916 + " for thread " + thread.asBinder());
917 mApp = app;
918 mPid = pid;
919 mAppThread = thread;
920 }
921
922 public void binderDied() {
923 if (localLOGV) Log.v(
924 TAG, "Death received in " + this
925 + " for thread " + mAppThread.asBinder());
926 removeRequestedPss(mApp);
927 synchronized(ActivityManagerService.this) {
928 appDiedLocked(mApp, mPid, mAppThread);
929 }
930 }
931 }
932
933 static final int SHOW_ERROR_MSG = 1;
934 static final int SHOW_NOT_RESPONDING_MSG = 2;
935 static final int SHOW_FACTORY_ERROR_MSG = 3;
936 static final int UPDATE_CONFIGURATION_MSG = 4;
937 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
938 static final int WAIT_FOR_DEBUGGER_MSG = 6;
939 static final int BROADCAST_INTENT_MSG = 7;
940 static final int BROADCAST_TIMEOUT_MSG = 8;
941 static final int PAUSE_TIMEOUT_MSG = 9;
942 static final int IDLE_TIMEOUT_MSG = 10;
943 static final int IDLE_NOW_MSG = 11;
944 static final int SERVICE_TIMEOUT_MSG = 12;
945 static final int UPDATE_TIME_ZONE = 13;
946 static final int SHOW_UID_ERROR_MSG = 14;
947 static final int IM_FEELING_LUCKY_MSG = 15;
948 static final int LAUNCH_TIMEOUT_MSG = 16;
949 static final int DESTROY_TIMEOUT_MSG = 17;
950 static final int SERVICE_ERROR_MSG = 18;
951 static final int RESUME_TOP_ACTIVITY_MSG = 19;
952 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700953 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700954 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800955
956 AlertDialog mUidAlert;
957
958 final Handler mHandler = new Handler() {
959 //public Handler() {
960 // if (localLOGV) Log.v(TAG, "Handler started!");
961 //}
962
963 public void handleMessage(Message msg) {
964 switch (msg.what) {
965 case SHOW_ERROR_MSG: {
966 HashMap data = (HashMap) msg.obj;
967 byte[] crashData = (byte[])data.get("crashData");
968 if (crashData != null) {
969 // This needs to be *un*synchronized to avoid deadlock.
970 ContentResolver resolver = mContext.getContentResolver();
971 Checkin.reportCrash(resolver, crashData);
972 }
973 synchronized (ActivityManagerService.this) {
974 ProcessRecord proc = (ProcessRecord)data.get("app");
975 if (proc != null && proc.crashDialog != null) {
976 Log.e(TAG, "App already has crash dialog: " + proc);
977 return;
978 }
979 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700980 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 Dialog d = new AppErrorDialog(
982 mContext, res, proc,
983 (Integer)data.get("flags"),
984 (String)data.get("shortMsg"),
985 (String)data.get("longMsg"));
986 d.show();
987 proc.crashDialog = d;
988 } else {
989 // The device is asleep, so just pretend that the user
990 // saw a crash dialog and hit "force quit".
991 res.set(0);
992 }
993 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700994
995 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 } break;
997 case SHOW_NOT_RESPONDING_MSG: {
998 synchronized (ActivityManagerService.this) {
999 HashMap data = (HashMap) msg.obj;
1000 ProcessRecord proc = (ProcessRecord)data.get("app");
1001 if (proc != null && proc.anrDialog != null) {
1002 Log.e(TAG, "App already has anr dialog: " + proc);
1003 return;
1004 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001005
1006 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1007 null, null, 0, null, null, null,
1008 false, false, MY_PID, Process.SYSTEM_UID);
1009
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1011 mContext, proc, (HistoryRecord)data.get("activity"));
1012 d.show();
1013 proc.anrDialog = d;
1014 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001015
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001016 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 } break;
1018 case SHOW_FACTORY_ERROR_MSG: {
1019 Dialog d = new FactoryErrorDialog(
1020 mContext, msg.getData().getCharSequence("msg"));
1021 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001022 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 } break;
1024 case UPDATE_CONFIGURATION_MSG: {
1025 final ContentResolver resolver = mContext.getContentResolver();
1026 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1027 } break;
1028 case GC_BACKGROUND_PROCESSES_MSG: {
1029 synchronized (ActivityManagerService.this) {
1030 performAppGcsIfAppropriateLocked();
1031 }
1032 } break;
1033 case WAIT_FOR_DEBUGGER_MSG: {
1034 synchronized (ActivityManagerService.this) {
1035 ProcessRecord app = (ProcessRecord)msg.obj;
1036 if (msg.arg1 != 0) {
1037 if (!app.waitedForDebugger) {
1038 Dialog d = new AppWaitingForDebuggerDialog(
1039 ActivityManagerService.this,
1040 mContext, app);
1041 app.waitDialog = d;
1042 app.waitedForDebugger = true;
1043 d.show();
1044 }
1045 } else {
1046 if (app.waitDialog != null) {
1047 app.waitDialog.dismiss();
1048 app.waitDialog = null;
1049 }
1050 }
1051 }
1052 } break;
1053 case BROADCAST_INTENT_MSG: {
1054 if (DEBUG_BROADCAST) Log.v(
1055 TAG, "Received BROADCAST_INTENT_MSG");
1056 processNextBroadcast(true);
1057 } break;
1058 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001059 if (mDidDexOpt) {
1060 mDidDexOpt = false;
1061 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1062 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1063 return;
1064 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 broadcastTimeout();
1066 } break;
1067 case PAUSE_TIMEOUT_MSG: {
1068 IBinder token = (IBinder)msg.obj;
1069 // We don't at this point know if the activity is fullscreen,
1070 // so we need to be conservative and assume it isn't.
1071 Log.w(TAG, "Activity pause timeout for " + token);
1072 activityPaused(token, null, true);
1073 } break;
1074 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001075 if (mDidDexOpt) {
1076 mDidDexOpt = false;
1077 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1078 nmsg.obj = msg.obj;
1079 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1080 return;
1081 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001082 // We don't at this point know if the activity is fullscreen,
1083 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001084 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001085 Log.w(TAG, "Activity idle timeout for " + token);
1086 activityIdleInternal(token, true);
1087 } break;
1088 case DESTROY_TIMEOUT_MSG: {
1089 IBinder token = (IBinder)msg.obj;
1090 // We don't at this point know if the activity is fullscreen,
1091 // so we need to be conservative and assume it isn't.
1092 Log.w(TAG, "Activity destroy timeout for " + token);
1093 activityDestroyed(token);
1094 } break;
1095 case IDLE_NOW_MSG: {
1096 IBinder token = (IBinder)msg.obj;
1097 activityIdle(token);
1098 } break;
1099 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001100 if (mDidDexOpt) {
1101 mDidDexOpt = false;
1102 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1103 nmsg.obj = msg.obj;
1104 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1105 return;
1106 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107 serviceTimeout((ProcessRecord)msg.obj);
1108 } break;
1109 case UPDATE_TIME_ZONE: {
1110 synchronized (ActivityManagerService.this) {
1111 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1112 ProcessRecord r = mLRUProcesses.get(i);
1113 if (r.thread != null) {
1114 try {
1115 r.thread.updateTimeZone();
1116 } catch (RemoteException ex) {
1117 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1118 }
1119 }
1120 }
1121 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001122 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123 case SHOW_UID_ERROR_MSG: {
1124 // XXX This is a temporary dialog, no need to localize.
1125 AlertDialog d = new BaseErrorDialog(mContext);
1126 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1127 d.setCancelable(false);
1128 d.setTitle("System UIDs Inconsistent");
1129 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1130 d.setButton("I'm Feeling Lucky",
1131 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1132 mUidAlert = d;
1133 d.show();
1134 } break;
1135 case IM_FEELING_LUCKY_MSG: {
1136 if (mUidAlert != null) {
1137 mUidAlert.dismiss();
1138 mUidAlert = null;
1139 }
1140 } break;
1141 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001142 if (mDidDexOpt) {
1143 mDidDexOpt = false;
1144 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1145 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1146 return;
1147 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148 synchronized (ActivityManagerService.this) {
1149 if (mLaunchingActivity.isHeld()) {
1150 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1151 mLaunchingActivity.release();
1152 }
1153 }
1154 } break;
1155 case SERVICE_ERROR_MSG: {
1156 ServiceRecord srv = (ServiceRecord)msg.obj;
1157 // This needs to be *un*synchronized to avoid deadlock.
1158 Checkin.logEvent(mContext.getContentResolver(),
1159 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1160 srv.name.toShortString());
1161 } break;
1162 case RESUME_TOP_ACTIVITY_MSG: {
1163 synchronized (ActivityManagerService.this) {
1164 resumeTopActivityLocked(null);
1165 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001166 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001167 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001168 if (mDidDexOpt) {
1169 mDidDexOpt = false;
1170 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1171 nmsg.obj = msg.obj;
1172 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1173 return;
1174 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001175 ProcessRecord app = (ProcessRecord)msg.obj;
1176 synchronized (ActivityManagerService.this) {
1177 processStartTimedOutLocked(app);
1178 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001179 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001180 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1181 synchronized (ActivityManagerService.this) {
1182 doPendingActivityLaunchesLocked(true);
1183 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001184 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001185 case KILL_APPLICATION_MSG: {
1186 synchronized (ActivityManagerService.this) {
1187 int uid = msg.arg1;
1188 boolean restart = (msg.arg2 == 1);
1189 String pkg = (String) msg.obj;
1190 uninstallPackageLocked(pkg, uid, restart);
1191 }
1192 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 }
1194 }
1195 };
1196
1197 public static void setSystemProcess() {
1198 try {
1199 ActivityManagerService m = mSelf;
1200
1201 ServiceManager.addService("activity", m);
1202 ServiceManager.addService("meminfo", new MemBinder(m));
1203 if (MONITOR_CPU_USAGE) {
1204 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1205 }
1206 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1207 ServiceManager.addService("activity.services", new ServicesBinder(m));
1208 ServiceManager.addService("activity.senders", new SendersBinder(m));
1209 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1210 ServiceManager.addService("permission", new PermissionController(m));
1211
1212 ApplicationInfo info =
1213 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001214 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 synchronized (mSelf) {
1216 ProcessRecord app = mSelf.newProcessRecordLocked(
1217 mSystemThread.getApplicationThread(), info,
1218 info.processName);
1219 app.persistent = true;
1220 app.pid = Process.myPid();
1221 app.maxAdj = SYSTEM_ADJ;
1222 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1223 synchronized (mSelf.mPidsSelfLocked) {
1224 mSelf.mPidsSelfLocked.put(app.pid, app);
1225 }
1226 mSelf.updateLRUListLocked(app, true);
1227 }
1228 } catch (PackageManager.NameNotFoundException e) {
1229 throw new RuntimeException(
1230 "Unable to find android system package", e);
1231 }
1232 }
1233
1234 public void setWindowManager(WindowManagerService wm) {
1235 mWindowManager = wm;
1236 }
1237
1238 public static final Context main(int factoryTest) {
1239 AThread thr = new AThread();
1240 thr.start();
1241
1242 synchronized (thr) {
1243 while (thr.mService == null) {
1244 try {
1245 thr.wait();
1246 } catch (InterruptedException e) {
1247 }
1248 }
1249 }
1250
1251 ActivityManagerService m = thr.mService;
1252 mSelf = m;
1253 ActivityThread at = ActivityThread.systemMain();
1254 mSystemThread = at;
1255 Context context = at.getSystemContext();
1256 m.mContext = context;
1257 m.mFactoryTest = factoryTest;
1258 PowerManager pm =
1259 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1260 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1261 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1262 m.mLaunchingActivity.setReferenceCounted(false);
1263
1264 m.mBatteryStatsService.publish(context);
1265 m.mUsageStatsService.publish(context);
1266
1267 synchronized (thr) {
1268 thr.mReady = true;
1269 thr.notifyAll();
1270 }
1271
1272 m.startRunning(null, null, null, null);
1273
1274 return context;
1275 }
1276
1277 public static ActivityManagerService self() {
1278 return mSelf;
1279 }
1280
1281 static class AThread extends Thread {
1282 ActivityManagerService mService;
1283 boolean mReady = false;
1284
1285 public AThread() {
1286 super("ActivityManager");
1287 }
1288
1289 public void run() {
1290 Looper.prepare();
1291
1292 android.os.Process.setThreadPriority(
1293 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1294
1295 ActivityManagerService m = new ActivityManagerService();
1296
1297 synchronized (this) {
1298 mService = m;
1299 notifyAll();
1300 }
1301
1302 synchronized (this) {
1303 while (!mReady) {
1304 try {
1305 wait();
1306 } catch (InterruptedException e) {
1307 }
1308 }
1309 }
1310
1311 Looper.loop();
1312 }
1313 }
1314
1315 static class BroadcastsBinder extends Binder {
1316 ActivityManagerService mActivityManagerService;
1317 BroadcastsBinder(ActivityManagerService activityManagerService) {
1318 mActivityManagerService = activityManagerService;
1319 }
1320
1321 @Override
1322 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1323 mActivityManagerService.dumpBroadcasts(pw);
1324 }
1325 }
1326
1327 static class ServicesBinder extends Binder {
1328 ActivityManagerService mActivityManagerService;
1329 ServicesBinder(ActivityManagerService activityManagerService) {
1330 mActivityManagerService = activityManagerService;
1331 }
1332
1333 @Override
1334 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1335 mActivityManagerService.dumpServices(pw);
1336 }
1337 }
1338
1339 static class SendersBinder extends Binder {
1340 ActivityManagerService mActivityManagerService;
1341 SendersBinder(ActivityManagerService activityManagerService) {
1342 mActivityManagerService = activityManagerService;
1343 }
1344
1345 @Override
1346 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1347 mActivityManagerService.dumpSenders(pw);
1348 }
1349 }
1350
1351 static class ProvidersBinder extends Binder {
1352 ActivityManagerService mActivityManagerService;
1353 ProvidersBinder(ActivityManagerService activityManagerService) {
1354 mActivityManagerService = activityManagerService;
1355 }
1356
1357 @Override
1358 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1359 mActivityManagerService.dumpProviders(pw);
1360 }
1361 }
1362
1363 static class MemBinder extends Binder {
1364 ActivityManagerService mActivityManagerService;
1365 MemBinder(ActivityManagerService activityManagerService) {
1366 mActivityManagerService = activityManagerService;
1367 }
1368
1369 @Override
1370 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1371 ActivityManagerService service = mActivityManagerService;
1372 ArrayList<ProcessRecord> procs;
1373 synchronized (mActivityManagerService) {
1374 if (args != null && args.length > 0
1375 && args[0].charAt(0) != '-') {
1376 procs = new ArrayList<ProcessRecord>();
1377 int pid = -1;
1378 try {
1379 pid = Integer.parseInt(args[0]);
1380 } catch (NumberFormatException e) {
1381
1382 }
1383 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1384 ProcessRecord proc = service.mLRUProcesses.get(i);
1385 if (proc.pid == pid) {
1386 procs.add(proc);
1387 } else if (proc.processName.equals(args[0])) {
1388 procs.add(proc);
1389 }
1390 }
1391 if (procs.size() <= 0) {
1392 pw.println("No process found for: " + args[0]);
1393 return;
1394 }
1395 } else {
1396 procs = service.mLRUProcesses;
1397 }
1398 }
1399 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1400 }
1401 }
1402
1403 static class CpuBinder extends Binder {
1404 ActivityManagerService mActivityManagerService;
1405 CpuBinder(ActivityManagerService activityManagerService) {
1406 mActivityManagerService = activityManagerService;
1407 }
1408
1409 @Override
1410 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1411 synchronized (mActivityManagerService.mProcessStatsThread) {
1412 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1413 }
1414 }
1415 }
1416
1417 private ActivityManagerService() {
1418 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1419 if (v != null && Integer.getInteger(v) != 0) {
1420 mSimpleProcessManagement = true;
1421 }
1422 v = System.getenv("ANDROID_DEBUG_APP");
1423 if (v != null) {
1424 mSimpleProcessManagement = true;
1425 }
1426
1427 MY_PID = Process.myPid();
1428
1429 File dataDir = Environment.getDataDirectory();
1430 File systemDir = new File(dataDir, "system");
1431 systemDir.mkdirs();
1432 mBatteryStatsService = new BatteryStatsService(new File(
1433 systemDir, "batterystats.bin").toString());
1434 mBatteryStatsService.getActiveStatistics().readLocked();
1435 mBatteryStatsService.getActiveStatistics().writeLocked();
1436
1437 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001438 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001439
Jack Palevichb90d28c2009-07-22 15:35:24 -07001440 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1441 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1442
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001443 mConfiguration.makeDefault();
1444 mProcessStats.init();
1445
1446 // Add ourself to the Watchdog monitors.
1447 Watchdog.getInstance().addMonitor(this);
1448
1449 // These values are set in system/rootdir/init.rc on startup.
1450 FOREGROUND_APP_ADJ =
1451 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1452 VISIBLE_APP_ADJ =
1453 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1454 SECONDARY_SERVER_ADJ =
1455 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001456 BACKUP_APP_ADJ =
1457 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001458 HOME_APP_ADJ =
1459 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 HIDDEN_APP_MIN_ADJ =
1461 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1462 CONTENT_PROVIDER_ADJ =
1463 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1464 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1465 EMPTY_APP_ADJ =
1466 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1467 FOREGROUND_APP_MEM =
1468 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1469 VISIBLE_APP_MEM =
1470 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1471 SECONDARY_SERVER_MEM =
1472 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001473 BACKUP_APP_MEM =
1474 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001475 HOME_APP_MEM =
1476 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001477 HIDDEN_APP_MEM =
1478 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1479 EMPTY_APP_MEM =
1480 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1481
1482 mProcessStatsThread = new Thread("ProcessStats") {
1483 public void run() {
1484 while (true) {
1485 try {
1486 try {
1487 synchronized(this) {
1488 final long now = SystemClock.uptimeMillis();
1489 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1490 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1491 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1492 // + ", write delay=" + nextWriteDelay);
1493 if (nextWriteDelay < nextCpuDelay) {
1494 nextCpuDelay = nextWriteDelay;
1495 }
1496 if (nextCpuDelay > 0) {
1497 this.wait(nextCpuDelay);
1498 }
1499 }
1500 } catch (InterruptedException e) {
1501 }
1502
1503 updateCpuStatsNow();
1504 } catch (Exception e) {
1505 Log.e(TAG, "Unexpected exception collecting process stats", e);
1506 }
1507 }
1508 }
1509 };
1510 mProcessStatsThread.start();
1511 }
1512
1513 @Override
1514 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1515 throws RemoteException {
1516 try {
1517 return super.onTransact(code, data, reply, flags);
1518 } catch (RuntimeException e) {
1519 // The activity manager only throws security exceptions, so let's
1520 // log all others.
1521 if (!(e instanceof SecurityException)) {
1522 Log.e(TAG, "Activity Manager Crash", e);
1523 }
1524 throw e;
1525 }
1526 }
1527
1528 void updateCpuStats() {
1529 synchronized (mProcessStatsThread) {
1530 final long now = SystemClock.uptimeMillis();
1531 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1532 mProcessStatsThread.notify();
1533 }
1534 }
1535 }
1536
1537 void updateCpuStatsNow() {
1538 synchronized (mProcessStatsThread) {
1539 final long now = SystemClock.uptimeMillis();
1540 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001541
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001542 if (MONITOR_CPU_USAGE &&
1543 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1544 mLastCpuTime = now;
1545 haveNewCpuStats = true;
1546 mProcessStats.update();
1547 //Log.i(TAG, mProcessStats.printCurrentState());
1548 //Log.i(TAG, "Total CPU usage: "
1549 // + mProcessStats.getTotalCpuPercent() + "%");
1550
1551 // Log the cpu usage if the property is set.
1552 if ("true".equals(SystemProperties.get("events.cpu"))) {
1553 int user = mProcessStats.getLastUserTime();
1554 int system = mProcessStats.getLastSystemTime();
1555 int iowait = mProcessStats.getLastIoWaitTime();
1556 int irq = mProcessStats.getLastIrqTime();
1557 int softIrq = mProcessStats.getLastSoftIrqTime();
1558 int idle = mProcessStats.getLastIdleTime();
1559
1560 int total = user + system + iowait + irq + softIrq + idle;
1561 if (total == 0) total = 1;
1562
1563 EventLog.writeEvent(LOG_CPU,
1564 ((user+system+iowait+irq+softIrq) * 100) / total,
1565 (user * 100) / total,
1566 (system * 100) / total,
1567 (iowait * 100) / total,
1568 (irq * 100) / total,
1569 (softIrq * 100) / total);
1570 }
1571 }
1572
Amith Yamasani819f9282009-06-24 23:18:15 -07001573 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001574 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001575 synchronized(mPidsSelfLocked) {
1576 if (haveNewCpuStats) {
1577 if (mBatteryStatsService.isOnBattery()) {
1578 final int N = mProcessStats.countWorkingStats();
1579 for (int i=0; i<N; i++) {
1580 ProcessStats.Stats st
1581 = mProcessStats.getWorkingStats(i);
1582 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1583 if (pr != null) {
1584 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1585 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001586 } else {
1587 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001588 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001589 if (ps != null) {
1590 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1591 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001592 }
1593 }
1594 }
1595 }
1596 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001597
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001598 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1599 mLastWriteTime = now;
1600 mBatteryStatsService.getActiveStatistics().writeLocked();
1601 }
1602 }
1603 }
1604 }
1605
1606 /**
1607 * Initialize the application bind args. These are passed to each
1608 * process when the bindApplication() IPC is sent to the process. They're
1609 * lazily setup to make sure the services are running when they're asked for.
1610 */
1611 private HashMap<String, IBinder> getCommonServicesLocked() {
1612 if (mAppBindArgs == null) {
1613 mAppBindArgs = new HashMap<String, IBinder>();
1614
1615 // Setup the application init args
1616 mAppBindArgs.put("package", ServiceManager.getService("package"));
1617 mAppBindArgs.put("window", ServiceManager.getService("window"));
1618 mAppBindArgs.put(Context.ALARM_SERVICE,
1619 ServiceManager.getService(Context.ALARM_SERVICE));
1620 }
1621 return mAppBindArgs;
1622 }
1623
1624 private final void setFocusedActivityLocked(HistoryRecord r) {
1625 if (mFocusedActivity != r) {
1626 mFocusedActivity = r;
1627 mWindowManager.setFocusedApp(r, true);
1628 }
1629 }
1630
1631 private final void updateLRUListLocked(ProcessRecord app,
1632 boolean oomAdj) {
1633 // put it on the LRU to keep track of when it should be exited.
1634 int lrui = mLRUProcesses.indexOf(app);
1635 if (lrui >= 0) mLRUProcesses.remove(lrui);
1636 mLRUProcesses.add(app);
1637 //Log.i(TAG, "Putting proc to front: " + app.processName);
1638 if (oomAdj) {
1639 updateOomAdjLocked();
1640 }
1641 }
1642
1643 private final boolean updateLRUListLocked(HistoryRecord r) {
1644 final boolean hadit = mLRUActivities.remove(r);
1645 mLRUActivities.add(r);
1646 return hadit;
1647 }
1648
1649 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1650 int i = mHistory.size()-1;
1651 while (i >= 0) {
1652 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1653 if (!r.finishing && r != notTop) {
1654 return r;
1655 }
1656 i--;
1657 }
1658 return null;
1659 }
1660
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001661 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1662 int i = mHistory.size()-1;
1663 while (i >= 0) {
1664 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1665 if (!r.finishing && !r.delayedResume && r != notTop) {
1666 return r;
1667 }
1668 i--;
1669 }
1670 return null;
1671 }
1672
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001673 /**
1674 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001675 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001676 *
1677 * @param token If non-null, any history records matching this token will be skipped.
1678 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1679 *
1680 * @return Returns the HistoryRecord of the next activity on the stack.
1681 */
1682 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1683 int i = mHistory.size()-1;
1684 while (i >= 0) {
1685 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1686 // Note: the taskId check depends on real taskId fields being non-zero
1687 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1688 return r;
1689 }
1690 i--;
1691 }
1692 return null;
1693 }
1694
1695 private final ProcessRecord getProcessRecordLocked(
1696 String processName, int uid) {
1697 if (uid == Process.SYSTEM_UID) {
1698 // The system gets to run in any process. If there are multiple
1699 // processes with the same uid, just pick the first (this
1700 // should never happen).
1701 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1702 processName);
1703 return procs != null ? procs.valueAt(0) : null;
1704 }
1705 ProcessRecord proc = mProcessNames.get(processName, uid);
1706 return proc;
1707 }
1708
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001709 private void ensurePackageDexOpt(String packageName) {
1710 IPackageManager pm = ActivityThread.getPackageManager();
1711 try {
1712 if (pm.performDexOpt(packageName)) {
1713 mDidDexOpt = true;
1714 }
1715 } catch (RemoteException e) {
1716 }
1717 }
1718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 private boolean isNextTransitionForward() {
1720 int transit = mWindowManager.getPendingAppTransition();
1721 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1722 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1723 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1724 }
1725
1726 private final boolean realStartActivityLocked(HistoryRecord r,
1727 ProcessRecord app, boolean andResume, boolean checkConfig)
1728 throws RemoteException {
1729
1730 r.startFreezingScreenLocked(app, 0);
1731 mWindowManager.setAppVisibility(r, true);
1732
1733 // Have the window manager re-evaluate the orientation of
1734 // the screen based on the new activity order. Note that
1735 // as a result of this, it can call back into the activity
1736 // manager with a new orientation. We don't care about that,
1737 // because the activity is not currently running so we are
1738 // just restarting it anyway.
1739 if (checkConfig) {
1740 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001741 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 r.mayFreezeScreenLocked(app) ? r : null);
1743 updateConfigurationLocked(config, r);
1744 }
1745
1746 r.app = app;
1747
1748 if (localLOGV) Log.v(TAG, "Launching: " + r);
1749
1750 int idx = app.activities.indexOf(r);
1751 if (idx < 0) {
1752 app.activities.add(r);
1753 }
1754 updateLRUListLocked(app, true);
1755
1756 try {
1757 if (app.thread == null) {
1758 throw new RemoteException();
1759 }
1760 List<ResultInfo> results = null;
1761 List<Intent> newIntents = null;
1762 if (andResume) {
1763 results = r.results;
1764 newIntents = r.newIntents;
1765 }
1766 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1767 + " icicle=" + r.icicle
1768 + " with results=" + results + " newIntents=" + newIntents
1769 + " andResume=" + andResume);
1770 if (andResume) {
1771 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1772 System.identityHashCode(r),
1773 r.task.taskId, r.shortComponentName);
1774 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001775 if (r.isHomeActivity) {
1776 mHomeProcess = app;
1777 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001778 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001779 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001780 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001781 r.info, r.icicle, results, newIntents, !andResume,
1782 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001783 } catch (RemoteException e) {
1784 if (r.launchFailed) {
1785 // This is the second time we failed -- finish activity
1786 // and give up.
1787 Log.e(TAG, "Second failure launching "
1788 + r.intent.getComponent().flattenToShortString()
1789 + ", giving up", e);
1790 appDiedLocked(app, app.pid, app.thread);
1791 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1792 "2nd-crash");
1793 return false;
1794 }
1795
1796 // This is the first time we failed -- restart process and
1797 // retry.
1798 app.activities.remove(r);
1799 throw e;
1800 }
1801
1802 r.launchFailed = false;
1803 if (updateLRUListLocked(r)) {
1804 Log.w(TAG, "Activity " + r
1805 + " being launched, but already in LRU list");
1806 }
1807
1808 if (andResume) {
1809 // As part of the process of launching, ActivityThread also performs
1810 // a resume.
1811 r.state = ActivityState.RESUMED;
1812 r.icicle = null;
1813 r.haveState = false;
1814 r.stopped = false;
1815 mResumedActivity = r;
1816 r.task.touchActiveTime();
1817 completeResumeLocked(r);
1818 pauseIfSleepingLocked();
1819 } else {
1820 // This activity is not starting in the resumed state... which
1821 // should look like we asked it to pause+stop (but remain visible),
1822 // and it has done so and reported back the current icicle and
1823 // other state.
1824 r.state = ActivityState.STOPPED;
1825 r.stopped = true;
1826 }
1827
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001828 // Launch the new version setup screen if needed. We do this -after-
1829 // launching the initial activity (that is, home), so that it can have
1830 // a chance to initialize itself while in the background, making the
1831 // switch back to it faster and look better.
1832 startSetupActivityLocked();
1833
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001834 return true;
1835 }
1836
1837 private final void startSpecificActivityLocked(HistoryRecord r,
1838 boolean andResume, boolean checkConfig) {
1839 // Is this activity's application already running?
1840 ProcessRecord app = getProcessRecordLocked(r.processName,
1841 r.info.applicationInfo.uid);
1842
1843 if (r.startTime == 0) {
1844 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001845 if (mInitialStartTime == 0) {
1846 mInitialStartTime = r.startTime;
1847 }
1848 } else if (mInitialStartTime == 0) {
1849 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 }
1851
1852 if (app != null && app.thread != null) {
1853 try {
1854 realStartActivityLocked(r, app, andResume, checkConfig);
1855 return;
1856 } catch (RemoteException e) {
1857 Log.w(TAG, "Exception when starting activity "
1858 + r.intent.getComponent().flattenToShortString(), e);
1859 }
1860
1861 // If a dead object exception was thrown -- fall through to
1862 // restart the application.
1863 }
1864
1865 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001866 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001867 }
1868
1869 private final ProcessRecord startProcessLocked(String processName,
1870 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001871 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001872 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1873 // We don't have to do anything more if:
1874 // (1) There is an existing application record; and
1875 // (2) The caller doesn't think it is dead, OR there is no thread
1876 // object attached to it so we know it couldn't have crashed; and
1877 // (3) There is a pid assigned to it, so it is either starting or
1878 // already running.
1879 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1880 + " app=" + app + " knownToBeDead=" + knownToBeDead
1881 + " thread=" + (app != null ? app.thread : null)
1882 + " pid=" + (app != null ? app.pid : -1));
1883 if (app != null &&
1884 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1885 return app;
1886 }
1887
1888 String hostingNameStr = hostingName != null
1889 ? hostingName.flattenToShortString() : null;
1890
1891 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1892 // If we are in the background, then check to see if this process
1893 // is bad. If so, we will just silently fail.
1894 if (mBadProcesses.get(info.processName, info.uid) != null) {
1895 return null;
1896 }
1897 } else {
1898 // When the user is explicitly starting a process, then clear its
1899 // crash count so that we won't make it bad until they see at
1900 // least one crash dialog again, and make the process good again
1901 // if it had been bad.
1902 mProcessCrashTimes.remove(info.processName, info.uid);
1903 if (mBadProcesses.get(info.processName, info.uid) != null) {
1904 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1905 info.processName);
1906 mBadProcesses.remove(info.processName, info.uid);
1907 if (app != null) {
1908 app.bad = false;
1909 }
1910 }
1911 }
1912
1913 if (app == null) {
1914 app = newProcessRecordLocked(null, info, processName);
1915 mProcessNames.put(processName, info.uid, app);
1916 } else {
1917 // If this is a new package in the process, add the package to the list
1918 app.addPackage(info.packageName);
1919 }
1920
1921 // If the system is not ready yet, then hold off on starting this
1922 // process until it is.
1923 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001924 && !isAllowedWhileBooting(info)
1925 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001926 if (!mProcessesOnHold.contains(app)) {
1927 mProcessesOnHold.add(app);
1928 }
1929 return app;
1930 }
1931
1932 startProcessLocked(app, hostingType, hostingNameStr);
1933 return (app.pid != 0) ? app : null;
1934 }
1935
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001936 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1937 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1938 }
1939
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001940 private final void startProcessLocked(ProcessRecord app,
1941 String hostingType, String hostingNameStr) {
1942 if (app.pid > 0 && app.pid != MY_PID) {
1943 synchronized (mPidsSelfLocked) {
1944 mPidsSelfLocked.remove(app.pid);
1945 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1946 }
1947 app.pid = 0;
1948 }
1949
1950 mProcessesOnHold.remove(app);
1951
1952 updateCpuStats();
1953
1954 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1955 mProcDeaths[0] = 0;
1956
1957 try {
1958 int uid = app.info.uid;
1959 int[] gids = null;
1960 try {
1961 gids = mContext.getPackageManager().getPackageGids(
1962 app.info.packageName);
1963 } catch (PackageManager.NameNotFoundException e) {
1964 Log.w(TAG, "Unable to retrieve gids", e);
1965 }
1966 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1967 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1968 && mTopComponent != null
1969 && app.processName.equals(mTopComponent.getPackageName())) {
1970 uid = 0;
1971 }
1972 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1973 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1974 uid = 0;
1975 }
1976 }
1977 int debugFlags = 0;
1978 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1979 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1980 }
1981 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1982 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1983 }
1984 if ("1".equals(SystemProperties.get("debug.assert"))) {
1985 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1986 }
1987 int pid = Process.start("android.app.ActivityThread",
1988 mSimpleProcessManagement ? app.processName : null, uid, uid,
1989 gids, debugFlags, null);
1990 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1991 synchronized (bs) {
1992 if (bs.isOnBattery()) {
1993 app.batteryStats.incStartsLocked();
1994 }
1995 }
1996
1997 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1998 app.processName, hostingType,
1999 hostingNameStr != null ? hostingNameStr : "");
2000
2001 if (app.persistent) {
2002 Watchdog.getInstance().processStarted(app, app.processName, pid);
2003 }
2004
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07002005 StringBuilder buf = mStringBuilder;
2006 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002007 buf.append("Start proc ");
2008 buf.append(app.processName);
2009 buf.append(" for ");
2010 buf.append(hostingType);
2011 if (hostingNameStr != null) {
2012 buf.append(" ");
2013 buf.append(hostingNameStr);
2014 }
2015 buf.append(": pid=");
2016 buf.append(pid);
2017 buf.append(" uid=");
2018 buf.append(uid);
2019 buf.append(" gids={");
2020 if (gids != null) {
2021 for (int gi=0; gi<gids.length; gi++) {
2022 if (gi != 0) buf.append(", ");
2023 buf.append(gids[gi]);
2024
2025 }
2026 }
2027 buf.append("}");
2028 Log.i(TAG, buf.toString());
2029 if (pid == 0 || pid == MY_PID) {
2030 // Processes are being emulated with threads.
2031 app.pid = MY_PID;
2032 app.removed = false;
2033 mStartingProcesses.add(app);
2034 } else if (pid > 0) {
2035 app.pid = pid;
2036 app.removed = false;
2037 synchronized (mPidsSelfLocked) {
2038 this.mPidsSelfLocked.put(pid, app);
2039 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2040 msg.obj = app;
2041 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2042 }
2043 } else {
2044 app.pid = 0;
2045 RuntimeException e = new RuntimeException(
2046 "Failure starting process " + app.processName
2047 + ": returned pid=" + pid);
2048 Log.e(TAG, e.getMessage(), e);
2049 }
2050 } catch (RuntimeException e) {
2051 // XXX do better error recovery.
2052 app.pid = 0;
2053 Log.e(TAG, "Failure starting process " + app.processName, e);
2054 }
2055 }
2056
2057 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2058 if (mPausingActivity != null) {
2059 RuntimeException e = new RuntimeException();
2060 Log.e(TAG, "Trying to pause when pause is already pending for "
2061 + mPausingActivity, e);
2062 }
2063 HistoryRecord prev = mResumedActivity;
2064 if (prev == null) {
2065 RuntimeException e = new RuntimeException();
2066 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2067 resumeTopActivityLocked(null);
2068 return;
2069 }
2070 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2071 mResumedActivity = null;
2072 mPausingActivity = prev;
2073 mLastPausedActivity = prev;
2074 prev.state = ActivityState.PAUSING;
2075 prev.task.touchActiveTime();
2076
2077 updateCpuStats();
2078
2079 if (prev.app != null && prev.app.thread != null) {
2080 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2081 try {
2082 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2083 System.identityHashCode(prev),
2084 prev.shortComponentName);
2085 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2086 prev.configChangeFlags);
2087 updateUsageStats(prev, false);
2088 } catch (Exception e) {
2089 // Ignore exception, if process died other code will cleanup.
2090 Log.w(TAG, "Exception thrown during pause", e);
2091 mPausingActivity = null;
2092 mLastPausedActivity = null;
2093 }
2094 } else {
2095 mPausingActivity = null;
2096 mLastPausedActivity = null;
2097 }
2098
2099 // If we are not going to sleep, we want to ensure the device is
2100 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002101 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002102 mLaunchingActivity.acquire();
2103 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2104 // To be safe, don't allow the wake lock to be held for too long.
2105 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2106 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2107 }
2108 }
2109
2110
2111 if (mPausingActivity != null) {
2112 // Have the window manager pause its key dispatching until the new
2113 // activity has started. If we're pausing the activity just because
2114 // the screen is being turned off and the UI is sleeping, don't interrupt
2115 // key dispatch; the same activity will pick it up again on wakeup.
2116 if (!uiSleeping) {
2117 prev.pauseKeyDispatchingLocked();
2118 } else {
2119 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2120 }
2121
2122 // Schedule a pause timeout in case the app doesn't respond.
2123 // We don't give it much time because this directly impacts the
2124 // responsiveness seen by the user.
2125 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2126 msg.obj = prev;
2127 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2128 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2129 } else {
2130 // This activity failed to schedule the
2131 // pause, so just treat it as being paused now.
2132 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2133 resumeTopActivityLocked(null);
2134 }
2135 }
2136
2137 private final void completePauseLocked() {
2138 HistoryRecord prev = mPausingActivity;
2139 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2140
2141 if (prev != null) {
2142 if (prev.finishing) {
2143 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2144 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2145 } else if (prev.app != null) {
2146 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2147 if (prev.waitingVisible) {
2148 prev.waitingVisible = false;
2149 mWaitingVisibleActivities.remove(prev);
2150 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2151 TAG, "Complete pause, no longer waiting: " + prev);
2152 }
2153 if (prev.configDestroy) {
2154 // The previous is being paused because the configuration
2155 // is changing, which means it is actually stopping...
2156 // To juggle the fact that we are also starting a new
2157 // instance right now, we need to first completely stop
2158 // the current instance before starting the new one.
2159 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2160 destroyActivityLocked(prev, true);
2161 } else {
2162 mStoppingActivities.add(prev);
2163 if (mStoppingActivities.size() > 3) {
2164 // If we already have a few activities waiting to stop,
2165 // then give up on things going idle and start clearing
2166 // them out.
2167 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2168 Message msg = Message.obtain();
2169 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2170 mHandler.sendMessage(msg);
2171 }
2172 }
2173 } else {
2174 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2175 prev = null;
2176 }
2177 mPausingActivity = null;
2178 }
2179
Dianne Hackborn55280a92009-05-07 15:53:46 -07002180 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002181 resumeTopActivityLocked(prev);
2182 } else {
2183 if (mGoingToSleep.isHeld()) {
2184 mGoingToSleep.release();
2185 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002186 if (mShuttingDown) {
2187 notifyAll();
2188 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002189 }
2190
2191 if (prev != null) {
2192 prev.resumeKeyDispatchingLocked();
2193 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002194
2195 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2196 long diff = 0;
2197 synchronized (mProcessStatsThread) {
2198 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2199 }
2200 if (diff > 0) {
2201 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2202 synchronized (bsi) {
2203 BatteryStatsImpl.Uid.Proc ps =
2204 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2205 prev.info.packageName);
2206 if (ps != null) {
2207 ps.addForegroundTimeLocked(diff);
2208 }
2209 }
2210 }
2211 }
2212 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002213 }
2214
2215 /**
2216 * Once we know that we have asked an application to put an activity in
2217 * the resumed state (either by launching it or explicitly telling it),
2218 * this function updates the rest of our state to match that fact.
2219 */
2220 private final void completeResumeLocked(HistoryRecord next) {
2221 next.idle = false;
2222 next.results = null;
2223 next.newIntents = null;
2224
2225 // schedule an idle timeout in case the app doesn't do it for us.
2226 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2227 msg.obj = next;
2228 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2229
2230 if (false) {
2231 // The activity was never told to pause, so just keep
2232 // things going as-is. To maintain our own state,
2233 // we need to emulate it coming back and saying it is
2234 // idle.
2235 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2236 msg.obj = next;
2237 mHandler.sendMessage(msg);
2238 }
2239
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002240 reportResumedActivity(next);
2241
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002242 next.thumbnail = null;
2243 setFocusedActivityLocked(next);
2244 next.resumeKeyDispatchingLocked();
2245 ensureActivitiesVisibleLocked(null, 0);
2246 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002247
2248 // Mark the point when the activity is resuming
2249 // TODO: To be more accurate, the mark should be before the onCreate,
2250 // not after the onResume. But for subsequent starts, onResume is fine.
2251 if (next.app != null) {
2252 synchronized (mProcessStatsThread) {
2253 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2254 }
2255 } else {
2256 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2257 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002258 }
2259
2260 /**
2261 * Make sure that all activities that need to be visible (that is, they
2262 * currently can be seen by the user) actually are.
2263 */
2264 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2265 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2266 if (DEBUG_VISBILITY) Log.v(
2267 TAG, "ensureActivitiesVisible behind " + top
2268 + " configChanges=0x" + Integer.toHexString(configChanges));
2269
2270 // If the top activity is not fullscreen, then we need to
2271 // make sure any activities under it are now visible.
2272 final int count = mHistory.size();
2273 int i = count-1;
2274 while (mHistory.get(i) != top) {
2275 i--;
2276 }
2277 HistoryRecord r;
2278 boolean behindFullscreen = false;
2279 for (; i>=0; i--) {
2280 r = (HistoryRecord)mHistory.get(i);
2281 if (DEBUG_VISBILITY) Log.v(
2282 TAG, "Make visible? " + r + " finishing=" + r.finishing
2283 + " state=" + r.state);
2284 if (r.finishing) {
2285 continue;
2286 }
2287
2288 final boolean doThisProcess = onlyThisProcess == null
2289 || onlyThisProcess.equals(r.processName);
2290
2291 // First: if this is not the current activity being started, make
2292 // sure it matches the current configuration.
2293 if (r != starting && doThisProcess) {
2294 ensureActivityConfigurationLocked(r, 0);
2295 }
2296
2297 if (r.app == null || r.app.thread == null) {
2298 if (onlyThisProcess == null
2299 || onlyThisProcess.equals(r.processName)) {
2300 // This activity needs to be visible, but isn't even
2301 // running... get it started, but don't resume it
2302 // at this point.
2303 if (DEBUG_VISBILITY) Log.v(
2304 TAG, "Start and freeze screen for " + r);
2305 if (r != starting) {
2306 r.startFreezingScreenLocked(r.app, configChanges);
2307 }
2308 if (!r.visible) {
2309 if (DEBUG_VISBILITY) Log.v(
2310 TAG, "Starting and making visible: " + r);
2311 mWindowManager.setAppVisibility(r, true);
2312 }
2313 if (r != starting) {
2314 startSpecificActivityLocked(r, false, false);
2315 }
2316 }
2317
2318 } else if (r.visible) {
2319 // If this activity is already visible, then there is nothing
2320 // else to do here.
2321 if (DEBUG_VISBILITY) Log.v(
2322 TAG, "Skipping: already visible at " + r);
2323 r.stopFreezingScreenLocked(false);
2324
2325 } else if (onlyThisProcess == null) {
2326 // This activity is not currently visible, but is running.
2327 // Tell it to become visible.
2328 r.visible = true;
2329 if (r.state != ActivityState.RESUMED && r != starting) {
2330 // If this activity is paused, tell it
2331 // to now show its window.
2332 if (DEBUG_VISBILITY) Log.v(
2333 TAG, "Making visible and scheduling visibility: " + r);
2334 try {
2335 mWindowManager.setAppVisibility(r, true);
2336 r.app.thread.scheduleWindowVisibility(r, true);
2337 r.stopFreezingScreenLocked(false);
2338 } catch (Exception e) {
2339 // Just skip on any failure; we'll make it
2340 // visible when it next restarts.
2341 Log.w(TAG, "Exception thrown making visibile: "
2342 + r.intent.getComponent(), e);
2343 }
2344 }
2345 }
2346
2347 // Aggregate current change flags.
2348 configChanges |= r.configChangeFlags;
2349
2350 if (r.fullscreen) {
2351 // At this point, nothing else needs to be shown
2352 if (DEBUG_VISBILITY) Log.v(
2353 TAG, "Stopping: fullscreen at " + r);
2354 behindFullscreen = true;
2355 i--;
2356 break;
2357 }
2358 }
2359
2360 // Now for any activities that aren't visible to the user, make
2361 // sure they no longer are keeping the screen frozen.
2362 while (i >= 0) {
2363 r = (HistoryRecord)mHistory.get(i);
2364 if (DEBUG_VISBILITY) Log.v(
2365 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2366 + " state=" + r.state
2367 + " behindFullscreen=" + behindFullscreen);
2368 if (!r.finishing) {
2369 if (behindFullscreen) {
2370 if (r.visible) {
2371 if (DEBUG_VISBILITY) Log.v(
2372 TAG, "Making invisible: " + r);
2373 r.visible = false;
2374 try {
2375 mWindowManager.setAppVisibility(r, false);
2376 if ((r.state == ActivityState.STOPPING
2377 || r.state == ActivityState.STOPPED)
2378 && r.app != null && r.app.thread != null) {
2379 if (DEBUG_VISBILITY) Log.v(
2380 TAG, "Scheduling invisibility: " + r);
2381 r.app.thread.scheduleWindowVisibility(r, false);
2382 }
2383 } catch (Exception e) {
2384 // Just skip on any failure; we'll make it
2385 // visible when it next restarts.
2386 Log.w(TAG, "Exception thrown making hidden: "
2387 + r.intent.getComponent(), e);
2388 }
2389 } else {
2390 if (DEBUG_VISBILITY) Log.v(
2391 TAG, "Already invisible: " + r);
2392 }
2393 } else if (r.fullscreen) {
2394 if (DEBUG_VISBILITY) Log.v(
2395 TAG, "Now behindFullscreen: " + r);
2396 behindFullscreen = true;
2397 }
2398 }
2399 i--;
2400 }
2401 }
2402
2403 /**
2404 * Version of ensureActivitiesVisible that can easily be called anywhere.
2405 */
2406 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2407 int configChanges) {
2408 HistoryRecord r = topRunningActivityLocked(null);
2409 if (r != null) {
2410 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2411 }
2412 }
2413
2414 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2415 if (resumed) {
2416 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2417 } else {
2418 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2419 }
2420 }
2421
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002422 private boolean startHomeActivityLocked() {
2423 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2424 && mTopAction == null) {
2425 // We are running in factory test mode, but unable to find
2426 // the factory test app, so just sit around displaying the
2427 // error message and don't try to start anything.
2428 return false;
2429 }
2430 Intent intent = new Intent(
2431 mTopAction,
2432 mTopData != null ? Uri.parse(mTopData) : null);
2433 intent.setComponent(mTopComponent);
2434 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2435 intent.addCategory(Intent.CATEGORY_HOME);
2436 }
2437 ActivityInfo aInfo =
2438 intent.resolveActivityInfo(mContext.getPackageManager(),
2439 STOCK_PM_FLAGS);
2440 if (aInfo != null) {
2441 intent.setComponent(new ComponentName(
2442 aInfo.applicationInfo.packageName, aInfo.name));
2443 // Don't do this if the home app is currently being
2444 // instrumented.
2445 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2446 aInfo.applicationInfo.uid);
2447 if (app == null || app.instrumentationClass == null) {
2448 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2449 startActivityLocked(null, intent, null, null, 0, aInfo,
2450 null, null, 0, 0, 0, false, false);
2451 }
2452 }
2453
2454
2455 return true;
2456 }
2457
2458 /**
2459 * Starts the "new version setup screen" if appropriate.
2460 */
2461 private void startSetupActivityLocked() {
2462 // Only do this once per boot.
2463 if (mCheckedForSetup) {
2464 return;
2465 }
2466
2467 // We will show this screen if the current one is a different
2468 // version than the last one shown, and we are not running in
2469 // low-level factory test mode.
2470 final ContentResolver resolver = mContext.getContentResolver();
2471 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2472 Settings.Secure.getInt(resolver,
2473 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2474 mCheckedForSetup = true;
2475
2476 // See if we should be showing the platform update setup UI.
2477 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2478 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2479 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2480
2481 // We don't allow third party apps to replace this.
2482 ResolveInfo ri = null;
2483 for (int i=0; ris != null && i<ris.size(); i++) {
2484 if ((ris.get(i).activityInfo.applicationInfo.flags
2485 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2486 ri = ris.get(i);
2487 break;
2488 }
2489 }
2490
2491 if (ri != null) {
2492 String vers = ri.activityInfo.metaData != null
2493 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2494 : null;
2495 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2496 vers = ri.activityInfo.applicationInfo.metaData.getString(
2497 Intent.METADATA_SETUP_VERSION);
2498 }
2499 String lastVers = Settings.Secure.getString(
2500 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2501 if (vers != null && !vers.equals(lastVers)) {
2502 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2503 intent.setComponent(new ComponentName(
2504 ri.activityInfo.packageName, ri.activityInfo.name));
2505 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2506 null, null, 0, 0, 0, false, false);
2507 }
2508 }
2509 }
2510 }
2511
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002512 private void reportResumedActivity(HistoryRecord r) {
2513 //Log.i(TAG, "**** REPORT RESUME: " + r);
2514
2515 final int identHash = System.identityHashCode(r);
2516 updateUsageStats(r, true);
2517
2518 int i = mWatchers.beginBroadcast();
2519 while (i > 0) {
2520 i--;
2521 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2522 if (w != null) {
2523 try {
2524 w.activityResuming(identHash);
2525 } catch (RemoteException e) {
2526 }
2527 }
2528 }
2529 mWatchers.finishBroadcast();
2530 }
2531
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002532 /**
2533 * Ensure that the top activity in the stack is resumed.
2534 *
2535 * @param prev The previously resumed activity, for when in the process
2536 * of pausing; can be null to call from elsewhere.
2537 *
2538 * @return Returns true if something is being resumed, or false if
2539 * nothing happened.
2540 */
2541 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2542 // Find the first activity that is not finishing.
2543 HistoryRecord next = topRunningActivityLocked(null);
2544
2545 // Remember how we'll process this pause/resume situation, and ensure
2546 // that the state is reset however we wind up proceeding.
2547 final boolean userLeaving = mUserLeaving;
2548 mUserLeaving = false;
2549
2550 if (next == null) {
2551 // There are no more activities! Let's just start up the
2552 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002553 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002554 }
2555
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002556 next.delayedResume = false;
2557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002558 // If the top activity is the resumed one, nothing to do.
2559 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2560 // Make sure we have executed any pending transitions, since there
2561 // should be nothing left to do at this point.
2562 mWindowManager.executeAppTransition();
2563 return false;
2564 }
2565
2566 // If we are sleeping, and there is no resumed activity, and the top
2567 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002568 if ((mSleeping || mShuttingDown)
2569 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002570 // Make sure we have executed any pending transitions, since there
2571 // should be nothing left to do at this point.
2572 mWindowManager.executeAppTransition();
2573 return false;
2574 }
2575
2576 // The activity may be waiting for stop, but that is no longer
2577 // appropriate for it.
2578 mStoppingActivities.remove(next);
2579 mWaitingVisibleActivities.remove(next);
2580
2581 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2582
2583 // If we are currently pausing an activity, then don't do anything
2584 // until that is done.
2585 if (mPausingActivity != null) {
2586 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2587 return false;
2588 }
2589
2590 // We need to start pausing the current activity so the top one
2591 // can be resumed...
2592 if (mResumedActivity != null) {
2593 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2594 startPausingLocked(userLeaving, false);
2595 return true;
2596 }
2597
2598 if (prev != null && prev != next) {
2599 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2600 prev.waitingVisible = true;
2601 mWaitingVisibleActivities.add(prev);
2602 if (DEBUG_SWITCH) Log.v(
2603 TAG, "Resuming top, waiting visible to hide: " + prev);
2604 } else {
2605 // The next activity is already visible, so hide the previous
2606 // activity's windows right now so we can show the new one ASAP.
2607 // We only do this if the previous is finishing, which should mean
2608 // it is on top of the one being resumed so hiding it quickly
2609 // is good. Otherwise, we want to do the normal route of allowing
2610 // the resumed activity to be shown so we can decide if the
2611 // previous should actually be hidden depending on whether the
2612 // new one is found to be full-screen or not.
2613 if (prev.finishing) {
2614 mWindowManager.setAppVisibility(prev, false);
2615 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2616 + prev + ", waitingVisible="
2617 + (prev != null ? prev.waitingVisible : null)
2618 + ", nowVisible=" + next.nowVisible);
2619 } else {
2620 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2621 + prev + ", waitingVisible="
2622 + (prev != null ? prev.waitingVisible : null)
2623 + ", nowVisible=" + next.nowVisible);
2624 }
2625 }
2626 }
2627
2628 // We are starting up the next activity, so tell the window manager
2629 // that the previous one will be hidden soon. This way it can know
2630 // to ignore it when computing the desired screen orientation.
2631 if (prev != null) {
2632 if (prev.finishing) {
2633 if (DEBUG_TRANSITION) Log.v(TAG,
2634 "Prepare close transition: prev=" + prev);
2635 mWindowManager.prepareAppTransition(prev.task == next.task
2636 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2637 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2638 mWindowManager.setAppWillBeHidden(prev);
2639 mWindowManager.setAppVisibility(prev, false);
2640 } else {
2641 if (DEBUG_TRANSITION) Log.v(TAG,
2642 "Prepare open transition: prev=" + prev);
2643 mWindowManager.prepareAppTransition(prev.task == next.task
2644 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2645 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2646 }
2647 if (false) {
2648 mWindowManager.setAppWillBeHidden(prev);
2649 mWindowManager.setAppVisibility(prev, false);
2650 }
2651 } else if (mHistory.size() > 1) {
2652 if (DEBUG_TRANSITION) Log.v(TAG,
2653 "Prepare open transition: no previous");
2654 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2655 }
2656
2657 if (next.app != null && next.app.thread != null) {
2658 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2659
2660 // This activity is now becoming visible.
2661 mWindowManager.setAppVisibility(next, true);
2662
2663 HistoryRecord lastResumedActivity = mResumedActivity;
2664 ActivityState lastState = next.state;
2665
2666 updateCpuStats();
2667
2668 next.state = ActivityState.RESUMED;
2669 mResumedActivity = next;
2670 next.task.touchActiveTime();
2671 updateLRUListLocked(next.app, true);
2672 updateLRUListLocked(next);
2673
2674 // Have the window manager re-evaluate the orientation of
2675 // the screen based on the new activity order.
2676 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002677 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002678 next.mayFreezeScreenLocked(next.app) ? next : null);
2679 if (config != null) {
2680 next.frozenBeforeDestroy = true;
2681 }
2682 if (!updateConfigurationLocked(config, next)) {
2683 // The configuration update wasn't able to keep the existing
2684 // instance of the activity, and instead started a new one.
2685 // We should be all done, but let's just make sure our activity
2686 // is still at the top and schedule another run if something
2687 // weird happened.
2688 HistoryRecord nextNext = topRunningActivityLocked(null);
2689 if (DEBUG_SWITCH) Log.i(TAG,
2690 "Activity config changed during resume: " + next
2691 + ", new next: " + nextNext);
2692 if (nextNext != next) {
2693 // Do over!
2694 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2695 }
2696 mWindowManager.executeAppTransition();
2697 return true;
2698 }
2699
2700 try {
2701 // Deliver all pending results.
2702 ArrayList a = next.results;
2703 if (a != null) {
2704 final int N = a.size();
2705 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002706 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002707 TAG, "Delivering results to " + next
2708 + ": " + a);
2709 next.app.thread.scheduleSendResult(next, a);
2710 }
2711 }
2712
2713 if (next.newIntents != null) {
2714 next.app.thread.scheduleNewIntent(next.newIntents, next);
2715 }
2716
2717 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2718 System.identityHashCode(next),
2719 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002720
2721 next.app.thread.scheduleResumeActivity(next,
2722 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002724 pauseIfSleepingLocked();
2725
2726 } catch (Exception e) {
2727 // Whoops, need to restart this activity!
2728 next.state = lastState;
2729 mResumedActivity = lastResumedActivity;
2730 if (Config.LOGD) Log.d(TAG,
2731 "Restarting because process died: " + next);
2732 if (!next.hasBeenLaunched) {
2733 next.hasBeenLaunched = true;
2734 } else {
2735 if (SHOW_APP_STARTING_ICON) {
2736 mWindowManager.setAppStartingWindow(
2737 next, next.packageName, next.theme,
2738 next.nonLocalizedLabel,
2739 next.labelRes, next.icon, null, true);
2740 }
2741 }
2742 startSpecificActivityLocked(next, true, false);
2743 return true;
2744 }
2745
2746 // From this point on, if something goes wrong there is no way
2747 // to recover the activity.
2748 try {
2749 next.visible = true;
2750 completeResumeLocked(next);
2751 } catch (Exception e) {
2752 // If any exception gets thrown, toss away this
2753 // activity and try the next one.
2754 Log.w(TAG, "Exception thrown during resume of " + next, e);
2755 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2756 "resume-exception");
2757 return true;
2758 }
2759
2760 // Didn't need to use the icicle, and it is now out of date.
2761 next.icicle = null;
2762 next.haveState = false;
2763 next.stopped = false;
2764
2765 } else {
2766 // Whoops, need to restart this activity!
2767 if (!next.hasBeenLaunched) {
2768 next.hasBeenLaunched = true;
2769 } else {
2770 if (SHOW_APP_STARTING_ICON) {
2771 mWindowManager.setAppStartingWindow(
2772 next, next.packageName, next.theme,
2773 next.nonLocalizedLabel,
2774 next.labelRes, next.icon, null, true);
2775 }
2776 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2777 }
2778 startSpecificActivityLocked(next, true, true);
2779 }
2780
2781 return true;
2782 }
2783
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002784 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2785 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002786 final int NH = mHistory.size();
2787
2788 int addPos = -1;
2789
2790 if (!newTask) {
2791 // If starting in an existing task, find where that is...
2792 HistoryRecord next = null;
2793 boolean startIt = true;
2794 for (int i = NH-1; i >= 0; i--) {
2795 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2796 if (p.finishing) {
2797 continue;
2798 }
2799 if (p.task == r.task) {
2800 // Here it is! Now, if this is not yet visible to the
2801 // user, then just add it without starting; it will
2802 // get started when the user navigates back to it.
2803 addPos = i+1;
2804 if (!startIt) {
2805 mHistory.add(addPos, r);
2806 r.inHistory = true;
2807 r.task.numActivities++;
2808 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2809 r.info.screenOrientation, r.fullscreen);
2810 if (VALIDATE_TOKENS) {
2811 mWindowManager.validateAppTokens(mHistory);
2812 }
2813 return;
2814 }
2815 break;
2816 }
2817 if (p.fullscreen) {
2818 startIt = false;
2819 }
2820 next = p;
2821 }
2822 }
2823
2824 // Place a new activity at top of stack, so it is next to interact
2825 // with the user.
2826 if (addPos < 0) {
2827 addPos = mHistory.size();
2828 }
2829
2830 // If we are not placing the new activity frontmost, we do not want
2831 // to deliver the onUserLeaving callback to the actual frontmost
2832 // activity
2833 if (addPos < NH) {
2834 mUserLeaving = false;
2835 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2836 }
2837
2838 // Slot the activity into the history stack and proceed
2839 mHistory.add(addPos, r);
2840 r.inHistory = true;
2841 r.frontOfTask = newTask;
2842 r.task.numActivities++;
2843 if (NH > 0) {
2844 // We want to show the starting preview window if we are
2845 // switching to a new task, or the next activity's process is
2846 // not currently running.
2847 boolean showStartingIcon = newTask;
2848 ProcessRecord proc = r.app;
2849 if (proc == null) {
2850 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2851 }
2852 if (proc == null || proc.thread == null) {
2853 showStartingIcon = true;
2854 }
2855 if (DEBUG_TRANSITION) Log.v(TAG,
2856 "Prepare open transition: starting " + r);
2857 mWindowManager.prepareAppTransition(newTask
2858 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2859 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2860 mWindowManager.addAppToken(
2861 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2862 boolean doShow = true;
2863 if (newTask) {
2864 // Even though this activity is starting fresh, we still need
2865 // to reset it to make sure we apply affinities to move any
2866 // existing activities from other tasks in to it.
2867 // If the caller has requested that the target task be
2868 // reset, then do so.
2869 if ((r.intent.getFlags()
2870 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2871 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002872 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002873 }
2874 }
2875 if (SHOW_APP_STARTING_ICON && doShow) {
2876 // Figure out if we are transitioning from another activity that is
2877 // "has the same starting icon" as the next one. This allows the
2878 // window manager to keep the previous window it had previously
2879 // created, if it still had one.
2880 HistoryRecord prev = mResumedActivity;
2881 if (prev != null) {
2882 // We don't want to reuse the previous starting preview if:
2883 // (1) The current activity is in a different task.
2884 if (prev.task != r.task) prev = null;
2885 // (2) The current activity is already displayed.
2886 else if (prev.nowVisible) prev = null;
2887 }
2888 mWindowManager.setAppStartingWindow(
2889 r, r.packageName, r.theme, r.nonLocalizedLabel,
2890 r.labelRes, r.icon, prev, showStartingIcon);
2891 }
2892 } else {
2893 // If this is the first activity, don't do any fancy animations,
2894 // because there is nothing for it to animate on top of.
2895 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2896 r.info.screenOrientation, r.fullscreen);
2897 }
2898 if (VALIDATE_TOKENS) {
2899 mWindowManager.validateAppTokens(mHistory);
2900 }
2901
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002902 if (doResume) {
2903 resumeTopActivityLocked(null);
2904 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002905 }
2906
2907 /**
2908 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002909 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2910 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002911 * an instance of that activity in the stack and, if found, finish all
2912 * activities on top of it and return the instance.
2913 *
2914 * @param newR Description of the new activity being started.
2915 * @return Returns the old activity that should be continue to be used,
2916 * or null if none was found.
2917 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002918 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002919 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002920 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002921
2922 // First find the requested task.
2923 while (i > 0) {
2924 i--;
2925 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2926 if (r.task.taskId == taskId) {
2927 i++;
2928 break;
2929 }
2930 }
2931
2932 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002933 while (i > 0) {
2934 i--;
2935 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2936 if (r.finishing) {
2937 continue;
2938 }
2939 if (r.task.taskId != taskId) {
2940 return null;
2941 }
2942 if (r.realActivity.equals(newR.realActivity)) {
2943 // Here it is! Now finish everything in front...
2944 HistoryRecord ret = r;
2945 if (doClear) {
2946 while (i < (mHistory.size()-1)) {
2947 i++;
2948 r = (HistoryRecord)mHistory.get(i);
2949 if (r.finishing) {
2950 continue;
2951 }
2952 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2953 null, "clear")) {
2954 i--;
2955 }
2956 }
2957 }
2958
2959 // Finally, if this is a normal launch mode (that is, not
2960 // expecting onNewIntent()), then we will finish the current
2961 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002962 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
2963 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002964 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002965 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002966 if (index >= 0) {
2967 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2968 null, "clear");
2969 }
2970 return null;
2971 }
2972 }
2973
2974 return ret;
2975 }
2976 }
2977
2978 return null;
2979 }
2980
2981 /**
2982 * Find the activity in the history stack within the given task. Returns
2983 * the index within the history at which it's found, or < 0 if not found.
2984 */
2985 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2986 int i = mHistory.size();
2987 while (i > 0) {
2988 i--;
2989 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2990 if (candidate.task.taskId != task) {
2991 break;
2992 }
2993 if (candidate.realActivity.equals(r.realActivity)) {
2994 return i;
2995 }
2996 }
2997
2998 return -1;
2999 }
3000
3001 /**
3002 * Reorder the history stack so that the activity at the given index is
3003 * brought to the front.
3004 */
3005 private final HistoryRecord moveActivityToFrontLocked(int where) {
3006 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3007 int top = mHistory.size();
3008 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3009 mHistory.add(top, newTop);
3010 oldTop.frontOfTask = false;
3011 newTop.frontOfTask = true;
3012 return newTop;
3013 }
3014
3015 /**
3016 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3017 * method will be called at the proper time.
3018 */
3019 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3020 boolean sent = false;
3021 if (r.state == ActivityState.RESUMED
3022 && r.app != null && r.app.thread != null) {
3023 try {
3024 ArrayList<Intent> ar = new ArrayList<Intent>();
3025 ar.add(new Intent(intent));
3026 r.app.thread.scheduleNewIntent(ar, r);
3027 sent = true;
3028 } catch (Exception e) {
3029 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3030 }
3031 }
3032 if (!sent) {
3033 r.addNewIntentLocked(new Intent(intent));
3034 }
3035 }
3036
3037 private final void logStartActivity(int tag, HistoryRecord r,
3038 TaskRecord task) {
3039 EventLog.writeEvent(tag,
3040 System.identityHashCode(r), task.taskId,
3041 r.shortComponentName, r.intent.getAction(),
3042 r.intent.getType(), r.intent.getDataString(),
3043 r.intent.getFlags());
3044 }
3045
3046 private final int startActivityLocked(IApplicationThread caller,
3047 Intent intent, String resolvedType,
3048 Uri[] grantedUriPermissions,
3049 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3050 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003051 int callingPid, int callingUid, boolean onlyIfNeeded,
3052 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003053 Log.i(TAG, "Starting activity: " + intent);
3054
3055 HistoryRecord sourceRecord = null;
3056 HistoryRecord resultRecord = null;
3057 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003058 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003059 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003060 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3061 if (index >= 0) {
3062 sourceRecord = (HistoryRecord)mHistory.get(index);
3063 if (requestCode >= 0 && !sourceRecord.finishing) {
3064 resultRecord = sourceRecord;
3065 }
3066 }
3067 }
3068
3069 int launchFlags = intent.getFlags();
3070
3071 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3072 && sourceRecord != null) {
3073 // Transfer the result target from the source activity to the new
3074 // one being started, including any failures.
3075 if (requestCode >= 0) {
3076 return START_FORWARD_AND_REQUEST_CONFLICT;
3077 }
3078 resultRecord = sourceRecord.resultTo;
3079 resultWho = sourceRecord.resultWho;
3080 requestCode = sourceRecord.requestCode;
3081 sourceRecord.resultTo = null;
3082 if (resultRecord != null) {
3083 resultRecord.removeResultsLocked(
3084 sourceRecord, resultWho, requestCode);
3085 }
3086 }
3087
3088 int err = START_SUCCESS;
3089
3090 if (intent.getComponent() == null) {
3091 // We couldn't find a class that can handle the given Intent.
3092 // That's the end of that!
3093 err = START_INTENT_NOT_RESOLVED;
3094 }
3095
3096 if (err == START_SUCCESS && aInfo == null) {
3097 // We couldn't find the specific class specified in the Intent.
3098 // Also the end of the line.
3099 err = START_CLASS_NOT_FOUND;
3100 }
3101
3102 ProcessRecord callerApp = null;
3103 if (err == START_SUCCESS && caller != null) {
3104 callerApp = getRecordForAppLocked(caller);
3105 if (callerApp != null) {
3106 callingPid = callerApp.pid;
3107 callingUid = callerApp.info.uid;
3108 } else {
3109 Log.w(TAG, "Unable to find app for caller " + caller
3110 + " (pid=" + callingPid + ") when starting: "
3111 + intent.toString());
3112 err = START_PERMISSION_DENIED;
3113 }
3114 }
3115
3116 if (err != START_SUCCESS) {
3117 if (resultRecord != null) {
3118 sendActivityResultLocked(-1,
3119 resultRecord, resultWho, requestCode,
3120 Activity.RESULT_CANCELED, null);
3121 }
3122 return err;
3123 }
3124
3125 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3126 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3127 if (perm != PackageManager.PERMISSION_GRANTED) {
3128 if (resultRecord != null) {
3129 sendActivityResultLocked(-1,
3130 resultRecord, resultWho, requestCode,
3131 Activity.RESULT_CANCELED, null);
3132 }
3133 String msg = "Permission Denial: starting " + intent.toString()
3134 + " from " + callerApp + " (pid=" + callingPid
3135 + ", uid=" + callingUid + ")"
3136 + " requires " + aInfo.permission;
3137 Log.w(TAG, msg);
3138 throw new SecurityException(msg);
3139 }
3140
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003141 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003142 boolean abort = false;
3143 try {
3144 // The Intent we give to the watcher has the extra data
3145 // stripped off, since it can contain private information.
3146 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003147 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003148 aInfo.applicationInfo.packageName);
3149 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003150 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003151 }
3152
3153 if (abort) {
3154 if (resultRecord != null) {
3155 sendActivityResultLocked(-1,
3156 resultRecord, resultWho, requestCode,
3157 Activity.RESULT_CANCELED, null);
3158 }
3159 // We pretend to the caller that it was really started, but
3160 // they will just get a cancel result.
3161 return START_SUCCESS;
3162 }
3163 }
3164
3165 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3166 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003167 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003168
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003169 if (mResumedActivity == null
3170 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3171 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3172 PendingActivityLaunch pal = new PendingActivityLaunch();
3173 pal.r = r;
3174 pal.sourceRecord = sourceRecord;
3175 pal.grantedUriPermissions = grantedUriPermissions;
3176 pal.grantedMode = grantedMode;
3177 pal.onlyIfNeeded = onlyIfNeeded;
3178 mPendingActivityLaunches.add(pal);
3179 return START_SWITCHES_CANCELED;
3180 }
3181 }
3182
3183 if (mDidAppSwitch) {
3184 // This is the second allowed switch since we stopped switches,
3185 // so now just generally allow switches. Use case: user presses
3186 // home (switches disabled, switch to home, mDidAppSwitch now true);
3187 // user taps a home icon (coming from home so allowed, we hit here
3188 // and now allow anyone to switch again).
3189 mAppSwitchesAllowedTime = 0;
3190 } else {
3191 mDidAppSwitch = true;
3192 }
3193
3194 doPendingActivityLaunchesLocked(false);
3195
3196 return startActivityUncheckedLocked(r, sourceRecord,
3197 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3198 }
3199
3200 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3201 final int N = mPendingActivityLaunches.size();
3202 if (N <= 0) {
3203 return;
3204 }
3205 for (int i=0; i<N; i++) {
3206 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3207 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3208 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3209 doResume && i == (N-1));
3210 }
3211 mPendingActivityLaunches.clear();
3212 }
3213
3214 private final int startActivityUncheckedLocked(HistoryRecord r,
3215 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3216 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3217 final Intent intent = r.intent;
3218 final int callingUid = r.launchedFromUid;
3219
3220 int launchFlags = intent.getFlags();
3221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003222 // We'll invoke onUserLeaving before onPause only if the launching
3223 // activity did not explicitly state that this is an automated launch.
3224 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3225 if (DEBUG_USER_LEAVING) Log.v(TAG,
3226 "startActivity() => mUserLeaving=" + mUserLeaving);
3227
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003228 // If the caller has asked not to resume at this point, we make note
3229 // of this in the record so that we can skip it when trying to find
3230 // the top running activity.
3231 if (!doResume) {
3232 r.delayedResume = true;
3233 }
3234
3235 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3236 != 0 ? r : null;
3237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003238 // If the onlyIfNeeded flag is set, then we can do this if the activity
3239 // being launched is the same as the one making the call... or, as
3240 // a special case, if we do not know the caller then we count the
3241 // current top activity as the caller.
3242 if (onlyIfNeeded) {
3243 HistoryRecord checkedCaller = sourceRecord;
3244 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003245 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003246 }
3247 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3248 // Caller is not the same as launcher, so always needed.
3249 onlyIfNeeded = false;
3250 }
3251 }
3252
3253 if (grantedUriPermissions != null && callingUid > 0) {
3254 for (int i=0; i<grantedUriPermissions.length; i++) {
3255 grantUriPermissionLocked(callingUid, r.packageName,
3256 grantedUriPermissions[i], grantedMode, r);
3257 }
3258 }
3259
3260 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3261 intent, r);
3262
3263 if (sourceRecord == null) {
3264 // This activity is not being started from another... in this
3265 // case we -always- start a new task.
3266 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3267 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3268 + intent);
3269 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3270 }
3271 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3272 // The original activity who is starting us is running as a single
3273 // instance... this new activity it is starting must go on its
3274 // own task.
3275 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3276 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3277 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3278 // The activity being started is a single instance... it always
3279 // gets launched into its own task.
3280 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3281 }
3282
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003283 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003284 // For whatever reason this activity is being launched into a new
3285 // task... yet the caller has requested a result back. Well, that
3286 // is pretty messed up, so instead immediately send back a cancel
3287 // and let the new task continue launched as normal without a
3288 // dependency on its originator.
3289 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3290 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003291 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003292 Activity.RESULT_CANCELED, null);
3293 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003294 }
3295
3296 boolean addingToTask = false;
3297 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3298 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3299 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3300 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3301 // If bring to front is requested, and no result is requested, and
3302 // we can find a task that was started with this same
3303 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003304 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003305 // See if there is a task to bring to the front. If this is
3306 // a SINGLE_INSTANCE activity, there can be one and only one
3307 // instance of it in the history, and it is always in its own
3308 // unique task, so we do a special search.
3309 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3310 ? findTaskLocked(intent, r.info)
3311 : findActivityLocked(intent, r.info);
3312 if (taskTop != null) {
3313 if (taskTop.task.intent == null) {
3314 // This task was started because of movement of
3315 // the activity based on affinity... now that we
3316 // are actually launching it, we can assign the
3317 // base intent.
3318 taskTop.task.setIntent(intent, r.info);
3319 }
3320 // If the target task is not in the front, then we need
3321 // to bring it to the front... except... well, with
3322 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3323 // to have the same behavior as if a new instance was
3324 // being started, which means not bringing it to the front
3325 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003326 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003327 if (curTop.task != taskTop.task) {
3328 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3329 boolean callerAtFront = sourceRecord == null
3330 || curTop.task == sourceRecord.task;
3331 if (callerAtFront) {
3332 // We really do want to push this one into the
3333 // user's face, right now.
3334 moveTaskToFrontLocked(taskTop.task);
3335 }
3336 }
3337 // If the caller has requested that the target task be
3338 // reset, then do so.
3339 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3340 taskTop = resetTaskIfNeededLocked(taskTop, r);
3341 }
3342 if (onlyIfNeeded) {
3343 // We don't need to start a new activity, and
3344 // the client said not to do anything if that
3345 // is the case, so this is it! And for paranoia, make
3346 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003347 if (doResume) {
3348 resumeTopActivityLocked(null);
3349 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003350 return START_RETURN_INTENT_TO_CALLER;
3351 }
3352 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3353 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3354 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3355 // In this situation we want to remove all activities
3356 // from the task up to the one being started. In most
3357 // cases this means we are resetting the task to its
3358 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003359 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003360 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003361 if (top != null) {
3362 if (top.frontOfTask) {
3363 // Activity aliases may mean we use different
3364 // intents for the top activity, so make sure
3365 // the task now has the identity of the new
3366 // intent.
3367 top.task.setIntent(r.intent, r.info);
3368 }
3369 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3370 deliverNewIntentLocked(top, r.intent);
3371 } else {
3372 // A special case: we need to
3373 // start the activity because it is not currently
3374 // running, and the caller has asked to clear the
3375 // current task to have this activity at the top.
3376 addingToTask = true;
3377 // Now pretend like this activity is being started
3378 // by the top of its task, so it is put in the
3379 // right place.
3380 sourceRecord = taskTop;
3381 }
3382 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3383 // In this case the top activity on the task is the
3384 // same as the one being launched, so we take that
3385 // as a request to bring the task to the foreground.
3386 // If the top activity in the task is the root
3387 // activity, deliver this new intent to it if it
3388 // desires.
3389 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3390 && taskTop.realActivity.equals(r.realActivity)) {
3391 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3392 if (taskTop.frontOfTask) {
3393 taskTop.task.setIntent(r.intent, r.info);
3394 }
3395 deliverNewIntentLocked(taskTop, r.intent);
3396 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3397 // In this case we are launching the root activity
3398 // of the task, but with a different intent. We
3399 // should start a new instance on top.
3400 addingToTask = true;
3401 sourceRecord = taskTop;
3402 }
3403 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3404 // In this case an activity is being launched in to an
3405 // existing task, without resetting that task. This
3406 // is typically the situation of launching an activity
3407 // from a notification or shortcut. We want to place
3408 // the new activity on top of the current task.
3409 addingToTask = true;
3410 sourceRecord = taskTop;
3411 } else if (!taskTop.task.rootWasReset) {
3412 // In this case we are launching in to an existing task
3413 // that has not yet been started from its front door.
3414 // The current task has been brought to the front.
3415 // Ideally, we'd probably like to place this new task
3416 // at the bottom of its stack, but that's a little hard
3417 // to do with the current organization of the code so
3418 // for now we'll just drop it.
3419 taskTop.task.setIntent(r.intent, r.info);
3420 }
3421 if (!addingToTask) {
3422 // We didn't do anything... but it was needed (a.k.a., client
3423 // don't use that intent!) And for paranoia, make
3424 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003425 if (doResume) {
3426 resumeTopActivityLocked(null);
3427 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003428 return START_TASK_TO_FRONT;
3429 }
3430 }
3431 }
3432 }
3433
3434 //String uri = r.intent.toURI();
3435 //Intent intent2 = new Intent(uri);
3436 //Log.i(TAG, "Given intent: " + r.intent);
3437 //Log.i(TAG, "URI is: " + uri);
3438 //Log.i(TAG, "To intent: " + intent2);
3439
3440 if (r.packageName != null) {
3441 // If the activity being launched is the same as the one currently
3442 // at the top, then we need to check if it should only be launched
3443 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003444 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3445 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003446 if (top.realActivity.equals(r.realActivity)) {
3447 if (top.app != null && top.app.thread != null) {
3448 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3449 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3450 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3451 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3452 // For paranoia, make sure we have correctly
3453 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003454 if (doResume) {
3455 resumeTopActivityLocked(null);
3456 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003457 if (onlyIfNeeded) {
3458 // We don't need to start a new activity, and
3459 // the client said not to do anything if that
3460 // is the case, so this is it!
3461 return START_RETURN_INTENT_TO_CALLER;
3462 }
3463 deliverNewIntentLocked(top, r.intent);
3464 return START_DELIVERED_TO_TOP;
3465 }
3466 }
3467 }
3468 }
3469
3470 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003471 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003472 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003473 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003474 Activity.RESULT_CANCELED, null);
3475 }
3476 return START_CLASS_NOT_FOUND;
3477 }
3478
3479 boolean newTask = false;
3480
3481 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003482 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003483 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3484 // todo: should do better management of integers.
3485 mCurTask++;
3486 if (mCurTask <= 0) {
3487 mCurTask = 1;
3488 }
3489 r.task = new TaskRecord(mCurTask, r.info, intent,
3490 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3491 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3492 + " in new task " + r.task);
3493 newTask = true;
3494 addRecentTask(r.task);
3495
3496 } else if (sourceRecord != null) {
3497 if (!addingToTask &&
3498 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3499 // In this case, we are adding the activity to an existing
3500 // task, but the caller has asked to clear that task if the
3501 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003502 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003503 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003504 if (top != null) {
3505 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3506 deliverNewIntentLocked(top, r.intent);
3507 // For paranoia, make sure we have correctly
3508 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003509 if (doResume) {
3510 resumeTopActivityLocked(null);
3511 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003512 return START_DELIVERED_TO_TOP;
3513 }
3514 } else if (!addingToTask &&
3515 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3516 // In this case, we are launching an activity in our own task
3517 // that may already be running somewhere in the history, and
3518 // we want to shuffle it to the front of the stack if so.
3519 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3520 if (where >= 0) {
3521 HistoryRecord top = moveActivityToFrontLocked(where);
3522 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3523 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003524 if (doResume) {
3525 resumeTopActivityLocked(null);
3526 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003527 return START_DELIVERED_TO_TOP;
3528 }
3529 }
3530 // An existing activity is starting this new activity, so we want
3531 // to keep the new one in the same task as the one that is starting
3532 // it.
3533 r.task = sourceRecord.task;
3534 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3535 + " in existing task " + r.task);
3536
3537 } else {
3538 // This not being started from an existing activity, and not part
3539 // of a new task... just put it in the top task, though these days
3540 // this case should never happen.
3541 final int N = mHistory.size();
3542 HistoryRecord prev =
3543 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3544 r.task = prev != null
3545 ? prev.task
3546 : new TaskRecord(mCurTask, r.info, intent,
3547 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3548 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3549 + " in new guessed " + r.task);
3550 }
3551 if (newTask) {
3552 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3553 }
3554 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003555 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003556 return START_SUCCESS;
3557 }
3558
3559 public final int startActivity(IApplicationThread caller,
3560 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3561 int grantedMode, IBinder resultTo,
3562 String resultWho, int requestCode, boolean onlyIfNeeded,
3563 boolean debug) {
3564 // Refuse possible leaked file descriptors
3565 if (intent != null && intent.hasFileDescriptors()) {
3566 throw new IllegalArgumentException("File descriptors passed in Intent");
3567 }
3568
The Android Open Source Project4df24232009-03-05 14:34:35 -08003569 final boolean componentSpecified = intent.getComponent() != null;
3570
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003571 // Don't modify the client's object!
3572 intent = new Intent(intent);
3573
3574 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003575 ActivityInfo aInfo;
3576 try {
3577 ResolveInfo rInfo =
3578 ActivityThread.getPackageManager().resolveIntent(
3579 intent, resolvedType,
3580 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003581 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003582 aInfo = rInfo != null ? rInfo.activityInfo : null;
3583 } catch (RemoteException e) {
3584 aInfo = null;
3585 }
3586
3587 if (aInfo != null) {
3588 // Store the found target back into the intent, because now that
3589 // we have it we never want to do this again. For example, if the
3590 // user navigates back to this point in the history, we should
3591 // always restart the exact same activity.
3592 intent.setComponent(new ComponentName(
3593 aInfo.applicationInfo.packageName, aInfo.name));
3594
3595 // Don't debug things in the system process
3596 if (debug) {
3597 if (!aInfo.processName.equals("system")) {
3598 setDebugApp(aInfo.processName, true, false);
3599 }
3600 }
3601 }
3602
3603 synchronized(this) {
3604 final long origId = Binder.clearCallingIdentity();
3605 int res = startActivityLocked(caller, intent, resolvedType,
3606 grantedUriPermissions, grantedMode, aInfo,
3607 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003608 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003609 Binder.restoreCallingIdentity(origId);
3610 return res;
3611 }
3612 }
3613
3614 public boolean startNextMatchingActivity(IBinder callingActivity,
3615 Intent intent) {
3616 // Refuse possible leaked file descriptors
3617 if (intent != null && intent.hasFileDescriptors() == true) {
3618 throw new IllegalArgumentException("File descriptors passed in Intent");
3619 }
3620
3621 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003622 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003623 if (index < 0) {
3624 return false;
3625 }
3626 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3627 if (r.app == null || r.app.thread == null) {
3628 // The caller is not running... d'oh!
3629 return false;
3630 }
3631 intent = new Intent(intent);
3632 // The caller is not allowed to change the data.
3633 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3634 // And we are resetting to find the next component...
3635 intent.setComponent(null);
3636
3637 ActivityInfo aInfo = null;
3638 try {
3639 List<ResolveInfo> resolves =
3640 ActivityThread.getPackageManager().queryIntentActivities(
3641 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003642 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003643
3644 // Look for the original activity in the list...
3645 final int N = resolves != null ? resolves.size() : 0;
3646 for (int i=0; i<N; i++) {
3647 ResolveInfo rInfo = resolves.get(i);
3648 if (rInfo.activityInfo.packageName.equals(r.packageName)
3649 && rInfo.activityInfo.name.equals(r.info.name)) {
3650 // We found the current one... the next matching is
3651 // after it.
3652 i++;
3653 if (i<N) {
3654 aInfo = resolves.get(i).activityInfo;
3655 }
3656 break;
3657 }
3658 }
3659 } catch (RemoteException e) {
3660 }
3661
3662 if (aInfo == null) {
3663 // Nobody who is next!
3664 return false;
3665 }
3666
3667 intent.setComponent(new ComponentName(
3668 aInfo.applicationInfo.packageName, aInfo.name));
3669 intent.setFlags(intent.getFlags()&~(
3670 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3671 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3672 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3673 Intent.FLAG_ACTIVITY_NEW_TASK));
3674
3675 // Okay now we need to start the new activity, replacing the
3676 // currently running activity. This is a little tricky because
3677 // we want to start the new one as if the current one is finished,
3678 // but not finish the current one first so that there is no flicker.
3679 // And thus...
3680 final boolean wasFinishing = r.finishing;
3681 r.finishing = true;
3682
3683 // Propagate reply information over to the new activity.
3684 final HistoryRecord resultTo = r.resultTo;
3685 final String resultWho = r.resultWho;
3686 final int requestCode = r.requestCode;
3687 r.resultTo = null;
3688 if (resultTo != null) {
3689 resultTo.removeResultsLocked(r, resultWho, requestCode);
3690 }
3691
3692 final long origId = Binder.clearCallingIdentity();
3693 // XXX we are not dealing with propagating grantedUriPermissions...
3694 // those are not yet exposed to user code, so there is no need.
3695 int res = startActivityLocked(r.app.thread, intent,
3696 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003697 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003698 Binder.restoreCallingIdentity(origId);
3699
3700 r.finishing = wasFinishing;
3701 if (res != START_SUCCESS) {
3702 return false;
3703 }
3704 return true;
3705 }
3706 }
3707
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003708 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003709 Intent intent, String resolvedType, IBinder resultTo,
3710 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003711
3712 // This is so super not safe, that only the system (or okay root)
3713 // can do it.
3714 final int callingUid = Binder.getCallingUid();
3715 if (callingUid != 0 && callingUid != Process.myUid()) {
3716 throw new SecurityException(
3717 "startActivityInPackage only available to the system");
3718 }
3719
The Android Open Source Project4df24232009-03-05 14:34:35 -08003720 final boolean componentSpecified = intent.getComponent() != null;
3721
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003722 // Don't modify the client's object!
3723 intent = new Intent(intent);
3724
3725 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003726 ActivityInfo aInfo;
3727 try {
3728 ResolveInfo rInfo =
3729 ActivityThread.getPackageManager().resolveIntent(
3730 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003731 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003732 aInfo = rInfo != null ? rInfo.activityInfo : null;
3733 } catch (RemoteException e) {
3734 aInfo = null;
3735 }
3736
3737 if (aInfo != null) {
3738 // Store the found target back into the intent, because now that
3739 // we have it we never want to do this again. For example, if the
3740 // user navigates back to this point in the history, we should
3741 // always restart the exact same activity.
3742 intent.setComponent(new ComponentName(
3743 aInfo.applicationInfo.packageName, aInfo.name));
3744 }
3745
3746 synchronized(this) {
3747 return startActivityLocked(null, intent, resolvedType,
3748 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003749 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003750 }
3751 }
3752
3753 private final void addRecentTask(TaskRecord task) {
3754 // Remove any existing entries that are the same kind of task.
3755 int N = mRecentTasks.size();
3756 for (int i=0; i<N; i++) {
3757 TaskRecord tr = mRecentTasks.get(i);
3758 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3759 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3760 mRecentTasks.remove(i);
3761 i--;
3762 N--;
3763 if (task.intent == null) {
3764 // If the new recent task we are adding is not fully
3765 // specified, then replace it with the existing recent task.
3766 task = tr;
3767 }
3768 }
3769 }
3770 if (N >= MAX_RECENT_TASKS) {
3771 mRecentTasks.remove(N-1);
3772 }
3773 mRecentTasks.add(0, task);
3774 }
3775
3776 public void setRequestedOrientation(IBinder token,
3777 int requestedOrientation) {
3778 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003779 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003780 if (index < 0) {
3781 return;
3782 }
3783 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3784 final long origId = Binder.clearCallingIdentity();
3785 mWindowManager.setAppOrientation(r, requestedOrientation);
3786 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003787 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003788 r.mayFreezeScreenLocked(r.app) ? r : null);
3789 if (config != null) {
3790 r.frozenBeforeDestroy = true;
3791 if (!updateConfigurationLocked(config, r)) {
3792 resumeTopActivityLocked(null);
3793 }
3794 }
3795 Binder.restoreCallingIdentity(origId);
3796 }
3797 }
3798
3799 public int getRequestedOrientation(IBinder token) {
3800 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003801 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003802 if (index < 0) {
3803 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3804 }
3805 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3806 return mWindowManager.getAppOrientation(r);
3807 }
3808 }
3809
3810 private final void stopActivityLocked(HistoryRecord r) {
3811 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3812 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3813 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3814 if (!r.finishing) {
3815 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3816 "no-history");
3817 }
3818 } else if (r.app != null && r.app.thread != null) {
3819 if (mFocusedActivity == r) {
3820 setFocusedActivityLocked(topRunningActivityLocked(null));
3821 }
3822 r.resumeKeyDispatchingLocked();
3823 try {
3824 r.stopped = false;
3825 r.state = ActivityState.STOPPING;
3826 if (DEBUG_VISBILITY) Log.v(
3827 TAG, "Stopping visible=" + r.visible + " for " + r);
3828 if (!r.visible) {
3829 mWindowManager.setAppVisibility(r, false);
3830 }
3831 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3832 } catch (Exception e) {
3833 // Maybe just ignore exceptions here... if the process
3834 // has crashed, our death notification will clean things
3835 // up.
3836 Log.w(TAG, "Exception thrown during pause", e);
3837 // Just in case, assume it to be stopped.
3838 r.stopped = true;
3839 r.state = ActivityState.STOPPED;
3840 if (r.configDestroy) {
3841 destroyActivityLocked(r, true);
3842 }
3843 }
3844 }
3845 }
3846
3847 /**
3848 * @return Returns true if the activity is being finished, false if for
3849 * some reason it is being left as-is.
3850 */
3851 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3852 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003853 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003854 TAG, "Finishing activity: token=" + token
3855 + ", result=" + resultCode + ", data=" + resultData);
3856
Dianne Hackborn75b03852009-06-12 15:43:26 -07003857 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003858 if (index < 0) {
3859 return false;
3860 }
3861 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3862
3863 // Is this the last activity left?
3864 boolean lastActivity = true;
3865 for (int i=mHistory.size()-1; i>=0; i--) {
3866 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3867 if (!p.finishing && p != r) {
3868 lastActivity = false;
3869 break;
3870 }
3871 }
3872
3873 // If this is the last activity, but it is the home activity, then
3874 // just don't finish it.
3875 if (lastActivity) {
3876 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3877 return false;
3878 }
3879 }
3880
3881 finishActivityLocked(r, index, resultCode, resultData, reason);
3882 return true;
3883 }
3884
3885 /**
3886 * @return Returns true if this activity has been removed from the history
3887 * list, or false if it is still in the list and will be removed later.
3888 */
3889 private final boolean finishActivityLocked(HistoryRecord r, int index,
3890 int resultCode, Intent resultData, String reason) {
3891 if (r.finishing) {
3892 Log.w(TAG, "Duplicate finish request for " + r);
3893 return false;
3894 }
3895
3896 r.finishing = true;
3897 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3898 System.identityHashCode(r),
3899 r.task.taskId, r.shortComponentName, reason);
3900 r.task.numActivities--;
3901 if (r.frontOfTask && index < (mHistory.size()-1)) {
3902 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3903 if (next.task == r.task) {
3904 next.frontOfTask = true;
3905 }
3906 }
3907
3908 r.pauseKeyDispatchingLocked();
3909 if (mFocusedActivity == r) {
3910 setFocusedActivityLocked(topRunningActivityLocked(null));
3911 }
3912
3913 // send the result
3914 HistoryRecord resultTo = r.resultTo;
3915 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003916 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3917 + " who=" + r.resultWho + " req=" + r.requestCode
3918 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003919 if (r.info.applicationInfo.uid > 0) {
3920 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3921 r.packageName, resultData, r);
3922 }
3923 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3924 resultData);
3925 r.resultTo = null;
3926 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003927 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003928
3929 // Make sure this HistoryRecord is not holding on to other resources,
3930 // because clients have remote IPC references to this object so we
3931 // can't assume that will go away and want to avoid circular IPC refs.
3932 r.results = null;
3933 r.pendingResults = null;
3934 r.newIntents = null;
3935 r.icicle = null;
3936
3937 if (mPendingThumbnails.size() > 0) {
3938 // There are clients waiting to receive thumbnails so, in case
3939 // this is an activity that someone is waiting for, add it
3940 // to the pending list so we can correctly update the clients.
3941 mCancelledThumbnails.add(r);
3942 }
3943
3944 if (mResumedActivity == r) {
3945 boolean endTask = index <= 0
3946 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3947 if (DEBUG_TRANSITION) Log.v(TAG,
3948 "Prepare close transition: finishing " + r);
3949 mWindowManager.prepareAppTransition(endTask
3950 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3951 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3952
3953 // Tell window manager to prepare for this one to be removed.
3954 mWindowManager.setAppVisibility(r, false);
3955
3956 if (mPausingActivity == null) {
3957 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3958 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3959 startPausingLocked(false, false);
3960 }
3961
3962 } else if (r.state != ActivityState.PAUSING) {
3963 // If the activity is PAUSING, we will complete the finish once
3964 // it is done pausing; else we can just directly finish it here.
3965 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3966 return finishCurrentActivityLocked(r, index,
3967 FINISH_AFTER_PAUSE) == null;
3968 } else {
3969 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3970 }
3971
3972 return false;
3973 }
3974
3975 private static final int FINISH_IMMEDIATELY = 0;
3976 private static final int FINISH_AFTER_PAUSE = 1;
3977 private static final int FINISH_AFTER_VISIBLE = 2;
3978
3979 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3980 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003981 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003982 if (index < 0) {
3983 return null;
3984 }
3985
3986 return finishCurrentActivityLocked(r, index, mode);
3987 }
3988
3989 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3990 int index, int mode) {
3991 // First things first: if this activity is currently visible,
3992 // and the resumed activity is not yet visible, then hold off on
3993 // finishing until the resumed one becomes visible.
3994 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3995 if (!mStoppingActivities.contains(r)) {
3996 mStoppingActivities.add(r);
3997 if (mStoppingActivities.size() > 3) {
3998 // If we already have a few activities waiting to stop,
3999 // then give up on things going idle and start clearing
4000 // them out.
4001 Message msg = Message.obtain();
4002 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4003 mHandler.sendMessage(msg);
4004 }
4005 }
4006 r.state = ActivityState.STOPPING;
4007 updateOomAdjLocked();
4008 return r;
4009 }
4010
4011 // make sure the record is cleaned out of other places.
4012 mStoppingActivities.remove(r);
4013 mWaitingVisibleActivities.remove(r);
4014 if (mResumedActivity == r) {
4015 mResumedActivity = null;
4016 }
4017 final ActivityState prevState = r.state;
4018 r.state = ActivityState.FINISHING;
4019
4020 if (mode == FINISH_IMMEDIATELY
4021 || prevState == ActivityState.STOPPED
4022 || prevState == ActivityState.INITIALIZING) {
4023 // If this activity is already stopped, we can just finish
4024 // it right now.
4025 return destroyActivityLocked(r, true) ? null : r;
4026 } else {
4027 // Need to go through the full pause cycle to get this
4028 // activity into the stopped state and then finish it.
4029 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4030 mFinishingActivities.add(r);
4031 resumeTopActivityLocked(null);
4032 }
4033 return r;
4034 }
4035
4036 /**
4037 * This is the internal entry point for handling Activity.finish().
4038 *
4039 * @param token The Binder token referencing the Activity we want to finish.
4040 * @param resultCode Result code, if any, from this Activity.
4041 * @param resultData Result data (Intent), if any, from this Activity.
4042 *
4043 * @result Returns true if the activity successfully finished, or false if it is still running.
4044 */
4045 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4046 // Refuse possible leaked file descriptors
4047 if (resultData != null && resultData.hasFileDescriptors() == true) {
4048 throw new IllegalArgumentException("File descriptors passed in Intent");
4049 }
4050
4051 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004052 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004053 // Find the first activity that is not finishing.
4054 HistoryRecord next = topRunningActivityLocked(token, 0);
4055 if (next != null) {
4056 // ask watcher if this is allowed
4057 boolean resumeOK = true;
4058 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004059 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004060 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004061 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004062 }
4063
4064 if (!resumeOK) {
4065 return false;
4066 }
4067 }
4068 }
4069 final long origId = Binder.clearCallingIdentity();
4070 boolean res = requestFinishActivityLocked(token, resultCode,
4071 resultData, "app-request");
4072 Binder.restoreCallingIdentity(origId);
4073 return res;
4074 }
4075 }
4076
4077 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4078 String resultWho, int requestCode, int resultCode, Intent data) {
4079
4080 if (callingUid > 0) {
4081 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4082 data, r);
4083 }
4084
The Android Open Source Project10592532009-03-18 17:39:46 -07004085 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4086 + " : who=" + resultWho + " req=" + requestCode
4087 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004088 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4089 try {
4090 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4091 list.add(new ResultInfo(resultWho, requestCode,
4092 resultCode, data));
4093 r.app.thread.scheduleSendResult(r, list);
4094 return;
4095 } catch (Exception e) {
4096 Log.w(TAG, "Exception thrown sending result to " + r, e);
4097 }
4098 }
4099
4100 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4101 }
4102
4103 public final void finishSubActivity(IBinder token, String resultWho,
4104 int requestCode) {
4105 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004106 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004107 if (index < 0) {
4108 return;
4109 }
4110 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4111
4112 final long origId = Binder.clearCallingIdentity();
4113
4114 int i;
4115 for (i=mHistory.size()-1; i>=0; i--) {
4116 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4117 if (r.resultTo == self && r.requestCode == requestCode) {
4118 if ((r.resultWho == null && resultWho == null) ||
4119 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4120 finishActivityLocked(r, i,
4121 Activity.RESULT_CANCELED, null, "request-sub");
4122 }
4123 }
4124 }
4125
4126 Binder.restoreCallingIdentity(origId);
4127 }
4128 }
4129
4130 /**
4131 * Perform clean-up of service connections in an activity record.
4132 */
4133 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4134 // Throw away any services that have been bound by this activity.
4135 if (r.connections != null) {
4136 Iterator<ConnectionRecord> it = r.connections.iterator();
4137 while (it.hasNext()) {
4138 ConnectionRecord c = it.next();
4139 removeConnectionLocked(c, null, r);
4140 }
4141 r.connections = null;
4142 }
4143 }
4144
4145 /**
4146 * Perform the common clean-up of an activity record. This is called both
4147 * as part of destroyActivityLocked() (when destroying the client-side
4148 * representation) and cleaning things up as a result of its hosting
4149 * processing going away, in which case there is no remaining client-side
4150 * state to destroy so only the cleanup here is needed.
4151 */
4152 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4153 if (mResumedActivity == r) {
4154 mResumedActivity = null;
4155 }
4156 if (mFocusedActivity == r) {
4157 mFocusedActivity = null;
4158 }
4159
4160 r.configDestroy = false;
4161 r.frozenBeforeDestroy = false;
4162
4163 // Make sure this record is no longer in the pending finishes list.
4164 // This could happen, for example, if we are trimming activities
4165 // down to the max limit while they are still waiting to finish.
4166 mFinishingActivities.remove(r);
4167 mWaitingVisibleActivities.remove(r);
4168
4169 // Remove any pending results.
4170 if (r.finishing && r.pendingResults != null) {
4171 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4172 PendingIntentRecord rec = apr.get();
4173 if (rec != null) {
4174 cancelIntentSenderLocked(rec, false);
4175 }
4176 }
4177 r.pendingResults = null;
4178 }
4179
4180 if (cleanServices) {
4181 cleanUpActivityServicesLocked(r);
4182 }
4183
4184 if (mPendingThumbnails.size() > 0) {
4185 // There are clients waiting to receive thumbnails so, in case
4186 // this is an activity that someone is waiting for, add it
4187 // to the pending list so we can correctly update the clients.
4188 mCancelledThumbnails.add(r);
4189 }
4190
4191 // Get rid of any pending idle timeouts.
4192 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4193 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4194 }
4195
4196 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4197 if (r.state != ActivityState.DESTROYED) {
4198 mHistory.remove(r);
4199 r.inHistory = false;
4200 r.state = ActivityState.DESTROYED;
4201 mWindowManager.removeAppToken(r);
4202 if (VALIDATE_TOKENS) {
4203 mWindowManager.validateAppTokens(mHistory);
4204 }
4205 cleanUpActivityServicesLocked(r);
4206 removeActivityUriPermissionsLocked(r);
4207 }
4208 }
4209
4210 /**
4211 * Destroy the current CLIENT SIDE instance of an activity. This may be
4212 * called both when actually finishing an activity, or when performing
4213 * a configuration switch where we destroy the current client-side object
4214 * but then create a new client-side object for this same HistoryRecord.
4215 */
4216 private final boolean destroyActivityLocked(HistoryRecord r,
4217 boolean removeFromApp) {
4218 if (DEBUG_SWITCH) Log.v(
4219 TAG, "Removing activity: token=" + r
4220 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4221 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4222 System.identityHashCode(r),
4223 r.task.taskId, r.shortComponentName);
4224
4225 boolean removedFromHistory = false;
4226
4227 cleanUpActivityLocked(r, false);
4228
4229 if (r.app != null) {
4230 if (removeFromApp) {
4231 int idx = r.app.activities.indexOf(r);
4232 if (idx >= 0) {
4233 r.app.activities.remove(idx);
4234 }
4235 if (r.persistent) {
4236 decPersistentCountLocked(r.app);
4237 }
4238 }
4239
4240 boolean skipDestroy = false;
4241
4242 try {
4243 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4244 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4245 r.configChangeFlags);
4246 } catch (Exception e) {
4247 // We can just ignore exceptions here... if the process
4248 // has crashed, our death notification will clean things
4249 // up.
4250 //Log.w(TAG, "Exception thrown during finish", e);
4251 if (r.finishing) {
4252 removeActivityFromHistoryLocked(r);
4253 removedFromHistory = true;
4254 skipDestroy = true;
4255 }
4256 }
4257
4258 r.app = null;
4259 r.nowVisible = false;
4260
4261 if (r.finishing && !skipDestroy) {
4262 r.state = ActivityState.DESTROYING;
4263 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4264 msg.obj = r;
4265 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4266 } else {
4267 r.state = ActivityState.DESTROYED;
4268 }
4269 } else {
4270 // remove this record from the history.
4271 if (r.finishing) {
4272 removeActivityFromHistoryLocked(r);
4273 removedFromHistory = true;
4274 } else {
4275 r.state = ActivityState.DESTROYED;
4276 }
4277 }
4278
4279 r.configChangeFlags = 0;
4280
4281 if (!mLRUActivities.remove(r)) {
4282 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4283 }
4284
4285 return removedFromHistory;
4286 }
4287
4288 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4289 ProcessRecord app)
4290 {
4291 int i = list.size();
4292 if (localLOGV) Log.v(
4293 TAG, "Removing app " + app + " from list " + list
4294 + " with " + i + " entries");
4295 while (i > 0) {
4296 i--;
4297 HistoryRecord r = (HistoryRecord)list.get(i);
4298 if (localLOGV) Log.v(
4299 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4300 if (r.app == app) {
4301 if (localLOGV) Log.v(TAG, "Removing this entry!");
4302 list.remove(i);
4303 }
4304 }
4305 }
4306
4307 /**
4308 * Main function for removing an existing process from the activity manager
4309 * as a result of that process going away. Clears out all connections
4310 * to the process.
4311 */
4312 private final void handleAppDiedLocked(ProcessRecord app,
4313 boolean restarting) {
4314 cleanUpApplicationRecordLocked(app, restarting, -1);
4315 if (!restarting) {
4316 mLRUProcesses.remove(app);
4317 }
4318
4319 // Just in case...
4320 if (mPausingActivity != null && mPausingActivity.app == app) {
4321 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4322 mPausingActivity = null;
4323 }
4324 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4325 mLastPausedActivity = null;
4326 }
4327
4328 // Remove this application's activities from active lists.
4329 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4330 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4331 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4332 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4333
4334 boolean atTop = true;
4335 boolean hasVisibleActivities = false;
4336
4337 // Clean out the history list.
4338 int i = mHistory.size();
4339 if (localLOGV) Log.v(
4340 TAG, "Removing app " + app + " from history with " + i + " entries");
4341 while (i > 0) {
4342 i--;
4343 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4344 if (localLOGV) Log.v(
4345 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4346 if (r.app == app) {
4347 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4348 if (localLOGV) Log.v(
4349 TAG, "Removing this entry! frozen=" + r.haveState
4350 + " finishing=" + r.finishing);
4351 mHistory.remove(i);
4352
4353 r.inHistory = false;
4354 mWindowManager.removeAppToken(r);
4355 if (VALIDATE_TOKENS) {
4356 mWindowManager.validateAppTokens(mHistory);
4357 }
4358 removeActivityUriPermissionsLocked(r);
4359
4360 } else {
4361 // We have the current state for this activity, so
4362 // it can be restarted later when needed.
4363 if (localLOGV) Log.v(
4364 TAG, "Keeping entry, setting app to null");
4365 if (r.visible) {
4366 hasVisibleActivities = true;
4367 }
4368 r.app = null;
4369 r.nowVisible = false;
4370 if (!r.haveState) {
4371 r.icicle = null;
4372 }
4373 }
4374
4375 cleanUpActivityLocked(r, true);
4376 r.state = ActivityState.STOPPED;
4377 }
4378 atTop = false;
4379 }
4380
4381 app.activities.clear();
4382
4383 if (app.instrumentationClass != null) {
4384 Log.w(TAG, "Crash of app " + app.processName
4385 + " running instrumentation " + app.instrumentationClass);
4386 Bundle info = new Bundle();
4387 info.putString("shortMsg", "Process crashed.");
4388 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4389 }
4390
4391 if (!restarting) {
4392 if (!resumeTopActivityLocked(null)) {
4393 // If there was nothing to resume, and we are not already
4394 // restarting this process, but there is a visible activity that
4395 // is hosted by the process... then make sure all visible
4396 // activities are running, taking care of restarting this
4397 // process.
4398 if (hasVisibleActivities) {
4399 ensureActivitiesVisibleLocked(null, 0);
4400 }
4401 }
4402 }
4403 }
4404
4405 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4406 IBinder threadBinder = thread.asBinder();
4407
4408 // Find the application record.
4409 int count = mLRUProcesses.size();
4410 int i;
4411 for (i=0; i<count; i++) {
4412 ProcessRecord rec = mLRUProcesses.get(i);
4413 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4414 return i;
4415 }
4416 }
4417 return -1;
4418 }
4419
4420 private final ProcessRecord getRecordForAppLocked(
4421 IApplicationThread thread) {
4422 if (thread == null) {
4423 return null;
4424 }
4425
4426 int appIndex = getLRURecordIndexForAppLocked(thread);
4427 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4428 }
4429
4430 private final void appDiedLocked(ProcessRecord app, int pid,
4431 IApplicationThread thread) {
4432
4433 mProcDeaths[0]++;
4434
4435 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4436 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4437 + ") has died.");
4438 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4439 if (localLOGV) Log.v(
4440 TAG, "Dying app: " + app + ", pid: " + pid
4441 + ", thread: " + thread.asBinder());
4442 boolean doLowMem = app.instrumentationClass == null;
4443 handleAppDiedLocked(app, false);
4444
4445 if (doLowMem) {
4446 // If there are no longer any background processes running,
4447 // and the app that died was not running instrumentation,
4448 // then tell everyone we are now low on memory.
4449 boolean haveBg = false;
4450 int count = mLRUProcesses.size();
4451 int i;
4452 for (i=0; i<count; i++) {
4453 ProcessRecord rec = mLRUProcesses.get(i);
4454 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4455 haveBg = true;
4456 break;
4457 }
4458 }
4459
4460 if (!haveBg) {
4461 Log.i(TAG, "Low Memory: No more background processes.");
4462 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004463 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004464 for (i=0; i<count; i++) {
4465 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004466 if (rec.thread != null &&
4467 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4468 // The low memory report is overriding any current
4469 // state for a GC request. Make sure to do
4470 // visible/foreground processes first.
4471 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4472 rec.lastRequestedGc = 0;
4473 } else {
4474 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004475 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004476 rec.reportLowMemory = true;
4477 rec.lastLowMemory = now;
4478 mProcessesToGc.remove(rec);
4479 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004480 }
4481 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004482 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004483 }
4484 }
4485 } else if (Config.LOGD) {
4486 Log.d(TAG, "Received spurious death notification for thread "
4487 + thread.asBinder());
4488 }
4489 }
4490
4491 final String readFile(String filename) {
4492 try {
4493 FileInputStream fs = new FileInputStream(filename);
4494 byte[] inp = new byte[8192];
4495 int size = fs.read(inp);
4496 fs.close();
4497 return new String(inp, 0, 0, size);
4498 } catch (java.io.IOException e) {
4499 }
4500 return "";
4501 }
4502
4503 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004504 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004505 if (app.notResponding || app.crashing) {
4506 return;
4507 }
4508
4509 // Log the ANR to the event log.
4510 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4511
4512 // If we are on a secure build and the application is not interesting to the user (it is
4513 // not visible or in the background), just kill it instead of displaying a dialog.
4514 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4515 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4516 Process.killProcess(app.pid);
4517 return;
4518 }
4519
4520 // DeviceMonitor.start();
4521
4522 String processInfo = null;
4523 if (MONITOR_CPU_USAGE) {
4524 updateCpuStatsNow();
4525 synchronized (mProcessStatsThread) {
4526 processInfo = mProcessStats.printCurrentState();
4527 }
4528 }
4529
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004530 StringBuilder info = mStringBuilder;
4531 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004532 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004533 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004534 if (reportedActivity != null && reportedActivity.app != null) {
4535 info.append(" (last in ");
4536 info.append(reportedActivity.app.processName);
4537 info.append(")");
4538 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004539 if (annotation != null) {
4540 info.append("\nAnnotation: ");
4541 info.append(annotation);
4542 }
4543 if (MONITOR_CPU_USAGE) {
4544 info.append("\nCPU usage:\n");
4545 info.append(processInfo);
4546 }
4547 Log.i(TAG, info.toString());
4548
4549 // The application is not responding. Dump as many thread traces as we can.
4550 boolean fileDump = prepareTraceFile(true);
4551 if (!fileDump) {
4552 // Dumping traces to the log, just dump the process that isn't responding so
4553 // we don't overflow the log
4554 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4555 } else {
4556 // Dumping traces to a file so dump all active processes we know about
4557 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004558 // First, these are the most important processes.
4559 final int[] imppids = new int[3];
4560 int i=0;
4561 imppids[0] = app.pid;
4562 i++;
4563 if (reportedActivity != null && reportedActivity.app != null
4564 && reportedActivity.app.thread != null
4565 && reportedActivity.app.pid != app.pid) {
4566 imppids[i] = reportedActivity.app.pid;
4567 i++;
4568 }
4569 imppids[i] = Process.myPid();
4570 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4571 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4572 synchronized (this) {
4573 try {
4574 wait(200);
4575 } catch (InterruptedException e) {
4576 }
4577 }
4578 }
4579 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004580 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004581 boolean done = false;
4582 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4583 if (imppids[j] == r.pid) {
4584 done = true;
4585 break;
4586 }
4587 }
4588 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004589 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004590 synchronized (this) {
4591 try {
4592 wait(200);
4593 } catch (InterruptedException e) {
4594 }
4595 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004596 }
4597 }
4598 }
4599 }
4600
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004601 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004602 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004603 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004604 app.pid, info.toString());
4605 if (res != 0) {
4606 if (res < 0) {
4607 // wait until the SIGQUIT has had a chance to process before killing the
4608 // process.
4609 try {
4610 wait(2000);
4611 } catch (InterruptedException e) {
4612 }
4613
4614 Process.killProcess(app.pid);
4615 return;
4616 }
4617 }
4618 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004619 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004620 }
4621 }
4622
4623 makeAppNotRespondingLocked(app,
4624 activity != null ? activity.shortComponentName : null,
4625 annotation != null ? "ANR " + annotation : "ANR",
4626 info.toString(), null);
4627 Message msg = Message.obtain();
4628 HashMap map = new HashMap();
4629 msg.what = SHOW_NOT_RESPONDING_MSG;
4630 msg.obj = map;
4631 map.put("app", app);
4632 if (activity != null) {
4633 map.put("activity", activity);
4634 }
4635
4636 mHandler.sendMessage(msg);
4637 return;
4638 }
4639
4640 /**
4641 * If a stack trace file has been configured, prepare the filesystem
4642 * by creating the directory if it doesn't exist and optionally
4643 * removing the old trace file.
4644 *
4645 * @param removeExisting If set, the existing trace file will be removed.
4646 * @return Returns true if the trace file preparations succeeded
4647 */
4648 public static boolean prepareTraceFile(boolean removeExisting) {
4649 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4650 boolean fileReady = false;
4651 if (!TextUtils.isEmpty(tracesPath)) {
4652 File f = new File(tracesPath);
4653 if (!f.exists()) {
4654 // Ensure the enclosing directory exists
4655 File dir = f.getParentFile();
4656 if (!dir.exists()) {
4657 fileReady = dir.mkdirs();
4658 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004659 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004660 } else if (dir.isDirectory()) {
4661 fileReady = true;
4662 }
4663 } else if (removeExisting) {
4664 // Remove the previous traces file, so we don't fill the disk.
4665 // The VM will recreate it
4666 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4667 fileReady = f.delete();
4668 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004669
4670 if (removeExisting) {
4671 try {
4672 f.createNewFile();
4673 FileUtils.setPermissions(f.getAbsolutePath(),
4674 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4675 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4676 fileReady = true;
4677 } catch (IOException e) {
4678 Log.w(TAG, "Unable to make ANR traces file", e);
4679 }
4680 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004681 }
4682
4683 return fileReady;
4684 }
4685
4686
4687 private final void decPersistentCountLocked(ProcessRecord app)
4688 {
4689 app.persistentActivities--;
4690 if (app.persistentActivities > 0) {
4691 // Still more of 'em...
4692 return;
4693 }
4694 if (app.persistent) {
4695 // Ah, but the application itself is persistent. Whatever!
4696 return;
4697 }
4698
4699 // App is no longer persistent... make sure it and the ones
4700 // following it in the LRU list have the correc oom_adj.
4701 updateOomAdjLocked();
4702 }
4703
4704 public void setPersistent(IBinder token, boolean isPersistent) {
4705 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4706 != PackageManager.PERMISSION_GRANTED) {
4707 String msg = "Permission Denial: setPersistent() from pid="
4708 + Binder.getCallingPid()
4709 + ", uid=" + Binder.getCallingUid()
4710 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4711 Log.w(TAG, msg);
4712 throw new SecurityException(msg);
4713 }
4714
4715 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004716 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004717 if (index < 0) {
4718 return;
4719 }
4720 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4721 ProcessRecord app = r.app;
4722
4723 if (localLOGV) Log.v(
4724 TAG, "Setting persistence " + isPersistent + ": " + r);
4725
4726 if (isPersistent) {
4727 if (r.persistent) {
4728 // Okay okay, I heard you already!
4729 if (localLOGV) Log.v(TAG, "Already persistent!");
4730 return;
4731 }
4732 r.persistent = true;
4733 app.persistentActivities++;
4734 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4735 if (app.persistentActivities > 1) {
4736 // We aren't the first...
4737 if (localLOGV) Log.v(TAG, "Not the first!");
4738 return;
4739 }
4740 if (app.persistent) {
4741 // This would be redundant.
4742 if (localLOGV) Log.v(TAG, "App is persistent!");
4743 return;
4744 }
4745
4746 // App is now persistent... make sure it and the ones
4747 // following it now have the correct oom_adj.
4748 final long origId = Binder.clearCallingIdentity();
4749 updateOomAdjLocked();
4750 Binder.restoreCallingIdentity(origId);
4751
4752 } else {
4753 if (!r.persistent) {
4754 // Okay okay, I heard you already!
4755 return;
4756 }
4757 r.persistent = false;
4758 final long origId = Binder.clearCallingIdentity();
4759 decPersistentCountLocked(app);
4760 Binder.restoreCallingIdentity(origId);
4761
4762 }
4763 }
4764 }
4765
4766 public boolean clearApplicationUserData(final String packageName,
4767 final IPackageDataObserver observer) {
4768 int uid = Binder.getCallingUid();
4769 int pid = Binder.getCallingPid();
4770 long callingId = Binder.clearCallingIdentity();
4771 try {
4772 IPackageManager pm = ActivityThread.getPackageManager();
4773 int pkgUid = -1;
4774 synchronized(this) {
4775 try {
4776 pkgUid = pm.getPackageUid(packageName);
4777 } catch (RemoteException e) {
4778 }
4779 if (pkgUid == -1) {
4780 Log.w(TAG, "Invalid packageName:" + packageName);
4781 return false;
4782 }
4783 if (uid == pkgUid || checkComponentPermission(
4784 android.Manifest.permission.CLEAR_APP_USER_DATA,
4785 pid, uid, -1)
4786 == PackageManager.PERMISSION_GRANTED) {
4787 restartPackageLocked(packageName, pkgUid);
4788 } else {
4789 throw new SecurityException(pid+" does not have permission:"+
4790 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4791 "for process:"+packageName);
4792 }
4793 }
4794
4795 try {
4796 //clear application user data
4797 pm.clearApplicationUserData(packageName, observer);
4798 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4799 Uri.fromParts("package", packageName, null));
4800 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4801 broadcastIntentLocked(null, null, intent,
4802 null, null, 0, null, null, null,
4803 false, false, MY_PID, Process.SYSTEM_UID);
4804 } catch (RemoteException e) {
4805 }
4806 } finally {
4807 Binder.restoreCallingIdentity(callingId);
4808 }
4809 return true;
4810 }
4811
4812 public void restartPackage(final String packageName) {
4813 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4814 != PackageManager.PERMISSION_GRANTED) {
4815 String msg = "Permission Denial: restartPackage() from pid="
4816 + Binder.getCallingPid()
4817 + ", uid=" + Binder.getCallingUid()
4818 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4819 Log.w(TAG, msg);
4820 throw new SecurityException(msg);
4821 }
4822
4823 long callingId = Binder.clearCallingIdentity();
4824 try {
4825 IPackageManager pm = ActivityThread.getPackageManager();
4826 int pkgUid = -1;
4827 synchronized(this) {
4828 try {
4829 pkgUid = pm.getPackageUid(packageName);
4830 } catch (RemoteException e) {
4831 }
4832 if (pkgUid == -1) {
4833 Log.w(TAG, "Invalid packageName: " + packageName);
4834 return;
4835 }
4836 restartPackageLocked(packageName, pkgUid);
4837 }
4838 } finally {
4839 Binder.restoreCallingIdentity(callingId);
4840 }
4841 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004842
4843 /*
4844 * The pkg name and uid have to be specified.
4845 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4846 */
4847 public void killApplicationWithUid(String pkg, int uid) {
4848 if (pkg == null) {
4849 return;
4850 }
4851 // Make sure the uid is valid.
4852 if (uid < 0) {
4853 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4854 return;
4855 }
4856 int callerUid = Binder.getCallingUid();
4857 // Only the system server can kill an application
4858 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004859 // Post an aysnc message to kill the application
4860 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4861 msg.arg1 = uid;
4862 msg.arg2 = 0;
4863 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004864 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004865 } else {
4866 throw new SecurityException(callerUid + " cannot kill pkg: " +
4867 pkg);
4868 }
4869 }
4870
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004871 public void closeSystemDialogs(String reason) {
4872 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4873 if (reason != null) {
4874 intent.putExtra("reason", reason);
4875 }
4876
4877 final int uid = Binder.getCallingUid();
4878 final long origId = Binder.clearCallingIdentity();
4879 synchronized (this) {
4880 int i = mWatchers.beginBroadcast();
4881 while (i > 0) {
4882 i--;
4883 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4884 if (w != null) {
4885 try {
4886 w.closingSystemDialogs(reason);
4887 } catch (RemoteException e) {
4888 }
4889 }
4890 }
4891 mWatchers.finishBroadcast();
4892
4893 broadcastIntentLocked(null, null, intent, null,
4894 null, 0, null, null, null, false, false, -1, uid);
4895 }
4896 Binder.restoreCallingIdentity(origId);
4897 }
4898
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004899 public void getProcessMemoryInfo(int pid, Debug.MemoryInfo mi)
4900 throws RemoteException {
4901 ProcessRecord proc;
4902 synchronized (mPidsSelfLocked) {
4903 proc = mPidsSelfLocked.get(pid);
4904 }
4905
4906 if (proc == null) {
4907 throw new RemoteException();
4908 }
4909
4910 IApplicationThread thread = proc.thread;
4911 if (thread == null) {
4912 throw new RemoteException();
4913 }
4914
4915 thread.getMemoryInfo(mi);
4916 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07004917
4918 public void killApplicationProcess(String processName, int uid) {
4919 if (processName == null) {
4920 return;
4921 }
4922
4923 int callerUid = Binder.getCallingUid();
4924 // Only the system server can kill an application
4925 if (callerUid == Process.SYSTEM_UID) {
4926 synchronized (this) {
4927 ProcessRecord app = getProcessRecordLocked(processName, uid);
4928 if (app != null) {
4929 try {
4930 app.thread.scheduleSuicide();
4931 } catch (RemoteException e) {
4932 // If the other end already died, then our work here is done.
4933 }
4934 } else {
4935 Log.w(TAG, "Process/uid not found attempting kill of "
4936 + processName + " / " + uid);
4937 }
4938 }
4939 } else {
4940 throw new SecurityException(callerUid + " cannot kill app process: " +
4941 processName);
4942 }
4943 }
4944
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004945 private void restartPackageLocked(final String packageName, int uid) {
4946 uninstallPackageLocked(packageName, uid, false);
4947 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4948 Uri.fromParts("package", packageName, null));
4949 intent.putExtra(Intent.EXTRA_UID, uid);
4950 broadcastIntentLocked(null, null, intent,
4951 null, null, 0, null, null, null,
4952 false, false, MY_PID, Process.SYSTEM_UID);
4953 }
4954
4955 private final void uninstallPackageLocked(String name, int uid,
4956 boolean callerWillRestart) {
4957 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4958
4959 int i, N;
4960
4961 final String procNamePrefix = name + ":";
4962 if (uid < 0) {
4963 try {
4964 uid = ActivityThread.getPackageManager().getPackageUid(name);
4965 } catch (RemoteException e) {
4966 }
4967 }
4968
4969 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4970 while (badApps.hasNext()) {
4971 SparseArray<Long> ba = badApps.next();
4972 if (ba.get(uid) != null) {
4973 badApps.remove();
4974 }
4975 }
4976
4977 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4978
4979 // Remove all processes this package may have touched: all with the
4980 // same UID (except for the system or root user), and all whose name
4981 // matches the package name.
4982 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4983 final int NA = apps.size();
4984 for (int ia=0; ia<NA; ia++) {
4985 ProcessRecord app = apps.valueAt(ia);
4986 if (app.removed) {
4987 procs.add(app);
4988 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4989 || app.processName.equals(name)
4990 || app.processName.startsWith(procNamePrefix)) {
4991 app.removed = true;
4992 procs.add(app);
4993 }
4994 }
4995 }
4996
4997 N = procs.size();
4998 for (i=0; i<N; i++) {
4999 removeProcessLocked(procs.get(i), callerWillRestart);
5000 }
5001
5002 for (i=mHistory.size()-1; i>=0; i--) {
5003 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5004 if (r.packageName.equals(name)) {
5005 if (Config.LOGD) Log.d(
5006 TAG, " Force finishing activity "
5007 + r.intent.getComponent().flattenToShortString());
5008 if (r.app != null) {
5009 r.app.removed = true;
5010 }
5011 r.app = null;
5012 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5013 }
5014 }
5015
5016 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5017 for (ServiceRecord service : mServices.values()) {
5018 if (service.packageName.equals(name)) {
5019 if (service.app != null) {
5020 service.app.removed = true;
5021 }
5022 service.app = null;
5023 services.add(service);
5024 }
5025 }
5026
5027 N = services.size();
5028 for (i=0; i<N; i++) {
5029 bringDownServiceLocked(services.get(i), true);
5030 }
5031
5032 resumeTopActivityLocked(null);
5033 }
5034
5035 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5036 final String name = app.processName;
5037 final int uid = app.info.uid;
5038 if (Config.LOGD) Log.d(
5039 TAG, "Force removing process " + app + " (" + name
5040 + "/" + uid + ")");
5041
5042 mProcessNames.remove(name, uid);
5043 boolean needRestart = false;
5044 if (app.pid > 0 && app.pid != MY_PID) {
5045 int pid = app.pid;
5046 synchronized (mPidsSelfLocked) {
5047 mPidsSelfLocked.remove(pid);
5048 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5049 }
5050 handleAppDiedLocked(app, true);
5051 mLRUProcesses.remove(app);
5052 Process.killProcess(pid);
5053
5054 if (app.persistent) {
5055 if (!callerWillRestart) {
5056 addAppLocked(app.info);
5057 } else {
5058 needRestart = true;
5059 }
5060 }
5061 } else {
5062 mRemovedProcesses.add(app);
5063 }
5064
5065 return needRestart;
5066 }
5067
5068 private final void processStartTimedOutLocked(ProcessRecord app) {
5069 final int pid = app.pid;
5070 boolean gone = false;
5071 synchronized (mPidsSelfLocked) {
5072 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5073 if (knownApp != null && knownApp.thread == null) {
5074 mPidsSelfLocked.remove(pid);
5075 gone = true;
5076 }
5077 }
5078
5079 if (gone) {
5080 Log.w(TAG, "Process " + app + " failed to attach");
5081 mProcessNames.remove(app.processName, app.info.uid);
5082 Process.killProcess(pid);
5083 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5084 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5085 mPendingBroadcast = null;
5086 scheduleBroadcastsLocked();
5087 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005088 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5089 Log.w(TAG, "Unattached app died before backup, skipping");
5090 try {
5091 IBackupManager bm = IBackupManager.Stub.asInterface(
5092 ServiceManager.getService(Context.BACKUP_SERVICE));
5093 bm.agentDisconnected(app.info.packageName);
5094 } catch (RemoteException e) {
5095 // Can't happen; the backup manager is local
5096 }
5097 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005098 } else {
5099 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5100 }
5101 }
5102
5103 private final boolean attachApplicationLocked(IApplicationThread thread,
5104 int pid) {
5105
5106 // Find the application record that is being attached... either via
5107 // the pid if we are running in multiple processes, or just pull the
5108 // next app record if we are emulating process with anonymous threads.
5109 ProcessRecord app;
5110 if (pid != MY_PID && pid >= 0) {
5111 synchronized (mPidsSelfLocked) {
5112 app = mPidsSelfLocked.get(pid);
5113 }
5114 } else if (mStartingProcesses.size() > 0) {
5115 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005116 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005117 } else {
5118 app = null;
5119 }
5120
5121 if (app == null) {
5122 Log.w(TAG, "No pending application record for pid " + pid
5123 + " (IApplicationThread " + thread + "); dropping process");
5124 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5125 if (pid > 0 && pid != MY_PID) {
5126 Process.killProcess(pid);
5127 } else {
5128 try {
5129 thread.scheduleExit();
5130 } catch (Exception e) {
5131 // Ignore exceptions.
5132 }
5133 }
5134 return false;
5135 }
5136
5137 // If this application record is still attached to a previous
5138 // process, clean it up now.
5139 if (app.thread != null) {
5140 handleAppDiedLocked(app, true);
5141 }
5142
5143 // Tell the process all about itself.
5144
5145 if (localLOGV) Log.v(
5146 TAG, "Binding process pid " + pid + " to record " + app);
5147
5148 String processName = app.processName;
5149 try {
5150 thread.asBinder().linkToDeath(new AppDeathRecipient(
5151 app, pid, thread), 0);
5152 } catch (RemoteException e) {
5153 app.resetPackageList();
5154 startProcessLocked(app, "link fail", processName);
5155 return false;
5156 }
5157
5158 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5159
5160 app.thread = thread;
5161 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005162 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005163 app.forcingToForeground = null;
5164 app.foregroundServices = false;
5165 app.debugging = false;
5166
5167 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5168
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005169 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5170 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005171
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005172 if (!normalMode) {
5173 Log.i(TAG, "Launching preboot mode app: " + app);
5174 }
5175
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005176 if (localLOGV) Log.v(
5177 TAG, "New app record " + app
5178 + " thread=" + thread.asBinder() + " pid=" + pid);
5179 try {
5180 int testMode = IApplicationThread.DEBUG_OFF;
5181 if (mDebugApp != null && mDebugApp.equals(processName)) {
5182 testMode = mWaitForDebugger
5183 ? IApplicationThread.DEBUG_WAIT
5184 : IApplicationThread.DEBUG_ON;
5185 app.debugging = true;
5186 if (mDebugTransient) {
5187 mDebugApp = mOrigDebugApp;
5188 mWaitForDebugger = mOrigWaitForDebugger;
5189 }
5190 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005191
Christopher Tate181fafa2009-05-14 11:12:14 -07005192 // If the app is being launched for restore or full backup, set it up specially
5193 boolean isRestrictedBackupMode = false;
5194 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5195 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5196 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5197 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005198
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005199 ensurePackageDexOpt(app.instrumentationInfo != null
5200 ? app.instrumentationInfo.packageName
5201 : app.info.packageName);
5202 if (app.instrumentationClass != null) {
5203 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005204 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07005205 thread.bindApplication(processName, app.instrumentationInfo != null
5206 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005207 app.instrumentationClass, app.instrumentationProfileFile,
5208 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005209 isRestrictedBackupMode || !normalMode,
5210 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005211 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005212 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005213 } catch (Exception e) {
5214 // todo: Yikes! What should we do? For now we will try to
5215 // start another process, but that could easily get us in
5216 // an infinite loop of restarting processes...
5217 Log.w(TAG, "Exception thrown during bind!", e);
5218
5219 app.resetPackageList();
5220 startProcessLocked(app, "bind fail", processName);
5221 return false;
5222 }
5223
5224 // Remove this record from the list of starting applications.
5225 mPersistentStartingProcesses.remove(app);
5226 mProcessesOnHold.remove(app);
5227
5228 boolean badApp = false;
5229 boolean didSomething = false;
5230
5231 // See if the top visible activity is waiting to run in this process...
5232 HistoryRecord hr = topRunningActivityLocked(null);
5233 if (hr != null) {
5234 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5235 && processName.equals(hr.processName)) {
5236 try {
5237 if (realStartActivityLocked(hr, app, true, true)) {
5238 didSomething = true;
5239 }
5240 } catch (Exception e) {
5241 Log.w(TAG, "Exception in new application when starting activity "
5242 + hr.intent.getComponent().flattenToShortString(), e);
5243 badApp = true;
5244 }
5245 } else {
5246 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5247 }
5248 }
5249
5250 // Find any services that should be running in this process...
5251 if (!badApp && mPendingServices.size() > 0) {
5252 ServiceRecord sr = null;
5253 try {
5254 for (int i=0; i<mPendingServices.size(); i++) {
5255 sr = mPendingServices.get(i);
5256 if (app.info.uid != sr.appInfo.uid
5257 || !processName.equals(sr.processName)) {
5258 continue;
5259 }
5260
5261 mPendingServices.remove(i);
5262 i--;
5263 realStartServiceLocked(sr, app);
5264 didSomething = true;
5265 }
5266 } catch (Exception e) {
5267 Log.w(TAG, "Exception in new application when starting service "
5268 + sr.shortName, e);
5269 badApp = true;
5270 }
5271 }
5272
5273 // Check if the next broadcast receiver is in this process...
5274 BroadcastRecord br = mPendingBroadcast;
5275 if (!badApp && br != null && br.curApp == app) {
5276 try {
5277 mPendingBroadcast = null;
5278 processCurBroadcastLocked(br, app);
5279 didSomething = true;
5280 } catch (Exception e) {
5281 Log.w(TAG, "Exception in new application when starting receiver "
5282 + br.curComponent.flattenToShortString(), e);
5283 badApp = true;
5284 logBroadcastReceiverDiscard(br);
5285 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5286 br.resultExtras, br.resultAbort, true);
5287 scheduleBroadcastsLocked();
5288 }
5289 }
5290
Christopher Tate181fafa2009-05-14 11:12:14 -07005291 // Check whether the next backup agent is in this process...
5292 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5293 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005294 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005295 try {
5296 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5297 } catch (Exception e) {
5298 Log.w(TAG, "Exception scheduling backup agent creation: ");
5299 e.printStackTrace();
5300 }
5301 }
5302
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005303 if (badApp) {
5304 // todo: Also need to kill application to deal with all
5305 // kinds of exceptions.
5306 handleAppDiedLocked(app, false);
5307 return false;
5308 }
5309
5310 if (!didSomething) {
5311 updateOomAdjLocked();
5312 }
5313
5314 return true;
5315 }
5316
5317 public final void attachApplication(IApplicationThread thread) {
5318 synchronized (this) {
5319 int callingPid = Binder.getCallingPid();
5320 final long origId = Binder.clearCallingIdentity();
5321 attachApplicationLocked(thread, callingPid);
5322 Binder.restoreCallingIdentity(origId);
5323 }
5324 }
5325
5326 public final void activityIdle(IBinder token) {
5327 final long origId = Binder.clearCallingIdentity();
5328 activityIdleInternal(token, false);
5329 Binder.restoreCallingIdentity(origId);
5330 }
5331
5332 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5333 boolean remove) {
5334 int N = mStoppingActivities.size();
5335 if (N <= 0) return null;
5336
5337 ArrayList<HistoryRecord> stops = null;
5338
5339 final boolean nowVisible = mResumedActivity != null
5340 && mResumedActivity.nowVisible
5341 && !mResumedActivity.waitingVisible;
5342 for (int i=0; i<N; i++) {
5343 HistoryRecord s = mStoppingActivities.get(i);
5344 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5345 + nowVisible + " waitingVisible=" + s.waitingVisible
5346 + " finishing=" + s.finishing);
5347 if (s.waitingVisible && nowVisible) {
5348 mWaitingVisibleActivities.remove(s);
5349 s.waitingVisible = false;
5350 if (s.finishing) {
5351 // If this activity is finishing, it is sitting on top of
5352 // everyone else but we now know it is no longer needed...
5353 // so get rid of it. Otherwise, we need to go through the
5354 // normal flow and hide it once we determine that it is
5355 // hidden by the activities in front of it.
5356 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5357 mWindowManager.setAppVisibility(s, false);
5358 }
5359 }
5360 if (!s.waitingVisible && remove) {
5361 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5362 if (stops == null) {
5363 stops = new ArrayList<HistoryRecord>();
5364 }
5365 stops.add(s);
5366 mStoppingActivities.remove(i);
5367 N--;
5368 i--;
5369 }
5370 }
5371
5372 return stops;
5373 }
5374
5375 void enableScreenAfterBoot() {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005376 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5377 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005378 mWindowManager.enableScreenAfterBoot();
5379 }
5380
5381 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5382 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5383
5384 ArrayList<HistoryRecord> stops = null;
5385 ArrayList<HistoryRecord> finishes = null;
5386 ArrayList<HistoryRecord> thumbnails = null;
5387 int NS = 0;
5388 int NF = 0;
5389 int NT = 0;
5390 IApplicationThread sendThumbnail = null;
5391 boolean booting = false;
5392 boolean enableScreen = false;
5393
5394 synchronized (this) {
5395 if (token != null) {
5396 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5397 }
5398
5399 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005400 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005401 if (index >= 0) {
5402 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5403
5404 // No longer need to keep the device awake.
5405 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5406 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5407 mLaunchingActivity.release();
5408 }
5409
5410 // We are now idle. If someone is waiting for a thumbnail from
5411 // us, we can now deliver.
5412 r.idle = true;
5413 scheduleAppGcsLocked();
5414 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5415 sendThumbnail = r.app.thread;
5416 r.thumbnailNeeded = false;
5417 }
5418
5419 // If this activity is fullscreen, set up to hide those under it.
5420
5421 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5422 ensureActivitiesVisibleLocked(null, 0);
5423
5424 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5425 if (!mBooted && !fromTimeout) {
5426 mBooted = true;
5427 enableScreen = true;
5428 }
5429 }
5430
5431 // Atomically retrieve all of the other things to do.
5432 stops = processStoppingActivitiesLocked(true);
5433 NS = stops != null ? stops.size() : 0;
5434 if ((NF=mFinishingActivities.size()) > 0) {
5435 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5436 mFinishingActivities.clear();
5437 }
5438 if ((NT=mCancelledThumbnails.size()) > 0) {
5439 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5440 mCancelledThumbnails.clear();
5441 }
5442
5443 booting = mBooting;
5444 mBooting = false;
5445 }
5446
5447 int i;
5448
5449 // Send thumbnail if requested.
5450 if (sendThumbnail != null) {
5451 try {
5452 sendThumbnail.requestThumbnail(token);
5453 } catch (Exception e) {
5454 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5455 sendPendingThumbnail(null, token, null, null, true);
5456 }
5457 }
5458
5459 // Stop any activities that are scheduled to do so but have been
5460 // waiting for the next one to start.
5461 for (i=0; i<NS; i++) {
5462 HistoryRecord r = (HistoryRecord)stops.get(i);
5463 synchronized (this) {
5464 if (r.finishing) {
5465 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5466 } else {
5467 stopActivityLocked(r);
5468 }
5469 }
5470 }
5471
5472 // Finish any activities that are scheduled to do so but have been
5473 // waiting for the next one to start.
5474 for (i=0; i<NF; i++) {
5475 HistoryRecord r = (HistoryRecord)finishes.get(i);
5476 synchronized (this) {
5477 destroyActivityLocked(r, true);
5478 }
5479 }
5480
5481 // Report back to any thumbnail receivers.
5482 for (i=0; i<NT; i++) {
5483 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5484 sendPendingThumbnail(r, null, null, null, true);
5485 }
5486
5487 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005488 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005489 }
5490
5491 trimApplications();
5492 //dump();
5493 //mWindowManager.dump();
5494
5495 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005496 enableScreenAfterBoot();
5497 }
5498 }
5499
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005500 final void finishBooting() {
5501 // Ensure that any processes we had put on hold are now started
5502 // up.
5503 final int NP = mProcessesOnHold.size();
5504 if (NP > 0) {
5505 ArrayList<ProcessRecord> procs =
5506 new ArrayList<ProcessRecord>(mProcessesOnHold);
5507 for (int ip=0; ip<NP; ip++) {
5508 this.startProcessLocked(procs.get(ip), "on-hold", null);
5509 }
5510 }
5511 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5512 // Tell anyone interested that we are done booting!
5513 synchronized (this) {
5514 broadcastIntentLocked(null, null,
5515 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5516 null, null, 0, null, null,
5517 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5518 false, false, MY_PID, Process.SYSTEM_UID);
5519 }
5520 }
5521 }
5522
5523 final void ensureBootCompleted() {
5524 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005525 boolean enableScreen;
5526 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005527 booting = mBooting;
5528 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005529 enableScreen = !mBooted;
5530 mBooted = true;
5531 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005532
5533 if (booting) {
5534 finishBooting();
5535 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005536
5537 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005538 enableScreenAfterBoot();
5539 }
5540 }
5541
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005542 public final void activityPaused(IBinder token, Bundle icicle) {
5543 // Refuse possible leaked file descriptors
5544 if (icicle != null && icicle.hasFileDescriptors()) {
5545 throw new IllegalArgumentException("File descriptors passed in Bundle");
5546 }
5547
5548 final long origId = Binder.clearCallingIdentity();
5549 activityPaused(token, icicle, false);
5550 Binder.restoreCallingIdentity(origId);
5551 }
5552
5553 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5554 if (DEBUG_PAUSE) Log.v(
5555 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5556 + ", timeout=" + timeout);
5557
5558 HistoryRecord r = null;
5559
5560 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005561 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005562 if (index >= 0) {
5563 r = (HistoryRecord)mHistory.get(index);
5564 if (!timeout) {
5565 r.icicle = icicle;
5566 r.haveState = true;
5567 }
5568 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5569 if (mPausingActivity == r) {
5570 r.state = ActivityState.PAUSED;
5571 completePauseLocked();
5572 } else {
5573 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5574 System.identityHashCode(r), r.shortComponentName,
5575 mPausingActivity != null
5576 ? mPausingActivity.shortComponentName : "(none)");
5577 }
5578 }
5579 }
5580 }
5581
5582 public final void activityStopped(IBinder token, Bitmap thumbnail,
5583 CharSequence description) {
5584 if (localLOGV) Log.v(
5585 TAG, "Activity stopped: token=" + token);
5586
5587 HistoryRecord r = null;
5588
5589 final long origId = Binder.clearCallingIdentity();
5590
5591 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005592 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005593 if (index >= 0) {
5594 r = (HistoryRecord)mHistory.get(index);
5595 r.thumbnail = thumbnail;
5596 r.description = description;
5597 r.stopped = true;
5598 r.state = ActivityState.STOPPED;
5599 if (!r.finishing) {
5600 if (r.configDestroy) {
5601 destroyActivityLocked(r, true);
5602 resumeTopActivityLocked(null);
5603 }
5604 }
5605 }
5606 }
5607
5608 if (r != null) {
5609 sendPendingThumbnail(r, null, null, null, false);
5610 }
5611
5612 trimApplications();
5613
5614 Binder.restoreCallingIdentity(origId);
5615 }
5616
5617 public final void activityDestroyed(IBinder token) {
5618 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5619 synchronized (this) {
5620 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5621
Dianne Hackborn75b03852009-06-12 15:43:26 -07005622 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005623 if (index >= 0) {
5624 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5625 if (r.state == ActivityState.DESTROYING) {
5626 final long origId = Binder.clearCallingIdentity();
5627 removeActivityFromHistoryLocked(r);
5628 Binder.restoreCallingIdentity(origId);
5629 }
5630 }
5631 }
5632 }
5633
5634 public String getCallingPackage(IBinder token) {
5635 synchronized (this) {
5636 HistoryRecord r = getCallingRecordLocked(token);
5637 return r != null && r.app != null ? r.app.processName : null;
5638 }
5639 }
5640
5641 public ComponentName getCallingActivity(IBinder token) {
5642 synchronized (this) {
5643 HistoryRecord r = getCallingRecordLocked(token);
5644 return r != null ? r.intent.getComponent() : null;
5645 }
5646 }
5647
5648 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005649 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005650 if (index >= 0) {
5651 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5652 if (r != null) {
5653 return r.resultTo;
5654 }
5655 }
5656 return null;
5657 }
5658
5659 public ComponentName getActivityClassForToken(IBinder token) {
5660 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005661 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005662 if (index >= 0) {
5663 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5664 return r.intent.getComponent();
5665 }
5666 return null;
5667 }
5668 }
5669
5670 public String getPackageForToken(IBinder token) {
5671 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005672 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005673 if (index >= 0) {
5674 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5675 return r.packageName;
5676 }
5677 return null;
5678 }
5679 }
5680
5681 public IIntentSender getIntentSender(int type,
5682 String packageName, IBinder token, String resultWho,
5683 int requestCode, Intent intent, String resolvedType, int flags) {
5684 // Refuse possible leaked file descriptors
5685 if (intent != null && intent.hasFileDescriptors() == true) {
5686 throw new IllegalArgumentException("File descriptors passed in Intent");
5687 }
5688
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005689 if (type == INTENT_SENDER_BROADCAST) {
5690 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5691 throw new IllegalArgumentException(
5692 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5693 }
5694 }
5695
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005696 synchronized(this) {
5697 int callingUid = Binder.getCallingUid();
5698 try {
5699 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5700 Process.supportsProcesses()) {
5701 int uid = ActivityThread.getPackageManager()
5702 .getPackageUid(packageName);
5703 if (uid != Binder.getCallingUid()) {
5704 String msg = "Permission Denial: getIntentSender() from pid="
5705 + Binder.getCallingPid()
5706 + ", uid=" + Binder.getCallingUid()
5707 + ", (need uid=" + uid + ")"
5708 + " is not allowed to send as package " + packageName;
5709 Log.w(TAG, msg);
5710 throw new SecurityException(msg);
5711 }
5712 }
5713 } catch (RemoteException e) {
5714 throw new SecurityException(e);
5715 }
5716 HistoryRecord activity = null;
5717 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
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 return null;
5721 }
5722 activity = (HistoryRecord)mHistory.get(index);
5723 if (activity.finishing) {
5724 return null;
5725 }
5726 }
5727
5728 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5729 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5730 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5731 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5732 |PendingIntent.FLAG_UPDATE_CURRENT);
5733
5734 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5735 type, packageName, activity, resultWho,
5736 requestCode, intent, resolvedType, flags);
5737 WeakReference<PendingIntentRecord> ref;
5738 ref = mIntentSenderRecords.get(key);
5739 PendingIntentRecord rec = ref != null ? ref.get() : null;
5740 if (rec != null) {
5741 if (!cancelCurrent) {
5742 if (updateCurrent) {
5743 rec.key.requestIntent.replaceExtras(intent);
5744 }
5745 return rec;
5746 }
5747 rec.canceled = true;
5748 mIntentSenderRecords.remove(key);
5749 }
5750 if (noCreate) {
5751 return rec;
5752 }
5753 rec = new PendingIntentRecord(this, key, callingUid);
5754 mIntentSenderRecords.put(key, rec.ref);
5755 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5756 if (activity.pendingResults == null) {
5757 activity.pendingResults
5758 = new HashSet<WeakReference<PendingIntentRecord>>();
5759 }
5760 activity.pendingResults.add(rec.ref);
5761 }
5762 return rec;
5763 }
5764 }
5765
5766 public void cancelIntentSender(IIntentSender sender) {
5767 if (!(sender instanceof PendingIntentRecord)) {
5768 return;
5769 }
5770 synchronized(this) {
5771 PendingIntentRecord rec = (PendingIntentRecord)sender;
5772 try {
5773 int uid = ActivityThread.getPackageManager()
5774 .getPackageUid(rec.key.packageName);
5775 if (uid != Binder.getCallingUid()) {
5776 String msg = "Permission Denial: cancelIntentSender() from pid="
5777 + Binder.getCallingPid()
5778 + ", uid=" + Binder.getCallingUid()
5779 + " is not allowed to cancel packges "
5780 + rec.key.packageName;
5781 Log.w(TAG, msg);
5782 throw new SecurityException(msg);
5783 }
5784 } catch (RemoteException e) {
5785 throw new SecurityException(e);
5786 }
5787 cancelIntentSenderLocked(rec, true);
5788 }
5789 }
5790
5791 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5792 rec.canceled = true;
5793 mIntentSenderRecords.remove(rec.key);
5794 if (cleanActivity && rec.key.activity != null) {
5795 rec.key.activity.pendingResults.remove(rec.ref);
5796 }
5797 }
5798
5799 public String getPackageForIntentSender(IIntentSender pendingResult) {
5800 if (!(pendingResult instanceof PendingIntentRecord)) {
5801 return null;
5802 }
5803 synchronized(this) {
5804 try {
5805 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5806 return res.key.packageName;
5807 } catch (ClassCastException e) {
5808 }
5809 }
5810 return null;
5811 }
5812
5813 public void setProcessLimit(int max) {
5814 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5815 "setProcessLimit()");
5816 mProcessLimit = max;
5817 }
5818
5819 public int getProcessLimit() {
5820 return mProcessLimit;
5821 }
5822
5823 void foregroundTokenDied(ForegroundToken token) {
5824 synchronized (ActivityManagerService.this) {
5825 synchronized (mPidsSelfLocked) {
5826 ForegroundToken cur
5827 = mForegroundProcesses.get(token.pid);
5828 if (cur != token) {
5829 return;
5830 }
5831 mForegroundProcesses.remove(token.pid);
5832 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5833 if (pr == null) {
5834 return;
5835 }
5836 pr.forcingToForeground = null;
5837 pr.foregroundServices = false;
5838 }
5839 updateOomAdjLocked();
5840 }
5841 }
5842
5843 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5844 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5845 "setProcessForeground()");
5846 synchronized(this) {
5847 boolean changed = false;
5848
5849 synchronized (mPidsSelfLocked) {
5850 ProcessRecord pr = mPidsSelfLocked.get(pid);
5851 if (pr == null) {
5852 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5853 return;
5854 }
5855 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5856 if (oldToken != null) {
5857 oldToken.token.unlinkToDeath(oldToken, 0);
5858 mForegroundProcesses.remove(pid);
5859 pr.forcingToForeground = null;
5860 changed = true;
5861 }
5862 if (isForeground && token != null) {
5863 ForegroundToken newToken = new ForegroundToken() {
5864 public void binderDied() {
5865 foregroundTokenDied(this);
5866 }
5867 };
5868 newToken.pid = pid;
5869 newToken.token = token;
5870 try {
5871 token.linkToDeath(newToken, 0);
5872 mForegroundProcesses.put(pid, newToken);
5873 pr.forcingToForeground = token;
5874 changed = true;
5875 } catch (RemoteException e) {
5876 // If the process died while doing this, we will later
5877 // do the cleanup with the process death link.
5878 }
5879 }
5880 }
5881
5882 if (changed) {
5883 updateOomAdjLocked();
5884 }
5885 }
5886 }
5887
5888 // =========================================================
5889 // PERMISSIONS
5890 // =========================================================
5891
5892 static class PermissionController extends IPermissionController.Stub {
5893 ActivityManagerService mActivityManagerService;
5894 PermissionController(ActivityManagerService activityManagerService) {
5895 mActivityManagerService = activityManagerService;
5896 }
5897
5898 public boolean checkPermission(String permission, int pid, int uid) {
5899 return mActivityManagerService.checkPermission(permission, pid,
5900 uid) == PackageManager.PERMISSION_GRANTED;
5901 }
5902 }
5903
5904 /**
5905 * This can be called with or without the global lock held.
5906 */
5907 int checkComponentPermission(String permission, int pid, int uid,
5908 int reqUid) {
5909 // We might be performing an operation on behalf of an indirect binder
5910 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5911 // client identity accordingly before proceeding.
5912 Identity tlsIdentity = sCallerIdentity.get();
5913 if (tlsIdentity != null) {
5914 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5915 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5916 uid = tlsIdentity.uid;
5917 pid = tlsIdentity.pid;
5918 }
5919
5920 // Root, system server and our own process get to do everything.
5921 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5922 !Process.supportsProcesses()) {
5923 return PackageManager.PERMISSION_GRANTED;
5924 }
5925 // If the target requires a specific UID, always fail for others.
5926 if (reqUid >= 0 && uid != reqUid) {
5927 return PackageManager.PERMISSION_DENIED;
5928 }
5929 if (permission == null) {
5930 return PackageManager.PERMISSION_GRANTED;
5931 }
5932 try {
5933 return ActivityThread.getPackageManager()
5934 .checkUidPermission(permission, uid);
5935 } catch (RemoteException e) {
5936 // Should never happen, but if it does... deny!
5937 Log.e(TAG, "PackageManager is dead?!?", e);
5938 }
5939 return PackageManager.PERMISSION_DENIED;
5940 }
5941
5942 /**
5943 * As the only public entry point for permissions checking, this method
5944 * can enforce the semantic that requesting a check on a null global
5945 * permission is automatically denied. (Internally a null permission
5946 * string is used when calling {@link #checkComponentPermission} in cases
5947 * when only uid-based security is needed.)
5948 *
5949 * This can be called with or without the global lock held.
5950 */
5951 public int checkPermission(String permission, int pid, int uid) {
5952 if (permission == null) {
5953 return PackageManager.PERMISSION_DENIED;
5954 }
5955 return checkComponentPermission(permission, pid, uid, -1);
5956 }
5957
5958 /**
5959 * Binder IPC calls go through the public entry point.
5960 * This can be called with or without the global lock held.
5961 */
5962 int checkCallingPermission(String permission) {
5963 return checkPermission(permission,
5964 Binder.getCallingPid(),
5965 Binder.getCallingUid());
5966 }
5967
5968 /**
5969 * This can be called with or without the global lock held.
5970 */
5971 void enforceCallingPermission(String permission, String func) {
5972 if (checkCallingPermission(permission)
5973 == PackageManager.PERMISSION_GRANTED) {
5974 return;
5975 }
5976
5977 String msg = "Permission Denial: " + func + " from pid="
5978 + Binder.getCallingPid()
5979 + ", uid=" + Binder.getCallingUid()
5980 + " requires " + permission;
5981 Log.w(TAG, msg);
5982 throw new SecurityException(msg);
5983 }
5984
5985 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5986 ProviderInfo pi, int uid, int modeFlags) {
5987 try {
5988 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5989 if ((pi.readPermission != null) &&
5990 (pm.checkUidPermission(pi.readPermission, uid)
5991 != PackageManager.PERMISSION_GRANTED)) {
5992 return false;
5993 }
5994 }
5995 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5996 if ((pi.writePermission != null) &&
5997 (pm.checkUidPermission(pi.writePermission, uid)
5998 != PackageManager.PERMISSION_GRANTED)) {
5999 return false;
6000 }
6001 }
6002 return true;
6003 } catch (RemoteException e) {
6004 return false;
6005 }
6006 }
6007
6008 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6009 int modeFlags) {
6010 // Root gets to do everything.
6011 if (uid == 0 || !Process.supportsProcesses()) {
6012 return true;
6013 }
6014 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6015 if (perms == null) return false;
6016 UriPermission perm = perms.get(uri);
6017 if (perm == null) return false;
6018 return (modeFlags&perm.modeFlags) == modeFlags;
6019 }
6020
6021 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6022 // Another redirected-binder-call permissions check as in
6023 // {@link checkComponentPermission}.
6024 Identity tlsIdentity = sCallerIdentity.get();
6025 if (tlsIdentity != null) {
6026 uid = tlsIdentity.uid;
6027 pid = tlsIdentity.pid;
6028 }
6029
6030 // Our own process gets to do everything.
6031 if (pid == MY_PID) {
6032 return PackageManager.PERMISSION_GRANTED;
6033 }
6034 synchronized(this) {
6035 return checkUriPermissionLocked(uri, uid, modeFlags)
6036 ? PackageManager.PERMISSION_GRANTED
6037 : PackageManager.PERMISSION_DENIED;
6038 }
6039 }
6040
6041 private void grantUriPermissionLocked(int callingUid,
6042 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6043 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6044 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6045 if (modeFlags == 0) {
6046 return;
6047 }
6048
6049 final IPackageManager pm = ActivityThread.getPackageManager();
6050
6051 // If this is not a content: uri, we can't do anything with it.
6052 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6053 return;
6054 }
6055
6056 String name = uri.getAuthority();
6057 ProviderInfo pi = null;
6058 ContentProviderRecord cpr
6059 = (ContentProviderRecord)mProvidersByName.get(name);
6060 if (cpr != null) {
6061 pi = cpr.info;
6062 } else {
6063 try {
6064 pi = pm.resolveContentProvider(name,
6065 PackageManager.GET_URI_PERMISSION_PATTERNS);
6066 } catch (RemoteException ex) {
6067 }
6068 }
6069 if (pi == null) {
6070 Log.w(TAG, "No content provider found for: " + name);
6071 return;
6072 }
6073
6074 int targetUid;
6075 try {
6076 targetUid = pm.getPackageUid(targetPkg);
6077 if (targetUid < 0) {
6078 return;
6079 }
6080 } catch (RemoteException ex) {
6081 return;
6082 }
6083
6084 // First... does the target actually need this permission?
6085 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6086 // No need to grant the target this permission.
6087 return;
6088 }
6089
6090 // Second... maybe someone else has already granted the
6091 // permission?
6092 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6093 // No need to grant the target this permission.
6094 return;
6095 }
6096
6097 // Third... is the provider allowing granting of URI permissions?
6098 if (!pi.grantUriPermissions) {
6099 throw new SecurityException("Provider " + pi.packageName
6100 + "/" + pi.name
6101 + " does not allow granting of Uri permissions (uri "
6102 + uri + ")");
6103 }
6104 if (pi.uriPermissionPatterns != null) {
6105 final int N = pi.uriPermissionPatterns.length;
6106 boolean allowed = false;
6107 for (int i=0; i<N; i++) {
6108 if (pi.uriPermissionPatterns[i] != null
6109 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6110 allowed = true;
6111 break;
6112 }
6113 }
6114 if (!allowed) {
6115 throw new SecurityException("Provider " + pi.packageName
6116 + "/" + pi.name
6117 + " does not allow granting of permission to path of Uri "
6118 + uri);
6119 }
6120 }
6121
6122 // Fourth... does the caller itself have permission to access
6123 // this uri?
6124 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6125 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6126 throw new SecurityException("Uid " + callingUid
6127 + " does not have permission to uri " + uri);
6128 }
6129 }
6130
6131 // Okay! So here we are: the caller has the assumed permission
6132 // to the uri, and the target doesn't. Let's now give this to
6133 // the target.
6134
6135 HashMap<Uri, UriPermission> targetUris
6136 = mGrantedUriPermissions.get(targetUid);
6137 if (targetUris == null) {
6138 targetUris = new HashMap<Uri, UriPermission>();
6139 mGrantedUriPermissions.put(targetUid, targetUris);
6140 }
6141
6142 UriPermission perm = targetUris.get(uri);
6143 if (perm == null) {
6144 perm = new UriPermission(targetUid, uri);
6145 targetUris.put(uri, perm);
6146
6147 }
6148 perm.modeFlags |= modeFlags;
6149 if (activity == null) {
6150 perm.globalModeFlags |= modeFlags;
6151 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6152 perm.readActivities.add(activity);
6153 if (activity.readUriPermissions == null) {
6154 activity.readUriPermissions = new HashSet<UriPermission>();
6155 }
6156 activity.readUriPermissions.add(perm);
6157 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6158 perm.writeActivities.add(activity);
6159 if (activity.writeUriPermissions == null) {
6160 activity.writeUriPermissions = new HashSet<UriPermission>();
6161 }
6162 activity.writeUriPermissions.add(perm);
6163 }
6164 }
6165
6166 private void grantUriPermissionFromIntentLocked(int callingUid,
6167 String targetPkg, Intent intent, HistoryRecord activity) {
6168 if (intent == null) {
6169 return;
6170 }
6171 Uri data = intent.getData();
6172 if (data == null) {
6173 return;
6174 }
6175 grantUriPermissionLocked(callingUid, targetPkg, data,
6176 intent.getFlags(), activity);
6177 }
6178
6179 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6180 Uri uri, int modeFlags) {
6181 synchronized(this) {
6182 final ProcessRecord r = getRecordForAppLocked(caller);
6183 if (r == null) {
6184 throw new SecurityException("Unable to find app for caller "
6185 + caller
6186 + " when granting permission to uri " + uri);
6187 }
6188 if (targetPkg == null) {
6189 Log.w(TAG, "grantUriPermission: null target");
6190 return;
6191 }
6192 if (uri == null) {
6193 Log.w(TAG, "grantUriPermission: null uri");
6194 return;
6195 }
6196
6197 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6198 null);
6199 }
6200 }
6201
6202 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6203 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6204 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6205 HashMap<Uri, UriPermission> perms
6206 = mGrantedUriPermissions.get(perm.uid);
6207 if (perms != null) {
6208 perms.remove(perm.uri);
6209 if (perms.size() == 0) {
6210 mGrantedUriPermissions.remove(perm.uid);
6211 }
6212 }
6213 }
6214 }
6215
6216 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6217 if (activity.readUriPermissions != null) {
6218 for (UriPermission perm : activity.readUriPermissions) {
6219 perm.readActivities.remove(activity);
6220 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6221 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6222 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6223 removeUriPermissionIfNeededLocked(perm);
6224 }
6225 }
6226 }
6227 if (activity.writeUriPermissions != null) {
6228 for (UriPermission perm : activity.writeUriPermissions) {
6229 perm.writeActivities.remove(activity);
6230 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6231 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6232 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6233 removeUriPermissionIfNeededLocked(perm);
6234 }
6235 }
6236 }
6237 }
6238
6239 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6240 int modeFlags) {
6241 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6242 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6243 if (modeFlags == 0) {
6244 return;
6245 }
6246
6247 final IPackageManager pm = ActivityThread.getPackageManager();
6248
6249 final String authority = uri.getAuthority();
6250 ProviderInfo pi = null;
6251 ContentProviderRecord cpr
6252 = (ContentProviderRecord)mProvidersByName.get(authority);
6253 if (cpr != null) {
6254 pi = cpr.info;
6255 } else {
6256 try {
6257 pi = pm.resolveContentProvider(authority,
6258 PackageManager.GET_URI_PERMISSION_PATTERNS);
6259 } catch (RemoteException ex) {
6260 }
6261 }
6262 if (pi == null) {
6263 Log.w(TAG, "No content provider found for: " + authority);
6264 return;
6265 }
6266
6267 // Does the caller have this permission on the URI?
6268 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6269 // Right now, if you are not the original owner of the permission,
6270 // you are not allowed to revoke it.
6271 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6272 throw new SecurityException("Uid " + callingUid
6273 + " does not have permission to uri " + uri);
6274 //}
6275 }
6276
6277 // Go through all of the permissions and remove any that match.
6278 final List<String> SEGMENTS = uri.getPathSegments();
6279 if (SEGMENTS != null) {
6280 final int NS = SEGMENTS.size();
6281 int N = mGrantedUriPermissions.size();
6282 for (int i=0; i<N; i++) {
6283 HashMap<Uri, UriPermission> perms
6284 = mGrantedUriPermissions.valueAt(i);
6285 Iterator<UriPermission> it = perms.values().iterator();
6286 toploop:
6287 while (it.hasNext()) {
6288 UriPermission perm = it.next();
6289 Uri targetUri = perm.uri;
6290 if (!authority.equals(targetUri.getAuthority())) {
6291 continue;
6292 }
6293 List<String> targetSegments = targetUri.getPathSegments();
6294 if (targetSegments == null) {
6295 continue;
6296 }
6297 if (targetSegments.size() < NS) {
6298 continue;
6299 }
6300 for (int j=0; j<NS; j++) {
6301 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6302 continue toploop;
6303 }
6304 }
6305 perm.clearModes(modeFlags);
6306 if (perm.modeFlags == 0) {
6307 it.remove();
6308 }
6309 }
6310 if (perms.size() == 0) {
6311 mGrantedUriPermissions.remove(
6312 mGrantedUriPermissions.keyAt(i));
6313 N--;
6314 i--;
6315 }
6316 }
6317 }
6318 }
6319
6320 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6321 int modeFlags) {
6322 synchronized(this) {
6323 final ProcessRecord r = getRecordForAppLocked(caller);
6324 if (r == null) {
6325 throw new SecurityException("Unable to find app for caller "
6326 + caller
6327 + " when revoking permission to uri " + uri);
6328 }
6329 if (uri == null) {
6330 Log.w(TAG, "revokeUriPermission: null uri");
6331 return;
6332 }
6333
6334 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6335 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6336 if (modeFlags == 0) {
6337 return;
6338 }
6339
6340 final IPackageManager pm = ActivityThread.getPackageManager();
6341
6342 final String authority = uri.getAuthority();
6343 ProviderInfo pi = null;
6344 ContentProviderRecord cpr
6345 = (ContentProviderRecord)mProvidersByName.get(authority);
6346 if (cpr != null) {
6347 pi = cpr.info;
6348 } else {
6349 try {
6350 pi = pm.resolveContentProvider(authority,
6351 PackageManager.GET_URI_PERMISSION_PATTERNS);
6352 } catch (RemoteException ex) {
6353 }
6354 }
6355 if (pi == null) {
6356 Log.w(TAG, "No content provider found for: " + authority);
6357 return;
6358 }
6359
6360 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6361 }
6362 }
6363
6364 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6365 synchronized (this) {
6366 ProcessRecord app =
6367 who != null ? getRecordForAppLocked(who) : null;
6368 if (app == null) return;
6369
6370 Message msg = Message.obtain();
6371 msg.what = WAIT_FOR_DEBUGGER_MSG;
6372 msg.obj = app;
6373 msg.arg1 = waiting ? 1 : 0;
6374 mHandler.sendMessage(msg);
6375 }
6376 }
6377
6378 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6379 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006380 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006381 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006382 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006383 }
6384
6385 // =========================================================
6386 // TASK MANAGEMENT
6387 // =========================================================
6388
6389 public List getTasks(int maxNum, int flags,
6390 IThumbnailReceiver receiver) {
6391 ArrayList list = new ArrayList();
6392
6393 PendingThumbnailsRecord pending = null;
6394 IApplicationThread topThumbnail = null;
6395 HistoryRecord topRecord = null;
6396
6397 synchronized(this) {
6398 if (localLOGV) Log.v(
6399 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6400 + ", receiver=" + receiver);
6401
6402 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6403 != PackageManager.PERMISSION_GRANTED) {
6404 if (receiver != null) {
6405 // If the caller wants to wait for pending thumbnails,
6406 // it ain't gonna get them.
6407 try {
6408 receiver.finished();
6409 } catch (RemoteException ex) {
6410 }
6411 }
6412 String msg = "Permission Denial: getTasks() from pid="
6413 + Binder.getCallingPid()
6414 + ", uid=" + Binder.getCallingUid()
6415 + " requires " + android.Manifest.permission.GET_TASKS;
6416 Log.w(TAG, msg);
6417 throw new SecurityException(msg);
6418 }
6419
6420 int pos = mHistory.size()-1;
6421 HistoryRecord next =
6422 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6423 HistoryRecord top = null;
6424 CharSequence topDescription = null;
6425 TaskRecord curTask = null;
6426 int numActivities = 0;
6427 int numRunning = 0;
6428 while (pos >= 0 && maxNum > 0) {
6429 final HistoryRecord r = next;
6430 pos--;
6431 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6432
6433 // Initialize state for next task if needed.
6434 if (top == null ||
6435 (top.state == ActivityState.INITIALIZING
6436 && top.task == r.task)) {
6437 top = r;
6438 topDescription = r.description;
6439 curTask = r.task;
6440 numActivities = numRunning = 0;
6441 }
6442
6443 // Add 'r' into the current task.
6444 numActivities++;
6445 if (r.app != null && r.app.thread != null) {
6446 numRunning++;
6447 }
6448 if (topDescription == null) {
6449 topDescription = r.description;
6450 }
6451
6452 if (localLOGV) Log.v(
6453 TAG, r.intent.getComponent().flattenToShortString()
6454 + ": task=" + r.task);
6455
6456 // If the next one is a different task, generate a new
6457 // TaskInfo entry for what we have.
6458 if (next == null || next.task != curTask) {
6459 ActivityManager.RunningTaskInfo ci
6460 = new ActivityManager.RunningTaskInfo();
6461 ci.id = curTask.taskId;
6462 ci.baseActivity = r.intent.getComponent();
6463 ci.topActivity = top.intent.getComponent();
6464 ci.thumbnail = top.thumbnail;
6465 ci.description = topDescription;
6466 ci.numActivities = numActivities;
6467 ci.numRunning = numRunning;
6468 //System.out.println(
6469 // "#" + maxNum + ": " + " descr=" + ci.description);
6470 if (ci.thumbnail == null && receiver != null) {
6471 if (localLOGV) Log.v(
6472 TAG, "State=" + top.state + "Idle=" + top.idle
6473 + " app=" + top.app
6474 + " thr=" + (top.app != null ? top.app.thread : null));
6475 if (top.state == ActivityState.RESUMED
6476 || top.state == ActivityState.PAUSING) {
6477 if (top.idle && top.app != null
6478 && top.app.thread != null) {
6479 topRecord = top;
6480 topThumbnail = top.app.thread;
6481 } else {
6482 top.thumbnailNeeded = true;
6483 }
6484 }
6485 if (pending == null) {
6486 pending = new PendingThumbnailsRecord(receiver);
6487 }
6488 pending.pendingRecords.add(top);
6489 }
6490 list.add(ci);
6491 maxNum--;
6492 top = null;
6493 }
6494 }
6495
6496 if (pending != null) {
6497 mPendingThumbnails.add(pending);
6498 }
6499 }
6500
6501 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6502
6503 if (topThumbnail != null) {
6504 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6505 try {
6506 topThumbnail.requestThumbnail(topRecord);
6507 } catch (Exception e) {
6508 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6509 sendPendingThumbnail(null, topRecord, null, null, true);
6510 }
6511 }
6512
6513 if (pending == null && receiver != null) {
6514 // In this case all thumbnails were available and the client
6515 // is being asked to be told when the remaining ones come in...
6516 // which is unusually, since the top-most currently running
6517 // activity should never have a canned thumbnail! Oh well.
6518 try {
6519 receiver.finished();
6520 } catch (RemoteException ex) {
6521 }
6522 }
6523
6524 return list;
6525 }
6526
6527 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6528 int flags) {
6529 synchronized (this) {
6530 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6531 "getRecentTasks()");
6532
6533 final int N = mRecentTasks.size();
6534 ArrayList<ActivityManager.RecentTaskInfo> res
6535 = new ArrayList<ActivityManager.RecentTaskInfo>(
6536 maxNum < N ? maxNum : N);
6537 for (int i=0; i<N && maxNum > 0; i++) {
6538 TaskRecord tr = mRecentTasks.get(i);
6539 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6540 || (tr.intent == null)
6541 || ((tr.intent.getFlags()
6542 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6543 ActivityManager.RecentTaskInfo rti
6544 = new ActivityManager.RecentTaskInfo();
6545 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6546 rti.baseIntent = new Intent(
6547 tr.intent != null ? tr.intent : tr.affinityIntent);
6548 rti.origActivity = tr.origActivity;
6549 res.add(rti);
6550 maxNum--;
6551 }
6552 }
6553 return res;
6554 }
6555 }
6556
6557 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6558 int j;
6559 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6560 TaskRecord jt = startTask;
6561
6562 // First look backwards
6563 for (j=startIndex-1; j>=0; j--) {
6564 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6565 if (r.task != jt) {
6566 jt = r.task;
6567 if (affinity.equals(jt.affinity)) {
6568 return j;
6569 }
6570 }
6571 }
6572
6573 // Now look forwards
6574 final int N = mHistory.size();
6575 jt = startTask;
6576 for (j=startIndex+1; j<N; j++) {
6577 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6578 if (r.task != jt) {
6579 if (affinity.equals(jt.affinity)) {
6580 return j;
6581 }
6582 jt = r.task;
6583 }
6584 }
6585
6586 // Might it be at the top?
6587 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6588 return N-1;
6589 }
6590
6591 return -1;
6592 }
6593
6594 /**
6595 * Perform a reset of the given task, if needed as part of launching it.
6596 * Returns the new HistoryRecord at the top of the task.
6597 */
6598 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6599 HistoryRecord newActivity) {
6600 boolean forceReset = (newActivity.info.flags
6601 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6602 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6603 if ((newActivity.info.flags
6604 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6605 forceReset = true;
6606 }
6607 }
6608
6609 final TaskRecord task = taskTop.task;
6610
6611 // We are going to move through the history list so that we can look
6612 // at each activity 'target' with 'below' either the interesting
6613 // activity immediately below it in the stack or null.
6614 HistoryRecord target = null;
6615 int targetI = 0;
6616 int taskTopI = -1;
6617 int replyChainEnd = -1;
6618 int lastReparentPos = -1;
6619 for (int i=mHistory.size()-1; i>=-1; i--) {
6620 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6621
6622 if (below != null && below.finishing) {
6623 continue;
6624 }
6625 if (target == null) {
6626 target = below;
6627 targetI = i;
6628 // If we were in the middle of a reply chain before this
6629 // task, it doesn't appear like the root of the chain wants
6630 // anything interesting, so drop it.
6631 replyChainEnd = -1;
6632 continue;
6633 }
6634
6635 final int flags = target.info.flags;
6636
6637 final boolean finishOnTaskLaunch =
6638 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6639 final boolean allowTaskReparenting =
6640 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6641
6642 if (target.task == task) {
6643 // We are inside of the task being reset... we'll either
6644 // finish this activity, push it out for another task,
6645 // or leave it as-is. We only do this
6646 // for activities that are not the root of the task (since
6647 // if we finish the root, we may no longer have the task!).
6648 if (taskTopI < 0) {
6649 taskTopI = targetI;
6650 }
6651 if (below != null && below.task == task) {
6652 final boolean clearWhenTaskReset =
6653 (target.intent.getFlags()
6654 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006655 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006656 // If this activity is sending a reply to a previous
6657 // activity, we can't do anything with it now until
6658 // we reach the start of the reply chain.
6659 // XXX note that we are assuming the result is always
6660 // to the previous activity, which is almost always
6661 // the case but we really shouldn't count on.
6662 if (replyChainEnd < 0) {
6663 replyChainEnd = targetI;
6664 }
Ed Heyl73798232009-03-24 21:32:21 -07006665 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006666 && target.taskAffinity != null
6667 && !target.taskAffinity.equals(task.affinity)) {
6668 // If this activity has an affinity for another
6669 // task, then we need to move it out of here. We will
6670 // move it as far out of the way as possible, to the
6671 // bottom of the activity stack. This also keeps it
6672 // correctly ordered with any activities we previously
6673 // moved.
6674 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6675 if (target.taskAffinity != null
6676 && target.taskAffinity.equals(p.task.affinity)) {
6677 // If the activity currently at the bottom has the
6678 // same task affinity as the one we are moving,
6679 // then merge it into the same task.
6680 target.task = p.task;
6681 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6682 + " out to bottom task " + p.task);
6683 } else {
6684 mCurTask++;
6685 if (mCurTask <= 0) {
6686 mCurTask = 1;
6687 }
6688 target.task = new TaskRecord(mCurTask, target.info, null,
6689 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6690 target.task.affinityIntent = target.intent;
6691 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6692 + " out to new task " + target.task);
6693 }
6694 mWindowManager.setAppGroupId(target, task.taskId);
6695 if (replyChainEnd < 0) {
6696 replyChainEnd = targetI;
6697 }
6698 int dstPos = 0;
6699 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6700 p = (HistoryRecord)mHistory.get(srcPos);
6701 if (p.finishing) {
6702 continue;
6703 }
6704 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6705 + " out to target's task " + target.task);
6706 task.numActivities--;
6707 p.task = target.task;
6708 target.task.numActivities++;
6709 mHistory.remove(srcPos);
6710 mHistory.add(dstPos, p);
6711 mWindowManager.moveAppToken(dstPos, p);
6712 mWindowManager.setAppGroupId(p, p.task.taskId);
6713 dstPos++;
6714 if (VALIDATE_TOKENS) {
6715 mWindowManager.validateAppTokens(mHistory);
6716 }
6717 i++;
6718 }
6719 if (taskTop == p) {
6720 taskTop = below;
6721 }
6722 if (taskTopI == replyChainEnd) {
6723 taskTopI = -1;
6724 }
6725 replyChainEnd = -1;
6726 addRecentTask(target.task);
6727 } else if (forceReset || finishOnTaskLaunch
6728 || clearWhenTaskReset) {
6729 // If the activity should just be removed -- either
6730 // because it asks for it, or the task should be
6731 // cleared -- then finish it and anything that is
6732 // part of its reply chain.
6733 if (clearWhenTaskReset) {
6734 // In this case, we want to finish this activity
6735 // and everything above it, so be sneaky and pretend
6736 // like these are all in the reply chain.
6737 replyChainEnd = targetI+1;
6738 while (replyChainEnd < mHistory.size() &&
6739 ((HistoryRecord)mHistory.get(
6740 replyChainEnd)).task == task) {
6741 replyChainEnd++;
6742 }
6743 replyChainEnd--;
6744 } else if (replyChainEnd < 0) {
6745 replyChainEnd = targetI;
6746 }
6747 HistoryRecord p = null;
6748 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6749 p = (HistoryRecord)mHistory.get(srcPos);
6750 if (p.finishing) {
6751 continue;
6752 }
6753 if (finishActivityLocked(p, srcPos,
6754 Activity.RESULT_CANCELED, null, "reset")) {
6755 replyChainEnd--;
6756 srcPos--;
6757 }
6758 }
6759 if (taskTop == p) {
6760 taskTop = below;
6761 }
6762 if (taskTopI == replyChainEnd) {
6763 taskTopI = -1;
6764 }
6765 replyChainEnd = -1;
6766 } else {
6767 // If we were in the middle of a chain, well the
6768 // activity that started it all doesn't want anything
6769 // special, so leave it all as-is.
6770 replyChainEnd = -1;
6771 }
6772 } else {
6773 // Reached the bottom of the task -- any reply chain
6774 // should be left as-is.
6775 replyChainEnd = -1;
6776 }
6777
6778 } else if (target.resultTo != null) {
6779 // If this activity is sending a reply to a previous
6780 // activity, we can't do anything with it now until
6781 // we reach the start of the reply chain.
6782 // XXX note that we are assuming the result is always
6783 // to the previous activity, which is almost always
6784 // the case but we really shouldn't count on.
6785 if (replyChainEnd < 0) {
6786 replyChainEnd = targetI;
6787 }
6788
6789 } else if (taskTopI >= 0 && allowTaskReparenting
6790 && task.affinity != null
6791 && task.affinity.equals(target.taskAffinity)) {
6792 // We are inside of another task... if this activity has
6793 // an affinity for our task, then either remove it if we are
6794 // clearing or move it over to our task. Note that
6795 // we currently punt on the case where we are resetting a
6796 // task that is not at the top but who has activities above
6797 // with an affinity to it... this is really not a normal
6798 // case, and we will need to later pull that task to the front
6799 // and usually at that point we will do the reset and pick
6800 // up those remaining activities. (This only happens if
6801 // someone starts an activity in a new task from an activity
6802 // in a task that is not currently on top.)
6803 if (forceReset || finishOnTaskLaunch) {
6804 if (replyChainEnd < 0) {
6805 replyChainEnd = targetI;
6806 }
6807 HistoryRecord p = null;
6808 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6809 p = (HistoryRecord)mHistory.get(srcPos);
6810 if (p.finishing) {
6811 continue;
6812 }
6813 if (finishActivityLocked(p, srcPos,
6814 Activity.RESULT_CANCELED, null, "reset")) {
6815 taskTopI--;
6816 lastReparentPos--;
6817 replyChainEnd--;
6818 srcPos--;
6819 }
6820 }
6821 replyChainEnd = -1;
6822 } else {
6823 if (replyChainEnd < 0) {
6824 replyChainEnd = targetI;
6825 }
6826 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6827 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6828 if (p.finishing) {
6829 continue;
6830 }
6831 if (lastReparentPos < 0) {
6832 lastReparentPos = taskTopI;
6833 taskTop = p;
6834 } else {
6835 lastReparentPos--;
6836 }
6837 mHistory.remove(srcPos);
6838 p.task.numActivities--;
6839 p.task = task;
6840 mHistory.add(lastReparentPos, p);
6841 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6842 + " in to resetting task " + task);
6843 task.numActivities++;
6844 mWindowManager.moveAppToken(lastReparentPos, p);
6845 mWindowManager.setAppGroupId(p, p.task.taskId);
6846 if (VALIDATE_TOKENS) {
6847 mWindowManager.validateAppTokens(mHistory);
6848 }
6849 }
6850 replyChainEnd = -1;
6851
6852 // Now we've moved it in to place... but what if this is
6853 // a singleTop activity and we have put it on top of another
6854 // instance of the same activity? Then we drop the instance
6855 // below so it remains singleTop.
6856 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6857 for (int j=lastReparentPos-1; j>=0; j--) {
6858 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6859 if (p.finishing) {
6860 continue;
6861 }
6862 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6863 if (finishActivityLocked(p, j,
6864 Activity.RESULT_CANCELED, null, "replace")) {
6865 taskTopI--;
6866 lastReparentPos--;
6867 }
6868 }
6869 }
6870 }
6871 }
6872 }
6873
6874 target = below;
6875 targetI = i;
6876 }
6877
6878 return taskTop;
6879 }
6880
6881 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006882 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006883 */
6884 public void moveTaskToFront(int task) {
6885 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6886 "moveTaskToFront()");
6887
6888 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006889 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6890 Binder.getCallingUid(), "Task to front")) {
6891 return;
6892 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006893 final long origId = Binder.clearCallingIdentity();
6894 try {
6895 int N = mRecentTasks.size();
6896 for (int i=0; i<N; i++) {
6897 TaskRecord tr = mRecentTasks.get(i);
6898 if (tr.taskId == task) {
6899 moveTaskToFrontLocked(tr);
6900 return;
6901 }
6902 }
6903 for (int i=mHistory.size()-1; i>=0; i--) {
6904 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6905 if (hr.task.taskId == task) {
6906 moveTaskToFrontLocked(hr.task);
6907 return;
6908 }
6909 }
6910 } finally {
6911 Binder.restoreCallingIdentity(origId);
6912 }
6913 }
6914 }
6915
6916 private final void moveTaskToFrontLocked(TaskRecord tr) {
6917 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6918
6919 final int task = tr.taskId;
6920 int top = mHistory.size()-1;
6921
6922 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6923 // nothing to do!
6924 return;
6925 }
6926
6927 if (DEBUG_TRANSITION) Log.v(TAG,
6928 "Prepare to front transition: task=" + tr);
6929 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6930
6931 ArrayList moved = new ArrayList();
6932
6933 // Applying the affinities may have removed entries from the history,
6934 // so get the size again.
6935 top = mHistory.size()-1;
6936 int pos = top;
6937
6938 // Shift all activities with this task up to the top
6939 // of the stack, keeping them in the same internal order.
6940 while (pos >= 0) {
6941 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6942 if (localLOGV) Log.v(
6943 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6944 boolean first = true;
6945 if (r.task.taskId == task) {
6946 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6947 mHistory.remove(pos);
6948 mHistory.add(top, r);
6949 moved.add(0, r);
6950 top--;
6951 if (first) {
6952 addRecentTask(r.task);
6953 first = false;
6954 }
6955 }
6956 pos--;
6957 }
6958
6959 mWindowManager.moveAppTokensToTop(moved);
6960 if (VALIDATE_TOKENS) {
6961 mWindowManager.validateAppTokens(mHistory);
6962 }
6963
6964 finishTaskMove(task);
6965 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6966 }
6967
6968 private final void finishTaskMove(int task) {
6969 resumeTopActivityLocked(null);
6970 }
6971
6972 public void moveTaskToBack(int task) {
6973 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6974 "moveTaskToBack()");
6975
6976 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006977 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6978 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6979 Binder.getCallingUid(), "Task to back")) {
6980 return;
6981 }
6982 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006983 final long origId = Binder.clearCallingIdentity();
6984 moveTaskToBackLocked(task);
6985 Binder.restoreCallingIdentity(origId);
6986 }
6987 }
6988
6989 /**
6990 * Moves an activity, and all of the other activities within the same task, to the bottom
6991 * of the history stack. The activity's order within the task is unchanged.
6992 *
6993 * @param token A reference to the activity we wish to move
6994 * @param nonRoot If false then this only works if the activity is the root
6995 * of a task; if true it will work for any activity in a task.
6996 * @return Returns true if the move completed, false if not.
6997 */
6998 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6999 synchronized(this) {
7000 final long origId = Binder.clearCallingIdentity();
7001 int taskId = getTaskForActivityLocked(token, !nonRoot);
7002 if (taskId >= 0) {
7003 return moveTaskToBackLocked(taskId);
7004 }
7005 Binder.restoreCallingIdentity(origId);
7006 }
7007 return false;
7008 }
7009
7010 /**
7011 * Worker method for rearranging history stack. Implements the function of moving all
7012 * activities for a specific task (gathering them if disjoint) into a single group at the
7013 * bottom of the stack.
7014 *
7015 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7016 * to premeptively cancel the move.
7017 *
7018 * @param task The taskId to collect and move to the bottom.
7019 * @return Returns true if the move completed, false if not.
7020 */
7021 private final boolean moveTaskToBackLocked(int task) {
7022 Log.i(TAG, "moveTaskToBack: " + task);
7023
7024 // If we have a watcher, preflight the move before committing to it. First check
7025 // for *other* available tasks, but if none are available, then try again allowing the
7026 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007027 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007028 HistoryRecord next = topRunningActivityLocked(null, task);
7029 if (next == null) {
7030 next = topRunningActivityLocked(null, 0);
7031 }
7032 if (next != null) {
7033 // ask watcher if this is allowed
7034 boolean moveOK = true;
7035 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007036 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007037 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007038 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007039 }
7040 if (!moveOK) {
7041 return false;
7042 }
7043 }
7044 }
7045
7046 ArrayList moved = new ArrayList();
7047
7048 if (DEBUG_TRANSITION) Log.v(TAG,
7049 "Prepare to back transition: task=" + task);
7050 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
7051
7052 final int N = mHistory.size();
7053 int bottom = 0;
7054 int pos = 0;
7055
7056 // Shift all activities with this task down to the bottom
7057 // of the stack, keeping them in the same internal order.
7058 while (pos < N) {
7059 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7060 if (localLOGV) Log.v(
7061 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7062 if (r.task.taskId == task) {
7063 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7064 mHistory.remove(pos);
7065 mHistory.add(bottom, r);
7066 moved.add(r);
7067 bottom++;
7068 }
7069 pos++;
7070 }
7071
7072 mWindowManager.moveAppTokensToBottom(moved);
7073 if (VALIDATE_TOKENS) {
7074 mWindowManager.validateAppTokens(mHistory);
7075 }
7076
7077 finishTaskMove(task);
7078 return true;
7079 }
7080
7081 public void moveTaskBackwards(int task) {
7082 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7083 "moveTaskBackwards()");
7084
7085 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007086 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7087 Binder.getCallingUid(), "Task backwards")) {
7088 return;
7089 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007090 final long origId = Binder.clearCallingIdentity();
7091 moveTaskBackwardsLocked(task);
7092 Binder.restoreCallingIdentity(origId);
7093 }
7094 }
7095
7096 private final void moveTaskBackwardsLocked(int task) {
7097 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7098 }
7099
7100 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7101 synchronized(this) {
7102 return getTaskForActivityLocked(token, onlyRoot);
7103 }
7104 }
7105
7106 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7107 final int N = mHistory.size();
7108 TaskRecord lastTask = null;
7109 for (int i=0; i<N; i++) {
7110 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7111 if (r == token) {
7112 if (!onlyRoot || lastTask != r.task) {
7113 return r.task.taskId;
7114 }
7115 return -1;
7116 }
7117 lastTask = r.task;
7118 }
7119
7120 return -1;
7121 }
7122
7123 /**
7124 * Returns the top activity in any existing task matching the given
7125 * Intent. Returns null if no such task is found.
7126 */
7127 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7128 ComponentName cls = intent.getComponent();
7129 if (info.targetActivity != null) {
7130 cls = new ComponentName(info.packageName, info.targetActivity);
7131 }
7132
7133 TaskRecord cp = null;
7134
7135 final int N = mHistory.size();
7136 for (int i=(N-1); i>=0; i--) {
7137 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7138 if (!r.finishing && r.task != cp
7139 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7140 cp = r.task;
7141 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7142 // + "/aff=" + r.task.affinity + " to new cls="
7143 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7144 if (r.task.affinity != null) {
7145 if (r.task.affinity.equals(info.taskAffinity)) {
7146 //Log.i(TAG, "Found matching affinity!");
7147 return r;
7148 }
7149 } else if (r.task.intent != null
7150 && r.task.intent.getComponent().equals(cls)) {
7151 //Log.i(TAG, "Found matching class!");
7152 //dump();
7153 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7154 return r;
7155 } else if (r.task.affinityIntent != null
7156 && r.task.affinityIntent.getComponent().equals(cls)) {
7157 //Log.i(TAG, "Found matching class!");
7158 //dump();
7159 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7160 return r;
7161 }
7162 }
7163 }
7164
7165 return null;
7166 }
7167
7168 /**
7169 * Returns the first activity (starting from the top of the stack) that
7170 * is the same as the given activity. Returns null if no such activity
7171 * is found.
7172 */
7173 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7174 ComponentName cls = intent.getComponent();
7175 if (info.targetActivity != null) {
7176 cls = new ComponentName(info.packageName, info.targetActivity);
7177 }
7178
7179 final int N = mHistory.size();
7180 for (int i=(N-1); i>=0; i--) {
7181 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7182 if (!r.finishing) {
7183 if (r.intent.getComponent().equals(cls)) {
7184 //Log.i(TAG, "Found matching class!");
7185 //dump();
7186 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7187 return r;
7188 }
7189 }
7190 }
7191
7192 return null;
7193 }
7194
7195 public void finishOtherInstances(IBinder token, ComponentName className) {
7196 synchronized(this) {
7197 final long origId = Binder.clearCallingIdentity();
7198
7199 int N = mHistory.size();
7200 TaskRecord lastTask = null;
7201 for (int i=0; i<N; i++) {
7202 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7203 if (r.realActivity.equals(className)
7204 && r != token && lastTask != r.task) {
7205 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7206 null, "others")) {
7207 i--;
7208 N--;
7209 }
7210 }
7211 lastTask = r.task;
7212 }
7213
7214 Binder.restoreCallingIdentity(origId);
7215 }
7216 }
7217
7218 // =========================================================
7219 // THUMBNAILS
7220 // =========================================================
7221
7222 public void reportThumbnail(IBinder token,
7223 Bitmap thumbnail, CharSequence description) {
7224 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7225 final long origId = Binder.clearCallingIdentity();
7226 sendPendingThumbnail(null, token, thumbnail, description, true);
7227 Binder.restoreCallingIdentity(origId);
7228 }
7229
7230 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7231 Bitmap thumbnail, CharSequence description, boolean always) {
7232 TaskRecord task = null;
7233 ArrayList receivers = null;
7234
7235 //System.out.println("Send pending thumbnail: " + r);
7236
7237 synchronized(this) {
7238 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007239 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007240 if (index < 0) {
7241 return;
7242 }
7243 r = (HistoryRecord)mHistory.get(index);
7244 }
7245 if (thumbnail == null) {
7246 thumbnail = r.thumbnail;
7247 description = r.description;
7248 }
7249 if (thumbnail == null && !always) {
7250 // If there is no thumbnail, and this entry is not actually
7251 // going away, then abort for now and pick up the next
7252 // thumbnail we get.
7253 return;
7254 }
7255 task = r.task;
7256
7257 int N = mPendingThumbnails.size();
7258 int i=0;
7259 while (i<N) {
7260 PendingThumbnailsRecord pr =
7261 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7262 //System.out.println("Looking in " + pr.pendingRecords);
7263 if (pr.pendingRecords.remove(r)) {
7264 if (receivers == null) {
7265 receivers = new ArrayList();
7266 }
7267 receivers.add(pr);
7268 if (pr.pendingRecords.size() == 0) {
7269 pr.finished = true;
7270 mPendingThumbnails.remove(i);
7271 N--;
7272 continue;
7273 }
7274 }
7275 i++;
7276 }
7277 }
7278
7279 if (receivers != null) {
7280 final int N = receivers.size();
7281 for (int i=0; i<N; i++) {
7282 try {
7283 PendingThumbnailsRecord pr =
7284 (PendingThumbnailsRecord)receivers.get(i);
7285 pr.receiver.newThumbnail(
7286 task != null ? task.taskId : -1, thumbnail, description);
7287 if (pr.finished) {
7288 pr.receiver.finished();
7289 }
7290 } catch (Exception e) {
7291 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7292 }
7293 }
7294 }
7295 }
7296
7297 // =========================================================
7298 // CONTENT PROVIDERS
7299 // =========================================================
7300
7301 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7302 List providers = null;
7303 try {
7304 providers = ActivityThread.getPackageManager().
7305 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007306 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007307 } catch (RemoteException ex) {
7308 }
7309 if (providers != null) {
7310 final int N = providers.size();
7311 for (int i=0; i<N; i++) {
7312 ProviderInfo cpi =
7313 (ProviderInfo)providers.get(i);
7314 ContentProviderRecord cpr =
7315 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7316 if (cpr == null) {
7317 cpr = new ContentProviderRecord(cpi, app.info);
7318 mProvidersByClass.put(cpi.name, cpr);
7319 }
7320 app.pubProviders.put(cpi.name, cpr);
7321 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007322 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007323 }
7324 }
7325 return providers;
7326 }
7327
7328 private final String checkContentProviderPermissionLocked(
7329 ProviderInfo cpi, ProcessRecord r, int mode) {
7330 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7331 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7332 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7333 cpi.exported ? -1 : cpi.applicationInfo.uid)
7334 == PackageManager.PERMISSION_GRANTED
7335 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7336 return null;
7337 }
7338 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7339 cpi.exported ? -1 : cpi.applicationInfo.uid)
7340 == PackageManager.PERMISSION_GRANTED) {
7341 return null;
7342 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007343
7344 PathPermission[] pps = cpi.pathPermissions;
7345 if (pps != null) {
7346 int i = pps.length;
7347 while (i > 0) {
7348 i--;
7349 PathPermission pp = pps[i];
7350 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7351 cpi.exported ? -1 : cpi.applicationInfo.uid)
7352 == PackageManager.PERMISSION_GRANTED
7353 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7354 return null;
7355 }
7356 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7357 cpi.exported ? -1 : cpi.applicationInfo.uid)
7358 == PackageManager.PERMISSION_GRANTED) {
7359 return null;
7360 }
7361 }
7362 }
7363
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007364 String msg = "Permission Denial: opening provider " + cpi.name
7365 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7366 + ", uid=" + callingUid + ") requires "
7367 + cpi.readPermission + " or " + cpi.writePermission;
7368 Log.w(TAG, msg);
7369 return msg;
7370 }
7371
7372 private final ContentProviderHolder getContentProviderImpl(
7373 IApplicationThread caller, String name) {
7374 ContentProviderRecord cpr;
7375 ProviderInfo cpi = null;
7376
7377 synchronized(this) {
7378 ProcessRecord r = null;
7379 if (caller != null) {
7380 r = getRecordForAppLocked(caller);
7381 if (r == null) {
7382 throw new SecurityException(
7383 "Unable to find app for caller " + caller
7384 + " (pid=" + Binder.getCallingPid()
7385 + ") when getting content provider " + name);
7386 }
7387 }
7388
7389 // First check if this content provider has been published...
7390 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7391 if (cpr != null) {
7392 cpi = cpr.info;
7393 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7394 return new ContentProviderHolder(cpi,
7395 cpi.readPermission != null
7396 ? cpi.readPermission : cpi.writePermission);
7397 }
7398
7399 if (r != null && cpr.canRunHere(r)) {
7400 // This provider has been published or is in the process
7401 // of being published... but it is also allowed to run
7402 // in the caller's process, so don't make a connection
7403 // and just let the caller instantiate its own instance.
7404 if (cpr.provider != null) {
7405 // don't give caller the provider object, it needs
7406 // to make its own.
7407 cpr = new ContentProviderRecord(cpr);
7408 }
7409 return cpr;
7410 }
7411
7412 final long origId = Binder.clearCallingIdentity();
7413
7414 // In this case the provider is a single instance, so we can
7415 // return it right away.
7416 if (r != null) {
7417 r.conProviders.add(cpr);
7418 cpr.clients.add(r);
7419 } else {
7420 cpr.externals++;
7421 }
7422
7423 if (cpr.app != null) {
7424 updateOomAdjLocked(cpr.app);
7425 }
7426
7427 Binder.restoreCallingIdentity(origId);
7428
7429 } else {
7430 try {
7431 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007432 resolveContentProvider(name,
7433 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007434 } catch (RemoteException ex) {
7435 }
7436 if (cpi == null) {
7437 return null;
7438 }
7439
7440 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7441 return new ContentProviderHolder(cpi,
7442 cpi.readPermission != null
7443 ? cpi.readPermission : cpi.writePermission);
7444 }
7445
7446 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7447 final boolean firstClass = cpr == null;
7448 if (firstClass) {
7449 try {
7450 ApplicationInfo ai =
7451 ActivityThread.getPackageManager().
7452 getApplicationInfo(
7453 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007454 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007455 if (ai == null) {
7456 Log.w(TAG, "No package info for content provider "
7457 + cpi.name);
7458 return null;
7459 }
7460 cpr = new ContentProviderRecord(cpi, ai);
7461 } catch (RemoteException ex) {
7462 // pm is in same process, this will never happen.
7463 }
7464 }
7465
7466 if (r != null && cpr.canRunHere(r)) {
7467 // If this is a multiprocess provider, then just return its
7468 // info and allow the caller to instantiate it. Only do
7469 // this if the provider is the same user as the caller's
7470 // process, or can run as root (so can be in any process).
7471 return cpr;
7472 }
7473
7474 if (false) {
7475 RuntimeException e = new RuntimeException("foo");
7476 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7477 // + " pruid " + ai.uid + "): " + cpi.className, e);
7478 }
7479
7480 // This is single process, and our app is now connecting to it.
7481 // See if we are already in the process of launching this
7482 // provider.
7483 final int N = mLaunchingProviders.size();
7484 int i;
7485 for (i=0; i<N; i++) {
7486 if (mLaunchingProviders.get(i) == cpr) {
7487 break;
7488 }
7489 if (false) {
7490 final ContentProviderRecord rec =
7491 (ContentProviderRecord)mLaunchingProviders.get(i);
7492 if (rec.info.name.equals(cpr.info.name)) {
7493 cpr = rec;
7494 break;
7495 }
7496 }
7497 }
7498
7499 // If the provider is not already being launched, then get it
7500 // started.
7501 if (i >= N) {
7502 final long origId = Binder.clearCallingIdentity();
7503 ProcessRecord proc = startProcessLocked(cpi.processName,
7504 cpr.appInfo, false, 0, "content provider",
7505 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007506 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007507 if (proc == null) {
7508 Log.w(TAG, "Unable to launch app "
7509 + cpi.applicationInfo.packageName + "/"
7510 + cpi.applicationInfo.uid + " for provider "
7511 + name + ": process is bad");
7512 return null;
7513 }
7514 cpr.launchingApp = proc;
7515 mLaunchingProviders.add(cpr);
7516 Binder.restoreCallingIdentity(origId);
7517 }
7518
7519 // Make sure the provider is published (the same provider class
7520 // may be published under multiple names).
7521 if (firstClass) {
7522 mProvidersByClass.put(cpi.name, cpr);
7523 }
7524 mProvidersByName.put(name, cpr);
7525
7526 if (r != null) {
7527 r.conProviders.add(cpr);
7528 cpr.clients.add(r);
7529 } else {
7530 cpr.externals++;
7531 }
7532 }
7533 }
7534
7535 // Wait for the provider to be published...
7536 synchronized (cpr) {
7537 while (cpr.provider == null) {
7538 if (cpr.launchingApp == null) {
7539 Log.w(TAG, "Unable to launch app "
7540 + cpi.applicationInfo.packageName + "/"
7541 + cpi.applicationInfo.uid + " for provider "
7542 + name + ": launching app became null");
7543 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7544 cpi.applicationInfo.packageName,
7545 cpi.applicationInfo.uid, name);
7546 return null;
7547 }
7548 try {
7549 cpr.wait();
7550 } catch (InterruptedException ex) {
7551 }
7552 }
7553 }
7554 return cpr;
7555 }
7556
7557 public final ContentProviderHolder getContentProvider(
7558 IApplicationThread caller, String name) {
7559 if (caller == null) {
7560 String msg = "null IApplicationThread when getting content provider "
7561 + name;
7562 Log.w(TAG, msg);
7563 throw new SecurityException(msg);
7564 }
7565
7566 return getContentProviderImpl(caller, name);
7567 }
7568
7569 private ContentProviderHolder getContentProviderExternal(String name) {
7570 return getContentProviderImpl(null, name);
7571 }
7572
7573 /**
7574 * Drop a content provider from a ProcessRecord's bookkeeping
7575 * @param cpr
7576 */
7577 public void removeContentProvider(IApplicationThread caller, String name) {
7578 synchronized (this) {
7579 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7580 if(cpr == null) {
7581 //remove from mProvidersByClass
Dianne Hackborne1b44372009-09-01 19:21:08 -07007582 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007583 return;
7584 }
7585 final ProcessRecord r = getRecordForAppLocked(caller);
7586 if (r == null) {
7587 throw new SecurityException(
7588 "Unable to find app for caller " + caller +
7589 " when removing content provider " + name);
7590 }
7591 //update content provider record entry info
7592 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
Dianne Hackborne1b44372009-09-01 19:21:08 -07007593 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7594 r.info.processName+" from process "+localCpr.appInfo.processName);
7595 if(localCpr.appInfo.processName == r.info.processName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007596 //should not happen. taken care of as a local provider
Dianne Hackborne1b44372009-09-01 19:21:08 -07007597 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007598 return;
7599 } else {
7600 localCpr.clients.remove(r);
7601 r.conProviders.remove(localCpr);
7602 }
7603 updateOomAdjLocked();
7604 }
7605 }
7606
7607 private void removeContentProviderExternal(String name) {
7608 synchronized (this) {
7609 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7610 if(cpr == null) {
7611 //remove from mProvidersByClass
7612 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7613 return;
7614 }
7615
7616 //update content provider record entry info
7617 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7618 localCpr.externals--;
7619 if (localCpr.externals < 0) {
7620 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7621 }
7622 updateOomAdjLocked();
7623 }
7624 }
7625
7626 public final void publishContentProviders(IApplicationThread caller,
7627 List<ContentProviderHolder> providers) {
7628 if (providers == null) {
7629 return;
7630 }
7631
7632 synchronized(this) {
7633 final ProcessRecord r = getRecordForAppLocked(caller);
7634 if (r == null) {
7635 throw new SecurityException(
7636 "Unable to find app for caller " + caller
7637 + " (pid=" + Binder.getCallingPid()
7638 + ") when publishing content providers");
7639 }
7640
7641 final long origId = Binder.clearCallingIdentity();
7642
7643 final int N = providers.size();
7644 for (int i=0; i<N; i++) {
7645 ContentProviderHolder src = providers.get(i);
7646 if (src == null || src.info == null || src.provider == null) {
7647 continue;
7648 }
7649 ContentProviderRecord dst =
7650 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7651 if (dst != null) {
7652 mProvidersByClass.put(dst.info.name, dst);
7653 String names[] = dst.info.authority.split(";");
7654 for (int j = 0; j < names.length; j++) {
7655 mProvidersByName.put(names[j], dst);
7656 }
7657
7658 int NL = mLaunchingProviders.size();
7659 int j;
7660 for (j=0; j<NL; j++) {
7661 if (mLaunchingProviders.get(j) == dst) {
7662 mLaunchingProviders.remove(j);
7663 j--;
7664 NL--;
7665 }
7666 }
7667 synchronized (dst) {
7668 dst.provider = src.provider;
7669 dst.app = r;
7670 dst.notifyAll();
7671 }
7672 updateOomAdjLocked(r);
7673 }
7674 }
7675
7676 Binder.restoreCallingIdentity(origId);
7677 }
7678 }
7679
7680 public static final void installSystemProviders() {
7681 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7682 List providers = mSelf.generateApplicationProvidersLocked(app);
7683 mSystemThread.installSystemProviders(providers);
7684 }
7685
7686 // =========================================================
7687 // GLOBAL MANAGEMENT
7688 // =========================================================
7689
7690 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7691 ApplicationInfo info, String customProcess) {
7692 String proc = customProcess != null ? customProcess : info.processName;
7693 BatteryStatsImpl.Uid.Proc ps = null;
7694 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7695 synchronized (stats) {
7696 ps = stats.getProcessStatsLocked(info.uid, proc);
7697 }
7698 return new ProcessRecord(ps, thread, info, proc);
7699 }
7700
7701 final ProcessRecord addAppLocked(ApplicationInfo info) {
7702 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7703
7704 if (app == null) {
7705 app = newProcessRecordLocked(null, info, null);
7706 mProcessNames.put(info.processName, info.uid, app);
7707 updateLRUListLocked(app, true);
7708 }
7709
7710 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7711 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7712 app.persistent = true;
7713 app.maxAdj = CORE_SERVER_ADJ;
7714 }
7715 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7716 mPersistentStartingProcesses.add(app);
7717 startProcessLocked(app, "added application", app.processName);
7718 }
7719
7720 return app;
7721 }
7722
7723 public void unhandledBack() {
7724 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7725 "unhandledBack()");
7726
7727 synchronized(this) {
7728 int count = mHistory.size();
7729 if (Config.LOGD) Log.d(
7730 TAG, "Performing unhandledBack(): stack size = " + count);
7731 if (count > 1) {
7732 final long origId = Binder.clearCallingIdentity();
7733 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7734 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7735 Binder.restoreCallingIdentity(origId);
7736 }
7737 }
7738 }
7739
7740 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7741 String name = uri.getAuthority();
7742 ContentProviderHolder cph = getContentProviderExternal(name);
7743 ParcelFileDescriptor pfd = null;
7744 if (cph != null) {
7745 // We record the binder invoker's uid in thread-local storage before
7746 // going to the content provider to open the file. Later, in the code
7747 // that handles all permissions checks, we look for this uid and use
7748 // that rather than the Activity Manager's own uid. The effect is that
7749 // we do the check against the caller's permissions even though it looks
7750 // to the content provider like the Activity Manager itself is making
7751 // the request.
7752 sCallerIdentity.set(new Identity(
7753 Binder.getCallingPid(), Binder.getCallingUid()));
7754 try {
7755 pfd = cph.provider.openFile(uri, "r");
7756 } catch (FileNotFoundException e) {
7757 // do nothing; pfd will be returned null
7758 } finally {
7759 // Ensure that whatever happens, we clean up the identity state
7760 sCallerIdentity.remove();
7761 }
7762
7763 // We've got the fd now, so we're done with the provider.
7764 removeContentProviderExternal(name);
7765 } else {
7766 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7767 }
7768 return pfd;
7769 }
7770
7771 public void goingToSleep() {
7772 synchronized(this) {
7773 mSleeping = true;
7774 mWindowManager.setEventDispatching(false);
7775
7776 if (mResumedActivity != null) {
7777 pauseIfSleepingLocked();
7778 } else {
7779 Log.w(TAG, "goingToSleep with no resumed activity!");
7780 }
7781 }
7782 }
7783
Dianne Hackborn55280a92009-05-07 15:53:46 -07007784 public boolean shutdown(int timeout) {
7785 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7786 != PackageManager.PERMISSION_GRANTED) {
7787 throw new SecurityException("Requires permission "
7788 + android.Manifest.permission.SHUTDOWN);
7789 }
7790
7791 boolean timedout = false;
7792
7793 synchronized(this) {
7794 mShuttingDown = true;
7795 mWindowManager.setEventDispatching(false);
7796
7797 if (mResumedActivity != null) {
7798 pauseIfSleepingLocked();
7799 final long endTime = System.currentTimeMillis() + timeout;
7800 while (mResumedActivity != null || mPausingActivity != null) {
7801 long delay = endTime - System.currentTimeMillis();
7802 if (delay <= 0) {
7803 Log.w(TAG, "Activity manager shutdown timed out");
7804 timedout = true;
7805 break;
7806 }
7807 try {
7808 this.wait();
7809 } catch (InterruptedException e) {
7810 }
7811 }
7812 }
7813 }
7814
7815 mUsageStatsService.shutdown();
7816 mBatteryStatsService.shutdown();
7817
7818 return timedout;
7819 }
7820
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007821 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007822 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007823 if (!mGoingToSleep.isHeld()) {
7824 mGoingToSleep.acquire();
7825 if (mLaunchingActivity.isHeld()) {
7826 mLaunchingActivity.release();
7827 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7828 }
7829 }
7830
7831 // If we are not currently pausing an activity, get the current
7832 // one to pause. If we are pausing one, we will just let that stuff
7833 // run and release the wake lock when all done.
7834 if (mPausingActivity == null) {
7835 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7836 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7837 startPausingLocked(false, true);
7838 }
7839 }
7840 }
7841
7842 public void wakingUp() {
7843 synchronized(this) {
7844 if (mGoingToSleep.isHeld()) {
7845 mGoingToSleep.release();
7846 }
7847 mWindowManager.setEventDispatching(true);
7848 mSleeping = false;
7849 resumeTopActivityLocked(null);
7850 }
7851 }
7852
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007853 public void stopAppSwitches() {
7854 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7855 != PackageManager.PERMISSION_GRANTED) {
7856 throw new SecurityException("Requires permission "
7857 + android.Manifest.permission.STOP_APP_SWITCHES);
7858 }
7859
7860 synchronized(this) {
7861 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7862 + APP_SWITCH_DELAY_TIME;
7863 mDidAppSwitch = false;
7864 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7865 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7866 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7867 }
7868 }
7869
7870 public void resumeAppSwitches() {
7871 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7872 != PackageManager.PERMISSION_GRANTED) {
7873 throw new SecurityException("Requires permission "
7874 + android.Manifest.permission.STOP_APP_SWITCHES);
7875 }
7876
7877 synchronized(this) {
7878 // Note that we don't execute any pending app switches... we will
7879 // let those wait until either the timeout, or the next start
7880 // activity request.
7881 mAppSwitchesAllowedTime = 0;
7882 }
7883 }
7884
7885 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7886 String name) {
7887 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7888 return true;
7889 }
7890
7891 final int perm = checkComponentPermission(
7892 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7893 callingUid, -1);
7894 if (perm == PackageManager.PERMISSION_GRANTED) {
7895 return true;
7896 }
7897
7898 Log.w(TAG, name + " request from " + callingUid + " stopped");
7899 return false;
7900 }
7901
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007902 public void setDebugApp(String packageName, boolean waitForDebugger,
7903 boolean persistent) {
7904 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7905 "setDebugApp()");
7906
7907 // Note that this is not really thread safe if there are multiple
7908 // callers into it at the same time, but that's not a situation we
7909 // care about.
7910 if (persistent) {
7911 final ContentResolver resolver = mContext.getContentResolver();
7912 Settings.System.putString(
7913 resolver, Settings.System.DEBUG_APP,
7914 packageName);
7915 Settings.System.putInt(
7916 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7917 waitForDebugger ? 1 : 0);
7918 }
7919
7920 synchronized (this) {
7921 if (!persistent) {
7922 mOrigDebugApp = mDebugApp;
7923 mOrigWaitForDebugger = mWaitForDebugger;
7924 }
7925 mDebugApp = packageName;
7926 mWaitForDebugger = waitForDebugger;
7927 mDebugTransient = !persistent;
7928 if (packageName != null) {
7929 final long origId = Binder.clearCallingIdentity();
7930 uninstallPackageLocked(packageName, -1, false);
7931 Binder.restoreCallingIdentity(origId);
7932 }
7933 }
7934 }
7935
7936 public void setAlwaysFinish(boolean enabled) {
7937 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7938 "setAlwaysFinish()");
7939
7940 Settings.System.putInt(
7941 mContext.getContentResolver(),
7942 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7943
7944 synchronized (this) {
7945 mAlwaysFinishActivities = enabled;
7946 }
7947 }
7948
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007949 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007950 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007951 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007952 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007953 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007954 }
7955 }
7956
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007957 public void registerActivityWatcher(IActivityWatcher watcher) {
7958 mWatchers.register(watcher);
7959 }
7960
7961 public void unregisterActivityWatcher(IActivityWatcher watcher) {
7962 mWatchers.unregister(watcher);
7963 }
7964
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007965 public final void enterSafeMode() {
7966 synchronized(this) {
7967 // It only makes sense to do this before the system is ready
7968 // and started launching other packages.
7969 if (!mSystemReady) {
7970 try {
7971 ActivityThread.getPackageManager().enterSafeMode();
7972 } catch (RemoteException e) {
7973 }
7974
7975 View v = LayoutInflater.from(mContext).inflate(
7976 com.android.internal.R.layout.safe_mode, null);
7977 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7978 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7979 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7980 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7981 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7982 lp.format = v.getBackground().getOpacity();
7983 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7984 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7985 ((WindowManager)mContext.getSystemService(
7986 Context.WINDOW_SERVICE)).addView(v, lp);
7987 }
7988 }
7989 }
7990
7991 public void noteWakeupAlarm(IIntentSender sender) {
7992 if (!(sender instanceof PendingIntentRecord)) {
7993 return;
7994 }
7995 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7996 synchronized (stats) {
7997 if (mBatteryStatsService.isOnBattery()) {
7998 mBatteryStatsService.enforceCallingPermission();
7999 PendingIntentRecord rec = (PendingIntentRecord)sender;
8000 int MY_UID = Binder.getCallingUid();
8001 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8002 BatteryStatsImpl.Uid.Pkg pkg =
8003 stats.getPackageStatsLocked(uid, rec.key.packageName);
8004 pkg.incWakeupsLocked();
8005 }
8006 }
8007 }
8008
8009 public boolean killPidsForMemory(int[] pids) {
8010 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8011 throw new SecurityException("killPidsForMemory only available to the system");
8012 }
8013
8014 // XXX Note: don't acquire main activity lock here, because the window
8015 // manager calls in with its locks held.
8016
8017 boolean killed = false;
8018 synchronized (mPidsSelfLocked) {
8019 int[] types = new int[pids.length];
8020 int worstType = 0;
8021 for (int i=0; i<pids.length; i++) {
8022 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8023 if (proc != null) {
8024 int type = proc.setAdj;
8025 types[i] = type;
8026 if (type > worstType) {
8027 worstType = type;
8028 }
8029 }
8030 }
8031
8032 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8033 // then constrain it so we will kill all hidden procs.
8034 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8035 worstType = HIDDEN_APP_MIN_ADJ;
8036 }
8037 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8038 for (int i=0; i<pids.length; i++) {
8039 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8040 if (proc == null) {
8041 continue;
8042 }
8043 int adj = proc.setAdj;
8044 if (adj >= worstType) {
8045 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8046 + adj + ")");
8047 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
8048 proc.processName, adj);
8049 killed = true;
8050 Process.killProcess(pids[i]);
8051 }
8052 }
8053 }
8054 return killed;
8055 }
8056
8057 public void reportPss(IApplicationThread caller, int pss) {
8058 Watchdog.PssRequestor req;
8059 String name;
8060 ProcessRecord callerApp;
8061 synchronized (this) {
8062 if (caller == null) {
8063 return;
8064 }
8065 callerApp = getRecordForAppLocked(caller);
8066 if (callerApp == null) {
8067 return;
8068 }
8069 callerApp.lastPss = pss;
8070 req = callerApp;
8071 name = callerApp.processName;
8072 }
8073 Watchdog.getInstance().reportPss(req, name, pss);
8074 if (!callerApp.persistent) {
8075 removeRequestedPss(callerApp);
8076 }
8077 }
8078
8079 public void requestPss(Runnable completeCallback) {
8080 ArrayList<ProcessRecord> procs;
8081 synchronized (this) {
8082 mRequestPssCallback = completeCallback;
8083 mRequestPssList.clear();
8084 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8085 ProcessRecord proc = mLRUProcesses.get(i);
8086 if (!proc.persistent) {
8087 mRequestPssList.add(proc);
8088 }
8089 }
8090 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8091 }
8092
8093 int oldPri = Process.getThreadPriority(Process.myTid());
8094 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8095 for (int i=procs.size()-1; i>=0; i--) {
8096 ProcessRecord proc = procs.get(i);
8097 proc.lastPss = 0;
8098 proc.requestPss();
8099 }
8100 Process.setThreadPriority(oldPri);
8101 }
8102
8103 void removeRequestedPss(ProcessRecord proc) {
8104 Runnable callback = null;
8105 synchronized (this) {
8106 if (mRequestPssList.remove(proc)) {
8107 if (mRequestPssList.size() == 0) {
8108 callback = mRequestPssCallback;
8109 mRequestPssCallback = null;
8110 }
8111 }
8112 }
8113
8114 if (callback != null) {
8115 callback.run();
8116 }
8117 }
8118
8119 public void collectPss(Watchdog.PssStats stats) {
8120 stats.mEmptyPss = 0;
8121 stats.mEmptyCount = 0;
8122 stats.mBackgroundPss = 0;
8123 stats.mBackgroundCount = 0;
8124 stats.mServicePss = 0;
8125 stats.mServiceCount = 0;
8126 stats.mVisiblePss = 0;
8127 stats.mVisibleCount = 0;
8128 stats.mForegroundPss = 0;
8129 stats.mForegroundCount = 0;
8130 stats.mNoPssCount = 0;
8131 synchronized (this) {
8132 int i;
8133 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8134 ? mProcDeaths.length : stats.mProcDeaths.length;
8135 int aggr = 0;
8136 for (i=0; i<NPD; i++) {
8137 aggr += mProcDeaths[i];
8138 stats.mProcDeaths[i] = aggr;
8139 }
8140 while (i<stats.mProcDeaths.length) {
8141 stats.mProcDeaths[i] = 0;
8142 i++;
8143 }
8144
8145 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8146 ProcessRecord proc = mLRUProcesses.get(i);
8147 if (proc.persistent) {
8148 continue;
8149 }
8150 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8151 if (proc.lastPss == 0) {
8152 stats.mNoPssCount++;
8153 continue;
8154 }
8155 if (proc.setAdj == EMPTY_APP_ADJ) {
8156 stats.mEmptyPss += proc.lastPss;
8157 stats.mEmptyCount++;
8158 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8159 stats.mEmptyPss += proc.lastPss;
8160 stats.mEmptyCount++;
8161 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8162 stats.mBackgroundPss += proc.lastPss;
8163 stats.mBackgroundCount++;
8164 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8165 stats.mVisiblePss += proc.lastPss;
8166 stats.mVisibleCount++;
8167 } else {
8168 stats.mForegroundPss += proc.lastPss;
8169 stats.mForegroundCount++;
8170 }
8171 }
8172 }
8173 }
8174
8175 public final void startRunning(String pkg, String cls, String action,
8176 String data) {
8177 synchronized(this) {
8178 if (mStartRunning) {
8179 return;
8180 }
8181 mStartRunning = true;
8182 mTopComponent = pkg != null && cls != null
8183 ? new ComponentName(pkg, cls) : null;
8184 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8185 mTopData = data;
8186 if (!mSystemReady) {
8187 return;
8188 }
8189 }
8190
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008191 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008192 }
8193
8194 private void retrieveSettings() {
8195 final ContentResolver resolver = mContext.getContentResolver();
8196 String debugApp = Settings.System.getString(
8197 resolver, Settings.System.DEBUG_APP);
8198 boolean waitForDebugger = Settings.System.getInt(
8199 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8200 boolean alwaysFinishActivities = Settings.System.getInt(
8201 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8202
8203 Configuration configuration = new Configuration();
8204 Settings.System.getConfiguration(resolver, configuration);
8205
8206 synchronized (this) {
8207 mDebugApp = mOrigDebugApp = debugApp;
8208 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8209 mAlwaysFinishActivities = alwaysFinishActivities;
8210 // This happens before any activities are started, so we can
8211 // change mConfiguration in-place.
8212 mConfiguration.updateFrom(configuration);
8213 }
8214 }
8215
8216 public boolean testIsSystemReady() {
8217 // no need to synchronize(this) just to read & return the value
8218 return mSystemReady;
8219 }
8220
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008221 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008222 // In the simulator, startRunning will never have been called, which
8223 // normally sets a few crucial variables. Do it here instead.
8224 if (!Process.supportsProcesses()) {
8225 mStartRunning = true;
8226 mTopAction = Intent.ACTION_MAIN;
8227 }
8228
8229 synchronized(this) {
8230 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008231 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008232 return;
8233 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008234
8235 // Check to see if there are any update receivers to run.
8236 if (!mDidUpdate) {
8237 if (mWaitingUpdate) {
8238 return;
8239 }
8240 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8241 List<ResolveInfo> ris = null;
8242 try {
8243 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8244 intent, null, 0);
8245 } catch (RemoteException e) {
8246 }
8247 if (ris != null) {
8248 for (int i=ris.size()-1; i>=0; i--) {
8249 if ((ris.get(i).activityInfo.applicationInfo.flags
8250 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8251 ris.remove(i);
8252 }
8253 }
8254 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8255 for (int i=0; i<ris.size(); i++) {
8256 ActivityInfo ai = ris.get(i).activityInfo;
8257 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8258 IIntentReceiver finisher = null;
8259 if (i == 0) {
8260 finisher = new IIntentReceiver.Stub() {
8261 public void performReceive(Intent intent, int resultCode,
8262 String data, Bundle extras, boolean ordered)
8263 throws RemoteException {
8264 synchronized (ActivityManagerService.this) {
8265 mDidUpdate = true;
8266 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008267 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008268 }
8269 };
8270 }
8271 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8272 broadcastIntentLocked(null, null, intent, null, finisher,
8273 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8274 if (i == 0) {
8275 mWaitingUpdate = true;
8276 }
8277 }
8278 }
8279 if (mWaitingUpdate) {
8280 return;
8281 }
8282 mDidUpdate = true;
8283 }
8284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008285 mSystemReady = true;
8286 if (!mStartRunning) {
8287 return;
8288 }
8289 }
8290
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008291 ArrayList<ProcessRecord> procsToKill = null;
8292 synchronized(mPidsSelfLocked) {
8293 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8294 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8295 if (!isAllowedWhileBooting(proc.info)){
8296 if (procsToKill == null) {
8297 procsToKill = new ArrayList<ProcessRecord>();
8298 }
8299 procsToKill.add(proc);
8300 }
8301 }
8302 }
8303
8304 if (procsToKill != null) {
8305 synchronized(this) {
8306 for (int i=procsToKill.size()-1; i>=0; i--) {
8307 ProcessRecord proc = procsToKill.get(i);
8308 Log.i(TAG, "Removing system update proc: " + proc);
8309 removeProcessLocked(proc, true);
8310 }
8311 }
8312 }
8313
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008314 Log.i(TAG, "System now ready");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008315 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8316 SystemClock.uptimeMillis());
8317
8318 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008319 // Make sure we have no pre-ready processes sitting around.
8320
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008321 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8322 ResolveInfo ri = mContext.getPackageManager()
8323 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008324 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008325 CharSequence errorMsg = null;
8326 if (ri != null) {
8327 ActivityInfo ai = ri.activityInfo;
8328 ApplicationInfo app = ai.applicationInfo;
8329 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8330 mTopAction = Intent.ACTION_FACTORY_TEST;
8331 mTopData = null;
8332 mTopComponent = new ComponentName(app.packageName,
8333 ai.name);
8334 } else {
8335 errorMsg = mContext.getResources().getText(
8336 com.android.internal.R.string.factorytest_not_system);
8337 }
8338 } else {
8339 errorMsg = mContext.getResources().getText(
8340 com.android.internal.R.string.factorytest_no_action);
8341 }
8342 if (errorMsg != null) {
8343 mTopAction = null;
8344 mTopData = null;
8345 mTopComponent = null;
8346 Message msg = Message.obtain();
8347 msg.what = SHOW_FACTORY_ERROR_MSG;
8348 msg.getData().putCharSequence("msg", errorMsg);
8349 mHandler.sendMessage(msg);
8350 }
8351 }
8352 }
8353
8354 retrieveSettings();
8355
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008356 if (goingCallback != null) goingCallback.run();
8357
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008358 synchronized (this) {
8359 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8360 try {
8361 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008362 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008363 if (apps != null) {
8364 int N = apps.size();
8365 int i;
8366 for (i=0; i<N; i++) {
8367 ApplicationInfo info
8368 = (ApplicationInfo)apps.get(i);
8369 if (info != null &&
8370 !info.packageName.equals("android")) {
8371 addAppLocked(info);
8372 }
8373 }
8374 }
8375 } catch (RemoteException ex) {
8376 // pm is in same process, this will never happen.
8377 }
8378 }
8379
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008380 // Start up initial activity.
8381 mBooting = true;
8382
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008383 try {
8384 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8385 Message msg = Message.obtain();
8386 msg.what = SHOW_UID_ERROR_MSG;
8387 mHandler.sendMessage(msg);
8388 }
8389 } catch (RemoteException e) {
8390 }
8391
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008392 resumeTopActivityLocked(null);
8393 }
8394 }
8395
8396 boolean makeAppCrashingLocked(ProcessRecord app,
8397 String tag, String shortMsg, String longMsg, byte[] crashData) {
8398 app.crashing = true;
8399 app.crashingReport = generateProcessError(app,
8400 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8401 startAppProblemLocked(app);
8402 app.stopFreezingAllLocked();
8403 return handleAppCrashLocked(app);
8404 }
8405
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008406 private ComponentName getErrorReportReceiver(ProcessRecord app) {
8407 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008408
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008409 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008410 // look for receiver in the installer package
8411 String candidate = pm.getInstallerPackageName(app.info.packageName);
8412 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8413 if (result != null) {
8414 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008415 }
8416
Jacek Surazski82a73df2009-06-17 14:33:18 +02008417 // if the error app is on the system image, look for system apps
8418 // error receiver
8419 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8420 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8421 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8422 if (result != null) {
8423 return result;
8424 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008425 }
8426
Jacek Surazski82a73df2009-06-17 14:33:18 +02008427 // if there is a default receiver, try that
8428 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8429 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008430 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008431 // should not happen
8432 Log.e(TAG, "error talking to PackageManager", e);
8433 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008434 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008435 }
8436
8437 /**
8438 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8439 *
8440 * @param pm PackageManager isntance
8441 * @param errorPackage package which caused the error
8442 * @param receiverPackage candidate package to receive the error
8443 * @return activity component within receiverPackage which handles
8444 * ACTION_APP_ERROR, or null if not found
8445 */
8446 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8447 String receiverPackage) throws RemoteException {
8448 if (receiverPackage == null || receiverPackage.length() == 0) {
8449 return null;
8450 }
8451
8452 // break the loop if it's the error report receiver package that crashed
8453 if (receiverPackage.equals(errorPackage)) {
8454 return null;
8455 }
8456
8457 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8458 intent.setPackage(receiverPackage);
8459 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8460 if (info == null || info.activityInfo == null) {
8461 return null;
8462 }
8463 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008464 }
8465
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008466 void makeAppNotRespondingLocked(ProcessRecord app,
8467 String tag, String shortMsg, String longMsg, byte[] crashData) {
8468 app.notResponding = true;
8469 app.notRespondingReport = generateProcessError(app,
8470 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8471 crashData);
8472 startAppProblemLocked(app);
8473 app.stopFreezingAllLocked();
8474 }
8475
8476 /**
8477 * Generate a process error record, suitable for attachment to a ProcessRecord.
8478 *
8479 * @param app The ProcessRecord in which the error occurred.
8480 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8481 * ActivityManager.AppErrorStateInfo
8482 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8483 * @param shortMsg Short message describing the crash.
8484 * @param longMsg Long message describing the crash.
8485 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8486 *
8487 * @return Returns a fully-formed AppErrorStateInfo record.
8488 */
8489 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8490 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8491 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8492
8493 report.condition = condition;
8494 report.processName = app.processName;
8495 report.pid = app.pid;
8496 report.uid = app.info.uid;
8497 report.tag = tag;
8498 report.shortMsg = shortMsg;
8499 report.longMsg = longMsg;
8500 report.crashData = crashData;
8501
8502 return report;
8503 }
8504
8505 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8506 boolean crashed) {
8507 synchronized (this) {
8508 app.crashing = false;
8509 app.crashingReport = null;
8510 app.notResponding = false;
8511 app.notRespondingReport = null;
8512 if (app.anrDialog == fromDialog) {
8513 app.anrDialog = null;
8514 }
8515 if (app.waitDialog == fromDialog) {
8516 app.waitDialog = null;
8517 }
8518 if (app.pid > 0 && app.pid != MY_PID) {
8519 if (crashed) {
8520 handleAppCrashLocked(app);
8521 }
8522 Log.i(ActivityManagerService.TAG, "Killing process "
8523 + app.processName
8524 + " (pid=" + app.pid + ") at user's request");
8525 Process.killProcess(app.pid);
8526 }
8527
8528 }
8529 }
8530
8531 boolean handleAppCrashLocked(ProcessRecord app) {
8532 long now = SystemClock.uptimeMillis();
8533
8534 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8535 app.info.uid);
8536 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8537 // This process loses!
8538 Log.w(TAG, "Process " + app.info.processName
8539 + " has crashed too many times: killing!");
8540 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8541 app.info.processName, app.info.uid);
8542 killServicesLocked(app, false);
8543 for (int i=mHistory.size()-1; i>=0; i--) {
8544 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8545 if (r.app == app) {
8546 if (Config.LOGD) Log.d(
8547 TAG, " Force finishing activity "
8548 + r.intent.getComponent().flattenToShortString());
8549 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8550 }
8551 }
8552 if (!app.persistent) {
8553 // We don't want to start this process again until the user
8554 // explicitly does so... but for persistent process, we really
8555 // need to keep it running. If a persistent process is actually
8556 // repeatedly crashing, then badness for everyone.
8557 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8558 app.info.processName);
8559 mBadProcesses.put(app.info.processName, app.info.uid, now);
8560 app.bad = true;
8561 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8562 app.removed = true;
8563 removeProcessLocked(app, false);
8564 return false;
8565 }
8566 }
8567
8568 // Bump up the crash count of any services currently running in the proc.
8569 if (app.services.size() != 0) {
8570 // Any services running in the application need to be placed
8571 // back in the pending list.
8572 Iterator it = app.services.iterator();
8573 while (it.hasNext()) {
8574 ServiceRecord sr = (ServiceRecord)it.next();
8575 sr.crashCount++;
8576 }
8577 }
8578
8579 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8580 return true;
8581 }
8582
8583 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008584 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008585 skipCurrentReceiverLocked(app);
8586 }
8587
8588 void skipCurrentReceiverLocked(ProcessRecord app) {
8589 boolean reschedule = false;
8590 BroadcastRecord r = app.curReceiver;
8591 if (r != null) {
8592 // The current broadcast is waiting for this app's receiver
8593 // to be finished. Looks like that's not going to happen, so
8594 // let the broadcast continue.
8595 logBroadcastReceiverDiscard(r);
8596 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8597 r.resultExtras, r.resultAbort, true);
8598 reschedule = true;
8599 }
8600 r = mPendingBroadcast;
8601 if (r != null && r.curApp == app) {
8602 if (DEBUG_BROADCAST) Log.v(TAG,
8603 "skip & discard pending app " + r);
8604 logBroadcastReceiverDiscard(r);
8605 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8606 r.resultExtras, r.resultAbort, true);
8607 reschedule = true;
8608 }
8609 if (reschedule) {
8610 scheduleBroadcastsLocked();
8611 }
8612 }
8613
8614 public int handleApplicationError(IBinder app, int flags,
8615 String tag, String shortMsg, String longMsg, byte[] crashData) {
8616 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008617 ProcessRecord r = null;
8618 synchronized (this) {
8619 if (app != null) {
8620 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8621 final int NA = apps.size();
8622 for (int ia=0; ia<NA; ia++) {
8623 ProcessRecord p = apps.valueAt(ia);
8624 if (p.thread != null && p.thread.asBinder() == app) {
8625 r = p;
8626 break;
8627 }
8628 }
8629 }
8630 }
8631
8632 if (r != null) {
8633 // The application has crashed. Send the SIGQUIT to the process so
8634 // that it can dump its state.
8635 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8636 //Log.i(TAG, "Current system threads:");
8637 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8638 }
8639
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008640 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008641 try {
8642 String name = r != null ? r.processName : null;
8643 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008644 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008645 shortMsg, longMsg, crashData)) {
8646 Log.w(TAG, "Force-killing crashed app " + name
8647 + " at watcher's request");
8648 Process.killProcess(pid);
8649 return 0;
8650 }
8651 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008652 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008653 }
8654 }
8655
8656 final long origId = Binder.clearCallingIdentity();
8657
8658 // If this process is running instrumentation, finish it.
8659 if (r != null && r.instrumentationClass != null) {
8660 Log.w(TAG, "Error in app " + r.processName
8661 + " running instrumentation " + r.instrumentationClass + ":");
8662 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8663 if (longMsg != null) Log.w(TAG, " " + longMsg);
8664 Bundle info = new Bundle();
8665 info.putString("shortMsg", shortMsg);
8666 info.putString("longMsg", longMsg);
8667 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8668 Binder.restoreCallingIdentity(origId);
8669 return 0;
8670 }
8671
8672 if (r != null) {
8673 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8674 return 0;
8675 }
8676 } else {
8677 Log.w(TAG, "Some application object " + app + " tag " + tag
8678 + " has crashed, but I don't know who it is.");
8679 Log.w(TAG, "ShortMsg:" + shortMsg);
8680 Log.w(TAG, "LongMsg:" + longMsg);
8681 Binder.restoreCallingIdentity(origId);
8682 return 0;
8683 }
8684
8685 Message msg = Message.obtain();
8686 msg.what = SHOW_ERROR_MSG;
8687 HashMap data = new HashMap();
8688 data.put("result", result);
8689 data.put("app", r);
8690 data.put("flags", flags);
8691 data.put("shortMsg", shortMsg);
8692 data.put("longMsg", longMsg);
8693 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8694 // For system processes, submit crash data to the server.
8695 data.put("crashData", crashData);
8696 }
8697 msg.obj = data;
8698 mHandler.sendMessage(msg);
8699
8700 Binder.restoreCallingIdentity(origId);
8701 }
8702
8703 int res = result.get();
8704
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008705 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008706 synchronized (this) {
8707 if (r != null) {
8708 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8709 SystemClock.uptimeMillis());
8710 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008711 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8712 appErrorIntent = createAppErrorIntentLocked(r);
8713 res = AppErrorDialog.FORCE_QUIT;
8714 }
8715 }
8716
8717 if (appErrorIntent != null) {
8718 try {
8719 mContext.startActivity(appErrorIntent);
8720 } catch (ActivityNotFoundException e) {
8721 Log.w(TAG, "bug report receiver dissappeared", e);
8722 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008723 }
8724
8725 return res;
8726 }
8727
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008728 Intent createAppErrorIntentLocked(ProcessRecord r) {
8729 ApplicationErrorReport report = createAppErrorReportLocked(r);
8730 if (report == null) {
8731 return null;
8732 }
8733 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8734 result.setComponent(r.errorReportReceiver);
8735 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8736 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8737 return result;
8738 }
8739
8740 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8741 if (r.errorReportReceiver == null) {
8742 return null;
8743 }
8744
8745 if (!r.crashing && !r.notResponding) {
8746 return null;
8747 }
8748
8749 try {
8750 ApplicationErrorReport report = new ApplicationErrorReport();
8751 report.packageName = r.info.packageName;
8752 report.installerPackageName = r.errorReportReceiver.getPackageName();
8753 report.processName = r.processName;
8754
8755 if (r.crashing) {
8756 report.type = ApplicationErrorReport.TYPE_CRASH;
8757 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8758
8759 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8760 r.crashingReport.crashData);
8761 DataInputStream dataStream = new DataInputStream(byteStream);
8762 CrashData crashData = new CrashData(dataStream);
8763 ThrowableData throwData = crashData.getThrowableData();
8764
8765 report.time = crashData.getTime();
8766 report.crashInfo.stackTrace = throwData.toString();
8767
Jacek Surazskif829a782009-06-11 22:47:02 +02008768 // Extract the source of the exception, useful for report
8769 // clustering. Also extract the "deepest" non-null exception
8770 // message.
8771 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008772 while (throwData.getCause() != null) {
8773 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008774 String msg = throwData.getMessage();
8775 if (msg != null && msg.length() > 0) {
8776 exceptionMessage = msg;
8777 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008778 }
8779 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008780 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008781 report.crashInfo.exceptionClassName = throwData.getType();
8782 report.crashInfo.throwFileName = trace.getFileName();
8783 report.crashInfo.throwClassName = trace.getClassName();
8784 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008785 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008786 } else if (r.notResponding) {
8787 report.type = ApplicationErrorReport.TYPE_ANR;
8788 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8789
8790 report.anrInfo.activity = r.notRespondingReport.tag;
8791 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8792 report.anrInfo.info = r.notRespondingReport.longMsg;
8793 }
8794
8795 return report;
8796 } catch (IOException e) {
8797 // we don't send it
8798 }
8799
8800 return null;
8801 }
8802
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008803 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8804 // assume our apps are happy - lazy create the list
8805 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8806
8807 synchronized (this) {
8808
8809 // iterate across all processes
8810 final int N = mLRUProcesses.size();
8811 for (int i = 0; i < N; i++) {
8812 ProcessRecord app = mLRUProcesses.get(i);
8813 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8814 // This one's in trouble, so we'll generate a report for it
8815 // crashes are higher priority (in case there's a crash *and* an anr)
8816 ActivityManager.ProcessErrorStateInfo report = null;
8817 if (app.crashing) {
8818 report = app.crashingReport;
8819 } else if (app.notResponding) {
8820 report = app.notRespondingReport;
8821 }
8822
8823 if (report != null) {
8824 if (errList == null) {
8825 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8826 }
8827 errList.add(report);
8828 } else {
8829 Log.w(TAG, "Missing app error report, app = " + app.processName +
8830 " crashing = " + app.crashing +
8831 " notResponding = " + app.notResponding);
8832 }
8833 }
8834 }
8835 }
8836
8837 return errList;
8838 }
8839
8840 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8841 // Lazy instantiation of list
8842 List<ActivityManager.RunningAppProcessInfo> runList = null;
8843 synchronized (this) {
8844 // Iterate across all processes
8845 final int N = mLRUProcesses.size();
8846 for (int i = 0; i < N; i++) {
8847 ProcessRecord app = mLRUProcesses.get(i);
8848 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8849 // Generate process state info for running application
8850 ActivityManager.RunningAppProcessInfo currApp =
8851 new ActivityManager.RunningAppProcessInfo(app.processName,
8852 app.pid, app.getPackageList());
8853 int adj = app.curAdj;
8854 if (adj >= CONTENT_PROVIDER_ADJ) {
8855 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8856 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8857 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008858 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8859 } else if (adj >= HOME_APP_ADJ) {
8860 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8861 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008862 } else if (adj >= SECONDARY_SERVER_ADJ) {
8863 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8864 } else if (adj >= VISIBLE_APP_ADJ) {
8865 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8866 } else {
8867 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8868 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07008869 currApp.importanceReasonCode = app.adjTypeCode;
8870 if (app.adjSource instanceof ProcessRecord) {
8871 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
8872 } else if (app.adjSource instanceof HistoryRecord) {
8873 HistoryRecord r = (HistoryRecord)app.adjSource;
8874 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
8875 }
8876 if (app.adjTarget instanceof ComponentName) {
8877 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
8878 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008879 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8880 // + " lru=" + currApp.lru);
8881 if (runList == null) {
8882 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8883 }
8884 runList.add(currApp);
8885 }
8886 }
8887 }
8888 return runList;
8889 }
8890
8891 @Override
8892 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8893 synchronized (this) {
8894 if (checkCallingPermission(android.Manifest.permission.DUMP)
8895 != PackageManager.PERMISSION_GRANTED) {
8896 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8897 + Binder.getCallingPid()
8898 + ", uid=" + Binder.getCallingUid()
8899 + " without permission "
8900 + android.Manifest.permission.DUMP);
8901 return;
8902 }
8903 if (args.length != 0 && "service".equals(args[0])) {
8904 dumpService(fd, pw, args);
8905 return;
8906 }
8907 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008908 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008909 pw.println(" ");
8910 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008911 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008912 if (mWaitingVisibleActivities.size() > 0) {
8913 pw.println(" ");
8914 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008915 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008916 }
8917 if (mStoppingActivities.size() > 0) {
8918 pw.println(" ");
8919 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008920 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008921 }
8922 if (mFinishingActivities.size() > 0) {
8923 pw.println(" ");
8924 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008925 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008926 }
8927
8928 pw.println(" ");
8929 pw.println(" mPausingActivity: " + mPausingActivity);
8930 pw.println(" mResumedActivity: " + mResumedActivity);
8931 pw.println(" mFocusedActivity: " + mFocusedActivity);
8932 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8933
8934 if (mRecentTasks.size() > 0) {
8935 pw.println(" ");
8936 pw.println("Recent tasks in Current Activity Manager State:");
8937
8938 final int N = mRecentTasks.size();
8939 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008940 TaskRecord tr = mRecentTasks.get(i);
8941 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8942 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008943 mRecentTasks.get(i).dump(pw, " ");
8944 }
8945 }
8946
8947 pw.println(" ");
8948 pw.println(" mCurTask: " + mCurTask);
8949
8950 pw.println(" ");
8951 pw.println("Processes in Current Activity Manager State:");
8952
8953 boolean needSep = false;
8954 int numPers = 0;
8955
8956 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8957 final int NA = procs.size();
8958 for (int ia=0; ia<NA; ia++) {
8959 if (!needSep) {
8960 pw.println(" All known processes:");
8961 needSep = true;
8962 }
8963 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008964 pw.print(r.persistent ? " *PERS*" : " *APP*");
8965 pw.print(" UID "); pw.print(procs.keyAt(ia));
8966 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008967 r.dump(pw, " ");
8968 if (r.persistent) {
8969 numPers++;
8970 }
8971 }
8972 }
8973
8974 if (mLRUProcesses.size() > 0) {
8975 if (needSep) pw.println(" ");
8976 needSep = true;
8977 pw.println(" Running processes (most recent first):");
8978 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008979 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008980 needSep = true;
8981 }
8982
8983 synchronized (mPidsSelfLocked) {
8984 if (mPidsSelfLocked.size() > 0) {
8985 if (needSep) pw.println(" ");
8986 needSep = true;
8987 pw.println(" PID mappings:");
8988 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008989 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8990 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008991 }
8992 }
8993 }
8994
8995 if (mForegroundProcesses.size() > 0) {
8996 if (needSep) pw.println(" ");
8997 needSep = true;
8998 pw.println(" Foreground Processes:");
8999 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009000 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9001 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009002 }
9003 }
9004
9005 if (mPersistentStartingProcesses.size() > 0) {
9006 if (needSep) pw.println(" ");
9007 needSep = true;
9008 pw.println(" Persisent processes that are starting:");
9009 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009010 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009011 }
9012
9013 if (mStartingProcesses.size() > 0) {
9014 if (needSep) pw.println(" ");
9015 needSep = true;
9016 pw.println(" Processes that are starting:");
9017 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009018 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009019 }
9020
9021 if (mRemovedProcesses.size() > 0) {
9022 if (needSep) pw.println(" ");
9023 needSep = true;
9024 pw.println(" Processes that are being removed:");
9025 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009026 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009027 }
9028
9029 if (mProcessesOnHold.size() > 0) {
9030 if (needSep) pw.println(" ");
9031 needSep = true;
9032 pw.println(" Processes that are on old until the system is ready:");
9033 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009034 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009035 }
9036
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009037 if (mProcessesToGc.size() > 0) {
9038 if (needSep) pw.println(" ");
9039 needSep = true;
9040 pw.println(" Processes that are waiting to GC:");
9041 long now = SystemClock.uptimeMillis();
9042 for (int i=0; i<mProcessesToGc.size(); i++) {
9043 ProcessRecord proc = mProcessesToGc.get(i);
9044 pw.print(" Process "); pw.println(proc);
9045 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9046 pw.print(", last gced=");
9047 pw.print(now-proc.lastRequestedGc);
9048 pw.print(" ms ago, last lowMwm=");
9049 pw.print(now-proc.lastLowMemory);
9050 pw.println(" ms ago");
9051
9052 }
9053 }
9054
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009055 if (mProcessCrashTimes.getMap().size() > 0) {
9056 if (needSep) pw.println(" ");
9057 needSep = true;
9058 pw.println(" Time since processes crashed:");
9059 long now = SystemClock.uptimeMillis();
9060 for (Map.Entry<String, SparseArray<Long>> procs
9061 : mProcessCrashTimes.getMap().entrySet()) {
9062 SparseArray<Long> uids = procs.getValue();
9063 final int N = uids.size();
9064 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009065 pw.print(" Process "); pw.print(procs.getKey());
9066 pw.print(" uid "); pw.print(uids.keyAt(i));
9067 pw.print(": last crashed ");
9068 pw.print((now-uids.valueAt(i)));
9069 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009070 }
9071 }
9072 }
9073
9074 if (mBadProcesses.getMap().size() > 0) {
9075 if (needSep) pw.println(" ");
9076 needSep = true;
9077 pw.println(" Bad processes:");
9078 for (Map.Entry<String, SparseArray<Long>> procs
9079 : mBadProcesses.getMap().entrySet()) {
9080 SparseArray<Long> uids = procs.getValue();
9081 final int N = uids.size();
9082 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009083 pw.print(" Bad process "); pw.print(procs.getKey());
9084 pw.print(" uid "); pw.print(uids.keyAt(i));
9085 pw.print(": crashed at time ");
9086 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009087 }
9088 }
9089 }
9090
9091 pw.println(" ");
9092 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009093 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009094 pw.println(" mConfiguration: " + mConfiguration);
9095 pw.println(" mStartRunning=" + mStartRunning
9096 + " mSystemReady=" + mSystemReady
9097 + " mBooting=" + mBooting
9098 + " mBooted=" + mBooted
9099 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009100 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009101 pw.println(" mGoingToSleep=" + mGoingToSleep);
9102 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9103 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9104 + " mDebugTransient=" + mDebugTransient
9105 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9106 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009107 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009108 }
9109 }
9110
9111 /**
9112 * There are three ways to call this:
9113 * - no service specified: dump all the services
9114 * - a flattened component name that matched an existing service was specified as the
9115 * first arg: dump that one service
9116 * - the first arg isn't the flattened component name of an existing service:
9117 * dump all services whose component contains the first arg as a substring
9118 */
9119 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9120 String[] newArgs;
9121 String componentNameString;
9122 ServiceRecord r;
9123 if (args.length == 1) {
9124 componentNameString = null;
9125 newArgs = EMPTY_STRING_ARRAY;
9126 r = null;
9127 } else {
9128 componentNameString = args[1];
9129 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9130 r = componentName != null ? mServices.get(componentName) : null;
9131 newArgs = new String[args.length - 2];
9132 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9133 }
9134
9135 if (r != null) {
9136 dumpService(fd, pw, r, newArgs);
9137 } else {
9138 for (ServiceRecord r1 : mServices.values()) {
9139 if (componentNameString == null
9140 || r1.name.flattenToString().contains(componentNameString)) {
9141 dumpService(fd, pw, r1, newArgs);
9142 }
9143 }
9144 }
9145 }
9146
9147 /**
9148 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9149 * there is a thread associated with the service.
9150 */
9151 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9152 pw.println(" Service " + r.name.flattenToString());
9153 if (r.app != null && r.app.thread != null) {
9154 try {
9155 // flush anything that is already in the PrintWriter since the thread is going
9156 // to write to the file descriptor directly
9157 pw.flush();
9158 r.app.thread.dumpService(fd, r, args);
9159 pw.print("\n");
9160 } catch (RemoteException e) {
9161 pw.println("got a RemoteException while dumping the service");
9162 }
9163 }
9164 }
9165
9166 void dumpBroadcasts(PrintWriter pw) {
9167 synchronized (this) {
9168 if (checkCallingPermission(android.Manifest.permission.DUMP)
9169 != PackageManager.PERMISSION_GRANTED) {
9170 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9171 + Binder.getCallingPid()
9172 + ", uid=" + Binder.getCallingUid()
9173 + " without permission "
9174 + android.Manifest.permission.DUMP);
9175 return;
9176 }
9177 pw.println("Broadcasts in Current Activity Manager State:");
9178
9179 if (mRegisteredReceivers.size() > 0) {
9180 pw.println(" ");
9181 pw.println(" Registered Receivers:");
9182 Iterator it = mRegisteredReceivers.values().iterator();
9183 while (it.hasNext()) {
9184 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009185 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009186 r.dump(pw, " ");
9187 }
9188 }
9189
9190 pw.println(" ");
9191 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009192 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009193
9194 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9195 || mPendingBroadcast != null) {
9196 if (mParallelBroadcasts.size() > 0) {
9197 pw.println(" ");
9198 pw.println(" Active broadcasts:");
9199 }
9200 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9201 pw.println(" Broadcast #" + i + ":");
9202 mParallelBroadcasts.get(i).dump(pw, " ");
9203 }
9204 if (mOrderedBroadcasts.size() > 0) {
9205 pw.println(" ");
9206 pw.println(" Active serialized broadcasts:");
9207 }
9208 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9209 pw.println(" Serialized Broadcast #" + i + ":");
9210 mOrderedBroadcasts.get(i).dump(pw, " ");
9211 }
9212 pw.println(" ");
9213 pw.println(" Pending broadcast:");
9214 if (mPendingBroadcast != null) {
9215 mPendingBroadcast.dump(pw, " ");
9216 } else {
9217 pw.println(" (null)");
9218 }
9219 }
9220
9221 pw.println(" ");
9222 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9223 if (mStickyBroadcasts != null) {
9224 pw.println(" ");
9225 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009226 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009227 for (Map.Entry<String, ArrayList<Intent>> ent
9228 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009229 pw.print(" * Sticky action "); pw.print(ent.getKey());
9230 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009231 ArrayList<Intent> intents = ent.getValue();
9232 final int N = intents.size();
9233 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009234 sb.setLength(0);
9235 sb.append(" Intent: ");
9236 intents.get(i).toShortString(sb, true, false);
9237 pw.println(sb.toString());
9238 Bundle bundle = intents.get(i).getExtras();
9239 if (bundle != null) {
9240 pw.print(" ");
9241 pw.println(bundle.toString());
9242 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009243 }
9244 }
9245 }
9246
9247 pw.println(" ");
9248 pw.println(" mHandler:");
9249 mHandler.dump(new PrintWriterPrinter(pw), " ");
9250 }
9251 }
9252
9253 void dumpServices(PrintWriter pw) {
9254 synchronized (this) {
9255 if (checkCallingPermission(android.Manifest.permission.DUMP)
9256 != PackageManager.PERMISSION_GRANTED) {
9257 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9258 + Binder.getCallingPid()
9259 + ", uid=" + Binder.getCallingUid()
9260 + " without permission "
9261 + android.Manifest.permission.DUMP);
9262 return;
9263 }
9264 pw.println("Services in Current Activity Manager State:");
9265
9266 boolean needSep = false;
9267
9268 if (mServices.size() > 0) {
9269 pw.println(" Active services:");
9270 Iterator<ServiceRecord> it = mServices.values().iterator();
9271 while (it.hasNext()) {
9272 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009273 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009274 r.dump(pw, " ");
9275 }
9276 needSep = true;
9277 }
9278
9279 if (mPendingServices.size() > 0) {
9280 if (needSep) pw.println(" ");
9281 pw.println(" Pending services:");
9282 for (int i=0; i<mPendingServices.size(); i++) {
9283 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009284 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009285 r.dump(pw, " ");
9286 }
9287 needSep = true;
9288 }
9289
9290 if (mRestartingServices.size() > 0) {
9291 if (needSep) pw.println(" ");
9292 pw.println(" Restarting services:");
9293 for (int i=0; i<mRestartingServices.size(); i++) {
9294 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009295 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009296 r.dump(pw, " ");
9297 }
9298 needSep = true;
9299 }
9300
9301 if (mStoppingServices.size() > 0) {
9302 if (needSep) pw.println(" ");
9303 pw.println(" Stopping services:");
9304 for (int i=0; i<mStoppingServices.size(); i++) {
9305 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009306 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009307 r.dump(pw, " ");
9308 }
9309 needSep = true;
9310 }
9311
9312 if (mServiceConnections.size() > 0) {
9313 if (needSep) pw.println(" ");
9314 pw.println(" Connection bindings to services:");
9315 Iterator<ConnectionRecord> it
9316 = mServiceConnections.values().iterator();
9317 while (it.hasNext()) {
9318 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009319 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009320 r.dump(pw, " ");
9321 }
9322 }
9323 }
9324 }
9325
9326 void dumpProviders(PrintWriter pw) {
9327 synchronized (this) {
9328 if (checkCallingPermission(android.Manifest.permission.DUMP)
9329 != PackageManager.PERMISSION_GRANTED) {
9330 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9331 + Binder.getCallingPid()
9332 + ", uid=" + Binder.getCallingUid()
9333 + " without permission "
9334 + android.Manifest.permission.DUMP);
9335 return;
9336 }
9337
9338 pw.println("Content Providers in Current Activity Manager State:");
9339
9340 boolean needSep = false;
9341
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009342 if (mProvidersByClass.size() > 0) {
9343 if (needSep) pw.println(" ");
9344 pw.println(" Published content providers (by class):");
9345 Iterator it = mProvidersByClass.entrySet().iterator();
9346 while (it.hasNext()) {
9347 Map.Entry e = (Map.Entry)it.next();
9348 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009349 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009350 r.dump(pw, " ");
9351 }
9352 needSep = true;
9353 }
9354
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009355 if (mProvidersByName.size() > 0) {
9356 pw.println(" ");
9357 pw.println(" Authority to provider mappings:");
9358 Iterator it = mProvidersByName.entrySet().iterator();
9359 while (it.hasNext()) {
9360 Map.Entry e = (Map.Entry)it.next();
9361 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9362 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9363 pw.println(r);
9364 }
9365 needSep = true;
9366 }
9367
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009368 if (mLaunchingProviders.size() > 0) {
9369 if (needSep) pw.println(" ");
9370 pw.println(" Launching content providers:");
9371 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009372 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9373 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009374 }
9375 needSep = true;
9376 }
9377
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009378 if (mGrantedUriPermissions.size() > 0) {
9379 pw.println();
9380 pw.println("Granted Uri Permissions:");
9381 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9382 int uid = mGrantedUriPermissions.keyAt(i);
9383 HashMap<Uri, UriPermission> perms
9384 = mGrantedUriPermissions.valueAt(i);
9385 pw.print(" * UID "); pw.print(uid);
9386 pw.println(" holds:");
9387 for (UriPermission perm : perms.values()) {
9388 pw.print(" "); pw.println(perm);
9389 perm.dump(pw, " ");
9390 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009391 }
9392 }
9393 }
9394 }
9395
9396 void dumpSenders(PrintWriter pw) {
9397 synchronized (this) {
9398 if (checkCallingPermission(android.Manifest.permission.DUMP)
9399 != PackageManager.PERMISSION_GRANTED) {
9400 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9401 + Binder.getCallingPid()
9402 + ", uid=" + Binder.getCallingUid()
9403 + " without permission "
9404 + android.Manifest.permission.DUMP);
9405 return;
9406 }
9407
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009408 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009409
9410 if (this.mIntentSenderRecords.size() > 0) {
9411 Iterator<WeakReference<PendingIntentRecord>> it
9412 = mIntentSenderRecords.values().iterator();
9413 while (it.hasNext()) {
9414 WeakReference<PendingIntentRecord> ref = it.next();
9415 PendingIntentRecord rec = ref != null ? ref.get(): null;
9416 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009417 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009418 rec.dump(pw, " ");
9419 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009420 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009421 }
9422 }
9423 }
9424 }
9425 }
9426
9427 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009428 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009429 TaskRecord lastTask = null;
9430 for (int i=list.size()-1; i>=0; i--) {
9431 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009432 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009433 if (lastTask != r.task) {
9434 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009435 pw.print(prefix);
9436 pw.print(full ? "* " : " ");
9437 pw.println(lastTask);
9438 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009439 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009440 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009441 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009442 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9443 pw.print(" #"); pw.print(i); pw.print(": ");
9444 pw.println(r);
9445 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009446 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009447 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009448 }
9449 }
9450
9451 private static final int dumpProcessList(PrintWriter pw, List list,
9452 String prefix, String normalLabel, String persistentLabel,
9453 boolean inclOomAdj) {
9454 int numPers = 0;
9455 for (int i=list.size()-1; i>=0; i--) {
9456 ProcessRecord r = (ProcessRecord)list.get(i);
9457 if (false) {
9458 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9459 + " #" + i + ":");
9460 r.dump(pw, prefix + " ");
9461 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009462 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009463 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009464 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9465 if (r.adjSource != null || r.adjTarget != null) {
9466 pw.println(prefix + " " + r.adjTarget
9467 + " used by " + r.adjSource);
9468 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009469 } else {
9470 pw.println(String.format("%s%s #%2d: %s",
9471 prefix, (r.persistent ? persistentLabel : normalLabel),
9472 i, r.toString()));
9473 }
9474 if (r.persistent) {
9475 numPers++;
9476 }
9477 }
9478 return numPers;
9479 }
9480
9481 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9482 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009483 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009484 long uptime = SystemClock.uptimeMillis();
9485 long realtime = SystemClock.elapsedRealtime();
9486
9487 if (isCheckinRequest) {
9488 // short checkin version
9489 pw.println(uptime + "," + realtime);
9490 pw.flush();
9491 } else {
9492 pw.println("Applications Memory Usage (kB):");
9493 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9494 }
9495 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9496 ProcessRecord r = (ProcessRecord)list.get(i);
9497 if (r.thread != null) {
9498 if (!isCheckinRequest) {
9499 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9500 pw.flush();
9501 }
9502 try {
9503 r.thread.asBinder().dump(fd, args);
9504 } catch (RemoteException e) {
9505 if (!isCheckinRequest) {
9506 pw.println("Got RemoteException!");
9507 pw.flush();
9508 }
9509 }
9510 }
9511 }
9512 }
9513
9514 /**
9515 * Searches array of arguments for the specified string
9516 * @param args array of argument strings
9517 * @param value value to search for
9518 * @return true if the value is contained in the array
9519 */
9520 private static boolean scanArgs(String[] args, String value) {
9521 if (args != null) {
9522 for (String arg : args) {
9523 if (value.equals(arg)) {
9524 return true;
9525 }
9526 }
9527 }
9528 return false;
9529 }
9530
Dianne Hackborn75b03852009-06-12 15:43:26 -07009531 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009532 int count = mHistory.size();
9533
9534 // convert the token to an entry in the history.
9535 HistoryRecord r = null;
9536 int index = -1;
9537 for (int i=count-1; i>=0; i--) {
9538 Object o = mHistory.get(i);
9539 if (o == token) {
9540 r = (HistoryRecord)o;
9541 index = i;
9542 break;
9543 }
9544 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009545
9546 return index;
9547 }
9548
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009549 private final void killServicesLocked(ProcessRecord app,
9550 boolean allowRestart) {
9551 // Report disconnected services.
9552 if (false) {
9553 // XXX we are letting the client link to the service for
9554 // death notifications.
9555 if (app.services.size() > 0) {
9556 Iterator it = app.services.iterator();
9557 while (it.hasNext()) {
9558 ServiceRecord r = (ServiceRecord)it.next();
9559 if (r.connections.size() > 0) {
9560 Iterator<ConnectionRecord> jt
9561 = r.connections.values().iterator();
9562 while (jt.hasNext()) {
9563 ConnectionRecord c = jt.next();
9564 if (c.binding.client != app) {
9565 try {
9566 //c.conn.connected(r.className, null);
9567 } catch (Exception e) {
9568 // todo: this should be asynchronous!
9569 Log.w(TAG, "Exception thrown disconnected servce "
9570 + r.shortName
9571 + " from app " + app.processName, e);
9572 }
9573 }
9574 }
9575 }
9576 }
9577 }
9578 }
9579
9580 // Clean up any connections this application has to other services.
9581 if (app.connections.size() > 0) {
9582 Iterator<ConnectionRecord> it = app.connections.iterator();
9583 while (it.hasNext()) {
9584 ConnectionRecord r = it.next();
9585 removeConnectionLocked(r, app, null);
9586 }
9587 }
9588 app.connections.clear();
9589
9590 if (app.services.size() != 0) {
9591 // Any services running in the application need to be placed
9592 // back in the pending list.
9593 Iterator it = app.services.iterator();
9594 while (it.hasNext()) {
9595 ServiceRecord sr = (ServiceRecord)it.next();
9596 synchronized (sr.stats.getBatteryStats()) {
9597 sr.stats.stopLaunchedLocked();
9598 }
9599 sr.app = null;
9600 sr.executeNesting = 0;
9601 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009602
9603 boolean hasClients = sr.bindings.size() > 0;
9604 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009605 Iterator<IntentBindRecord> bindings
9606 = sr.bindings.values().iterator();
9607 while (bindings.hasNext()) {
9608 IntentBindRecord b = bindings.next();
9609 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9610 + ": shouldUnbind=" + b.hasBound);
9611 b.binder = null;
9612 b.requested = b.received = b.hasBound = false;
9613 }
9614 }
9615
9616 if (sr.crashCount >= 2) {
9617 Log.w(TAG, "Service crashed " + sr.crashCount
9618 + " times, stopping: " + sr);
9619 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9620 sr.crashCount, sr.shortName, app.pid);
9621 bringDownServiceLocked(sr, true);
9622 } else if (!allowRestart) {
9623 bringDownServiceLocked(sr, true);
9624 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009625 boolean canceled = scheduleServiceRestartLocked(sr, true);
9626
9627 // Should the service remain running? Note that in the
9628 // extreme case of so many attempts to deliver a command
9629 // that it failed, that we also will stop it here.
9630 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9631 if (sr.pendingStarts.size() == 0) {
9632 sr.startRequested = false;
9633 if (!hasClients) {
9634 // Whoops, no reason to restart!
9635 bringDownServiceLocked(sr, true);
9636 }
9637 }
9638 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009639 }
9640 }
9641
9642 if (!allowRestart) {
9643 app.services.clear();
9644 }
9645 }
9646
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009647 // Make sure we have no more records on the stopping list.
9648 int i = mStoppingServices.size();
9649 while (i > 0) {
9650 i--;
9651 ServiceRecord sr = mStoppingServices.get(i);
9652 if (sr.app == app) {
9653 mStoppingServices.remove(i);
9654 }
9655 }
9656
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009657 app.executingServices.clear();
9658 }
9659
9660 private final void removeDyingProviderLocked(ProcessRecord proc,
9661 ContentProviderRecord cpr) {
9662 synchronized (cpr) {
9663 cpr.launchingApp = null;
9664 cpr.notifyAll();
9665 }
9666
9667 mProvidersByClass.remove(cpr.info.name);
9668 String names[] = cpr.info.authority.split(";");
9669 for (int j = 0; j < names.length; j++) {
9670 mProvidersByName.remove(names[j]);
9671 }
9672
9673 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9674 while (cit.hasNext()) {
9675 ProcessRecord capp = cit.next();
9676 if (!capp.persistent && capp.thread != null
9677 && capp.pid != 0
9678 && capp.pid != MY_PID) {
9679 Log.i(TAG, "Killing app " + capp.processName
9680 + " (pid " + capp.pid
9681 + ") because provider " + cpr.info.name
9682 + " is in dying process " + proc.processName);
9683 Process.killProcess(capp.pid);
9684 }
9685 }
9686
9687 mLaunchingProviders.remove(cpr);
9688 }
9689
9690 /**
9691 * Main code for cleaning up a process when it has gone away. This is
9692 * called both as a result of the process dying, or directly when stopping
9693 * a process when running in single process mode.
9694 */
9695 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9696 boolean restarting, int index) {
9697 if (index >= 0) {
9698 mLRUProcesses.remove(index);
9699 }
9700
9701 // Dismiss any open dialogs.
9702 if (app.crashDialog != null) {
9703 app.crashDialog.dismiss();
9704 app.crashDialog = null;
9705 }
9706 if (app.anrDialog != null) {
9707 app.anrDialog.dismiss();
9708 app.anrDialog = null;
9709 }
9710 if (app.waitDialog != null) {
9711 app.waitDialog.dismiss();
9712 app.waitDialog = null;
9713 }
9714
9715 app.crashing = false;
9716 app.notResponding = false;
9717
9718 app.resetPackageList();
9719 app.thread = null;
9720 app.forcingToForeground = null;
9721 app.foregroundServices = false;
9722
9723 killServicesLocked(app, true);
9724
9725 boolean restart = false;
9726
9727 int NL = mLaunchingProviders.size();
9728
9729 // Remove published content providers.
9730 if (!app.pubProviders.isEmpty()) {
9731 Iterator it = app.pubProviders.values().iterator();
9732 while (it.hasNext()) {
9733 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9734 cpr.provider = null;
9735 cpr.app = null;
9736
9737 // See if someone is waiting for this provider... in which
9738 // case we don't remove it, but just let it restart.
9739 int i = 0;
9740 if (!app.bad) {
9741 for (; i<NL; i++) {
9742 if (mLaunchingProviders.get(i) == cpr) {
9743 restart = true;
9744 break;
9745 }
9746 }
9747 } else {
9748 i = NL;
9749 }
9750
9751 if (i >= NL) {
9752 removeDyingProviderLocked(app, cpr);
9753 NL = mLaunchingProviders.size();
9754 }
9755 }
9756 app.pubProviders.clear();
9757 }
9758
9759 // Look through the content providers we are waiting to have launched,
9760 // and if any run in this process then either schedule a restart of
9761 // the process or kill the client waiting for it if this process has
9762 // gone bad.
9763 for (int i=0; i<NL; i++) {
9764 ContentProviderRecord cpr = (ContentProviderRecord)
9765 mLaunchingProviders.get(i);
9766 if (cpr.launchingApp == app) {
9767 if (!app.bad) {
9768 restart = true;
9769 } else {
9770 removeDyingProviderLocked(app, cpr);
9771 NL = mLaunchingProviders.size();
9772 }
9773 }
9774 }
9775
9776 // Unregister from connected content providers.
9777 if (!app.conProviders.isEmpty()) {
9778 Iterator it = app.conProviders.iterator();
9779 while (it.hasNext()) {
9780 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9781 cpr.clients.remove(app);
9782 }
9783 app.conProviders.clear();
9784 }
9785
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009786 // At this point there may be remaining entries in mLaunchingProviders
9787 // where we were the only one waiting, so they are no longer of use.
9788 // Look for these and clean up if found.
9789 // XXX Commented out for now. Trying to figure out a way to reproduce
9790 // the actual situation to identify what is actually going on.
9791 if (false) {
9792 for (int i=0; i<NL; i++) {
9793 ContentProviderRecord cpr = (ContentProviderRecord)
9794 mLaunchingProviders.get(i);
9795 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9796 synchronized (cpr) {
9797 cpr.launchingApp = null;
9798 cpr.notifyAll();
9799 }
9800 }
9801 }
9802 }
9803
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009804 skipCurrentReceiverLocked(app);
9805
9806 // Unregister any receivers.
9807 if (app.receivers.size() > 0) {
9808 Iterator<ReceiverList> it = app.receivers.iterator();
9809 while (it.hasNext()) {
9810 removeReceiverLocked(it.next());
9811 }
9812 app.receivers.clear();
9813 }
9814
Christopher Tate181fafa2009-05-14 11:12:14 -07009815 // If the app is undergoing backup, tell the backup manager about it
9816 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9817 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9818 try {
9819 IBackupManager bm = IBackupManager.Stub.asInterface(
9820 ServiceManager.getService(Context.BACKUP_SERVICE));
9821 bm.agentDisconnected(app.info.packageName);
9822 } catch (RemoteException e) {
9823 // can't happen; backup manager is local
9824 }
9825 }
9826
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009827 // If the caller is restarting this app, then leave it in its
9828 // current lists and let the caller take care of it.
9829 if (restarting) {
9830 return;
9831 }
9832
9833 if (!app.persistent) {
9834 if (DEBUG_PROCESSES) Log.v(TAG,
9835 "Removing non-persistent process during cleanup: " + app);
9836 mProcessNames.remove(app.processName, app.info.uid);
9837 } else if (!app.removed) {
9838 // This app is persistent, so we need to keep its record around.
9839 // If it is not already on the pending app list, add it there
9840 // and start a new process for it.
9841 app.thread = null;
9842 app.forcingToForeground = null;
9843 app.foregroundServices = false;
9844 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9845 mPersistentStartingProcesses.add(app);
9846 restart = true;
9847 }
9848 }
9849 mProcessesOnHold.remove(app);
9850
The Android Open Source Project4df24232009-03-05 14:34:35 -08009851 if (app == mHomeProcess) {
9852 mHomeProcess = null;
9853 }
9854
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009855 if (restart) {
9856 // We have components that still need to be running in the
9857 // process, so re-launch it.
9858 mProcessNames.put(app.processName, app.info.uid, app);
9859 startProcessLocked(app, "restart", app.processName);
9860 } else if (app.pid > 0 && app.pid != MY_PID) {
9861 // Goodbye!
9862 synchronized (mPidsSelfLocked) {
9863 mPidsSelfLocked.remove(app.pid);
9864 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9865 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009866 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009867 }
9868 }
9869
9870 // =========================================================
9871 // SERVICES
9872 // =========================================================
9873
9874 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9875 ActivityManager.RunningServiceInfo info =
9876 new ActivityManager.RunningServiceInfo();
9877 info.service = r.name;
9878 if (r.app != null) {
9879 info.pid = r.app.pid;
9880 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -07009881 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009882 info.process = r.processName;
9883 info.foreground = r.isForeground;
9884 info.activeSince = r.createTime;
9885 info.started = r.startRequested;
9886 info.clientCount = r.connections.size();
9887 info.crashCount = r.crashCount;
9888 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07009889 if (r.isForeground) {
9890 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
9891 }
9892 if (r.startRequested) {
9893 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
9894 }
9895 if (r.app != null && r.app.pid == Process.myPid()) {
9896 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
9897 }
9898 if (r.app != null && r.app.persistent) {
9899 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
9900 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009901 for (ConnectionRecord conn : r.connections.values()) {
9902 if (conn.clientLabel != 0) {
9903 info.clientPackage = conn.binding.client.info.packageName;
9904 info.clientLabel = conn.clientLabel;
9905 break;
9906 }
9907 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009908 return info;
9909 }
9910
9911 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9912 int flags) {
9913 synchronized (this) {
9914 ArrayList<ActivityManager.RunningServiceInfo> res
9915 = new ArrayList<ActivityManager.RunningServiceInfo>();
9916
9917 if (mServices.size() > 0) {
9918 Iterator<ServiceRecord> it = mServices.values().iterator();
9919 while (it.hasNext() && res.size() < maxNum) {
9920 res.add(makeRunningServiceInfoLocked(it.next()));
9921 }
9922 }
9923
9924 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9925 ServiceRecord r = mRestartingServices.get(i);
9926 ActivityManager.RunningServiceInfo info =
9927 makeRunningServiceInfoLocked(r);
9928 info.restarting = r.nextRestartTime;
9929 res.add(info);
9930 }
9931
9932 return res;
9933 }
9934 }
9935
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009936 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
9937 synchronized (this) {
9938 ServiceRecord r = mServices.get(name);
9939 if (r != null) {
9940 for (ConnectionRecord conn : r.connections.values()) {
9941 if (conn.clientIntent != null) {
9942 return conn.clientIntent;
9943 }
9944 }
9945 }
9946 }
9947 return null;
9948 }
9949
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009950 private final ServiceRecord findServiceLocked(ComponentName name,
9951 IBinder token) {
9952 ServiceRecord r = mServices.get(name);
9953 return r == token ? r : null;
9954 }
9955
9956 private final class ServiceLookupResult {
9957 final ServiceRecord record;
9958 final String permission;
9959
9960 ServiceLookupResult(ServiceRecord _record, String _permission) {
9961 record = _record;
9962 permission = _permission;
9963 }
9964 };
9965
9966 private ServiceLookupResult findServiceLocked(Intent service,
9967 String resolvedType) {
9968 ServiceRecord r = null;
9969 if (service.getComponent() != null) {
9970 r = mServices.get(service.getComponent());
9971 }
9972 if (r == null) {
9973 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9974 r = mServicesByIntent.get(filter);
9975 }
9976
9977 if (r == null) {
9978 try {
9979 ResolveInfo rInfo =
9980 ActivityThread.getPackageManager().resolveService(
9981 service, resolvedType, 0);
9982 ServiceInfo sInfo =
9983 rInfo != null ? rInfo.serviceInfo : null;
9984 if (sInfo == null) {
9985 return null;
9986 }
9987
9988 ComponentName name = new ComponentName(
9989 sInfo.applicationInfo.packageName, sInfo.name);
9990 r = mServices.get(name);
9991 } catch (RemoteException ex) {
9992 // pm is in same process, this will never happen.
9993 }
9994 }
9995 if (r != null) {
9996 int callingPid = Binder.getCallingPid();
9997 int callingUid = Binder.getCallingUid();
9998 if (checkComponentPermission(r.permission,
9999 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10000 != PackageManager.PERMISSION_GRANTED) {
10001 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10002 + " from pid=" + callingPid
10003 + ", uid=" + callingUid
10004 + " requires " + r.permission);
10005 return new ServiceLookupResult(null, r.permission);
10006 }
10007 return new ServiceLookupResult(r, null);
10008 }
10009 return null;
10010 }
10011
10012 private class ServiceRestarter implements Runnable {
10013 private ServiceRecord mService;
10014
10015 void setService(ServiceRecord service) {
10016 mService = service;
10017 }
10018
10019 public void run() {
10020 synchronized(ActivityManagerService.this) {
10021 performServiceRestartLocked(mService);
10022 }
10023 }
10024 }
10025
10026 private ServiceLookupResult retrieveServiceLocked(Intent service,
10027 String resolvedType, int callingPid, int callingUid) {
10028 ServiceRecord r = null;
10029 if (service.getComponent() != null) {
10030 r = mServices.get(service.getComponent());
10031 }
10032 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10033 r = mServicesByIntent.get(filter);
10034 if (r == null) {
10035 try {
10036 ResolveInfo rInfo =
10037 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010038 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010039 ServiceInfo sInfo =
10040 rInfo != null ? rInfo.serviceInfo : null;
10041 if (sInfo == null) {
10042 Log.w(TAG, "Unable to start service " + service +
10043 ": not found");
10044 return null;
10045 }
10046
10047 ComponentName name = new ComponentName(
10048 sInfo.applicationInfo.packageName, sInfo.name);
10049 r = mServices.get(name);
10050 if (r == null) {
10051 filter = new Intent.FilterComparison(service.cloneFilter());
10052 ServiceRestarter res = new ServiceRestarter();
10053 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10054 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10055 synchronized (stats) {
10056 ss = stats.getServiceStatsLocked(
10057 sInfo.applicationInfo.uid, sInfo.packageName,
10058 sInfo.name);
10059 }
10060 r = new ServiceRecord(ss, name, filter, sInfo, res);
10061 res.setService(r);
10062 mServices.put(name, r);
10063 mServicesByIntent.put(filter, r);
10064
10065 // Make sure this component isn't in the pending list.
10066 int N = mPendingServices.size();
10067 for (int i=0; i<N; i++) {
10068 ServiceRecord pr = mPendingServices.get(i);
10069 if (pr.name.equals(name)) {
10070 mPendingServices.remove(i);
10071 i--;
10072 N--;
10073 }
10074 }
10075 }
10076 } catch (RemoteException ex) {
10077 // pm is in same process, this will never happen.
10078 }
10079 }
10080 if (r != null) {
10081 if (checkComponentPermission(r.permission,
10082 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10083 != PackageManager.PERMISSION_GRANTED) {
10084 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10085 + " from pid=" + Binder.getCallingPid()
10086 + ", uid=" + Binder.getCallingUid()
10087 + " requires " + r.permission);
10088 return new ServiceLookupResult(null, r.permission);
10089 }
10090 return new ServiceLookupResult(r, null);
10091 }
10092 return null;
10093 }
10094
10095 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10096 long now = SystemClock.uptimeMillis();
10097 if (r.executeNesting == 0 && r.app != null) {
10098 if (r.app.executingServices.size() == 0) {
10099 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10100 msg.obj = r.app;
10101 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10102 }
10103 r.app.executingServices.add(r);
10104 }
10105 r.executeNesting++;
10106 r.executingStart = now;
10107 }
10108
10109 private final void sendServiceArgsLocked(ServiceRecord r,
10110 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010111 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010112 if (N == 0) {
10113 return;
10114 }
10115
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010116 int i = 0;
10117 while (i < N) {
10118 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010119 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010120 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010121 + r.name + " " + r.intent + " args=" + si.intent);
10122 if (si.intent == null && N > 0) {
10123 // If somehow we got a dummy start at the front, then
10124 // just drop it here.
10125 i++;
10126 continue;
10127 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010128 bumpServiceExecutingLocked(r);
10129 if (!oomAdjusted) {
10130 oomAdjusted = true;
10131 updateOomAdjLocked(r.app);
10132 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010133 int flags = 0;
10134 if (si.deliveryCount > 0) {
10135 flags |= Service.START_FLAG_RETRY;
10136 }
10137 if (si.doneExecutingCount > 0) {
10138 flags |= Service.START_FLAG_REDELIVERY;
10139 }
10140 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10141 si.deliveredTime = SystemClock.uptimeMillis();
10142 r.deliveredStarts.add(si);
10143 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010144 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010145 } catch (RemoteException e) {
10146 // Remote process gone... we'll let the normal cleanup take
10147 // care of this.
10148 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010149 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010150 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010151 break;
10152 }
10153 }
10154 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010155 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010156 } else {
10157 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010158 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010159 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010160 }
10161 }
10162 }
10163
10164 private final boolean requestServiceBindingLocked(ServiceRecord r,
10165 IntentBindRecord i, boolean rebind) {
10166 if (r.app == null || r.app.thread == null) {
10167 // If service is not currently running, can't yet bind.
10168 return false;
10169 }
10170 if ((!i.requested || rebind) && i.apps.size() > 0) {
10171 try {
10172 bumpServiceExecutingLocked(r);
10173 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10174 + ": shouldUnbind=" + i.hasBound);
10175 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10176 if (!rebind) {
10177 i.requested = true;
10178 }
10179 i.hasBound = true;
10180 i.doRebind = false;
10181 } catch (RemoteException e) {
10182 return false;
10183 }
10184 }
10185 return true;
10186 }
10187
10188 private final void requestServiceBindingsLocked(ServiceRecord r) {
10189 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10190 while (bindings.hasNext()) {
10191 IntentBindRecord i = bindings.next();
10192 if (!requestServiceBindingLocked(r, i, false)) {
10193 break;
10194 }
10195 }
10196 }
10197
10198 private final void realStartServiceLocked(ServiceRecord r,
10199 ProcessRecord app) throws RemoteException {
10200 if (app.thread == null) {
10201 throw new RemoteException();
10202 }
10203
10204 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010205 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010206
10207 app.services.add(r);
10208 bumpServiceExecutingLocked(r);
10209 updateLRUListLocked(app, true);
10210
10211 boolean created = false;
10212 try {
10213 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10214 + r.name + " " + r.intent);
10215 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
10216 System.identityHashCode(r), r.shortName,
10217 r.intent.getIntent().toString(), r.app.pid);
10218 synchronized (r.stats.getBatteryStats()) {
10219 r.stats.startLaunchedLocked();
10220 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010221 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010222 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010223 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010224 created = true;
10225 } finally {
10226 if (!created) {
10227 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010228 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010229 }
10230 }
10231
10232 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010233
10234 // If the service is in the started state, and there are no
10235 // pending arguments, then fake up one so its onStartCommand() will
10236 // be called.
10237 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10238 r.lastStartId++;
10239 if (r.lastStartId < 1) {
10240 r.lastStartId = 1;
10241 }
10242 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10243 }
10244
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010245 sendServiceArgsLocked(r, true);
10246 }
10247
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010248 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10249 boolean allowCancel) {
10250 boolean canceled = false;
10251
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010252 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010253 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010254 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010255
10256 // Any delivered but not yet finished starts should be put back
10257 // on the pending list.
10258 final int N = r.deliveredStarts.size();
10259 if (N > 0) {
10260 for (int i=N-1; i>=0; i--) {
10261 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10262 if (si.intent == null) {
10263 // We'll generate this again if needed.
10264 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10265 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10266 r.pendingStarts.add(0, si);
10267 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10268 dur *= 2;
10269 if (minDuration < dur) minDuration = dur;
10270 if (resetTime < dur) resetTime = dur;
10271 } else {
10272 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10273 + r.name);
10274 canceled = true;
10275 }
10276 }
10277 r.deliveredStarts.clear();
10278 }
10279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010280 r.totalRestartCount++;
10281 if (r.restartDelay == 0) {
10282 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010283 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010284 } else {
10285 // If it has been a "reasonably long time" since the service
10286 // was started, then reset our restart duration back to
10287 // the beginning, so we don't infinitely increase the duration
10288 // on a service that just occasionally gets killed (which is
10289 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010290 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010291 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010292 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010293 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010294 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010295 if (r.restartDelay < minDuration) {
10296 r.restartDelay = minDuration;
10297 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010298 }
10299 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010300
10301 r.nextRestartTime = now + r.restartDelay;
10302
10303 // Make sure that we don't end up restarting a bunch of services
10304 // all at the same time.
10305 boolean repeat;
10306 do {
10307 repeat = false;
10308 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10309 ServiceRecord r2 = mRestartingServices.get(i);
10310 if (r2 != r && r.nextRestartTime
10311 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10312 && r.nextRestartTime
10313 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10314 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10315 r.restartDelay = r.nextRestartTime - now;
10316 repeat = true;
10317 break;
10318 }
10319 }
10320 } while (repeat);
10321
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010322 if (!mRestartingServices.contains(r)) {
10323 mRestartingServices.add(r);
10324 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010325
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010326 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010327
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010328 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010329 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010330 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10331 Log.w(TAG, "Scheduling restart of crashed service "
10332 + r.shortName + " in " + r.restartDelay + "ms");
10333 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10334 r.shortName, r.restartDelay);
10335
10336 Message msg = Message.obtain();
10337 msg.what = SERVICE_ERROR_MSG;
10338 msg.obj = r;
10339 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010340
10341 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010342 }
10343
10344 final void performServiceRestartLocked(ServiceRecord r) {
10345 if (!mRestartingServices.contains(r)) {
10346 return;
10347 }
10348 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10349 }
10350
10351 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10352 if (r.restartDelay == 0) {
10353 return false;
10354 }
10355 r.resetRestartCounter();
10356 mRestartingServices.remove(r);
10357 mHandler.removeCallbacks(r.restarter);
10358 return true;
10359 }
10360
10361 private final boolean bringUpServiceLocked(ServiceRecord r,
10362 int intentFlags, boolean whileRestarting) {
10363 //Log.i(TAG, "Bring up service:");
10364 //r.dump(" ");
10365
10366 if (r.app != null) {
10367 sendServiceArgsLocked(r, false);
10368 return true;
10369 }
10370
10371 if (!whileRestarting && r.restartDelay > 0) {
10372 // If waiting for a restart, then do nothing.
10373 return true;
10374 }
10375
10376 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10377 + " " + r.intent);
10378
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010379 // We are now bringing the service up, so no longer in the
10380 // restarting state.
10381 mRestartingServices.remove(r);
10382
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010383 final String appName = r.processName;
10384 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10385 if (app != null && app.thread != null) {
10386 try {
10387 realStartServiceLocked(r, app);
10388 return true;
10389 } catch (RemoteException e) {
10390 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10391 }
10392
10393 // If a dead object exception was thrown -- fall through to
10394 // restart the application.
10395 }
10396
10397 if (!mPendingServices.contains(r)) {
10398 // Not running -- get it started, and enqueue this service record
10399 // to be executed when the app comes up.
10400 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070010401 "service", r.name, false) == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010402 Log.w(TAG, "Unable to launch app "
10403 + r.appInfo.packageName + "/"
10404 + r.appInfo.uid + " for service "
10405 + r.intent.getIntent() + ": process is bad");
10406 bringDownServiceLocked(r, true);
10407 return false;
10408 }
10409 mPendingServices.add(r);
10410 }
10411 return true;
10412 }
10413
10414 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10415 //Log.i(TAG, "Bring down service:");
10416 //r.dump(" ");
10417
10418 // Does it still need to run?
10419 if (!force && r.startRequested) {
10420 return;
10421 }
10422 if (r.connections.size() > 0) {
10423 if (!force) {
10424 // XXX should probably keep a count of the number of auto-create
10425 // connections directly in the service.
10426 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10427 while (it.hasNext()) {
10428 ConnectionRecord cr = it.next();
10429 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10430 return;
10431 }
10432 }
10433 }
10434
10435 // Report to all of the connections that the service is no longer
10436 // available.
10437 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10438 while (it.hasNext()) {
10439 ConnectionRecord c = it.next();
10440 try {
10441 // todo: shouldn't be a synchronous call!
10442 c.conn.connected(r.name, null);
10443 } catch (Exception e) {
10444 Log.w(TAG, "Failure disconnecting service " + r.name +
10445 " to connection " + c.conn.asBinder() +
10446 " (in " + c.binding.client.processName + ")", e);
10447 }
10448 }
10449 }
10450
10451 // Tell the service that it has been unbound.
10452 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10453 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10454 while (it.hasNext()) {
10455 IntentBindRecord ibr = it.next();
10456 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10457 + ": hasBound=" + ibr.hasBound);
10458 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10459 try {
10460 bumpServiceExecutingLocked(r);
10461 updateOomAdjLocked(r.app);
10462 ibr.hasBound = false;
10463 r.app.thread.scheduleUnbindService(r,
10464 ibr.intent.getIntent());
10465 } catch (Exception e) {
10466 Log.w(TAG, "Exception when unbinding service "
10467 + r.shortName, e);
10468 serviceDoneExecutingLocked(r, true);
10469 }
10470 }
10471 }
10472 }
10473
10474 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10475 + " " + r.intent);
10476 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10477 System.identityHashCode(r), r.shortName,
10478 (r.app != null) ? r.app.pid : -1);
10479
10480 mServices.remove(r.name);
10481 mServicesByIntent.remove(r.intent);
10482 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10483 r.totalRestartCount = 0;
10484 unscheduleServiceRestartLocked(r);
10485
10486 // Also make sure it is not on the pending list.
10487 int N = mPendingServices.size();
10488 for (int i=0; i<N; i++) {
10489 if (mPendingServices.get(i) == r) {
10490 mPendingServices.remove(i);
10491 if (DEBUG_SERVICE) Log.v(
10492 TAG, "Removed pending service: " + r.shortName);
10493 i--;
10494 N--;
10495 }
10496 }
10497
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010498 r.cancelNotification();
10499 r.isForeground = false;
10500 r.foregroundId = 0;
10501 r.foregroundNoti = null;
10502
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010503 // Clear start entries.
10504 r.deliveredStarts.clear();
10505 r.pendingStarts.clear();
10506
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010507 if (r.app != null) {
10508 synchronized (r.stats.getBatteryStats()) {
10509 r.stats.stopLaunchedLocked();
10510 }
10511 r.app.services.remove(r);
10512 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010513 try {
10514 Log.i(TAG, "Stopping service: " + r.shortName);
10515 bumpServiceExecutingLocked(r);
10516 mStoppingServices.add(r);
10517 updateOomAdjLocked(r.app);
10518 r.app.thread.scheduleStopService(r);
10519 } catch (Exception e) {
10520 Log.w(TAG, "Exception when stopping service "
10521 + r.shortName, e);
10522 serviceDoneExecutingLocked(r, true);
10523 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010524 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010525 } else {
10526 if (DEBUG_SERVICE) Log.v(
10527 TAG, "Removed service that has no process: " + r.shortName);
10528 }
10529 } else {
10530 if (DEBUG_SERVICE) Log.v(
10531 TAG, "Removed service that is not running: " + r.shortName);
10532 }
10533 }
10534
10535 ComponentName startServiceLocked(IApplicationThread caller,
10536 Intent service, String resolvedType,
10537 int callingPid, int callingUid) {
10538 synchronized(this) {
10539 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10540 + " type=" + resolvedType + " args=" + service.getExtras());
10541
10542 if (caller != null) {
10543 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10544 if (callerApp == null) {
10545 throw new SecurityException(
10546 "Unable to find app for caller " + caller
10547 + " (pid=" + Binder.getCallingPid()
10548 + ") when starting service " + service);
10549 }
10550 }
10551
10552 ServiceLookupResult res =
10553 retrieveServiceLocked(service, resolvedType,
10554 callingPid, callingUid);
10555 if (res == null) {
10556 return null;
10557 }
10558 if (res.record == null) {
10559 return new ComponentName("!", res.permission != null
10560 ? res.permission : "private to package");
10561 }
10562 ServiceRecord r = res.record;
10563 if (unscheduleServiceRestartLocked(r)) {
10564 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10565 + r.shortName);
10566 }
10567 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010568 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010569 r.lastStartId++;
10570 if (r.lastStartId < 1) {
10571 r.lastStartId = 1;
10572 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010573 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010574 r.lastActivity = SystemClock.uptimeMillis();
10575 synchronized (r.stats.getBatteryStats()) {
10576 r.stats.startRunningLocked();
10577 }
10578 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10579 return new ComponentName("!", "Service process is bad");
10580 }
10581 return r.name;
10582 }
10583 }
10584
10585 public ComponentName startService(IApplicationThread caller, Intent service,
10586 String resolvedType) {
10587 // Refuse possible leaked file descriptors
10588 if (service != null && service.hasFileDescriptors() == true) {
10589 throw new IllegalArgumentException("File descriptors passed in Intent");
10590 }
10591
10592 synchronized(this) {
10593 final int callingPid = Binder.getCallingPid();
10594 final int callingUid = Binder.getCallingUid();
10595 final long origId = Binder.clearCallingIdentity();
10596 ComponentName res = startServiceLocked(caller, service,
10597 resolvedType, callingPid, callingUid);
10598 Binder.restoreCallingIdentity(origId);
10599 return res;
10600 }
10601 }
10602
10603 ComponentName startServiceInPackage(int uid,
10604 Intent service, String resolvedType) {
10605 synchronized(this) {
10606 final long origId = Binder.clearCallingIdentity();
10607 ComponentName res = startServiceLocked(null, service,
10608 resolvedType, -1, uid);
10609 Binder.restoreCallingIdentity(origId);
10610 return res;
10611 }
10612 }
10613
10614 public int stopService(IApplicationThread caller, Intent service,
10615 String resolvedType) {
10616 // Refuse possible leaked file descriptors
10617 if (service != null && service.hasFileDescriptors() == true) {
10618 throw new IllegalArgumentException("File descriptors passed in Intent");
10619 }
10620
10621 synchronized(this) {
10622 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10623 + " type=" + resolvedType);
10624
10625 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10626 if (caller != null && callerApp == null) {
10627 throw new SecurityException(
10628 "Unable to find app for caller " + caller
10629 + " (pid=" + Binder.getCallingPid()
10630 + ") when stopping service " + service);
10631 }
10632
10633 // If this service is active, make sure it is stopped.
10634 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10635 if (r != null) {
10636 if (r.record != null) {
10637 synchronized (r.record.stats.getBatteryStats()) {
10638 r.record.stats.stopRunningLocked();
10639 }
10640 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010641 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010642 final long origId = Binder.clearCallingIdentity();
10643 bringDownServiceLocked(r.record, false);
10644 Binder.restoreCallingIdentity(origId);
10645 return 1;
10646 }
10647 return -1;
10648 }
10649 }
10650
10651 return 0;
10652 }
10653
10654 public IBinder peekService(Intent service, String resolvedType) {
10655 // Refuse possible leaked file descriptors
10656 if (service != null && service.hasFileDescriptors() == true) {
10657 throw new IllegalArgumentException("File descriptors passed in Intent");
10658 }
10659
10660 IBinder ret = null;
10661
10662 synchronized(this) {
10663 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10664
10665 if (r != null) {
10666 // r.record is null if findServiceLocked() failed the caller permission check
10667 if (r.record == null) {
10668 throw new SecurityException(
10669 "Permission Denial: Accessing service " + r.record.name
10670 + " from pid=" + Binder.getCallingPid()
10671 + ", uid=" + Binder.getCallingUid()
10672 + " requires " + r.permission);
10673 }
10674 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10675 if (ib != null) {
10676 ret = ib.binder;
10677 }
10678 }
10679 }
10680
10681 return ret;
10682 }
10683
10684 public boolean stopServiceToken(ComponentName className, IBinder token,
10685 int startId) {
10686 synchronized(this) {
10687 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10688 + " " + token + " startId=" + startId);
10689 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010690 if (r != null) {
10691 if (startId >= 0) {
10692 // Asked to only stop if done with all work. Note that
10693 // to avoid leaks, we will take this as dropping all
10694 // start items up to and including this one.
10695 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10696 if (si != null) {
10697 while (r.deliveredStarts.size() > 0) {
10698 if (r.deliveredStarts.remove(0) == si) {
10699 break;
10700 }
10701 }
10702 }
10703
10704 if (r.lastStartId != startId) {
10705 return false;
10706 }
10707
10708 if (r.deliveredStarts.size() > 0) {
10709 Log.w(TAG, "stopServiceToken startId " + startId
10710 + " is last, but have " + r.deliveredStarts.size()
10711 + " remaining args");
10712 }
10713 }
10714
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010715 synchronized (r.stats.getBatteryStats()) {
10716 r.stats.stopRunningLocked();
10717 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010718 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010719 }
10720 final long origId = Binder.clearCallingIdentity();
10721 bringDownServiceLocked(r, false);
10722 Binder.restoreCallingIdentity(origId);
10723 return true;
10724 }
10725 }
10726 return false;
10727 }
10728
10729 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010730 int id, Notification notification, boolean removeNotification) {
10731 final long origId = Binder.clearCallingIdentity();
10732 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010733 synchronized(this) {
10734 ServiceRecord r = findServiceLocked(className, token);
10735 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010736 if (id != 0) {
10737 if (notification == null) {
10738 throw new IllegalArgumentException("null notification");
10739 }
10740 if (r.foregroundId != id) {
10741 r.cancelNotification();
10742 r.foregroundId = id;
10743 }
10744 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10745 r.foregroundNoti = notification;
10746 r.isForeground = true;
10747 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010748 if (r.app != null) {
10749 updateServiceForegroundLocked(r.app, true);
10750 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010751 } else {
10752 if (r.isForeground) {
10753 r.isForeground = false;
10754 if (r.app != null) {
10755 updateServiceForegroundLocked(r.app, true);
10756 }
10757 }
10758 if (removeNotification) {
10759 r.cancelNotification();
10760 r.foregroundId = 0;
10761 r.foregroundNoti = null;
10762 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010763 }
10764 }
10765 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010766 } finally {
10767 Binder.restoreCallingIdentity(origId);
10768 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010769 }
10770
10771 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10772 boolean anyForeground = false;
10773 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10774 if (sr.isForeground) {
10775 anyForeground = true;
10776 break;
10777 }
10778 }
10779 if (anyForeground != proc.foregroundServices) {
10780 proc.foregroundServices = anyForeground;
10781 if (oomAdj) {
10782 updateOomAdjLocked();
10783 }
10784 }
10785 }
10786
10787 public int bindService(IApplicationThread caller, IBinder token,
10788 Intent service, String resolvedType,
10789 IServiceConnection connection, int flags) {
10790 // Refuse possible leaked file descriptors
10791 if (service != null && service.hasFileDescriptors() == true) {
10792 throw new IllegalArgumentException("File descriptors passed in Intent");
10793 }
10794
10795 synchronized(this) {
10796 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10797 + " type=" + resolvedType + " conn=" + connection.asBinder()
10798 + " flags=0x" + Integer.toHexString(flags));
10799 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10800 if (callerApp == null) {
10801 throw new SecurityException(
10802 "Unable to find app for caller " + caller
10803 + " (pid=" + Binder.getCallingPid()
10804 + ") when binding service " + service);
10805 }
10806
10807 HistoryRecord activity = null;
10808 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010809 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010810 if (aindex < 0) {
10811 Log.w(TAG, "Binding with unknown activity: " + token);
10812 return 0;
10813 }
10814 activity = (HistoryRecord)mHistory.get(aindex);
10815 }
10816
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010817 int clientLabel = 0;
10818 PendingIntent clientIntent = null;
10819
10820 if (callerApp.info.uid == Process.SYSTEM_UID) {
10821 // Hacky kind of thing -- allow system stuff to tell us
10822 // what they are, so we can report this elsewhere for
10823 // others to know why certain services are running.
10824 try {
10825 clientIntent = (PendingIntent)service.getParcelableExtra(
10826 Intent.EXTRA_CLIENT_INTENT);
10827 } catch (RuntimeException e) {
10828 }
10829 if (clientIntent != null) {
10830 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
10831 if (clientLabel != 0) {
10832 // There are no useful extras in the intent, trash them.
10833 // System code calling with this stuff just needs to know
10834 // this will happen.
10835 service = service.cloneFilter();
10836 }
10837 }
10838 }
10839
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010840 ServiceLookupResult res =
10841 retrieveServiceLocked(service, resolvedType,
10842 Binder.getCallingPid(), Binder.getCallingUid());
10843 if (res == null) {
10844 return 0;
10845 }
10846 if (res.record == null) {
10847 return -1;
10848 }
10849 ServiceRecord s = res.record;
10850
10851 final long origId = Binder.clearCallingIdentity();
10852
10853 if (unscheduleServiceRestartLocked(s)) {
10854 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10855 + s.shortName);
10856 }
10857
10858 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10859 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010860 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010861
10862 IBinder binder = connection.asBinder();
10863 s.connections.put(binder, c);
10864 b.connections.add(c);
10865 if (activity != null) {
10866 if (activity.connections == null) {
10867 activity.connections = new HashSet<ConnectionRecord>();
10868 }
10869 activity.connections.add(c);
10870 }
10871 b.client.connections.add(c);
10872 mServiceConnections.put(binder, c);
10873
10874 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10875 s.lastActivity = SystemClock.uptimeMillis();
10876 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10877 return 0;
10878 }
10879 }
10880
10881 if (s.app != null) {
10882 // This could have made the service more important.
10883 updateOomAdjLocked(s.app);
10884 }
10885
10886 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10887 + ": received=" + b.intent.received
10888 + " apps=" + b.intent.apps.size()
10889 + " doRebind=" + b.intent.doRebind);
10890
10891 if (s.app != null && b.intent.received) {
10892 // Service is already running, so we can immediately
10893 // publish the connection.
10894 try {
10895 c.conn.connected(s.name, b.intent.binder);
10896 } catch (Exception e) {
10897 Log.w(TAG, "Failure sending service " + s.shortName
10898 + " to connection " + c.conn.asBinder()
10899 + " (in " + c.binding.client.processName + ")", e);
10900 }
10901
10902 // If this is the first app connected back to this binding,
10903 // and the service had previously asked to be told when
10904 // rebound, then do so.
10905 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10906 requestServiceBindingLocked(s, b.intent, true);
10907 }
10908 } else if (!b.intent.requested) {
10909 requestServiceBindingLocked(s, b.intent, false);
10910 }
10911
10912 Binder.restoreCallingIdentity(origId);
10913 }
10914
10915 return 1;
10916 }
10917
10918 private void removeConnectionLocked(
10919 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10920 IBinder binder = c.conn.asBinder();
10921 AppBindRecord b = c.binding;
10922 ServiceRecord s = b.service;
10923 s.connections.remove(binder);
10924 b.connections.remove(c);
10925 if (c.activity != null && c.activity != skipAct) {
10926 if (c.activity.connections != null) {
10927 c.activity.connections.remove(c);
10928 }
10929 }
10930 if (b.client != skipApp) {
10931 b.client.connections.remove(c);
10932 }
10933 mServiceConnections.remove(binder);
10934
10935 if (b.connections.size() == 0) {
10936 b.intent.apps.remove(b.client);
10937 }
10938
10939 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10940 + ": shouldUnbind=" + b.intent.hasBound);
10941 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10942 && b.intent.hasBound) {
10943 try {
10944 bumpServiceExecutingLocked(s);
10945 updateOomAdjLocked(s.app);
10946 b.intent.hasBound = false;
10947 // Assume the client doesn't want to know about a rebind;
10948 // we will deal with that later if it asks for one.
10949 b.intent.doRebind = false;
10950 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10951 } catch (Exception e) {
10952 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10953 serviceDoneExecutingLocked(s, true);
10954 }
10955 }
10956
10957 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10958 bringDownServiceLocked(s, false);
10959 }
10960 }
10961
10962 public boolean unbindService(IServiceConnection connection) {
10963 synchronized (this) {
10964 IBinder binder = connection.asBinder();
10965 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10966 ConnectionRecord r = mServiceConnections.get(binder);
10967 if (r == null) {
10968 Log.w(TAG, "Unbind failed: could not find connection for "
10969 + connection.asBinder());
10970 return false;
10971 }
10972
10973 final long origId = Binder.clearCallingIdentity();
10974
10975 removeConnectionLocked(r, null, null);
10976
10977 if (r.binding.service.app != null) {
10978 // This could have made the service less important.
10979 updateOomAdjLocked(r.binding.service.app);
10980 }
10981
10982 Binder.restoreCallingIdentity(origId);
10983 }
10984
10985 return true;
10986 }
10987
10988 public void publishService(IBinder token, Intent intent, IBinder service) {
10989 // Refuse possible leaked file descriptors
10990 if (intent != null && intent.hasFileDescriptors() == true) {
10991 throw new IllegalArgumentException("File descriptors passed in Intent");
10992 }
10993
10994 synchronized(this) {
10995 if (!(token instanceof ServiceRecord)) {
10996 throw new IllegalArgumentException("Invalid service token");
10997 }
10998 ServiceRecord r = (ServiceRecord)token;
10999
11000 final long origId = Binder.clearCallingIdentity();
11001
11002 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11003 + " " + intent + ": " + service);
11004 if (r != null) {
11005 Intent.FilterComparison filter
11006 = new Intent.FilterComparison(intent);
11007 IntentBindRecord b = r.bindings.get(filter);
11008 if (b != null && !b.received) {
11009 b.binder = service;
11010 b.requested = true;
11011 b.received = true;
11012 if (r.connections.size() > 0) {
11013 Iterator<ConnectionRecord> it
11014 = r.connections.values().iterator();
11015 while (it.hasNext()) {
11016 ConnectionRecord c = it.next();
11017 if (!filter.equals(c.binding.intent.intent)) {
11018 if (DEBUG_SERVICE) Log.v(
11019 TAG, "Not publishing to: " + c);
11020 if (DEBUG_SERVICE) Log.v(
11021 TAG, "Bound intent: " + c.binding.intent.intent);
11022 if (DEBUG_SERVICE) Log.v(
11023 TAG, "Published intent: " + intent);
11024 continue;
11025 }
11026 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11027 try {
11028 c.conn.connected(r.name, service);
11029 } catch (Exception e) {
11030 Log.w(TAG, "Failure sending service " + r.name +
11031 " to connection " + c.conn.asBinder() +
11032 " (in " + c.binding.client.processName + ")", e);
11033 }
11034 }
11035 }
11036 }
11037
11038 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11039
11040 Binder.restoreCallingIdentity(origId);
11041 }
11042 }
11043 }
11044
11045 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11046 // Refuse possible leaked file descriptors
11047 if (intent != null && intent.hasFileDescriptors() == true) {
11048 throw new IllegalArgumentException("File descriptors passed in Intent");
11049 }
11050
11051 synchronized(this) {
11052 if (!(token instanceof ServiceRecord)) {
11053 throw new IllegalArgumentException("Invalid service token");
11054 }
11055 ServiceRecord r = (ServiceRecord)token;
11056
11057 final long origId = Binder.clearCallingIdentity();
11058
11059 if (r != null) {
11060 Intent.FilterComparison filter
11061 = new Intent.FilterComparison(intent);
11062 IntentBindRecord b = r.bindings.get(filter);
11063 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11064 + " at " + b + ": apps="
11065 + (b != null ? b.apps.size() : 0));
11066 if (b != null) {
11067 if (b.apps.size() > 0) {
11068 // Applications have already bound since the last
11069 // unbind, so just rebind right here.
11070 requestServiceBindingLocked(r, b, true);
11071 } else {
11072 // Note to tell the service the next time there is
11073 // a new client.
11074 b.doRebind = true;
11075 }
11076 }
11077
11078 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11079
11080 Binder.restoreCallingIdentity(origId);
11081 }
11082 }
11083 }
11084
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011085 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011086 synchronized(this) {
11087 if (!(token instanceof ServiceRecord)) {
11088 throw new IllegalArgumentException("Invalid service token");
11089 }
11090 ServiceRecord r = (ServiceRecord)token;
11091 boolean inStopping = mStoppingServices.contains(token);
11092 if (r != null) {
11093 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11094 + ": nesting=" + r.executeNesting
11095 + ", inStopping=" + inStopping);
11096 if (r != token) {
11097 Log.w(TAG, "Done executing service " + r.name
11098 + " with incorrect token: given " + token
11099 + ", expected " + r);
11100 return;
11101 }
11102
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011103 if (type == 1) {
11104 // This is a call from a service start... take care of
11105 // book-keeping.
11106 r.callStart = true;
11107 switch (res) {
11108 case Service.START_STICKY_COMPATIBILITY:
11109 case Service.START_STICKY: {
11110 // We are done with the associated start arguments.
11111 r.findDeliveredStart(startId, true);
11112 // Don't stop if killed.
11113 r.stopIfKilled = false;
11114 break;
11115 }
11116 case Service.START_NOT_STICKY: {
11117 // We are done with the associated start arguments.
11118 r.findDeliveredStart(startId, true);
11119 if (r.lastStartId == startId) {
11120 // There is no more work, and this service
11121 // doesn't want to hang around if killed.
11122 r.stopIfKilled = true;
11123 }
11124 break;
11125 }
11126 case Service.START_REDELIVER_INTENT: {
11127 // We'll keep this item until they explicitly
11128 // call stop for it, but keep track of the fact
11129 // that it was delivered.
11130 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11131 if (si != null) {
11132 si.deliveryCount = 0;
11133 si.doneExecutingCount++;
11134 // Don't stop if killed.
11135 r.stopIfKilled = true;
11136 }
11137 break;
11138 }
11139 default:
11140 throw new IllegalArgumentException(
11141 "Unknown service start result: " + res);
11142 }
11143 if (res == Service.START_STICKY_COMPATIBILITY) {
11144 r.callStart = false;
11145 }
11146 }
11147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011148 final long origId = Binder.clearCallingIdentity();
11149 serviceDoneExecutingLocked(r, inStopping);
11150 Binder.restoreCallingIdentity(origId);
11151 } else {
11152 Log.w(TAG, "Done executing unknown service " + r.name
11153 + " with token " + token);
11154 }
11155 }
11156 }
11157
11158 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11159 r.executeNesting--;
11160 if (r.executeNesting <= 0 && r.app != null) {
11161 r.app.executingServices.remove(r);
11162 if (r.app.executingServices.size() == 0) {
11163 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11164 }
11165 if (inStopping) {
11166 mStoppingServices.remove(r);
11167 }
11168 updateOomAdjLocked(r.app);
11169 }
11170 }
11171
11172 void serviceTimeout(ProcessRecord proc) {
11173 synchronized(this) {
11174 if (proc.executingServices.size() == 0 || proc.thread == null) {
11175 return;
11176 }
11177 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11178 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11179 ServiceRecord timeout = null;
11180 long nextTime = 0;
11181 while (it.hasNext()) {
11182 ServiceRecord sr = it.next();
11183 if (sr.executingStart < maxTime) {
11184 timeout = sr;
11185 break;
11186 }
11187 if (sr.executingStart > nextTime) {
11188 nextTime = sr.executingStart;
11189 }
11190 }
11191 if (timeout != null && mLRUProcesses.contains(proc)) {
11192 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011193 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011194 + timeout.name);
11195 } else {
11196 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11197 msg.obj = proc;
11198 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11199 }
11200 }
11201 }
11202
11203 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011204 // BACKUP AND RESTORE
11205 // =========================================================
11206
11207 // Cause the target app to be launched if necessary and its backup agent
11208 // instantiated. The backup agent will invoke backupAgentCreated() on the
11209 // activity manager to announce its creation.
11210 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11211 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11212 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11213
11214 synchronized(this) {
11215 // !!! TODO: currently no check here that we're already bound
11216 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11217 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11218 synchronized (stats) {
11219 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11220 }
11221
11222 BackupRecord r = new BackupRecord(ss, app, backupMode);
11223 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11224 // startProcessLocked() returns existing proc's record if it's already running
11225 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011226 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011227 if (proc == null) {
11228 Log.e(TAG, "Unable to start backup agent process " + r);
11229 return false;
11230 }
11231
11232 r.app = proc;
11233 mBackupTarget = r;
11234 mBackupAppName = app.packageName;
11235
Christopher Tate6fa95972009-06-05 18:43:55 -070011236 // Try not to kill the process during backup
11237 updateOomAdjLocked(proc);
11238
Christopher Tate181fafa2009-05-14 11:12:14 -070011239 // If the process is already attached, schedule the creation of the backup agent now.
11240 // If it is not yet live, this will be done when it attaches to the framework.
11241 if (proc.thread != null) {
11242 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11243 try {
11244 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11245 } catch (RemoteException e) {
11246 // !!! TODO: notify the backup manager that we crashed, or rely on
11247 // death notices, or...?
11248 }
11249 } else {
11250 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11251 }
11252 // Invariants: at this point, the target app process exists and the application
11253 // is either already running or in the process of coming up. mBackupTarget and
11254 // mBackupAppName describe the app, so that when it binds back to the AM we
11255 // know that it's scheduled for a backup-agent operation.
11256 }
11257
11258 return true;
11259 }
11260
11261 // A backup agent has just come up
11262 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11263 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11264 + " = " + agent);
11265
11266 synchronized(this) {
11267 if (!agentPackageName.equals(mBackupAppName)) {
11268 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11269 return;
11270 }
11271
Christopher Tate043dadc2009-06-02 16:11:00 -070011272 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011273 try {
11274 IBackupManager bm = IBackupManager.Stub.asInterface(
11275 ServiceManager.getService(Context.BACKUP_SERVICE));
11276 bm.agentConnected(agentPackageName, agent);
11277 } catch (RemoteException e) {
11278 // can't happen; the backup manager service is local
11279 } catch (Exception e) {
11280 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11281 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011282 } finally {
11283 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011284 }
11285 }
11286 }
11287
11288 // done with this agent
11289 public void unbindBackupAgent(ApplicationInfo appInfo) {
11290 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011291 if (appInfo == null) {
11292 Log.w(TAG, "unbind backup agent for null app");
11293 return;
11294 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011295
11296 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011297 if (mBackupAppName == null) {
11298 Log.w(TAG, "Unbinding backup agent with no active backup");
11299 return;
11300 }
11301
Christopher Tate181fafa2009-05-14 11:12:14 -070011302 if (!mBackupAppName.equals(appInfo.packageName)) {
11303 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11304 return;
11305 }
11306
Christopher Tate6fa95972009-06-05 18:43:55 -070011307 ProcessRecord proc = mBackupTarget.app;
11308 mBackupTarget = null;
11309 mBackupAppName = null;
11310
11311 // Not backing this app up any more; reset its OOM adjustment
11312 updateOomAdjLocked(proc);
11313
Christopher Tatec7b31e32009-06-10 15:49:30 -070011314 // If the app crashed during backup, 'thread' will be null here
11315 if (proc.thread != null) {
11316 try {
11317 proc.thread.scheduleDestroyBackupAgent(appInfo);
11318 } catch (Exception e) {
11319 Log.e(TAG, "Exception when unbinding backup agent:");
11320 e.printStackTrace();
11321 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011322 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011323 }
11324 }
11325 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011326 // BROADCASTS
11327 // =========================================================
11328
11329 private final List getStickies(String action, IntentFilter filter,
11330 List cur) {
11331 final ContentResolver resolver = mContext.getContentResolver();
11332 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11333 if (list == null) {
11334 return cur;
11335 }
11336 int N = list.size();
11337 for (int i=0; i<N; i++) {
11338 Intent intent = list.get(i);
11339 if (filter.match(resolver, intent, true, TAG) >= 0) {
11340 if (cur == null) {
11341 cur = new ArrayList<Intent>();
11342 }
11343 cur.add(intent);
11344 }
11345 }
11346 return cur;
11347 }
11348
11349 private final void scheduleBroadcastsLocked() {
11350 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11351 + mBroadcastsScheduled);
11352
11353 if (mBroadcastsScheduled) {
11354 return;
11355 }
11356 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11357 mBroadcastsScheduled = true;
11358 }
11359
11360 public Intent registerReceiver(IApplicationThread caller,
11361 IIntentReceiver receiver, IntentFilter filter, String permission) {
11362 synchronized(this) {
11363 ProcessRecord callerApp = null;
11364 if (caller != null) {
11365 callerApp = getRecordForAppLocked(caller);
11366 if (callerApp == null) {
11367 throw new SecurityException(
11368 "Unable to find app for caller " + caller
11369 + " (pid=" + Binder.getCallingPid()
11370 + ") when registering receiver " + receiver);
11371 }
11372 }
11373
11374 List allSticky = null;
11375
11376 // Look for any matching sticky broadcasts...
11377 Iterator actions = filter.actionsIterator();
11378 if (actions != null) {
11379 while (actions.hasNext()) {
11380 String action = (String)actions.next();
11381 allSticky = getStickies(action, filter, allSticky);
11382 }
11383 } else {
11384 allSticky = getStickies(null, filter, allSticky);
11385 }
11386
11387 // The first sticky in the list is returned directly back to
11388 // the client.
11389 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11390
11391 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11392 + ": " + sticky);
11393
11394 if (receiver == null) {
11395 return sticky;
11396 }
11397
11398 ReceiverList rl
11399 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11400 if (rl == null) {
11401 rl = new ReceiverList(this, callerApp,
11402 Binder.getCallingPid(),
11403 Binder.getCallingUid(), receiver);
11404 if (rl.app != null) {
11405 rl.app.receivers.add(rl);
11406 } else {
11407 try {
11408 receiver.asBinder().linkToDeath(rl, 0);
11409 } catch (RemoteException e) {
11410 return sticky;
11411 }
11412 rl.linkedToDeath = true;
11413 }
11414 mRegisteredReceivers.put(receiver.asBinder(), rl);
11415 }
11416 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11417 rl.add(bf);
11418 if (!bf.debugCheck()) {
11419 Log.w(TAG, "==> For Dynamic broadast");
11420 }
11421 mReceiverResolver.addFilter(bf);
11422
11423 // Enqueue broadcasts for all existing stickies that match
11424 // this filter.
11425 if (allSticky != null) {
11426 ArrayList receivers = new ArrayList();
11427 receivers.add(bf);
11428
11429 int N = allSticky.size();
11430 for (int i=0; i<N; i++) {
11431 Intent intent = (Intent)allSticky.get(i);
11432 BroadcastRecord r = new BroadcastRecord(intent, null,
11433 null, -1, -1, null, receivers, null, 0, null, null,
11434 false);
11435 if (mParallelBroadcasts.size() == 0) {
11436 scheduleBroadcastsLocked();
11437 }
11438 mParallelBroadcasts.add(r);
11439 }
11440 }
11441
11442 return sticky;
11443 }
11444 }
11445
11446 public void unregisterReceiver(IIntentReceiver receiver) {
11447 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11448
11449 boolean doNext = false;
11450
11451 synchronized(this) {
11452 ReceiverList rl
11453 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11454 if (rl != null) {
11455 if (rl.curBroadcast != null) {
11456 BroadcastRecord r = rl.curBroadcast;
11457 doNext = finishReceiverLocked(
11458 receiver.asBinder(), r.resultCode, r.resultData,
11459 r.resultExtras, r.resultAbort, true);
11460 }
11461
11462 if (rl.app != null) {
11463 rl.app.receivers.remove(rl);
11464 }
11465 removeReceiverLocked(rl);
11466 if (rl.linkedToDeath) {
11467 rl.linkedToDeath = false;
11468 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11469 }
11470 }
11471 }
11472
11473 if (!doNext) {
11474 return;
11475 }
11476
11477 final long origId = Binder.clearCallingIdentity();
11478 processNextBroadcast(false);
11479 trimApplications();
11480 Binder.restoreCallingIdentity(origId);
11481 }
11482
11483 void removeReceiverLocked(ReceiverList rl) {
11484 mRegisteredReceivers.remove(rl.receiver.asBinder());
11485 int N = rl.size();
11486 for (int i=0; i<N; i++) {
11487 mReceiverResolver.removeFilter(rl.get(i));
11488 }
11489 }
11490
11491 private final int broadcastIntentLocked(ProcessRecord callerApp,
11492 String callerPackage, Intent intent, String resolvedType,
11493 IIntentReceiver resultTo, int resultCode, String resultData,
11494 Bundle map, String requiredPermission,
11495 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11496 intent = new Intent(intent);
11497
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011498 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011499 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11500 + " ordered=" + ordered);
11501 if ((resultTo != null) && !ordered) {
11502 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11503 }
11504
11505 // Handle special intents: if this broadcast is from the package
11506 // manager about a package being removed, we need to remove all of
11507 // its activities from the history stack.
11508 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11509 intent.getAction());
11510 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11511 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11512 || uidRemoved) {
11513 if (checkComponentPermission(
11514 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11515 callingPid, callingUid, -1)
11516 == PackageManager.PERMISSION_GRANTED) {
11517 if (uidRemoved) {
11518 final Bundle intentExtras = intent.getExtras();
11519 final int uid = intentExtras != null
11520 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11521 if (uid >= 0) {
11522 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11523 synchronized (bs) {
11524 bs.removeUidStatsLocked(uid);
11525 }
11526 }
11527 } else {
11528 Uri data = intent.getData();
11529 String ssp;
11530 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11531 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11532 uninstallPackageLocked(ssp,
11533 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011534 AttributeCache ac = AttributeCache.instance();
11535 if (ac != null) {
11536 ac.removePackage(ssp);
11537 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011538 }
11539 }
11540 }
11541 } else {
11542 String msg = "Permission Denial: " + intent.getAction()
11543 + " broadcast from " + callerPackage + " (pid=" + callingPid
11544 + ", uid=" + callingUid + ")"
11545 + " requires "
11546 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11547 Log.w(TAG, msg);
11548 throw new SecurityException(msg);
11549 }
11550 }
11551
11552 /*
11553 * If this is the time zone changed action, queue up a message that will reset the timezone
11554 * of all currently running processes. This message will get queued up before the broadcast
11555 * happens.
11556 */
11557 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11558 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11559 }
11560
Dianne Hackborn854060af2009-07-09 18:14:31 -070011561 /*
11562 * Prevent non-system code (defined here to be non-persistent
11563 * processes) from sending protected broadcasts.
11564 */
11565 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11566 || callingUid == Process.SHELL_UID || callingUid == 0) {
11567 // Always okay.
11568 } else if (callerApp == null || !callerApp.persistent) {
11569 try {
11570 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11571 intent.getAction())) {
11572 String msg = "Permission Denial: not allowed to send broadcast "
11573 + intent.getAction() + " from pid="
11574 + callingPid + ", uid=" + callingUid;
11575 Log.w(TAG, msg);
11576 throw new SecurityException(msg);
11577 }
11578 } catch (RemoteException e) {
11579 Log.w(TAG, "Remote exception", e);
11580 return BROADCAST_SUCCESS;
11581 }
11582 }
11583
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011584 // Add to the sticky list if requested.
11585 if (sticky) {
11586 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11587 callingPid, callingUid)
11588 != PackageManager.PERMISSION_GRANTED) {
11589 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11590 + callingPid + ", uid=" + callingUid
11591 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11592 Log.w(TAG, msg);
11593 throw new SecurityException(msg);
11594 }
11595 if (requiredPermission != null) {
11596 Log.w(TAG, "Can't broadcast sticky intent " + intent
11597 + " and enforce permission " + requiredPermission);
11598 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11599 }
11600 if (intent.getComponent() != null) {
11601 throw new SecurityException(
11602 "Sticky broadcasts can't target a specific component");
11603 }
11604 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11605 if (list == null) {
11606 list = new ArrayList<Intent>();
11607 mStickyBroadcasts.put(intent.getAction(), list);
11608 }
11609 int N = list.size();
11610 int i;
11611 for (i=0; i<N; i++) {
11612 if (intent.filterEquals(list.get(i))) {
11613 // This sticky already exists, replace it.
11614 list.set(i, new Intent(intent));
11615 break;
11616 }
11617 }
11618 if (i >= N) {
11619 list.add(new Intent(intent));
11620 }
11621 }
11622
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011623 // Figure out who all will receive this broadcast.
11624 List receivers = null;
11625 List<BroadcastFilter> registeredReceivers = null;
11626 try {
11627 if (intent.getComponent() != null) {
11628 // Broadcast is going to one specific receiver class...
11629 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011630 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011631 if (ai != null) {
11632 receivers = new ArrayList();
11633 ResolveInfo ri = new ResolveInfo();
11634 ri.activityInfo = ai;
11635 receivers.add(ri);
11636 }
11637 } else {
11638 // Need to resolve the intent to interested receivers...
11639 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11640 == 0) {
11641 receivers =
11642 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011643 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011644 }
Mihai Preda074edef2009-05-18 17:13:31 +020011645 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011646 }
11647 } catch (RemoteException ex) {
11648 // pm is in same process, this will never happen.
11649 }
11650
11651 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11652 if (!ordered && NR > 0) {
11653 // If we are not serializing this broadcast, then send the
11654 // registered receivers separately so they don't wait for the
11655 // components to be launched.
11656 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11657 callerPackage, callingPid, callingUid, requiredPermission,
11658 registeredReceivers, resultTo, resultCode, resultData, map,
11659 ordered);
11660 if (DEBUG_BROADCAST) Log.v(
11661 TAG, "Enqueueing parallel broadcast " + r
11662 + ": prev had " + mParallelBroadcasts.size());
11663 mParallelBroadcasts.add(r);
11664 scheduleBroadcastsLocked();
11665 registeredReceivers = null;
11666 NR = 0;
11667 }
11668
11669 // Merge into one list.
11670 int ir = 0;
11671 if (receivers != null) {
11672 // A special case for PACKAGE_ADDED: do not allow the package
11673 // being added to see this broadcast. This prevents them from
11674 // using this as a back door to get run as soon as they are
11675 // installed. Maybe in the future we want to have a special install
11676 // broadcast or such for apps, but we'd like to deliberately make
11677 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011678 boolean skip = false;
11679 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011680 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011681 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11682 skip = true;
11683 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11684 skip = true;
11685 }
11686 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011687 ? intent.getData().getSchemeSpecificPart()
11688 : null;
11689 if (skipPackage != null && receivers != null) {
11690 int NT = receivers.size();
11691 for (int it=0; it<NT; it++) {
11692 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11693 if (curt.activityInfo.packageName.equals(skipPackage)) {
11694 receivers.remove(it);
11695 it--;
11696 NT--;
11697 }
11698 }
11699 }
11700
11701 int NT = receivers != null ? receivers.size() : 0;
11702 int it = 0;
11703 ResolveInfo curt = null;
11704 BroadcastFilter curr = null;
11705 while (it < NT && ir < NR) {
11706 if (curt == null) {
11707 curt = (ResolveInfo)receivers.get(it);
11708 }
11709 if (curr == null) {
11710 curr = registeredReceivers.get(ir);
11711 }
11712 if (curr.getPriority() >= curt.priority) {
11713 // Insert this broadcast record into the final list.
11714 receivers.add(it, curr);
11715 ir++;
11716 curr = null;
11717 it++;
11718 NT++;
11719 } else {
11720 // Skip to the next ResolveInfo in the final list.
11721 it++;
11722 curt = null;
11723 }
11724 }
11725 }
11726 while (ir < NR) {
11727 if (receivers == null) {
11728 receivers = new ArrayList();
11729 }
11730 receivers.add(registeredReceivers.get(ir));
11731 ir++;
11732 }
11733
11734 if ((receivers != null && receivers.size() > 0)
11735 || resultTo != null) {
11736 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11737 callerPackage, callingPid, callingUid, requiredPermission,
11738 receivers, resultTo, resultCode, resultData, map, ordered);
11739 if (DEBUG_BROADCAST) Log.v(
11740 TAG, "Enqueueing ordered broadcast " + r
11741 + ": prev had " + mOrderedBroadcasts.size());
11742 if (DEBUG_BROADCAST) {
11743 int seq = r.intent.getIntExtra("seq", -1);
11744 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11745 }
11746 mOrderedBroadcasts.add(r);
11747 scheduleBroadcastsLocked();
11748 }
11749
11750 return BROADCAST_SUCCESS;
11751 }
11752
11753 public final int broadcastIntent(IApplicationThread caller,
11754 Intent intent, String resolvedType, IIntentReceiver resultTo,
11755 int resultCode, String resultData, Bundle map,
11756 String requiredPermission, boolean serialized, boolean sticky) {
11757 // Refuse possible leaked file descriptors
11758 if (intent != null && intent.hasFileDescriptors() == true) {
11759 throw new IllegalArgumentException("File descriptors passed in Intent");
11760 }
11761
11762 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011763 int flags = intent.getFlags();
11764
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011765 if (!mSystemReady) {
11766 // if the caller really truly claims to know what they're doing, go
11767 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011768 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11769 intent = new Intent(intent);
11770 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11771 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11772 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11773 + " before boot completion");
11774 throw new IllegalStateException("Cannot broadcast before boot completed");
11775 }
11776 }
11777
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011778 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
11779 throw new IllegalArgumentException(
11780 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
11781 }
11782
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011783 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11784 final int callingPid = Binder.getCallingPid();
11785 final int callingUid = Binder.getCallingUid();
11786 final long origId = Binder.clearCallingIdentity();
11787 int res = broadcastIntentLocked(callerApp,
11788 callerApp != null ? callerApp.info.packageName : null,
11789 intent, resolvedType, resultTo,
11790 resultCode, resultData, map, requiredPermission, serialized,
11791 sticky, callingPid, callingUid);
11792 Binder.restoreCallingIdentity(origId);
11793 return res;
11794 }
11795 }
11796
11797 int broadcastIntentInPackage(String packageName, int uid,
11798 Intent intent, String resolvedType, IIntentReceiver resultTo,
11799 int resultCode, String resultData, Bundle map,
11800 String requiredPermission, boolean serialized, boolean sticky) {
11801 synchronized(this) {
11802 final long origId = Binder.clearCallingIdentity();
11803 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11804 resultTo, resultCode, resultData, map, requiredPermission,
11805 serialized, sticky, -1, uid);
11806 Binder.restoreCallingIdentity(origId);
11807 return res;
11808 }
11809 }
11810
11811 public final void unbroadcastIntent(IApplicationThread caller,
11812 Intent intent) {
11813 // Refuse possible leaked file descriptors
11814 if (intent != null && intent.hasFileDescriptors() == true) {
11815 throw new IllegalArgumentException("File descriptors passed in Intent");
11816 }
11817
11818 synchronized(this) {
11819 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11820 != PackageManager.PERMISSION_GRANTED) {
11821 String msg = "Permission Denial: unbroadcastIntent() from pid="
11822 + Binder.getCallingPid()
11823 + ", uid=" + Binder.getCallingUid()
11824 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11825 Log.w(TAG, msg);
11826 throw new SecurityException(msg);
11827 }
11828 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11829 if (list != null) {
11830 int N = list.size();
11831 int i;
11832 for (i=0; i<N; i++) {
11833 if (intent.filterEquals(list.get(i))) {
11834 list.remove(i);
11835 break;
11836 }
11837 }
11838 }
11839 }
11840 }
11841
11842 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11843 String resultData, Bundle resultExtras, boolean resultAbort,
11844 boolean explicit) {
11845 if (mOrderedBroadcasts.size() == 0) {
11846 if (explicit) {
11847 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11848 }
11849 return false;
11850 }
11851 BroadcastRecord r = mOrderedBroadcasts.get(0);
11852 if (r.receiver == null) {
11853 if (explicit) {
11854 Log.w(TAG, "finishReceiver called but none active");
11855 }
11856 return false;
11857 }
11858 if (r.receiver != receiver) {
11859 Log.w(TAG, "finishReceiver called but active receiver is different");
11860 return false;
11861 }
11862 int state = r.state;
11863 r.state = r.IDLE;
11864 if (state == r.IDLE) {
11865 if (explicit) {
11866 Log.w(TAG, "finishReceiver called but state is IDLE");
11867 }
11868 }
11869 r.receiver = null;
11870 r.intent.setComponent(null);
11871 if (r.curApp != null) {
11872 r.curApp.curReceiver = null;
11873 }
11874 if (r.curFilter != null) {
11875 r.curFilter.receiverList.curBroadcast = null;
11876 }
11877 r.curFilter = null;
11878 r.curApp = null;
11879 r.curComponent = null;
11880 r.curReceiver = null;
11881 mPendingBroadcast = null;
11882
11883 r.resultCode = resultCode;
11884 r.resultData = resultData;
11885 r.resultExtras = resultExtras;
11886 r.resultAbort = resultAbort;
11887
11888 // We will process the next receiver right now if this is finishing
11889 // an app receiver (which is always asynchronous) or after we have
11890 // come back from calling a receiver.
11891 return state == BroadcastRecord.APP_RECEIVE
11892 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11893 }
11894
11895 public void finishReceiver(IBinder who, int resultCode, String resultData,
11896 Bundle resultExtras, boolean resultAbort) {
11897 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11898
11899 // Refuse possible leaked file descriptors
11900 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11901 throw new IllegalArgumentException("File descriptors passed in Bundle");
11902 }
11903
11904 boolean doNext;
11905
11906 final long origId = Binder.clearCallingIdentity();
11907
11908 synchronized(this) {
11909 doNext = finishReceiverLocked(
11910 who, resultCode, resultData, resultExtras, resultAbort, true);
11911 }
11912
11913 if (doNext) {
11914 processNextBroadcast(false);
11915 }
11916 trimApplications();
11917
11918 Binder.restoreCallingIdentity(origId);
11919 }
11920
11921 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11922 if (r.nextReceiver > 0) {
11923 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11924 if (curReceiver instanceof BroadcastFilter) {
11925 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11926 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11927 System.identityHashCode(r),
11928 r.intent.getAction(),
11929 r.nextReceiver - 1,
11930 System.identityHashCode(bf));
11931 } else {
11932 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11933 System.identityHashCode(r),
11934 r.intent.getAction(),
11935 r.nextReceiver - 1,
11936 ((ResolveInfo)curReceiver).toString());
11937 }
11938 } else {
11939 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11940 + r);
11941 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11942 System.identityHashCode(r),
11943 r.intent.getAction(),
11944 r.nextReceiver,
11945 "NONE");
11946 }
11947 }
11948
11949 private final void broadcastTimeout() {
11950 synchronized (this) {
11951 if (mOrderedBroadcasts.size() == 0) {
11952 return;
11953 }
11954 long now = SystemClock.uptimeMillis();
11955 BroadcastRecord r = mOrderedBroadcasts.get(0);
11956 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11957 if (DEBUG_BROADCAST) Log.v(TAG,
11958 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11959 + (r.startTime + BROADCAST_TIMEOUT));
11960 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11961 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11962 return;
11963 }
11964
11965 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11966 r.startTime = now;
11967 r.anrCount++;
11968
11969 // Current receiver has passed its expiration date.
11970 if (r.nextReceiver <= 0) {
11971 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11972 return;
11973 }
11974
11975 ProcessRecord app = null;
11976
11977 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11978 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11979 logBroadcastReceiverDiscard(r);
11980 if (curReceiver instanceof BroadcastFilter) {
11981 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11982 if (bf.receiverList.pid != 0
11983 && bf.receiverList.pid != MY_PID) {
11984 synchronized (this.mPidsSelfLocked) {
11985 app = this.mPidsSelfLocked.get(
11986 bf.receiverList.pid);
11987 }
11988 }
11989 } else {
11990 app = r.curApp;
11991 }
11992
11993 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011994 appNotRespondingLocked(app, null, null,
11995 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011996 }
11997
11998 if (mPendingBroadcast == r) {
11999 mPendingBroadcast = null;
12000 }
12001
12002 // Move on to the next receiver.
12003 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12004 r.resultExtras, r.resultAbort, true);
12005 scheduleBroadcastsLocked();
12006 }
12007 }
12008
12009 private final void processCurBroadcastLocked(BroadcastRecord r,
12010 ProcessRecord app) throws RemoteException {
12011 if (app.thread == null) {
12012 throw new RemoteException();
12013 }
12014 r.receiver = app.thread.asBinder();
12015 r.curApp = app;
12016 app.curReceiver = r;
12017 updateLRUListLocked(app, true);
12018
12019 // Tell the application to launch this receiver.
12020 r.intent.setComponent(r.curComponent);
12021
12022 boolean started = false;
12023 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012024 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012025 "Delivering to component " + r.curComponent
12026 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012027 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012028 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12029 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12030 started = true;
12031 } finally {
12032 if (!started) {
12033 r.receiver = null;
12034 r.curApp = null;
12035 app.curReceiver = null;
12036 }
12037 }
12038
12039 }
12040
12041 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
12042 Intent intent, int resultCode, String data,
12043 Bundle extras, boolean ordered) throws RemoteException {
12044 if (app != null && app.thread != null) {
12045 // If we have an app thread, do the call through that so it is
12046 // correctly ordered with other one-way calls.
12047 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
12048 data, extras, ordered);
12049 } else {
12050 receiver.performReceive(intent, resultCode, data, extras, ordered);
12051 }
12052 }
12053
12054 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12055 BroadcastFilter filter, boolean ordered) {
12056 boolean skip = false;
12057 if (filter.requiredPermission != null) {
12058 int perm = checkComponentPermission(filter.requiredPermission,
12059 r.callingPid, r.callingUid, -1);
12060 if (perm != PackageManager.PERMISSION_GRANTED) {
12061 Log.w(TAG, "Permission Denial: broadcasting "
12062 + r.intent.toString()
12063 + " from " + r.callerPackage + " (pid="
12064 + r.callingPid + ", uid=" + r.callingUid + ")"
12065 + " requires " + filter.requiredPermission
12066 + " due to registered receiver " + filter);
12067 skip = true;
12068 }
12069 }
12070 if (r.requiredPermission != null) {
12071 int perm = checkComponentPermission(r.requiredPermission,
12072 filter.receiverList.pid, filter.receiverList.uid, -1);
12073 if (perm != PackageManager.PERMISSION_GRANTED) {
12074 Log.w(TAG, "Permission Denial: receiving "
12075 + r.intent.toString()
12076 + " to " + filter.receiverList.app
12077 + " (pid=" + filter.receiverList.pid
12078 + ", uid=" + filter.receiverList.uid + ")"
12079 + " requires " + r.requiredPermission
12080 + " due to sender " + r.callerPackage
12081 + " (uid " + r.callingUid + ")");
12082 skip = true;
12083 }
12084 }
12085
12086 if (!skip) {
12087 // If this is not being sent as an ordered broadcast, then we
12088 // don't want to touch the fields that keep track of the current
12089 // state of ordered broadcasts.
12090 if (ordered) {
12091 r.receiver = filter.receiverList.receiver.asBinder();
12092 r.curFilter = filter;
12093 filter.receiverList.curBroadcast = r;
12094 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012095 if (filter.receiverList.app != null) {
12096 // Bump hosting application to no longer be in background
12097 // scheduling class. Note that we can't do that if there
12098 // isn't an app... but we can only be in that case for
12099 // things that directly call the IActivityManager API, which
12100 // are already core system stuff so don't matter for this.
12101 r.curApp = filter.receiverList.app;
12102 filter.receiverList.app.curReceiver = r;
12103 updateOomAdjLocked();
12104 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012105 }
12106 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012107 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012108 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012109 Log.i(TAG, "Delivering to " + filter.receiverList.app
12110 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012111 }
12112 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12113 new Intent(r.intent), r.resultCode,
12114 r.resultData, r.resultExtras, r.ordered);
12115 if (ordered) {
12116 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12117 }
12118 } catch (RemoteException e) {
12119 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12120 if (ordered) {
12121 r.receiver = null;
12122 r.curFilter = null;
12123 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012124 if (filter.receiverList.app != null) {
12125 filter.receiverList.app.curReceiver = null;
12126 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012127 }
12128 }
12129 }
12130 }
12131
12132 private final void processNextBroadcast(boolean fromMsg) {
12133 synchronized(this) {
12134 BroadcastRecord r;
12135
12136 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12137 + mParallelBroadcasts.size() + " broadcasts, "
12138 + mOrderedBroadcasts.size() + " serialized broadcasts");
12139
12140 updateCpuStats();
12141
12142 if (fromMsg) {
12143 mBroadcastsScheduled = false;
12144 }
12145
12146 // First, deliver any non-serialized broadcasts right away.
12147 while (mParallelBroadcasts.size() > 0) {
12148 r = mParallelBroadcasts.remove(0);
12149 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012150 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12151 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012152 for (int i=0; i<N; i++) {
12153 Object target = r.receivers.get(i);
12154 if (DEBUG_BROADCAST) Log.v(TAG,
12155 "Delivering non-serialized to registered "
12156 + target + ": " + r);
12157 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12158 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012159 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12160 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012161 }
12162
12163 // Now take care of the next serialized one...
12164
12165 // If we are waiting for a process to come up to handle the next
12166 // broadcast, then do nothing at this point. Just in case, we
12167 // check that the process we're waiting for still exists.
12168 if (mPendingBroadcast != null) {
12169 Log.i(TAG, "processNextBroadcast: waiting for "
12170 + mPendingBroadcast.curApp);
12171
12172 boolean isDead;
12173 synchronized (mPidsSelfLocked) {
12174 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12175 }
12176 if (!isDead) {
12177 // It's still alive, so keep waiting
12178 return;
12179 } else {
12180 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12181 + " died before responding to broadcast");
12182 mPendingBroadcast = null;
12183 }
12184 }
12185
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012186 boolean looped = false;
12187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012188 do {
12189 if (mOrderedBroadcasts.size() == 0) {
12190 // No more broadcasts pending, so all done!
12191 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012192 if (looped) {
12193 // If we had finished the last ordered broadcast, then
12194 // make sure all processes have correct oom and sched
12195 // adjustments.
12196 updateOomAdjLocked();
12197 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012198 return;
12199 }
12200 r = mOrderedBroadcasts.get(0);
12201 boolean forceReceive = false;
12202
12203 // Ensure that even if something goes awry with the timeout
12204 // detection, we catch "hung" broadcasts here, discard them,
12205 // and continue to make progress.
12206 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12207 long now = SystemClock.uptimeMillis();
12208 if (r.dispatchTime > 0) {
12209 if ((numReceivers > 0) &&
12210 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12211 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12212 + " now=" + now
12213 + " dispatchTime=" + r.dispatchTime
12214 + " startTime=" + r.startTime
12215 + " intent=" + r.intent
12216 + " numReceivers=" + numReceivers
12217 + " nextReceiver=" + r.nextReceiver
12218 + " state=" + r.state);
12219 broadcastTimeout(); // forcibly finish this broadcast
12220 forceReceive = true;
12221 r.state = BroadcastRecord.IDLE;
12222 }
12223 }
12224
12225 if (r.state != BroadcastRecord.IDLE) {
12226 if (DEBUG_BROADCAST) Log.d(TAG,
12227 "processNextBroadcast() called when not idle (state="
12228 + r.state + ")");
12229 return;
12230 }
12231
12232 if (r.receivers == null || r.nextReceiver >= numReceivers
12233 || r.resultAbort || forceReceive) {
12234 // No more receivers for this broadcast! Send the final
12235 // result if requested...
12236 if (r.resultTo != null) {
12237 try {
12238 if (DEBUG_BROADCAST) {
12239 int seq = r.intent.getIntExtra("seq", -1);
12240 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12241 + " seq=" + seq + " app=" + r.callerApp);
12242 }
12243 performReceive(r.callerApp, r.resultTo,
12244 new Intent(r.intent), r.resultCode,
12245 r.resultData, r.resultExtras, false);
12246 } catch (RemoteException e) {
12247 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12248 }
12249 }
12250
12251 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12252 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12253
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012254 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12255 + r);
12256
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012257 // ... and on to the next...
12258 mOrderedBroadcasts.remove(0);
12259 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012260 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012261 continue;
12262 }
12263 } while (r == null);
12264
12265 // Get the next receiver...
12266 int recIdx = r.nextReceiver++;
12267
12268 // Keep track of when this receiver started, and make sure there
12269 // is a timeout message pending to kill it if need be.
12270 r.startTime = SystemClock.uptimeMillis();
12271 if (recIdx == 0) {
12272 r.dispatchTime = r.startTime;
12273
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012274 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12275 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012276 if (DEBUG_BROADCAST) Log.v(TAG,
12277 "Submitting BROADCAST_TIMEOUT_MSG for "
12278 + (r.startTime + BROADCAST_TIMEOUT));
12279 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
12280 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
12281 }
12282
12283 Object nextReceiver = r.receivers.get(recIdx);
12284 if (nextReceiver instanceof BroadcastFilter) {
12285 // Simple case: this is a registered receiver who gets
12286 // a direct call.
12287 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12288 if (DEBUG_BROADCAST) Log.v(TAG,
12289 "Delivering serialized to registered "
12290 + filter + ": " + r);
12291 deliverToRegisteredReceiver(r, filter, r.ordered);
12292 if (r.receiver == null || !r.ordered) {
12293 // The receiver has already finished, so schedule to
12294 // process the next one.
12295 r.state = BroadcastRecord.IDLE;
12296 scheduleBroadcastsLocked();
12297 }
12298 return;
12299 }
12300
12301 // Hard case: need to instantiate the receiver, possibly
12302 // starting its application process to host it.
12303
12304 ResolveInfo info =
12305 (ResolveInfo)nextReceiver;
12306
12307 boolean skip = false;
12308 int perm = checkComponentPermission(info.activityInfo.permission,
12309 r.callingPid, r.callingUid,
12310 info.activityInfo.exported
12311 ? -1 : info.activityInfo.applicationInfo.uid);
12312 if (perm != PackageManager.PERMISSION_GRANTED) {
12313 Log.w(TAG, "Permission Denial: broadcasting "
12314 + r.intent.toString()
12315 + " from " + r.callerPackage + " (pid=" + r.callingPid
12316 + ", uid=" + r.callingUid + ")"
12317 + " requires " + info.activityInfo.permission
12318 + " due to receiver " + info.activityInfo.packageName
12319 + "/" + info.activityInfo.name);
12320 skip = true;
12321 }
12322 if (r.callingUid != Process.SYSTEM_UID &&
12323 r.requiredPermission != null) {
12324 try {
12325 perm = ActivityThread.getPackageManager().
12326 checkPermission(r.requiredPermission,
12327 info.activityInfo.applicationInfo.packageName);
12328 } catch (RemoteException e) {
12329 perm = PackageManager.PERMISSION_DENIED;
12330 }
12331 if (perm != PackageManager.PERMISSION_GRANTED) {
12332 Log.w(TAG, "Permission Denial: receiving "
12333 + r.intent + " to "
12334 + info.activityInfo.applicationInfo.packageName
12335 + " requires " + r.requiredPermission
12336 + " due to sender " + r.callerPackage
12337 + " (uid " + r.callingUid + ")");
12338 skip = true;
12339 }
12340 }
12341 if (r.curApp != null && r.curApp.crashing) {
12342 // If the target process is crashing, just skip it.
12343 skip = true;
12344 }
12345
12346 if (skip) {
12347 r.receiver = null;
12348 r.curFilter = null;
12349 r.state = BroadcastRecord.IDLE;
12350 scheduleBroadcastsLocked();
12351 return;
12352 }
12353
12354 r.state = BroadcastRecord.APP_RECEIVE;
12355 String targetProcess = info.activityInfo.processName;
12356 r.curComponent = new ComponentName(
12357 info.activityInfo.applicationInfo.packageName,
12358 info.activityInfo.name);
12359 r.curReceiver = info.activityInfo;
12360
12361 // Is this receiver's application already running?
12362 ProcessRecord app = getProcessRecordLocked(targetProcess,
12363 info.activityInfo.applicationInfo.uid);
12364 if (app != null && app.thread != null) {
12365 try {
12366 processCurBroadcastLocked(r, app);
12367 return;
12368 } catch (RemoteException e) {
12369 Log.w(TAG, "Exception when sending broadcast to "
12370 + r.curComponent, e);
12371 }
12372
12373 // If a dead object exception was thrown -- fall through to
12374 // restart the application.
12375 }
12376
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012377 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012378 if ((r.curApp=startProcessLocked(targetProcess,
12379 info.activityInfo.applicationInfo, true,
12380 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012381 "broadcast", r.curComponent,
12382 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12383 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012384 // Ah, this recipient is unavailable. Finish it if necessary,
12385 // and mark the broadcast record as ready for the next.
12386 Log.w(TAG, "Unable to launch app "
12387 + info.activityInfo.applicationInfo.packageName + "/"
12388 + info.activityInfo.applicationInfo.uid + " for broadcast "
12389 + r.intent + ": process is bad");
12390 logBroadcastReceiverDiscard(r);
12391 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12392 r.resultExtras, r.resultAbort, true);
12393 scheduleBroadcastsLocked();
12394 r.state = BroadcastRecord.IDLE;
12395 return;
12396 }
12397
12398 mPendingBroadcast = r;
12399 }
12400 }
12401
12402 // =========================================================
12403 // INSTRUMENTATION
12404 // =========================================================
12405
12406 public boolean startInstrumentation(ComponentName className,
12407 String profileFile, int flags, Bundle arguments,
12408 IInstrumentationWatcher watcher) {
12409 // Refuse possible leaked file descriptors
12410 if (arguments != null && arguments.hasFileDescriptors()) {
12411 throw new IllegalArgumentException("File descriptors passed in Bundle");
12412 }
12413
12414 synchronized(this) {
12415 InstrumentationInfo ii = null;
12416 ApplicationInfo ai = null;
12417 try {
12418 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012419 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012420 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012421 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012422 } catch (PackageManager.NameNotFoundException e) {
12423 }
12424 if (ii == null) {
12425 reportStartInstrumentationFailure(watcher, className,
12426 "Unable to find instrumentation info for: " + className);
12427 return false;
12428 }
12429 if (ai == null) {
12430 reportStartInstrumentationFailure(watcher, className,
12431 "Unable to find instrumentation target package: " + ii.targetPackage);
12432 return false;
12433 }
12434
12435 int match = mContext.getPackageManager().checkSignatures(
12436 ii.targetPackage, ii.packageName);
12437 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12438 String msg = "Permission Denial: starting instrumentation "
12439 + className + " from pid="
12440 + Binder.getCallingPid()
12441 + ", uid=" + Binder.getCallingPid()
12442 + " not allowed because package " + ii.packageName
12443 + " does not have a signature matching the target "
12444 + ii.targetPackage;
12445 reportStartInstrumentationFailure(watcher, className, msg);
12446 throw new SecurityException(msg);
12447 }
12448
12449 final long origId = Binder.clearCallingIdentity();
12450 uninstallPackageLocked(ii.targetPackage, -1, true);
12451 ProcessRecord app = addAppLocked(ai);
12452 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012453 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012454 app.instrumentationProfileFile = profileFile;
12455 app.instrumentationArguments = arguments;
12456 app.instrumentationWatcher = watcher;
12457 app.instrumentationResultClass = className;
12458 Binder.restoreCallingIdentity(origId);
12459 }
12460
12461 return true;
12462 }
12463
12464 /**
12465 * Report errors that occur while attempting to start Instrumentation. Always writes the
12466 * error to the logs, but if somebody is watching, send the report there too. This enables
12467 * the "am" command to report errors with more information.
12468 *
12469 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12470 * @param cn The component name of the instrumentation.
12471 * @param report The error report.
12472 */
12473 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12474 ComponentName cn, String report) {
12475 Log.w(TAG, report);
12476 try {
12477 if (watcher != null) {
12478 Bundle results = new Bundle();
12479 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12480 results.putString("Error", report);
12481 watcher.instrumentationStatus(cn, -1, results);
12482 }
12483 } catch (RemoteException e) {
12484 Log.w(TAG, e);
12485 }
12486 }
12487
12488 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12489 if (app.instrumentationWatcher != null) {
12490 try {
12491 // NOTE: IInstrumentationWatcher *must* be oneway here
12492 app.instrumentationWatcher.instrumentationFinished(
12493 app.instrumentationClass,
12494 resultCode,
12495 results);
12496 } catch (RemoteException e) {
12497 }
12498 }
12499 app.instrumentationWatcher = null;
12500 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012501 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012502 app.instrumentationProfileFile = null;
12503 app.instrumentationArguments = null;
12504
12505 uninstallPackageLocked(app.processName, -1, false);
12506 }
12507
12508 public void finishInstrumentation(IApplicationThread target,
12509 int resultCode, Bundle results) {
12510 // Refuse possible leaked file descriptors
12511 if (results != null && results.hasFileDescriptors()) {
12512 throw new IllegalArgumentException("File descriptors passed in Intent");
12513 }
12514
12515 synchronized(this) {
12516 ProcessRecord app = getRecordForAppLocked(target);
12517 if (app == null) {
12518 Log.w(TAG, "finishInstrumentation: no app for " + target);
12519 return;
12520 }
12521 final long origId = Binder.clearCallingIdentity();
12522 finishInstrumentationLocked(app, resultCode, results);
12523 Binder.restoreCallingIdentity(origId);
12524 }
12525 }
12526
12527 // =========================================================
12528 // CONFIGURATION
12529 // =========================================================
12530
12531 public ConfigurationInfo getDeviceConfigurationInfo() {
12532 ConfigurationInfo config = new ConfigurationInfo();
12533 synchronized (this) {
12534 config.reqTouchScreen = mConfiguration.touchscreen;
12535 config.reqKeyboardType = mConfiguration.keyboard;
12536 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012537 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12538 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012539 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12540 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012541 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12542 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012543 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12544 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012545 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012546 }
12547 return config;
12548 }
12549
12550 public Configuration getConfiguration() {
12551 Configuration ci;
12552 synchronized(this) {
12553 ci = new Configuration(mConfiguration);
12554 }
12555 return ci;
12556 }
12557
12558 public void updateConfiguration(Configuration values) {
12559 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12560 "updateConfiguration()");
12561
12562 synchronized(this) {
12563 if (values == null && mWindowManager != null) {
12564 // sentinel: fetch the current configuration from the window manager
12565 values = mWindowManager.computeNewConfiguration();
12566 }
12567
12568 final long origId = Binder.clearCallingIdentity();
12569 updateConfigurationLocked(values, null);
12570 Binder.restoreCallingIdentity(origId);
12571 }
12572 }
12573
12574 /**
12575 * Do either or both things: (1) change the current configuration, and (2)
12576 * make sure the given activity is running with the (now) current
12577 * configuration. Returns true if the activity has been left running, or
12578 * false if <var>starting</var> is being destroyed to match the new
12579 * configuration.
12580 */
12581 public boolean updateConfigurationLocked(Configuration values,
12582 HistoryRecord starting) {
12583 int changes = 0;
12584
12585 boolean kept = true;
12586
12587 if (values != null) {
12588 Configuration newConfig = new Configuration(mConfiguration);
12589 changes = newConfig.updateFrom(values);
12590 if (changes != 0) {
12591 if (DEBUG_SWITCH) {
12592 Log.i(TAG, "Updating configuration to: " + values);
12593 }
12594
12595 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12596
12597 if (values.locale != null) {
12598 saveLocaleLocked(values.locale,
12599 !values.locale.equals(mConfiguration.locale),
12600 values.userSetLocale);
12601 }
12602
12603 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012604 Log.i(TAG, "Config changed: " + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012605
12606 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12607 msg.obj = new Configuration(mConfiguration);
12608 mHandler.sendMessage(msg);
12609
12610 final int N = mLRUProcesses.size();
12611 for (int i=0; i<N; i++) {
12612 ProcessRecord app = mLRUProcesses.get(i);
12613 try {
12614 if (app.thread != null) {
12615 app.thread.scheduleConfigurationChanged(mConfiguration);
12616 }
12617 } catch (Exception e) {
12618 }
12619 }
12620 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12621 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12622 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012623
12624 AttributeCache ac = AttributeCache.instance();
12625 if (ac != null) {
12626 ac.updateConfiguration(mConfiguration);
12627 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012628 }
12629 }
12630
12631 if (changes != 0 && starting == null) {
12632 // If the configuration changed, and the caller is not already
12633 // in the process of starting an activity, then find the top
12634 // activity to check if its configuration needs to change.
12635 starting = topRunningActivityLocked(null);
12636 }
12637
12638 if (starting != null) {
12639 kept = ensureActivityConfigurationLocked(starting, changes);
12640 if (kept) {
12641 // If this didn't result in the starting activity being
12642 // destroyed, then we need to make sure at this point that all
12643 // other activities are made visible.
12644 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12645 + ", ensuring others are correct.");
12646 ensureActivitiesVisibleLocked(starting, changes);
12647 }
12648 }
12649
12650 return kept;
12651 }
12652
12653 private final boolean relaunchActivityLocked(HistoryRecord r,
12654 int changes, boolean andResume) {
12655 List<ResultInfo> results = null;
12656 List<Intent> newIntents = null;
12657 if (andResume) {
12658 results = r.results;
12659 newIntents = r.newIntents;
12660 }
12661 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12662 + " with results=" + results + " newIntents=" + newIntents
12663 + " andResume=" + andResume);
12664 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12665 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12666 r.task.taskId, r.shortComponentName);
12667
12668 r.startFreezingScreenLocked(r.app, 0);
12669
12670 try {
12671 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12672 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12673 changes, !andResume);
12674 // Note: don't need to call pauseIfSleepingLocked() here, because
12675 // the caller will only pass in 'andResume' if this activity is
12676 // currently resumed, which implies we aren't sleeping.
12677 } catch (RemoteException e) {
12678 return false;
12679 }
12680
12681 if (andResume) {
12682 r.results = null;
12683 r.newIntents = null;
12684 }
12685
12686 return true;
12687 }
12688
12689 /**
12690 * Make sure the given activity matches the current configuration. Returns
12691 * false if the activity had to be destroyed. Returns true if the
12692 * configuration is the same, or the activity will remain running as-is
12693 * for whatever reason. Ensures the HistoryRecord is updated with the
12694 * correct configuration and all other bookkeeping is handled.
12695 */
12696 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12697 int globalChanges) {
12698 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12699
12700 // Short circuit: if the two configurations are the exact same
12701 // object (the common case), then there is nothing to do.
12702 Configuration newConfig = mConfiguration;
12703 if (r.configuration == newConfig) {
12704 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12705 return true;
12706 }
12707
12708 // We don't worry about activities that are finishing.
12709 if (r.finishing) {
12710 if (DEBUG_SWITCH) Log.i(TAG,
12711 "Configuration doesn't matter in finishing " + r);
12712 r.stopFreezingScreenLocked(false);
12713 return true;
12714 }
12715
12716 // Okay we now are going to make this activity have the new config.
12717 // But then we need to figure out how it needs to deal with that.
12718 Configuration oldConfig = r.configuration;
12719 r.configuration = newConfig;
12720
12721 // If the activity isn't currently running, just leave the new
12722 // configuration and it will pick that up next time it starts.
12723 if (r.app == null || r.app.thread == null) {
12724 if (DEBUG_SWITCH) Log.i(TAG,
12725 "Configuration doesn't matter not running " + r);
12726 r.stopFreezingScreenLocked(false);
12727 return true;
12728 }
12729
12730 // If the activity isn't persistent, there is a chance we will
12731 // need to restart it.
12732 if (!r.persistent) {
12733
12734 // Figure out what has changed between the two configurations.
12735 int changes = oldConfig.diff(newConfig);
12736 if (DEBUG_SWITCH) {
12737 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12738 + Integer.toHexString(changes) + ", handles=0x"
12739 + Integer.toHexString(r.info.configChanges));
12740 }
12741 if ((changes&(~r.info.configChanges)) != 0) {
12742 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12743 r.configChangeFlags |= changes;
12744 r.startFreezingScreenLocked(r.app, globalChanges);
12745 if (r.app == null || r.app.thread == null) {
12746 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12747 destroyActivityLocked(r, true);
12748 } else if (r.state == ActivityState.PAUSING) {
12749 // A little annoying: we are waiting for this activity to
12750 // finish pausing. Let's not do anything now, but just
12751 // flag that it needs to be restarted when done pausing.
12752 r.configDestroy = true;
12753 return true;
12754 } else if (r.state == ActivityState.RESUMED) {
12755 // Try to optimize this case: the configuration is changing
12756 // and we need to restart the top, resumed activity.
12757 // Instead of doing the normal handshaking, just say
12758 // "restart!".
12759 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12760 relaunchActivityLocked(r, r.configChangeFlags, true);
12761 r.configChangeFlags = 0;
12762 } else {
12763 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12764 relaunchActivityLocked(r, r.configChangeFlags, false);
12765 r.configChangeFlags = 0;
12766 }
12767
12768 // All done... tell the caller we weren't able to keep this
12769 // activity around.
12770 return false;
12771 }
12772 }
12773
12774 // Default case: the activity can handle this new configuration, so
12775 // hand it over. Note that we don't need to give it the new
12776 // configuration, since we always send configuration changes to all
12777 // process when they happen so it can just use whatever configuration
12778 // it last got.
12779 if (r.app != null && r.app.thread != null) {
12780 try {
12781 r.app.thread.scheduleActivityConfigurationChanged(r);
12782 } catch (RemoteException e) {
12783 // If process died, whatever.
12784 }
12785 }
12786 r.stopFreezingScreenLocked(false);
12787
12788 return true;
12789 }
12790
12791 /**
12792 * Save the locale. You must be inside a synchronized (this) block.
12793 */
12794 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12795 if(isDiff) {
12796 SystemProperties.set("user.language", l.getLanguage());
12797 SystemProperties.set("user.region", l.getCountry());
12798 }
12799
12800 if(isPersist) {
12801 SystemProperties.set("persist.sys.language", l.getLanguage());
12802 SystemProperties.set("persist.sys.country", l.getCountry());
12803 SystemProperties.set("persist.sys.localevar", l.getVariant());
12804 }
12805 }
12806
12807 // =========================================================
12808 // LIFETIME MANAGEMENT
12809 // =========================================================
12810
12811 private final int computeOomAdjLocked(
12812 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12813 if (mAdjSeq == app.adjSeq) {
12814 // This adjustment has already been computed.
12815 return app.curAdj;
12816 }
12817
12818 if (app.thread == null) {
12819 app.adjSeq = mAdjSeq;
12820 return (app.curAdj=EMPTY_APP_ADJ);
12821 }
12822
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012823 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
12824 // The max adjustment doesn't allow this app to be anything
12825 // below foreground, so it is not worth doing work for it.
12826 app.adjType = "fixed";
12827 app.adjSeq = mAdjSeq;
12828 app.curRawAdj = app.maxAdj;
12829 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
12830 return (app.curAdj=app.maxAdj);
12831 }
12832
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070012833 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012834 app.adjSource = null;
12835 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012836
The Android Open Source Project4df24232009-03-05 14:34:35 -080012837 // Determine the importance of the process, starting with most
12838 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012839 int adj;
12840 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012841 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012842 // The last app on the list is the foreground app.
12843 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012844 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012845 } else if (app.instrumentationClass != null) {
12846 // Don't want to kill running instrumentation.
12847 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012848 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012849 } else if (app.persistentActivities > 0) {
12850 // Special persistent activities... shouldn't be used these days.
12851 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012852 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012853 } else if (app.curReceiver != null ||
12854 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12855 // An app that is currently receiving a broadcast also
12856 // counts as being in the foreground.
12857 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012858 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012859 } else if (app.executingServices.size() > 0) {
12860 // An app that is currently executing a service callback also
12861 // counts as being in the foreground.
12862 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012863 app.adjType = "exec-service";
12864 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012865 // The user is aware of this app, so make it visible.
12866 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012867 app.adjType = "foreground-service";
12868 } else if (app.forcingToForeground != null) {
12869 // The user is aware of this app, so make it visible.
12870 adj = VISIBLE_APP_ADJ;
12871 app.adjType = "force-foreground";
12872 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012873 } else if (app == mHomeProcess) {
12874 // This process is hosting what we currently consider to be the
12875 // home app, so we don't want to let it go into the background.
12876 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012877 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012878 } else if ((N=app.activities.size()) != 0) {
12879 // This app is in the background with paused activities.
12880 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012881 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012882 for (int j=0; j<N; j++) {
12883 if (((HistoryRecord)app.activities.get(j)).visible) {
12884 // This app has a visible activity!
12885 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012886 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012887 break;
12888 }
12889 }
12890 } else {
12891 // A very not-needed process.
12892 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012893 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012894 }
12895
The Android Open Source Project4df24232009-03-05 14:34:35 -080012896 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012897 // there are applications dependent on our services or providers, but
12898 // this gives us a baseline and makes sure we don't get into an
12899 // infinite recursion.
12900 app.adjSeq = mAdjSeq;
12901 app.curRawAdj = adj;
12902 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12903
Christopher Tate6fa95972009-06-05 18:43:55 -070012904 if (mBackupTarget != null && app == mBackupTarget.app) {
12905 // If possible we want to avoid killing apps while they're being backed up
12906 if (adj > BACKUP_APP_ADJ) {
12907 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12908 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012909 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070012910 }
12911 }
12912
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012913 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12914 // If this process has active services running in it, we would
12915 // like to avoid killing it unless it would prevent the current
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012916 // application from running. By default we put the process in
12917 // with the rest of the background processes; as we scan through
12918 // its services we may bump it up from there.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012919 if (adj > hiddenAdj) {
12920 adj = hiddenAdj;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070012921 app.adjType = "bg-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012922 }
12923 final long now = SystemClock.uptimeMillis();
12924 // This process is more important if the top activity is
12925 // bound to the service.
12926 Iterator jt = app.services.iterator();
12927 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12928 ServiceRecord s = (ServiceRecord)jt.next();
12929 if (s.startRequested) {
12930 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12931 // This service has seen some activity within
12932 // recent memory, so we will keep its process ahead
12933 // of the background processes.
12934 if (adj > SECONDARY_SERVER_ADJ) {
12935 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012936 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012937 }
12938 }
12939 }
12940 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12941 Iterator<ConnectionRecord> kt
12942 = s.connections.values().iterator();
12943 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12944 // XXX should compute this based on the max of
12945 // all connected clients.
12946 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012947 if (cr.binding.client == app) {
12948 // Binding to ourself is not interesting.
12949 continue;
12950 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012951 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12952 ProcessRecord client = cr.binding.client;
12953 int myHiddenAdj = hiddenAdj;
12954 if (myHiddenAdj > client.hiddenAdj) {
12955 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12956 myHiddenAdj = client.hiddenAdj;
12957 } else {
12958 myHiddenAdj = VISIBLE_APP_ADJ;
12959 }
12960 }
12961 int clientAdj = computeOomAdjLocked(
12962 client, myHiddenAdj, TOP_APP);
12963 if (adj > clientAdj) {
12964 adj = clientAdj > VISIBLE_APP_ADJ
12965 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012966 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070012967 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
12968 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012969 app.adjSource = cr.binding.client;
12970 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012971 }
12972 }
12973 HistoryRecord a = cr.activity;
12974 //if (a != null) {
12975 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12976 //}
12977 if (a != null && adj > FOREGROUND_APP_ADJ &&
12978 (a.state == ActivityState.RESUMED
12979 || a.state == ActivityState.PAUSING)) {
12980 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012981 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070012982 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
12983 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012984 app.adjSource = a;
12985 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012986 }
12987 }
12988 }
12989 }
12990 }
12991
12992 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12993 // If this process has published any content providers, then
12994 // its adjustment makes it at least as important as any of the
12995 // processes using those providers, and no less important than
12996 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12997 if (adj > CONTENT_PROVIDER_ADJ) {
12998 adj = CONTENT_PROVIDER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012999 app.adjType = "pub-providers";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013000 }
13001 Iterator jt = app.pubProviders.values().iterator();
13002 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13003 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13004 if (cpr.clients.size() != 0) {
13005 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13006 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13007 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013008 if (client == app) {
13009 // Being our own client is not interesting.
13010 continue;
13011 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013012 int myHiddenAdj = hiddenAdj;
13013 if (myHiddenAdj > client.hiddenAdj) {
13014 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13015 myHiddenAdj = client.hiddenAdj;
13016 } else {
13017 myHiddenAdj = FOREGROUND_APP_ADJ;
13018 }
13019 }
13020 int clientAdj = computeOomAdjLocked(
13021 client, myHiddenAdj, TOP_APP);
13022 if (adj > clientAdj) {
13023 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013024 ? clientAdj : FOREGROUND_APP_ADJ;
13025 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013026 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13027 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013028 app.adjSource = client;
13029 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013030 }
13031 }
13032 }
13033 // If the provider has external (non-framework) process
13034 // dependencies, ensure that its adjustment is at least
13035 // FOREGROUND_APP_ADJ.
13036 if (cpr.externals != 0) {
13037 if (adj > FOREGROUND_APP_ADJ) {
13038 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013039 app.adjType = "provider";
13040 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013041 }
13042 }
13043 }
13044 }
13045
13046 app.curRawAdj = adj;
13047
13048 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13049 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13050 if (adj > app.maxAdj) {
13051 adj = app.maxAdj;
13052 }
13053
13054 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013055 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013056 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
13057 : Process.THREAD_GROUP_DEFAULT;
13058
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013059 return adj;
13060 }
13061
13062 /**
13063 * Ask a given process to GC right now.
13064 */
13065 final void performAppGcLocked(ProcessRecord app) {
13066 try {
13067 app.lastRequestedGc = SystemClock.uptimeMillis();
13068 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013069 if (app.reportLowMemory) {
13070 app.reportLowMemory = false;
13071 app.thread.scheduleLowMemory();
13072 } else {
13073 app.thread.processInBackground();
13074 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013075 }
13076 } catch (Exception e) {
13077 // whatever.
13078 }
13079 }
13080
13081 /**
13082 * Returns true if things are idle enough to perform GCs.
13083 */
13084 private final boolean canGcNow() {
13085 return mParallelBroadcasts.size() == 0
13086 && mOrderedBroadcasts.size() == 0
13087 && (mSleeping || (mResumedActivity != null &&
13088 mResumedActivity.idle));
13089 }
13090
13091 /**
13092 * Perform GCs on all processes that are waiting for it, but only
13093 * if things are idle.
13094 */
13095 final void performAppGcsLocked() {
13096 final int N = mProcessesToGc.size();
13097 if (N <= 0) {
13098 return;
13099 }
13100 if (canGcNow()) {
13101 while (mProcessesToGc.size() > 0) {
13102 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013103 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13104 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13105 <= SystemClock.uptimeMillis()) {
13106 // To avoid spamming the system, we will GC processes one
13107 // at a time, waiting a few seconds between each.
13108 performAppGcLocked(proc);
13109 scheduleAppGcsLocked();
13110 return;
13111 } else {
13112 // It hasn't been long enough since we last GCed this
13113 // process... put it in the list to wait for its time.
13114 addProcessToGcListLocked(proc);
13115 break;
13116 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013117 }
13118 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013119
13120 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013121 }
13122 }
13123
13124 /**
13125 * If all looks good, perform GCs on all processes waiting for them.
13126 */
13127 final void performAppGcsIfAppropriateLocked() {
13128 if (canGcNow()) {
13129 performAppGcsLocked();
13130 return;
13131 }
13132 // Still not idle, wait some more.
13133 scheduleAppGcsLocked();
13134 }
13135
13136 /**
13137 * Schedule the execution of all pending app GCs.
13138 */
13139 final void scheduleAppGcsLocked() {
13140 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013141
13142 if (mProcessesToGc.size() > 0) {
13143 // Schedule a GC for the time to the next process.
13144 ProcessRecord proc = mProcessesToGc.get(0);
13145 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13146
13147 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13148 long now = SystemClock.uptimeMillis();
13149 if (when < (now+GC_TIMEOUT)) {
13150 when = now + GC_TIMEOUT;
13151 }
13152 mHandler.sendMessageAtTime(msg, when);
13153 }
13154 }
13155
13156 /**
13157 * Add a process to the array of processes waiting to be GCed. Keeps the
13158 * list in sorted order by the last GC time. The process can't already be
13159 * on the list.
13160 */
13161 final void addProcessToGcListLocked(ProcessRecord proc) {
13162 boolean added = false;
13163 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13164 if (mProcessesToGc.get(i).lastRequestedGc <
13165 proc.lastRequestedGc) {
13166 added = true;
13167 mProcessesToGc.add(i+1, proc);
13168 break;
13169 }
13170 }
13171 if (!added) {
13172 mProcessesToGc.add(0, proc);
13173 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013174 }
13175
13176 /**
13177 * Set up to ask a process to GC itself. This will either do it
13178 * immediately, or put it on the list of processes to gc the next
13179 * time things are idle.
13180 */
13181 final void scheduleAppGcLocked(ProcessRecord app) {
13182 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013183 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013184 return;
13185 }
13186 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013187 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013188 scheduleAppGcsLocked();
13189 }
13190 }
13191
13192 private final boolean updateOomAdjLocked(
13193 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13194 app.hiddenAdj = hiddenAdj;
13195
13196 if (app.thread == null) {
13197 return true;
13198 }
13199
13200 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
13201
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013202 if (app.pid != 0 && app.pid != MY_PID) {
13203 if (app.curRawAdj != app.setRawAdj) {
13204 if (app.curRawAdj > FOREGROUND_APP_ADJ
13205 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13206 // If this app is transitioning from foreground to
13207 // non-foreground, have it do a gc.
13208 scheduleAppGcLocked(app);
13209 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13210 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13211 // Likewise do a gc when an app is moving in to the
13212 // background (such as a service stopping).
13213 scheduleAppGcLocked(app);
13214 }
13215 app.setRawAdj = app.curRawAdj;
13216 }
13217 if (adj != app.setAdj) {
13218 if (Process.setOomAdj(app.pid, adj)) {
13219 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13220 TAG, "Set app " + app.processName +
13221 " oom adj to " + adj);
13222 app.setAdj = adj;
13223 } else {
13224 return false;
13225 }
13226 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013227 if (app.setSchedGroup != app.curSchedGroup) {
13228 app.setSchedGroup = app.curSchedGroup;
13229 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13230 "Setting process group of " + app.processName
13231 + " to " + app.curSchedGroup);
13232 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013233 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013234 try {
13235 Process.setProcessGroup(app.pid, app.curSchedGroup);
13236 } catch (Exception e) {
13237 Log.w(TAG, "Failed setting process group of " + app.pid
13238 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013239 e.printStackTrace();
13240 } finally {
13241 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013242 }
13243 }
13244 if (false) {
13245 if (app.thread != null) {
13246 try {
13247 app.thread.setSchedulingGroup(app.curSchedGroup);
13248 } catch (RemoteException e) {
13249 }
13250 }
13251 }
13252 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013253 }
13254
13255 return true;
13256 }
13257
13258 private final HistoryRecord resumedAppLocked() {
13259 HistoryRecord resumedActivity = mResumedActivity;
13260 if (resumedActivity == null || resumedActivity.app == null) {
13261 resumedActivity = mPausingActivity;
13262 if (resumedActivity == null || resumedActivity.app == null) {
13263 resumedActivity = topRunningActivityLocked(null);
13264 }
13265 }
13266 return resumedActivity;
13267 }
13268
13269 private final boolean updateOomAdjLocked(ProcessRecord app) {
13270 final HistoryRecord TOP_ACT = resumedAppLocked();
13271 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13272 int curAdj = app.curAdj;
13273 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13274 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13275
13276 mAdjSeq++;
13277
13278 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13279 if (res) {
13280 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13281 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13282 if (nowHidden != wasHidden) {
13283 // Changed to/from hidden state, so apps after it in the LRU
13284 // list may also be changed.
13285 updateOomAdjLocked();
13286 }
13287 }
13288 return res;
13289 }
13290
13291 private final boolean updateOomAdjLocked() {
13292 boolean didOomAdj = true;
13293 final HistoryRecord TOP_ACT = resumedAppLocked();
13294 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13295
13296 if (false) {
13297 RuntimeException e = new RuntimeException();
13298 e.fillInStackTrace();
13299 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13300 }
13301
13302 mAdjSeq++;
13303
13304 // First try updating the OOM adjustment for each of the
13305 // application processes based on their current state.
13306 int i = mLRUProcesses.size();
13307 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13308 while (i > 0) {
13309 i--;
13310 ProcessRecord app = mLRUProcesses.get(i);
13311 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13312 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13313 && app.curAdj == curHiddenAdj) {
13314 curHiddenAdj++;
13315 }
13316 } else {
13317 didOomAdj = false;
13318 }
13319 }
13320
13321 // todo: for now pretend like OOM ADJ didn't work, because things
13322 // aren't behaving as expected on Linux -- it's not killing processes.
13323 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13324 }
13325
13326 private final void trimApplications() {
13327 synchronized (this) {
13328 int i;
13329
13330 // First remove any unused application processes whose package
13331 // has been removed.
13332 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13333 final ProcessRecord app = mRemovedProcesses.get(i);
13334 if (app.activities.size() == 0
13335 && app.curReceiver == null && app.services.size() == 0) {
13336 Log.i(
13337 TAG, "Exiting empty application process "
13338 + app.processName + " ("
13339 + (app.thread != null ? app.thread.asBinder() : null)
13340 + ")\n");
13341 if (app.pid > 0 && app.pid != MY_PID) {
13342 Process.killProcess(app.pid);
13343 } else {
13344 try {
13345 app.thread.scheduleExit();
13346 } catch (Exception e) {
13347 // Ignore exceptions.
13348 }
13349 }
13350 cleanUpApplicationRecordLocked(app, false, -1);
13351 mRemovedProcesses.remove(i);
13352
13353 if (app.persistent) {
13354 if (app.persistent) {
13355 addAppLocked(app.info);
13356 }
13357 }
13358 }
13359 }
13360
13361 // Now try updating the OOM adjustment for each of the
13362 // application processes based on their current state.
13363 // If the setOomAdj() API is not supported, then go with our
13364 // back-up plan...
13365 if (!updateOomAdjLocked()) {
13366
13367 // Count how many processes are running services.
13368 int numServiceProcs = 0;
13369 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13370 final ProcessRecord app = mLRUProcesses.get(i);
13371
13372 if (app.persistent || app.services.size() != 0
13373 || app.curReceiver != null
13374 || app.persistentActivities > 0) {
13375 // Don't count processes holding services against our
13376 // maximum process count.
13377 if (localLOGV) Log.v(
13378 TAG, "Not trimming app " + app + " with services: "
13379 + app.services);
13380 numServiceProcs++;
13381 }
13382 }
13383
13384 int curMaxProcs = mProcessLimit;
13385 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13386 if (mAlwaysFinishActivities) {
13387 curMaxProcs = 1;
13388 }
13389 curMaxProcs += numServiceProcs;
13390
13391 // Quit as many processes as we can to get down to the desired
13392 // process count. First remove any processes that no longer
13393 // have activites running in them.
13394 for ( i=0;
13395 i<mLRUProcesses.size()
13396 && mLRUProcesses.size() > curMaxProcs;
13397 i++) {
13398 final ProcessRecord app = mLRUProcesses.get(i);
13399 // Quit an application only if it is not currently
13400 // running any activities.
13401 if (!app.persistent && app.activities.size() == 0
13402 && app.curReceiver == null && app.services.size() == 0) {
13403 Log.i(
13404 TAG, "Exiting empty application process "
13405 + app.processName + " ("
13406 + (app.thread != null ? app.thread.asBinder() : null)
13407 + ")\n");
13408 if (app.pid > 0 && app.pid != MY_PID) {
13409 Process.killProcess(app.pid);
13410 } else {
13411 try {
13412 app.thread.scheduleExit();
13413 } catch (Exception e) {
13414 // Ignore exceptions.
13415 }
13416 }
13417 // todo: For now we assume the application is not buggy
13418 // or evil, and will quit as a result of our request.
13419 // Eventually we need to drive this off of the death
13420 // notification, and kill the process if it takes too long.
13421 cleanUpApplicationRecordLocked(app, false, i);
13422 i--;
13423 }
13424 }
13425
13426 // If we still have too many processes, now from the least
13427 // recently used process we start finishing activities.
13428 if (Config.LOGV) Log.v(
13429 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13430 " of " + curMaxProcs + " processes");
13431 for ( i=0;
13432 i<mLRUProcesses.size()
13433 && mLRUProcesses.size() > curMaxProcs;
13434 i++) {
13435 final ProcessRecord app = mLRUProcesses.get(i);
13436 // Quit the application only if we have a state saved for
13437 // all of its activities.
13438 boolean canQuit = !app.persistent && app.curReceiver == null
13439 && app.services.size() == 0
13440 && app.persistentActivities == 0;
13441 int NUMA = app.activities.size();
13442 int j;
13443 if (Config.LOGV) Log.v(
13444 TAG, "Looking to quit " + app.processName);
13445 for (j=0; j<NUMA && canQuit; j++) {
13446 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13447 if (Config.LOGV) Log.v(
13448 TAG, " " + r.intent.getComponent().flattenToShortString()
13449 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13450 canQuit = (r.haveState || !r.stateNotNeeded)
13451 && !r.visible && r.stopped;
13452 }
13453 if (canQuit) {
13454 // Finish all of the activities, and then the app itself.
13455 for (j=0; j<NUMA; j++) {
13456 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13457 if (!r.finishing) {
13458 destroyActivityLocked(r, false);
13459 }
13460 r.resultTo = null;
13461 }
13462 Log.i(TAG, "Exiting application process "
13463 + app.processName + " ("
13464 + (app.thread != null ? app.thread.asBinder() : null)
13465 + ")\n");
13466 if (app.pid > 0 && app.pid != MY_PID) {
13467 Process.killProcess(app.pid);
13468 } else {
13469 try {
13470 app.thread.scheduleExit();
13471 } catch (Exception e) {
13472 // Ignore exceptions.
13473 }
13474 }
13475 // todo: For now we assume the application is not buggy
13476 // or evil, and will quit as a result of our request.
13477 // Eventually we need to drive this off of the death
13478 // notification, and kill the process if it takes too long.
13479 cleanUpApplicationRecordLocked(app, false, i);
13480 i--;
13481 //dump();
13482 }
13483 }
13484
13485 }
13486
13487 int curMaxActivities = MAX_ACTIVITIES;
13488 if (mAlwaysFinishActivities) {
13489 curMaxActivities = 1;
13490 }
13491
13492 // Finally, if there are too many activities now running, try to
13493 // finish as many as we can to get back down to the limit.
13494 for ( i=0;
13495 i<mLRUActivities.size()
13496 && mLRUActivities.size() > curMaxActivities;
13497 i++) {
13498 final HistoryRecord r
13499 = (HistoryRecord)mLRUActivities.get(i);
13500
13501 // We can finish this one if we have its icicle saved and
13502 // it is not persistent.
13503 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13504 && r.stopped && !r.persistent && !r.finishing) {
13505 final int origSize = mLRUActivities.size();
13506 destroyActivityLocked(r, true);
13507
13508 // This will remove it from the LRU list, so keep
13509 // our index at the same value. Note that this check to
13510 // see if the size changes is just paranoia -- if
13511 // something unexpected happens, we don't want to end up
13512 // in an infinite loop.
13513 if (origSize > mLRUActivities.size()) {
13514 i--;
13515 }
13516 }
13517 }
13518 }
13519 }
13520
13521 /** This method sends the specified signal to each of the persistent apps */
13522 public void signalPersistentProcesses(int sig) throws RemoteException {
13523 if (sig != Process.SIGNAL_USR1) {
13524 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13525 }
13526
13527 synchronized (this) {
13528 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13529 != PackageManager.PERMISSION_GRANTED) {
13530 throw new SecurityException("Requires permission "
13531 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13532 }
13533
13534 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13535 ProcessRecord r = mLRUProcesses.get(i);
13536 if (r.thread != null && r.persistent) {
13537 Process.sendSignal(r.pid, sig);
13538 }
13539 }
13540 }
13541 }
13542
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013543 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013544 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013545
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013546 try {
13547 synchronized (this) {
13548 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13549 // its own permission.
13550 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13551 != PackageManager.PERMISSION_GRANTED) {
13552 throw new SecurityException("Requires permission "
13553 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013554 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013555
13556 if (start && fd == null) {
13557 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013558 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013559
13560 ProcessRecord proc = null;
13561 try {
13562 int pid = Integer.parseInt(process);
13563 synchronized (mPidsSelfLocked) {
13564 proc = mPidsSelfLocked.get(pid);
13565 }
13566 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013567 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013568
13569 if (proc == null) {
13570 HashMap<String, SparseArray<ProcessRecord>> all
13571 = mProcessNames.getMap();
13572 SparseArray<ProcessRecord> procs = all.get(process);
13573 if (procs != null && procs.size() > 0) {
13574 proc = procs.valueAt(0);
13575 }
13576 }
13577
13578 if (proc == null || proc.thread == null) {
13579 throw new IllegalArgumentException("Unknown process: " + process);
13580 }
13581
13582 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13583 if (isSecure) {
13584 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13585 throw new SecurityException("Process not debuggable: " + proc);
13586 }
13587 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013588
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013589 proc.thread.profilerControl(start, path, fd);
13590 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013591 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013592 }
13593 } catch (RemoteException e) {
13594 throw new IllegalStateException("Process disappeared");
13595 } finally {
13596 if (fd != null) {
13597 try {
13598 fd.close();
13599 } catch (IOException e) {
13600 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013601 }
13602 }
13603 }
13604
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013605 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13606 public void monitor() {
13607 synchronized (this) { }
13608 }
13609}